Skip to the main content.

ScriptRunner Blog

Flexible SCCM Task Sequence with PowerShell

In customer projects with System Center Configuration Manager, the challenge is to design task sequences flexibly. In essence, this means that an SCCM task sequence should be able to change.

Post Featured Image

This is illustrated in the following by a practical example. The respective task sequence should be used for approx. 350 applications, so that with each change (Application A in, Application B out, Application C out…) a corresponding manual effort was necessary. The process could be automated by making the changes with Powershell. A major customer in the banking sector realizes this with ScriptRunner.

 

For this purpose a task sequence template was created, which contains all steps that never or only very rarely change (task sequence variables, .NET installer, patches etc.). This template is copied from the script and the copy is filled with the complete new release data to be used. In this specific case, the release data is contained in a text file with all application parameters and already provided with the correct name from the SCCM Application Model.

To the script in detail

First load the ConfigMgr Powershell module:

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

The following PowerShell function is used to copy the existing sequence, the template:

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;
		}
}

Source Technet

Calling the function creates a new task sequence from the template:

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

Then the object of the new sequence is loaded for editing via Get-CMTaskSequenz:

$CMTS = Get-CMTaskSequence -Name $TargetTS

The object $CMTS now contains the complete sequence with all steps. Get-CMTaskSequence returns an object of type Microsoft.ConfigurationManagement.ManagementProvider.IResultObject whose ConnectionManager property can be used to further edit the sequence below.

Note: All steps in the sequence must be added or returned as IResultObject.

The GetSequence method can now be used to edit the task sequence:

$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”)

Now we have the sequence about the ConnectionManager-Property in a$TaskSequence variable, with which steps can be added.

We define the new step we want to add as “Install Application Action” via the Connection Manager that has already been used:

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

With a “For-Each” loop, each application is created as a single step:
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 is the actual application that matches the name in the text file. The step “Install Application” is also given the name of the application.

Note: You have to be careful here, as the GUI can only assign 40 characters for a step name, but the Powershell script has no limit here. Longer names do not cause the sequence to stop working, but they cannot be edited later in the GUI.

To select the application we want to add to the step, we need the unique Application ID (ScopeID). This is located in the ModelName object.

Now the main part of the step has been described:

  • The type was defined (SMS_TaskSequence_InstallApplicationAction)
  • The name was defined ($app, i.e. the name from the text file)
  • The application was defined using ScopeID.

The step has more objects and options that are not used here for clarity.

A very interesting option is surely ContinueOnErrorWith

the line$newStep.ContinueOnError = “true” in SCCM the check mark at “Continue on Error” would be set. When used in the “For-Each” loop, however, this would apply to every step – which is somewhat unattractive or undesirable in productive sequences.

After many steps have been created, they are stored in a generated array and assigned to a task sequence group. In the example, this group is called APPLICATIONS.

To do this, the group is simply addressed with its sequential number (starting with 0, where 0 means no group):

$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);
}

So you select group 1 and add the steps from the array to that group.

Now the task sequence has to be saved or written back. This is done in the same way as “opening” the sequence:

$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)

The template before the script

Template before the script

The new sequence after the script

New sequence after the script

Extend ScriptRunner with ScriptRunner Connectors and integrate your monitoring, IT service management, ticket, rights management system, etc. to create fully automated control loops in your IT operations.

 

Related posts

2 min read

VMUG Webcast: Mastering VMware Management with PowerCLI

3 min read

Automate your spring cleaning with PowerShell

5 min read

Mastering PowerShell with Get-Help

About the author: