Skip to the main content.

ScriptRunner Blog

Flexible SCCM Task Sequence mit PowerShell

In Kundenprojekten mit System Center Configuration Manager steht man vor der Herausforderung, Task Sequences flexibel zu gestalten. Im Kern bedeutet das, dass sich eine SCCM-Task Sequenz ändern können sollte.

Post Featured Image

Dies wird nachfolgend an einem Praxisbeispiel dargestellt. Die betreffende Task Sequenz sollte für ca. 350 Applications eingesetzt werden, so dass bei jeder Änderung (Application A rein, Application B raus, Application C ersetzen…) ein entsprechender manueller Aufwand notwendig war. Der Prozess konnte automatisiert werden, in dem die Änderungen mit Powershell durchgeführt werden. Ein Großkunde im Bankenumfeld realisiert das mit ScriptRunner.

 

Es wurde dazu ein Task-Sequenz Template angelegt, in dem alle Schritte enthalten sind, die sich nie, oder nur sehr selten ändern (Task-Sequenz Variablen, .NET Installer, Patches etc.). Dieses Template wird vom Script kopiert und die Kopie wird mit dem kompletten neu zu verwendenden Releasedaten befüllt. Die Releasedaten sind im konkreten Fall in einer Text-Datei mit allen Applikationsparametern enthalten und bereits mit dem korrekten Namen aus dem SCCM Application Model versehen.

Zum Script im Einzelnen

Zunächst das ConfigMgr Powershell Modul laden:

Import modules ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + ‘ConfigurationManager.psd1’)

Um die bestehende Sequenz, also das Template, zu kopieren wird folgende PowerShell-Funktion verwendet:

function duplicate_tasksequence ($origTSName,$newTSName) {
try{
		$ns_root = “ROOTSMSSite_$sitecode”
		$origTSPkg = GWMI -ComputerName $siteServer -Namespace $ns_root -Class “SMS_TaskSequencePackage” -Filter “Name=’$origTSName'”” “SMS_TaskSequencePackage”.

# check if template exists

if ($origTSPkg.PackageID -ne “”){
		Write-Host “Template FOUND!” -ForegroundColor Green
		$methodTSPkgName = “SMS_TaskSequencePackage”
		$mc = [WMIClass]”$($ns_root):$($methodTSPkgName)”
		$inParamsGet = $mc.psbase.GetMethodParameters(“GetSequence”)
		$inParamsGet.TaskSequencePackage = $origTSPkg
		$outParamsGet = $mc.psbase.InvokeMethod(“GetSequence”,$inparamsGet,$null)
		$newTS = $outParamsGet.TaskSequence
		$newTSPkg = ([WMIClass]”$($ns_root):$($methodTSPkgName)”).CreateInstance()
		$newTSPkgID = $newTSPkg.PackageID
		$newTSPkg = $origTSPkg
		$newTSPkg.name = $newTSName
		$newTSPkg.PackageID = $newTSPkgID
		$inParamsSet = $mc.psbase.GetMethodParameters(“SetSequence”)
-==- proudly presents
		$inParamsSet.TaskSequencePackage = $newTSPkg
		$outParamsSet = $mc.psbase.InvokeMethod(“SetSequence”,$inParamsSet,$null)
		$ntsPkg = GWMI -ComputerName $siteServer -Namespace $ns_root -Class “SMS_TaskSequencePackage” | where { $outParamsSet.SavedTaskSequencePackagePath.Contains($_.PackageID)}
		return $ntsPkg.PackageID
		}
else{
		return “”
		}
}
catch{
		return $null;
		}
}

Quelle Technet 

Der Aufruf der Funktion erzeugt eine neue Task Sequence aus dem Template:

$newSequence = duplicate_tasksequence "$TSTemplate" "$TargetTS"

Anschließend wird das Objekt der neuen Sequenz zum Bearbeiten via Get-CMTaskSequence geladen:

$CMTS = Get-CMTaskSequence -Name $TargetTS

Das Objekt $CMTS enthält nun die komplette Sequenz mit allen Schritten. Get-CMTaskSequence liefert ein Objekt vom Typ Microsoft.ConfigurationManagement.ManagementProvider.IResultObject zurück, mit dessen ConnectionManager-Property die Sequenz im Folgenden weiter bearbeitet werden kann.

Hinweis: Alle Schritte in der Sequenz müssen als IResultObject hinzugefügt bzw. zurückgeliefert werden.

Mit der Methode GetSequence lässt sich die Task-Sequenz nun bearbeiten:


$Parameters = New-Object “System.Collections.Generic.Dictionary[string, object]”
$Parameters.Add(“TaskSequencePackage”,$CMTS)
$TSmethod =$CMTS.ConnectionManager.ExecuteMethod(“SMS_TaskSequencePackage”, “GetSequence”, $Parameters)
$TaskSequence = $TSmethod.GetSingleItem(“TaskSequence”)

