In diesem Beitrag möchte ich euch zeigen, wie ihr einen Tasksequenzschritt, in einer Tasksequenz über Powershell verändern könnt.
Was ist zu tun?
- Bestehende Tasksequenz laden (Get-CMTaskSequence)
- IResultObject “TaskSequence” aus dem TaskSequencePackage ziehen
- Existierenden Tasksequenzschritt aus der Tasksequenz heraussuchen und Werte ändern.
- Speichern der Änderungen
Wenn ihr meinen ersten Beitrag hierzu kennt, kommen euch die Schritte sicher bekannt vor. Wenn nicht, schaut ihn euch ggf. noch einmal an, denn ich werde hier nur auf den Punkt 3. näher eingehen 🙂 Bestehende Tasksequenz über Powershell editieren.
Im Unterschied zum Hinzufügen eines neuen Tasksequence Step, werden wir die bestehenden Tasksequenz zunächst nach dem Schritt durchsuchen, den wir ändern wollen.
Wir haben uns also die Tasksequenz ($taskSequence) aus dem Task Sequence Package extrahiert, ziehen uns im nächsten Schritt die Liste der Tasksequenzschritte heraus ($taskSequence.GetArrayItems(“Steps”)) und speichern diese in einer lokalen Variable ($taskSequenceSteps).
#1 Liste der Tasksequenzschritte SMS_TaskSequence_Steps aus der Tasksequenz holen. $taskSequenceSteps = $taskSequence.GetArrayItems("Steps")
Als nächstes suchen wir unseren Schritt aus der Liste heraus, den wir ändern möchten. Das machen wir über eine foreach-Schleife, in dem für jeden Schritt, das Attribute Name mit dem gesuchten Wert vergleichen ($step.Name -eq $ExistingTasksequenceStepName). In meinem Beispiel habe ich den Namen in der Variable $ExistingTaskSequenceStepName gespeichert.
#2 Suche nach dem gewünschten TaskSequenceStep foreach ($step in $taskSequenceSteps) { #3 Vergleiche den "Schritt"-Namen, mit dem Suchbegriff if (($step -ne $null) -and ($step.Name -eq $ExistingTaskSequenceStepName)) { #4 Ändern der Werte ... } }
Ok, damit haben wir also den gewünschten Tasksequenzschritte gefunden und können die gewünschte Änderung durchführen. Dazu ändern wir einfach die gewünschten Attribute des Tasksequenzschrittes ab:
#4 Ändern der Werte # Bspw.: "SMS_TaskSequence_RunCommandLineAction" $step.Name = "Edited Name"; $step.CommandLine = "cmd /c echo 'hello world' >> test.txt"; # .. setzen weiterer Attribute
Hierzu noch ein kleiner Hinweis:
Die TasksequenceSteps werden zunächst als einheitlicher Objecttyp geladen, sind aber grundsätzlich spezifisch typisiert durch Ihre Klasse. Abhängig davon, welchen Schritt ihr euch zum Ändern ausgesucht habt, hat dieser unterschiedliche Attribute. Um Laufzeitfehler zu vermeiden, solltet ihr zunächst prüfen, ob ihr auch den richtigen ObjectTyp vor euch habt, bevor ihr beginnt auf Attribute zu verweisen, die vielleicht bei diesem Step gar nicht vorhanden sind. Mehr dazu findet ihr im Anhang.
Sind alle Änderungen durchgeführt, schreiben wir die veränderte Liste der Tasksequenzschritte zurück in die Tasksequenz ($taskSequence.SetArrayItems(“Steps”, $taskSequenceSteps) und speichern das $taskSequencePackage. Die Detaillierten Schritte hierzu findet ihr in meinem ersten Beitrag: Bestehende Tasksequenz über Powershell editieren.
#6 Die veränderte Liste wieder zurück in das Tasksequenz Object schreiben. $taskSequence.SetArrayItems("Steps", $taskSequenceSteps); #7 Speichern der Änderungen "SetSequence" # prepare parameters for "SetSequence" # .. # Schaut euch hier den ersten Beitrag an, Punkt 5. Speichern der Änderungen $taskSequencePackage.ConnectionManager.ExecuteMethod("SMS_TaskSequencePackage", "SetSequence", $methodParams);
That’s it! 😉
Viel Spass beim Ausprobieren!
Anhang:
Wie im Beitrag kurz erwähnt, werden die TasksequenceSteps zunächst als einheitlicher Objecttyp geladen, sind aber grundsätzlich spezifisch typisiert. Um Fehlern vorzubeugen, könntet ihr Klasse des jeweiligen TaskSequenceSteps im Vorfeld überprüfen.
Die Prüfung könnt ihr bspw. über das Attribute $step.SmsProviderObjectPath durchführen. Das Attribute enthält den Wert der WMI Class also bspw. “SMS_TaskSequence_RunCommandLineAction“, den ihr auch mit dem Klassennamen (String) vergleichen könnt.
Möchte ich bspw. einen RunCommandLine-Schritt anpassen, prüfen ich zunächst auf die Klasse und kann dann direkt auf die Attribute, wie Name oder CommandLine zugreifen:
#4 Prüfen ob Quell- und Zielobject vom gleichen Typ sind (bspw. "SMS_TaskSequence_RunCommandLineAction") if ($step.SmsProviderObjectPath -eq "SMS_TaskSequence_RunCommandLineAction") { # Bspw.: "SMS_TaskSequence_RunCommandLineAction" $step.Name = "Edited Name"; $step.CommandLine = "cmd /c echo 'hello world' >> test.txt"; }
Gut, es ist natürlich etwas aufwendiger, die Prüfung für jeden einzelnen Schritt einzubauen, aber besser als Laufzeitfehler, hm?
Ein kleiner Tipp! Ihr könntet euch eine Funktion schreiben, die anstelle der einzelnen Attribute, einen neuen TasksequenceStep als Parameter akzeptiert und einfach beide SmsProviderObjectPath Werte miteinander vergleichen..
$NewTaskSequenceStep = ([WMICLASS] "\\$($SITESERVER)\ROOT\SMS\SITE_$($SITECODE):SMS_TaskSequenceRunCommandLineAction").CreateInstance(); # .. setzen der Attribute # $NewTaskSequenceStep.Name = "Edited Name"; # $NewTaskSequenceStep.CommandLine = "cmd /c echo 'hello world' >> test.txt"; #4 Prüfen ob Quell- und Zielobject vom gleichen Typ sind (bspw. "SMS_TaskSequence_RunCommandLineAction") if ($step.SmsProviderObjectPath -eq $NewTaskSequenceStep.SmsProviderObjectPath) { $step.Name = $NewTaskSequenceStep.Name; $step.CommandLine = NewTaskSequenceStep.CommandLine; # .. weitere Attribute }
Besser? Nein, eigentlich nicht, denn die Attribute selbst, sind immer noch nicht dynamisch und das Script würde im Zweifelsfalle wieder in einen Fehler laufen, wenn wir bspw. die WMI Klasse SMS_TaskSequenceApplyOperatingSystemAction für den neuen Tasksequenzschritt nutzen würden.
Eine Lösung wäre, die Attributliste abhängig der WMI Klasse abzurufen und die Werte vom neuen Schritt, auf den bestehenden übertragen?!
Zum Beispiel so:
#4 Prüfen ob Quell- und Zielobject vom gleichen Typ sind (bspw. "SMS_TaskSequence_RunCommandLineAction") if ($step.SmsProviderObjectPath -eq "SMS_TaskSequence_RunCommandLineAction") { #5 Alle Werte (Properties) der Quelle, durch die neuen ersetzen. foreach($propName in $step.PropertyNames) { # beim Auslesen, Setzen der Werte müsst ihr prüfen welchen DatenTyp der Wert hat und mit der entsprechenden Funktion, den Wert auslsesen bzw. setzen # bspw. für Name # $value = $NewTaskSequenceStep["Name"].StringValue; # $step["Name"].StringValue = $value; # $step["ContinueOnError"].BooleanValue = $true; # # Da es abhängig vom Property-DataType ist, habe ich mir hierfür zwei Funktionen geschrieben GetPropertyValue, SetPropertyValue # GetPropertyValue liest den Wert entsprechend des DataType ($value = $property.StringValue, .. = $property.IntegerValue, etc. $value = GetPropertyValue -resultObject $NewTaskSequenceStep -propertyName $propName # SetPropertyValue setzt den Wert entsprechend des DataType ($property.StringValue = $value, property.IntegerValue = .., etc.) $step = SetPropertyValue -resultObject $step -propertyName $propName -value $value } }
Als kleine Challenge! Für die Funktionen GetPropertyValue, SetPropertyValue seid ihr gefragt. 😉
Viel Spass beim Scripten!