Scripts Node: Task Sequence Info & Remediation.

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.

image

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):
image

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:
image

Here you can see the network file log has captured all of my testing:
image

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

12 thoughts on “Scripts Node: Task Sequence Info & Remediation.”

  1. 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?

    Reply
    • 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.

      Reply
    • 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.

      Reply
      • Hi,
        Is there anyway to force machines to re-download content for a precached TS?
        In powershell maybe.
        Thanks.
        Ludovic

        Reply
          • 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

  2. 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?

    Reply
    • 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?

      Reply
      • 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.

        Reply
  3. 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.

    Reply

Leave a Reply to gwblok Cancel reply

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