Nun haben wir die Sequenz über das ConnectionManager-Property in einer $TaskSequence Variable, mit welcher Schritte hinzugefügt werden können.

Wir definieren den neuen Schritt, den wir hinzufügen möchten, als „Install Application Action“ über den Connection Manager, der bereits verwendet wurde:

$newStep = $CMTS.ConnectionManager.CreateEmbeddedObjectInstance("SMS_TaskSequence_InstallApplicationAction")

Mit einer „For-Each“-Schleife wird jede Applikation ein einzelner Schritt erzeugt:


foreach ($app in $Applications){
		$appName= (Get-CMApplication -Name $app)
		$newStep.Name = “$app”
		$newStep.ApplicationName = $appName.ModelName
		if( $appName.LocalizedDisplayName -eq $null){ #Error Handling – If App is not available in SCCM Site -> EXIT
				Write-Host “NOT FOUND: $app — PLEASE ADD THE APPLICATION TO SCCM SITE $SiteCode” -ForegroundColor Red
				Exit
}

$appName ist die eigentliche Applikation, die mit dem Namen im Textfile matcht. Dem Schritt „Install Application“ wird ebenfalls der Name der Applikation gegeben.

Hinweis: Hier muss man aufpassen, da die GUI nur 40 Zeichen für einen Schrittnamen vergeben kann, das Powershell-Script hat hier jedoch keine Begrenzung. Längere Namen führen nicht dazu, dass die Sequenz nicht mehr funktioniert, aber sie können später nicht mehr in der GUI bearbeitet werden.

Um die Application auszuwählen, die wir dem Schritt hinzufügen wollen, brauchen wir die eindeutige Application ID (ScopeID). Diese befindet sich im Objekt ModelName.

Nun wurde der Schritt im Wesentlichen beschrieben:

  • Der Typ wurde definiert (SMS_TaskSequence_InstallApplicationAction)
  • Der Name wurde definiert ($app, also der Name aus dem Textfile)
  • Die Application wurde mittels ScopeID definiert

Der Schritt hat noch weitere Objekte und Optionen, die hier der Übersichtlichkeit wegen nicht genutzt werden. Eine sehr interessante Option ist sicher ContinueOnError

Mit der Zeile $newStep.ContinueOnError = „true“ würde in SCCM also der Haken bei „Continue on Error“ gesetzt. Bei der Nutzung in der „For-Each“-Schleife würde das aber auf jeden Schritt zutreffen – was in produktiven Sequenzen etwas unschön oder unerwünscht ist.

Nachdem so eine größere Menge an Schritten erzeugt wurde, werden diese in einem generierten Array gespeichert und einer Task-Sequenz Gruppe zugeordnet. Im Beispiel heißt diese Gruppe APPLICATIONS. Dazu wird die Gruppe einfach mit ihrer laufenden Nummer angesprochen (angefangen bei 0, wobei 0 keine Gruppe bedeutet.):

$TaskSequenceSteps = $TaskSequence.GetArrayItems(“Steps”)
$TaskSequenceSteps = $TaskSequence.GetArrayItems(“Steps”)
$GroupSteps = $TaskSequenceSteps[1].GetArrayItems(“Steps”)
$GroupSteps.Add($newStep);

# Write array into sequence

$TaskSequenceSteps[1].SetArrayItems(“Steps”, $GroupSteps);
$TaskSequence.SetArrayItems(“Steps”, $taskSequenceSteps);
}

Man wählt also die  Gruppe 1 aus und fügt die Schritte aus dem Array dieser Gruppe zu.

Nun muss die Task-Sequenz noch gespeichert bzw. zurückgeschrieben werden. Das geht auf demselben Wege wie das „öffnen“ der Sequenz:

$Parameters = New-Object “System.Collections.Generic.Dictionary[string, object]”
$Parameters.Add(“TaskSequence”, $TaskSequence)
$Parameters.Add(“TaskSequencePackage”, $CMTS)
$TSmethod = $CMTS.ConnectionManager.ExecuteMethod(“SMS_TaskSequencePackage”,”SetSequence”, $Parameters)

Das Template vor dem Script

Die neue Sequenz nach dem Script

Erweitern Sie ScriptRunner um ScriptRunner Connectoren und integrieren Sie Ihr Monitoring-, IT-Service-Management-, Ticket-, Rights-Management-System u. a. zur Schaffung vollautomatisierter Regelkreisläufe in Ihrem IT-Betrieb.

 

Zusammenhängende Posts

5 min read

Microsoft Exchange mit PowerShell managen

2 min read

VMUG Webcast: VMware Management meistern mit PowerCLI

Über den Autor: