I’ve written about this topic previously and also written a small PowerShell based tool to help administrators ease the pain of rerunning a task sequence. Recently, while developing a solution for a Windows 10 servicing project I needed a solution to rerun a task sequence at a given time. My previous solution consisted of removing the WMI object referring to the schedule for the task sequence deployment and restart the ConfigMgr client forcing it to pull down policies and check against it’s local policy and re-running the deployment.

Given this method is a well known and working one, I wanted to explore if there was a way where I did not have to restart the ConfigMgr client, and simply enforce the task sequence to run straight away.

Modifying the assignment

It may not be known by every ConfigMgr admin, but many of us know that the ConfigMgr client keeps track of it’s policy locally in WMI, more specifically in the root\ccm\policy\machine\actualconfig you can explore the different set of policies that’s currently in effect. Within a class named CCM_TaskSequence, there exists an instance of each advertisement for task sequences. Each instance has two properties that we need to be aware of:

  • ADV_MandatoryAssignments
  • ADV_RepeatRunBehavior

With this in mind, we can take advantage of these two properties and directly change the local policy and set it as mandatory and always rerun, even if that was not the original configuration made in the ConfigMgr console when it was deployed. This will help us mimic the behavior required for our goal of re-running a task sequence deployment (previously known as assignment back in the days).  However, there’s one last piece of the puzzle we’ve not been talking about yet and that’s the requirements of triggering the schedule for the task sequence deployment. For this, we require PackageID for the task sequence located in a class named CCM_SoftwareDistribution. With the PackageID property known to us, we can determine the correct ScheduleID from a class named CCM_Scheduler_History located in the namespace of root\ccm\scheduler. Finally with the ScheduleID value at hand, we can invoke the TriggerSchedule method from a class named SMS_Client located in the namespace of root\ccm.

Sample code

Below are the code that will accomplish our goal, re-running a task sequence deployment on a ConfigMgr client using PowerShell:

# Retrieve the name of the task sequence that should be executed
$TaskSequenceName = "Windows 10 Enterprise 1809 x64 - Upgrade Sequence"

# Retrieve the PackageID and AdvertisementID from the machine actual policy
$SoftwareDistributionPolicy = Get-WmiObject -Namespace "root\ccm\policy\machine\actualconfig" -Class "CCM_SoftwareDistribution" | Where-Object { $_.PKG_Name -like $TaskSequenceName } | Select-Object -Property PKG_PackageID, ADV_AdvertisementID

# Retrieve the ScheduleID used for triggering a new required assignment for task sequence
$ScheduleID = Get-WmiObject -Namespace "root\ccm\scheduler" -Class "CCM_Scheduler_History" | Where-Object { $_.ScheduleID -like "*$($SoftwareDistributionPolicy.PKG_PackageID)*" } | Select-Object -ExpandProperty ScheduleID

# Check if the RepeatRunBehavior is set to RerunAlways, if not change the value
$TaskSequencePolicy = Get-WmiObject -Namespace "root\ccm\policy\machine\actualconfig" -Class "CCM_TaskSequence" | Where-Object { $_.ADV_AdvertisementID -like $SoftwareDistributionPolicy.ADV_AdvertisementID }
if ($TaskSequencePolicy.ADV_RepeatRunBehavior -notlike "RerunAlways") {
    $TaskSequencePolicy.ADV_RepeatRunBehavior = "RerunAlways"
    $TaskSequencePolicy.Put() | Out-Null
}

# Set the mandatory assignment property to true mimicing it contains assignments
$TaskSequencePolicy.Get()
$TaskSequencePolicy.ADV_MandatoryAssignments = $true
$TaskSequencePolicy.Put() | Out-Null

# Invoke the mandatory assignment
Invoke-WmiMethod -Namespace "root\ccm" -Class "SMS_Client" -Name "TriggerSchedule" -ArgumentList $ScheduleID

Break down of sample code

Let’s take a look at how we can translate all of the above into some usable PowerShell code.

First off, we need to have the name of a task sequence at our disposal, that’s the single piece of information we need to start of with for this to work.

# Retrieve the name of the task sequence that should be executed
$TaskSequenceName = "OSD - Windows 10 Enterprise 1809 x64 - Upgrade"

After this, we need to retrieve the PKG_PackageID property from the CCM_SoftwareDistribution class for the instance that matches our task sequence name.

# Retrieve the PackageID and AdvertisementID from the machine actual policy
$SoftwareDistributionPolicy = Get-WmiObject -Namespace "root\ccm\policy\machine\actualconfig" -Class "CCM_SoftwareDistribution" | Where-Object { $_.PKG_Name -like $TaskSequenceName } | Select-Object -Property PKG_PackageID

Now we can go ahead and attempt to retrieve the ScheduleID property needed for triggering the task sequence deployment. To get our hands on it, we can retrieve the instance matching the PKG_PackageID property that we’ve stored in $SoftwareDistributionPolicy. A note here though, if you’d have several deployments for a single task sequence, the query below would return a string array containing all the ScheduleID’s. Let’s say that you have a task sequence deployment with the purpose of being Available and another deployment set as Required, you’d see both here. I strongly encourage you to manage this in your code, but for now we’re assuming that there’s only one ScheduleID returned from the below code.

# Retrieve the ScheduleID used for triggering a new required assignment for task sequence
$ScheduleID = Get-WmiObject -Namespace "root\ccm\scheduler" -Class "CCM_Scheduler_History" | Where-Object { $_.ScheduleID -like "*$($SoftwareDistributionPolicy.PKG_PackageID)*" } | Select-Object -ExpandProperty ScheduleID

In the case where a task sequence has already been deployed and executed before, and the rerun behavior has not been set to Always rerun, we need to make sure the local policy for the task sequence deployment is changed. This can be done with the following code below.

# Check if the RepeatRunBehavior is set to RerunAlways, if not change the value
$TaskSequencePolicy = Get-WmiObject -Namespace "root\ccm\policy\machine\actualconfig" -Class "CCM_TaskSequence" | Where-Object { $_.ADV_AdvertisementID -like $SoftwareDistributionPolicy.ADV_AdvertisementID }
if ($TaskSequencePolicy.ADV_RepeatRunBehavior -notlike "RerunAlways") {
    $TaskSequencePolicy.ADV_RepeatRunBehavior = "RerunAlways"
    $TaskSequencePolicy.Put() | Out-Null
}

Another thing we need to ensure is that the ADV_MandatoryAssignments property of the $TaskSequencePolicy instance is set to True.

# Set the mandatory assignment property to true mimicing it contains assignments
$TaskSequencePolicy.Get()
$TaskSequencePolicy.ADV_MandatoryAssignments = $true
$TaskSequencePolicy.Put() | Out-Null

And for the final step, we need to trigger the schedule associated with the task sequence deployment.

# Invoke the mandatory assignment
Invoke-WmiMethod -Namespace "root\ccm" -Class "SMS_Client" -Name "TriggerSchedule" -ArgumentList $ScheduleID

That concludes the break down of the sample code that will rerun a task sequence deployment on a ConfigMgr client.

(2173)

comments
  • Brian Ortega
    Posted at 17:12 February 18, 2019
    Brian Ortega
    Reply
    Author

    Should the second line include the ADV_AdvertisementID property as well, like below?

    $SoftwareDistributionPolicy = Get-WmiObject -Namespace “root\ccm\policy\machine\actualconfig” -Class “CCM_SoftwareDistribution” | Where-Object { $_.PKG_Name -like $TaskSequenceName } | Select-Object -Property PKG_PackageID, ADV_AdvertisementID

    I ended up just commenting out the select statement.

  • Leave a Reply

    This site uses Akismet to reduce spam. Learn how your comment data is processed.