So this script is just a part of one that I’ve developed for using at WF. The other one includes a lot more logic for remediation based on our WaaS Process Registry Keys that get created during the process. So I’ve cleaned it up, and stripped out a bunch to make it more generic to work in any environment.
The Script itself is like 75% functions, then 25% running actions.
Overview of what it does:
- Reports the Parameters you’ve specified
- ForceTSReset = This will force resetting of the CCMExec & SMSTSMGR services & process, effectively killing off a running (hung) TS. This will not run even if set to true if already upgraded ($CurrentBuild = $BuildNumber) Default = False
- ScriptLogging = Do you want it to log localling and on the server? Default = True
- ForceTriggerTS = Will kick off the PreCache or IPU TS, if both are available, IPU wins and will kick off. This will not run even if set to true if already upgraded ($CurrentBuild = $BuildNumber) Default = False
- DeleteExecutionHistory = It will find any Execution History for the PackageIDs you’ve specified, then delete them. This is another potential fix to help you retry running a TS . Default = False
- TSPCPackageID = Package ID of the PreCache TS
- TSIPUPackageID = Package ID of your IPU TS
- Report Make & Model
- Report Current OS Build
- Report CMCache Size & Fix if less than 25GB
- Disk Size & Free Space & Run Cleanup if less than 20GB Free
- Find Task Sequences Available to Machine
- Based on PackageID’s you’d put in parameters
- List Execution History of those PackageID
- Delete Execution History of those PacakageIDs
- Based on True or False Parameter
- Report Status & Startup Type of CCMExec & SMSTSMGR
- Report Provisioning Mode Status and Remediate
- If Machine has not already upgrade to the build you specify in Parameter (ex 1803)
- Gets Status if TS is hung
- Gets Status if SetupHost is running
- Will attempt to close the TS nicely
- Get Status if TS still hung
- Resets the CM Client & TS Services to clear out any running TS
- Triggers the Upgrade TS
- If you set the Parameter to Trigger TS
- If the Services were Reset, it rechecks..
- Waits 10 minutes for Policy to update
- Checks if same Task Sequences are available
- Will try to Trigger again with updated policy
- If you set the Parameter to Trigger TS
This will log everything locally on the machine and on a server share (See previous post for more details)
Feel free to modify to fit your needs. Hope this is useful, or at least parts.
In Action:
In the Console, 1607 Machine, it has run the PreCache TS, but not the 1803 Upgrade (as showing by the Execution History). You can also see in this example that the CCMCache size was less than the desired 25GB, so it set it to 25GB for you. This machine is looking pretty good, no TS is hung, and the Upgrade has never executed, so it’s all set now to try to upgrade.
Here is when the “ForceTriggerTS” is set to True, yep you guessed it, it kicks off the upgrade (if its not restricted by a service window):
Here is Example of running Script on the machine after the upgrade to 1803, it now has execution history for both the PreCache & Upgrade. I set this test with “Delete TS Execution” set to True, then rerun to show they are no longer found:
Here you can see the network file log has captured all of my testing:
Please note, I have not been able to reproduce a “Hung TS” in my lab, but I’ve tested the “Reset-TaskSequence” function on many machine and it does pull them out of a hung state, and get them to start checking back into ConfigMgr so I can then retry the upgrade.
So hopefully that helps explain most of what this script does, I also tried to comment a lot inside of the scripts. If you have any questions, hit me up
I use this script in the Scripts Node, why? Because even if the machine is not receiving policy, and the client seems “checked out”, the scripts node uses the fast channel, so it will run the script, where a package or application or TS would never get a chance to run.
<# GARYTOWN.COM WaaS Script - Info & Remediation More info HERE: https://garytown.com/scripts-node-task-sequence-info-remediation #> [CmdletBinding()] Param ( #ForceTSReset will Trigger Reset-TaskSequence Function at end of TS if True [Parameter(Mandatory=$false)][ValidateSet("True","False")][string] $ForceTSReset = "False", #Logs to Network (Make sure you update the Server Share info) [Parameter(Mandatory=$false)][ValidateSet("True","False")][string] $ScriptLogging = "True", #ForceTriggerTS will Force a Call to run the TS (Still obey's MWs) This was copied from Client Center [Parameter(Mandatory=$false)][ValidateSet("True","False")][string] $ForceTriggerTS = "False", #Deletethe Execution History for the Task Seqeunces Deployment(s) found. [Parameter(Mandatory=$false)][ValidateSet("True","False")][string] $DeleteExecutionHistory = "False", #PreCache TS Package ID: Used to determine if the machine has the PreCache TS available [Parameter(Mandatory=$false)][string] $TSPCPackageID = "PS10008E", #Upgrade TS Package ID: Used to determine if and which Upgrade TS is available [Parameter(Mandatory=$false)][string] $TSIPUPackageID = "PS10008F" ) $buildnumber = "1803" $registryPath = "HKLM:\SOFTWARE\WaaS\$buildnumber" function Test-RegistryValue { param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Path, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Value ) try { Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null return $true } catch { return $false } } #Get General Info about PC, and Service Status $ProvMode = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\CCM\CcmExec' 'ProvisioningMode' -ErrorAction SilentlyContinue $CCMExecServiceStatus = (Get-Service ccmexec).status $CCMExecServiceStartType = (Get-Service ccmexec).startType $SMSTSMGRServiceStatus = (Get-Service SMSTSMGR).status $SMSTSMGRServiceStartType = (Get-Service SMSTSMGR).startType if ((Test-RegistryValue -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Value "ReleaseId") -eq "True"){$CurrentBuild = Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" 'ReleaseId' -ErrorAction SilentlyContinue} if ($CurrentBuild -eq $null){$CurrentBuild = Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" 'CurrentBuild' -ErrorAction SilentlyContinue} #region: CMTraceLog Function formats logging in CMTrace style (If Running as System, write to Network Share) if ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name -eq "NT AUTHORITY\SYSTEM"){$RunningAsSystem = "True"} #If Parameter for Logging Enabled, setup variables for where to log to if ($ScriptLogging -eq "True") { $TargetRootLocal = 'C:\windows\ccm\logs' $LocalLogFile = "$TargetRootLocal\ScriptsNode.log" $TargetRoot = '\\src\src$\Logs' $LogID = "ScriptsNodeLogs\GeneralScripts\$env:ComputerName" $ServerLogFile = "$TargetRoot\$LogID\ScriptsNode-$env:ComputerName.log" } #If Logging enabled & script running in System Context, make sure Log folder on Server is there, or make it. if ($RunningAsSystem -eq "True" -and $ScriptLogging -eq "True") { write-verbose "Create Target $TargetRoot\$LogID" new-item -itemtype Directory -Path $TargetRoot\$LogID -force -erroraction SilentlyContinue | out-null } #region: CMTraceLog Function formats logging in CMTrace style (but to Server) #CMTraceLog Function stolen from @EphingPosh https://www.ephingadmin.com/powershell-cmtrace-log-function/ function CMTraceLog { [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] $Message, [Parameter(Mandatory=$false)] $ErrorMessage, [Parameter(Mandatory=$false)] $Component = $env:computername, [Parameter(Mandatory=$false)] [int]$Type, [Parameter(Mandatory=$true)] $ServerLogFile #[Parameter(Mandatory=$true)] #$LocalLogFile ) <# Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red) #> $Time = Get-Date -Format "HH:mm:ss.ffffff" $Date = Get-Date -Format "MM-dd-yyyy" if ($ErrorMessage -ne $null) {$Type = 3} if ($Component -eq $null) {$Component = " "} if ($Type -eq $null) {$Type = 1} $LogMessage = "<![LOG[$Message $ErrorMessage" + "]LOG]!><time=`"$Time`" date=`"$Date`" component=`"$Component`" context=`"`" type=`"$Type`" thread=`"`" file=`"`">" #This writes to Terminal Output Write-Host "$Message $ErrorMessage" #This writes to Server Log if running in System Context if ($RunningAsSystem -eq "True" -and $ScriptLogging -eq "True"){$LogMessage | Out-File -Append -Encoding UTF8 -FilePath $ServerLogFile} #This writes to local log in ccm\logs if ($ScriptLogging -eq "True"){$LogMessage | Out-File -Append -Encoding UTF8 -FilePath $LocalLogFile} } #Create Function Get SetupHost Running Status function Get-Win10SetupHostStatus { if ((Get-Process "SetupHost" -ea SilentlyContinue) -eq $null) { $global:SetupRunning = "False" $OutputText = "Windows 10 Setup NOT Running" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } Else { $global:SetupRunning = "True" $OutputText = "Windows 10 Setup Running" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} } } #Create Function Stop SetupHost Running function Stop-Win10SetupHost { $OutputText = "Setup Running - Stopping Now" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Get-Process "SetupHost"| Stop-Process -Force start-sleep -Seconds 30 if ((Get-Process "SetupHost" -ea SilentlyContinue) -eq $null){$global:SetupRunning = "False"} Else {$global:SetupRunning = "True" $OutputText = "Setup Still Running - Trying again to Stop" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Get-Process "SetupHost"| Stop-Process -Force if ((Get-Process "SetupHost" -ea SilentlyContinue) -eq $null){$global:SetupRunning = "False"} } } #Create Function to Reset TS if running - I've heard this can clear up a hung TS, so I try this first before hitting it with the hammer. function Reset-TaskSequenceNicely { $OutputText = "Setting SMSTSMGR to Manual & Starting - Waiting 5 Minutes" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Set-Service smstsmgr -StartupType manual Start-Service smstsmgr start-sleep -Seconds 300 } #Create Function to Reset TS if running (The Hammer) function Reset-TaskSequence { $OutputText = "Resetting CM Services to clear out TS - Takes about 3 minutes" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Set-Service smstsmgr -StartupType manual Start-Service smstsmgr if ((Get-Process CcmExec -ea SilentlyContinue) -ne $Null) {Get-Process CcmExec | Stop-Process -Force} #stop-service ccmexec if ((Get-Process TSManager -ea SilentlyContinue) -ne $Null) {Get-Process TSManager| Stop-Process -Force} #Stop-Service smstsmgr Start-Sleep -Seconds 5 Start-Service ccmexec Start-Sleep -Seconds 5 Start-Service smstsmgr Start-Sleep -Seconds 20 if ((Get-Process TSManager -ea SilentlyContinue) -ne $Null) {Get-Process TSManager| Stop-Process -Force} Start-Sleep -Seconds 20 if ((Get-Process CcmExec -ea SilentlyContinue) -ne $Null) {Get-Process CcmExec | Stop-Process -Force} Start-Sleep -Seconds 15 Start-Service ccmexec start-sleep -Seconds 60 #Trigger Machine Policy Update Invoke-WMIMethod -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule "{00000000-0000-0000-0000-000000000021}" Invoke-WMIMethod -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule "{00000000-0000-0000-0000-000000000022}" #Check for Setup Running, if it is KILL IT! It shouldn't be running at this point, bad things might happen. if ((Get-Process "SetupHost" -ea SilentlyContinue) -eq $null){$SetupRunning = "False"} Else { $SetupRunning = "True" $OutputText = "Setup Running - Stopping Now" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Get-Process "SetupHost"| Stop-Process -Force start-sleep -Seconds 30 #After waiting 30 seconds, just double checking if ((Get-Process "SetupHost" -ea SilentlyContinue) -eq $null) {$SetupRunning = "False"} Else { $SetupRunning = "True" $OutputText = "Setup Running - Stopping Now" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Get-Process "SetupHost"| Stop-Process -Force } } $Global:ResetTSRan = "True" } <#Create Function to Trigger TS, based on the two PackageIDs in the Parameters, it will allow you to trigger PreCache or IPU. Ideally you will not have both the PreCache & IPU TSs deployed to the same machine. #> function Start-TaskSequence { #Get TS Info (Short Version) Pull Deployment Policies for PreCache or Upgrade TS based on Package IDs (Which you set in the Parameters) $TSScheduleMessageIDPreCache = (get-wmiobject -query "SELECT * FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID LIKE""%-$TSPCPackageID-6F6BCC28""" -namespace "ROOT\ccm\policy\machine\actualconfig").ScheduledMessageID $TSScheduleMessageIDIPU = (get-wmiobject -query "SELECT * FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID LIKE""%-$TSIPUPackageID-6F6BCC28""" -namespace "ROOT\ccm\policy\machine\actualconfig").ScheduledMessageID #If there was a PreCache TS in the Policy, set RunTSID to PreCache & Set the TSPCAdvertID to the PreCache AdvertID that is available if ($TSScheduleMessageIDPreCache -ne $null) { $TSPCAdvertID = $TSScheduleMessageIDPreCache.Substring(0,$TSScheduleMessageIDPreCache.Length-18) $RunTSID = "PreCache" } #If there was an Upgrade TS in the Policy, set RunTSID to PreCache & Set the TSPCAdvertID to the Upgrade AdvertID that is available if ($TSScheduleMessageIDIPU -ne $null) { $TSAdvertID = $TSScheduleMessageIDIPU.Substring(0,$TSScheduleMessageIDIPU.Length-18) $RunTSID = "IPU" } #Trigger TS Again, get & set information if ($RunTSID -eq "PreCache") { $TriggerPackageID = $TSPCPackageID $TriggerAdvertID = $TSPCAdvertID $TriggerScheduleMessageID = $TSScheduleMessageIDPreCache } if ($RunTSID -eq "IPU") { $TriggerPackageID = $TSIPUPackageID $TriggerAdvertID = $TSAdvertID $TriggerScheduleMessageID = $TSScheduleMessageIDIPU } #These next set of lines are the magic that triggers the TS to run again (note, it respects Service Windows, unless the TS is set to not care about Service Windows) get-wmiobject -query "SELECT * FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID=""$TriggerScheduleMessageID""" -namespace "ROOT\ccm\policy\machine\actualconfig" $a=([wmi]"ROOT\ccm\policy\machine\actualconfig:CCM_TaskSequence.ADV_AdvertisementID=""$TriggerAdvertID"",PKG_PackageID=""$TriggerPackageID"",PRG_ProgramID='*'");$a.ADV_RepeatRunBehavior='RerunAlways';$a.Put() $a=([wmi]"ROOT\ccm\policy\machine\actualconfig:CCM_TaskSequence.ADV_AdvertisementID=""$TriggerAdvertID"",PKG_PackageID=""$TriggerPackageID"",PRG_ProgramID='*'");$a.ADV_MandatoryAssignments=$True;$a.Put() ([wmiclass]'ROOT\ccm:SMS_Client').TriggerSchedule($TriggerScheduleMessageID) Start-Sleep -Seconds 5 ([wmiclass]'ROOT\ccm:SMS_Client').TriggerSchedule($TriggerScheduleMessageID) $global:TriggeredTS = "True" $OutputText = "Start-TS: Force TS was Set to True, Triggered TS" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} } #Create Function to Remove from ProvMode function Disable-ProvMode { if ((Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\CCM\CcmExec' 'ProvisioningMode') -eq 'true') { $OutputText = "Provisioning Mode Status: $ProvMode" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile}Write-Host "Removing Machine From Provisioning Mode and wait 30 seconds" -ForegroundColor Yellow $OutputText = "Removing Machine From Provisioning Mode and wait 30 seconds" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Invoke-WmiMethod -Namespace root\CCM -Class SMS_Client -Name SetClientProvisioningMode -ArgumentList $false Start-Sleep -Seconds 30 $ProvMode = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\CCM\CcmExec' 'ProvisioningMode' -ErrorAction SilentlyContinue if ($provmode -eq "True") { $OutputText = "Provisioning Mode Status: $ProvMode" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile}Write-Host "Removing Machine From Provisioning Mode and wait 30 seconds" -ForegroundColor Yellow $OutputText = "Removing Machine From Provisioning Mode and wait 30 seconds" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} Invoke-WmiMethod -Namespace root\CCM -Class SMS_Client -Name SetClientProvisioningMode -ArgumentList $false } Else { $ProvMode = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\CCM\CcmExec' 'ProvisioningMode' -ErrorAction SilentlyContinue $OutputText = "Provisioning Mode Status: $ProvMode" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } } Else { $ProvMode = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\CCM\CcmExec' 'ProvisioningMode' -ErrorAction SilentlyContinue $OutputText = "Provisioning Mode Status: $ProvMode" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } } #Find out if TS is hung by checking to see if SMSTSLog folder is still hanging around (probably not the most technical way to do this) function Get-TaskSequenceStatus { $SMSTSLogLocation ="C:\Windows\ccm\Logs\SMSTSLog" If (Test-Path $SMSTSLogLocation) { $OutputText = "SMSTSLog Folder Found, TS Still Running" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} $global:SMSTSRunning = "True" } Else { $OutputText = "SMSTSLog Folder Not Found, TS Not Running" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} $global:SMSTSRunning = "False" } } function FindTSInfo { #Find Which TS is deployed to Device, PreCache or Upgrade TS Deployment (Based on the two Packages IDs in the Parameters) #PreCache TS Section $TSScheduleMessageIDPreCache = (get-wmiobject -query "SELECT * FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID LIKE""%-$TSPCPackageID-6F6BCC28""" -namespace "ROOT\ccm\policy\machine\actualconfig").ScheduledMessageID if ($TSScheduleMessageIDPreCache -ne $null) { $TSPCAdvertID = $TSScheduleMessageIDPreCache.Substring(0,$TSScheduleMessageIDPreCache.Length-18) $OutputText = "Task Sequence Available = PreCache ($TSScheduleMessageIDPreCache)" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} $RunTSID = "PreCache" } #Upgrade TS Section #First ID = DeploymentID (Manually had to add these for each of our deployment to make a table so it knew which TS was available in the reporting.. If you don't care about reporting, and just want to trigger it again, this is not needed.) #Second ID = Task Sequence Package ID (Specified earlier in Script) #Third ID = CM Native ID for a TS? Unsure exactly what this is, but it is also the same in my personal lab. $TSScheduleMessageIDIPU = (get-wmiobject -query "SELECT * FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID LIKE""%-$TSIPUPackageID-6F6BCC28""" -namespace "ROOT\ccm\policy\machine\actualconfig").ScheduledMessageID if ($TSScheduleMessageIDIPU -ne $null) { $TSAdvertID = $TSScheduleMessageIDIPU.Substring(0,$TSScheduleMessageIDIPU.Length-18) $RunTSID = "IPU" $DeploymentTable = @( #DeploymentID - PackageId - Static Number #This just maps Deployment IDs to Friendly names, not needed, but nifty @{ DID = "PS220006-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Group_01_8PM' } @{ DID = "PS220007-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Group_02_8PM' } @{ DID = "PS220008-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Group_03_8PM' } @{ DID = "PS220009-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Group_04_8PM' } @{ DID = "PS22000A-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Group_05_8PM' } @{ DID = "PS22000B-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Mandatory' } @{ DID = "PS22000C-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_Needs_Remedation' } @{ DID = "PS22000D-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_NextMW'} @{ DID = "PS220003-$TSIPUPackageID-6F6BCC28"; DIDName = 'OSD_W10_TestCollection'} ) $DeploymentDay = $DeploymentTable | ? DID -eq $TSScheduleMessageIDIPU | % DIDName $OutputText = "Task Sequence Available = $DeploymentDay ($TSScheduleMessageIDIPU)" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} } } #This will list the Execution History of the PackageIDs from the Parameters Function ListExecutionHistory { $GetPackIDsExecutionHistory = $TSIPUPackageID, $TSPCPackageID ForEach ($GetHistory in $GetPackIDsExecutionHistory) { if ($GetHistory -ne $null) { $OutputText = "Checking to see if $GetHistory exist in Execution History Registry" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} if ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\$GetHistory") -eq "True") { $ExecHistory = Get-Item "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\$GetHistory" $ExecHistoryName = ($ExecHistory).PSChildName $OutputText = "Found $ExecHistoryName in Execution History" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} $OutputText = "$ExecHistory" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } else { $OutputText = "$GetHistory does not exist in Execution History" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } } } } #This will list and DELETE the Execution History of the PackageIDs from the Parameters Function DeleteExecutionHistory { $OutputText = "Called Delete Execution History" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} $DelPackIDsExecutionHistory = $TSIPUPackageID, $TSPCPackageID ForEach ($DeleteHistory in $DelPackIDsExecutionHistory) { if ($DeleteHistory -ne $null) { $OutputText = "Check to see if $DeleteHistory exist in Execution History Registry" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} if ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\$DeleteHistory") -eq "True") { $ExecHistory = Get-Item "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\$DeleteHistory" $ExecHistoryName = ($ExecHistory).PSChildName $OutputText = "Found $ExecHistoryName in Execution History... Deleting NOW" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} $OutputText = "$ExecHistory" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} Remove-Item "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\$DeleteHistory" -Recurse } Else { $OutputText = "No $DeleteHistory in Execution History, Nothing to do" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} } } Else { $OutputText = "No PackageID Variable exist, Nothing to trigger against." if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} } } } #Run Delete Execution History if Paramater = True #Start Script if ($ScriptLogging -eq "True"){CMTraceLog -Message "----------Starting WaaS TS Remediation Script on: $env:computername----------" -Type 1 -ServerLogFile $ServerLogFile} $OutputText = "Script was run in modes: `n Logging: $ScriptLogging `n Force TS Reset (Reset CM Services): $ForceTSReset `n Force Trigger TS (Rerun Advertisement): $ForceTriggerTS `n Delete TS Execution History: $DeleteExecutionHistory" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} #Record Make & Model $Make = (Get-WmiObject win32_computersystem).Manufacturer $Model = (Get-WmiObject win32_computersystem).Model $OutputText = "Model: $Make $Model" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} #Record Current OS Build $OutputText = "Current OS Build: $CurrentBuild" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} #Provide Feedback about Cache Size, and set to 25GB if it is lower. #Get CM Cache Info $UIResourceMgr = New-Object -ComObject UIResource.UIResourceMgr if ($UIResourceMgr -ne $null) { $Cache = $UIResourceMgr.GetCacheInfo() $CacheSize = $Cache.TotalSize if ($CacheSize -lt "25600") { $OutputText = "CCM Cache size = $CacheSize" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} #Set Cache Size to 25 GB if it isn't $Cache.TotalSize = "25600" $OutputText = "Updated Size to 25GB" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} $CacheSize = $Cache.TotalSize } else { $OutputText = "CCM Cache size = $CacheSize" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } } #Provide Information about Disk FreeSpace & Try to clear up space if Less than 20GB Free, but don't bother if machine is already upgraded #Get Disk Info (Size & FreeSpace) Get-WmiObject win32_LogicalDisk -Filter "DeviceID='C:'" | % { $FreeSpace = $_.FreeSpace/1GB -as [int] ; $DiskSize = $_.Size/1GB -as [int] } if ($Freespace -ne $null) { if ($Freespace -le "20") { $OutputText = "DiskSize = $DiskSize, FreeSpace = $Freespace" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} if($CurrentBuild -ne $buildnumber) { $OutputText = "Running Cleanup Tasks" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} if (Test-Path "C:\drivers"){Remove-Item -Recurse -Force c:\drivers} Get-ChildItem "C:\Windows\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue | Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-7)) } | remove-item -force -recurse -ErrorAction SilentlyContinue Get-ChildItem "C:\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue | Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-7)) } | remove-item -force -recurse -ErrorAction SilentlyContinue Get-WmiObject win32_LogicalDisk -Filter "DeviceID='C:'" | % { $FreeSpace = $_.FreeSpace/1GB -as [int] ; $DiskSize = $_.Size/1GB -as [int] } if ($Freespace -le "20") { $OutputText = "Disk Still below 20GB Free: DiskSize = $DiskSize, FreeSpace = $Freespace" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 2 -ServerLogFile $ServerLogFile} } else { $OutputText = "Disk now above 20GB Free: DiskSize = $DiskSize, FreeSpace = $Freespace" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } } } else { $OutputText = "DiskSize = $DiskSize, FreeSpace = $Freespace" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } } FindTSInfo if ($DeleteExecutionHistory -eq "True"){DeleteExecutionHistory} else {ListExecutionHistory} #Get & Write Services & Process Status $SMSTSMGRServiceStatus = (Get-Service SMSTSMGR).status $OutputText = "SMSTSMGR Service: $SMSTSMGRServiceStatus" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} $SMSTSMGRServiceStartType = (Get-Service SMSTSMGR).startType $OutputText = "SMSTSMGR Service Start Type: $SMSTSMGRServiceStartType" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} $CCMExecServiceStatus = (Get-Service ccmexec).status $OutputText = "CCMExec Service: $CCMExecServiceStatus" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} $CCMExecServiceStartType =(Get-Service ccmexec).startType $OutputText = "CCMExec Service Start Type: $CCMExecServiceStartType" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} #Write Provisioning Mode Info $ProvMode = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\CCM\CcmExec' 'ProvisioningMode' -ErrorAction SilentlyContinue if ($provmode -eq "True") { Get-Win10SetupHostStatus if ($SetupRunning -ne "True"){Disable-ProvMode} } Else { $OutputText = "Provisioning Mode Status: $ProvMode" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} } #Only Run this if the machine hasn't upgraded yet (Still on 1709 when you're pushing 1803 upgrades) if ($CurrentBuild -ne $buildnumber) { Get-TaskSequenceStatus Get-Win10SetupHostStatus #If it found the TS was still running, try to close it nicely. if ($smstsrunning -eq "True") { Reset-TaskSequenceNicely Get-Win10SetupHostStatus if ($SetupRunning -eq "True"){Stop-Win10SetupHost} Get-TaskSequenceStatus Get-Win10SetupHostStatus } #If TS still running after trying to close it nicely... go ahead and kill it if ($smstsrunning -eq "True" -or $ForceTSReset -eq "True") { Reset-TaskSequence Get-Win10SetupHostStatus if ($SetupRunning -eq "True"){Stop-Win10SetupHost} Get-TaskSequenceStatus Get-Win10SetupHostStatus } if ($ResetTSRan -eq "True"){Disable-ProvMode} if ($ForceTriggerTS -eq "True" -or $RunTSID -eq "PreCache") { Start-TaskSequence } } <# If TS Rest was Run, trigger Machine Policy Update Wait 10 Minutes and recheck what TS is available. I've seen in the Past where if a TS what hung, it didn't get policy, so it still showed an old Deployment This will give it 10 minutes to check and report back if it updates what TS is available #> if ($ResetTSRan -eq "True") { $OutputText = "CM Servers were Reset, Triggering Policy Update and Double Checking items after 10 minutes" if ($ScriptLogging -eq "True"){CMTraceLog -Message $OutputText -Type 1 -ServerLogFile $ServerLogFile} #Trigger Machine Policy Update Invoke-WMIMethod -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule "{00000000-0000-0000-0000-000000000021}" Invoke-WMIMethod -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule "{00000000-0000-0000-0000-000000000022}" #Wait 10 Minutes and Recheck What TS available. Start-Sleep -Seconds 600 FindTSInfo if ($buildnumber -ne $CurrentBuild -and $ForceTriggerTS -eq "True") { Start-TaskSequence } } if ($ScriptLogging -eq "True"){CMTraceLog -Message "----------Ending WaaS TS Remediation Script on: $env:computername----------" -Type 1 -ServerLogFile $ServerLogFile}
Posted on GARYTOWN.COM
Is there a reason for setting the SCCM cache to 25GB? Never seen it that large. Is this just to account for all your TS content?
Yes and no, we have a large payload during a TS, but we also use a peer-to-peer cache technology. If machines have the storage, why not leave items in cache. Also helps if machines ever need to uninstall.
Is it possible to just start the pre-cache without starting the IPU Tasksequence?
Yes, if you check the box for Pre-Download Content for this task-sequence on the deployment General Tab. That will start pulling down any referenced content in the TS.
Hi,
Is there anyway to force machines to re-download content for a precached TS?
In powershell maybe.
Thanks.
Ludovic
You can have the Pre-Cache TS run again… and again…
DM me on Twitter if you want to go into it more.
Could you please share how you could retrigger the pre-cache function of the task sequence if it failed?
The Pre-Caching feature of a Task Sequence isn’t something you can trigger. You can trigger a machine policy, which would confirm you have the policy and then start downloading if anything has changed.
If you want to be able to remediate, then you’d have to have a dedicated TS that just pre-caches, then you could run a remediation script that triggers the actual task sequence to run and pull down the files.
My suggestion would be:
2 Task Sequences that have IDENTICAL Content. One that is setup for precaching and makes no actual changes to the system, and one that runs your action. You can then use the precache version of the TS for remediation by having the Configuration Item’s Remediation trigger the precache TS
Code to trigger Task Sequence: https://github.com/gwblok/garytown/blob/master/RunScripts/Start-TaskSequence.ps1
We have seen large number of devices stuck in progress in deployment monitoring tab in sccm console even though task sequence successfully completed. We tried many solution to overcome this issue but can’t get the status to be changed to success tab. Is there any way to force the client/sccm to update the particular Task sequence status in sccm?
I honestly never look there, I look at the status messages, and use the CM reports. Even after you force a DDR and HWInv, that status doesn’t change?
Thank you for your reply.
Unfortunately even though we force DDR and HWInv, it does not make any difference. We do see some intermediate socket connection failed error while execution of IPU Task sequence in SMSTS.log. We believe that could be causing this issue, but have not found the root cause yet.
I’m trying to do something similar with win7 to win10. I can get my client working after a rollback but i can not reset the upgrade TS or get it out of installing status without wiping the client – resetting wmi – and reinstalling the client.