Correct-ContentDistributionErrors.ps1
Description:
Script utilizes a function by Mike Laughlin to retarget errored packages specifically to DPs they are in an error state on. There is a flag to include in-progress content as well. This can be run on a scheduled task to automate redistribution of failed packages in your environment.
Language:
PowerShell
Usage Type:
Standalone
Script Source:
############################################ # Correct-ContentDistributionErrorsV2.ps1 # Version: 2020.4.6.3 # Author: Sean Huggans ############################################ $SiteCode = "FOO" $SiteServer = "SITESERVER" $ProviderMachineName = "SITESERVER.FOONET.NET" $Script:LogRoot = "C:\Temp\Logs\" $Script:LogName = "Correct-ContentDistributionErrors" $Script:LogPath = "$($script:LogRoot)$($script:LogName).log" $Script:CMCMDlets = $false $Script:ADCMDlets = $false $RedistributionThreshold = 20 $RedistributeAllInProgress = $false # Set to true to redistribute all in progress content to the DPs the content is in progress to function AddLogLine ($Message) { if (!(Test-Path -Path "$($Script:LogRoot)")) { new-item -ItemType directory -Path "$($Script:LogRoot)" -force -Confirm:$false -ErrorAction SilentlyContinue } "[ $(get-date -format 'yyyy.MM.dd hh:mm:ss') ] $Message" | out-file $Script:LogPath -Append } function MaintainLogs { # Truncate Log if over 10,000KB if ((Get-Item $Script:LogPath).length -gt 10000kb) { $ArchiveStamp = "-Archived-$(get-date -Format "yyyyMMddhhmmss")" $ArchivedLogName = "$($Script:LogRoot)Archived\$($script:LogName)$ArchiveStamp.log" $TryCount = 5 $Moved = $false do { try { Move-Item -Force $Script:LogPath -Destination $ArchivedLogName -ErrorAction Stop AddLogLine "This Log has been truncated. Messages from the previous truncation can be found at $ArchivedLogName" $Moved = $true } catch { Start-Sleep -Seconds 3 } } until (($TryCount -le 0) -or ($Moved -eq $true)) } #Check for Logs Older than 4 weeks and delete them } MaintainLogs # Customizations $initParams = @{} # Import the ConfigurationManager.psd1 module if((Get-Module ConfigurationManager) -eq $null) { Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams } # Connect to the site's drive if it is not already present if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams } # Set the current location to be the site code. Set-Location "$($SiteCode):\" @initParams Function Refresh-SpecificDP { ################################### # Function by Mike Laughlin ################################### param($packageID, $dpName) $dpFound = $false If ($packageID.Length -ne 8) { Throw "Invalid package" } $distPoints = Get-WmiObject -ComputerName $SiteServer -Namespace "root\SMS\Site_$($siteCode)" -Query "Select * From SMS_DistributionPoint WHERE PackageID='$packageID'" -ErrorAction Stop ForEach ($dp In $distPoints) { If ((($dp.ServerNALPath).ToUpper()).Contains($dpName.ToUpper())) { $dpFound = $true Try { $dp.RefreshNow = $true $dp.Put() | Out-Null return $true } Catch [Exception] { return $false } } } If ($dpFound -eq $false) { return $false } } cd SAN: AddLogLine "====================================" AddLogLine "====== Script Started Running ======" AddLogLine "====================================" #We will keep a running list of offline DPs to expedite script execution $OfflineDPs = New-Object System.Collections.ArrayList AddLogLine "Gathering List of Distribution Points..." [array]$DistributionPointsData = Get-CMDistributionPoint | sort-object -Property NetworkOSPath [array]$DistributionPoints = $DistributionPointsData.NetworkOSPath.ToUpper().Replace("\\","") # Handle in progress content if the option is enabled if ($RedistributeAllInProgress -eq $true) { $LoopCount = 0 AddLogLine "Warning! Redistribute In-Progress Content option is enabled! Building a list of all in progress content..." [array]$InProgressContentObjects = Get-CMDistributionStatus | Where-Object {$_.NumberInProgress -gt 0} | sort-object -Property SoftwareName AddLogLine "Total Count of Objects with In-Progress Content Distributions: $($InProgressContentObjects.Count)" foreach ($InProgressContentObject in $InProgressContentObjects) { $LoopCount +=1 AddLogLine "Building a list of DPs with content In-Progress for Package $($LoopCount)/$($InProgressContentObjects.count), ID: $($InProgressContentObject.PackageID) ($($InProgressContentObject.SoftwareName))" $DistributionPointsWithInProgressStatusForThisPackage = New-Object System.Collections.ArrayList #Check Each DP for the status of this package foreach ($DistributionPoint in $DistributionPoints) { $InProgressContentObjectStatusonDistributionPoint = Get-WmiObject –NameSpace Root\SMS\Site_$SiteCode –Class SMS_DistributionDPStatus -ComputerName $SiteServer –Filter "PackageID='$($InProgressContentObject.PackageID)' And Name='$($DistributionPoint)'" switch ($InProgressContentObjectStatusonDistributionPoint.MessageState) { 1 { #Compliant } 2 { #In Progress $DistributionPointsWithInProgressStatusForThisPackage.Add($DistributionPoint) | Out-Null } 3 { #Unknown } 4 { #Error } } } AddLogLine "Checking the status of each DP in the 'InProgress State' content list, and attempting to retrigger content redistribution if it is online..." foreach ($DistributionPointWithInProgressStatusForThisPackage in $DistributionPointsWithInProgressStatusForThisPackage) { #Content in InProgress State on this DP, If we already don't know, Check to see if the DP is online if (($DistributionPointWithInProgressStatusForThisPackage -like "*CMG*") -or (($OfflineDPs -notcontains $DistributionPointWithInProgressStatusForThisPackage) -and (Test-Connection -Cn $DistributionPointWithInProgressStatusForThisPackage -BufferSize 16 -Count 1 -ea 0 -quiet))) { AddLogLine "- $($DistributionPointWithInProgressStatusForThisPackage) - Online. Triggering Content Redistribution to this host for package: $($InProgressContentObject.PackageID)..." if (Refresh-SpecificDP $InProgressContentObject.PackageID $DistributionPointWithInProgressStatusForThisPackage) { AddLogLine "- - Success" } else { AddLogLine "- - Failure" } } else { $OfflineDPs.Add($DistributionPointWithInProgressStatusForThisPackage) | Out-Null AddLogLine "- $($DistributionPointWithInProgressStatusForThisPackage) - Offline. No Actions can be taken at this time." } } } } else { AddLogLine "Redistribute In-Progress Content option is not enabled (this is usually the desired setting), skipping." } AddLogLine "Building a list of all content with failues..." [array]$FailedContentObjects = Get-CMDistributionStatus | Where-Object {$_.NumberErrors -gt 0} | sort-object -Property SoftwareName AddLogLine "Total Count of Objects with Failed Content Distributions: $($FailedContentObjects.Count)" $LoopCount = 0 foreach ($FailedContentObject in $FailedContentObjects) { $LoopCount +=1 AddLogLine "Building a list of DPs with content failures for Package $($LoopCount)/$($FailedContentObjects.count), ID: $($FailedContentObject.PackageID) ($($FailedContentObject.SoftwareName))" $DistributionPointsWithErrorStatusForThisPackage = New-Object System.Collections.ArrayList #Check Each DP for the status of this package foreach ($DistributionPoint in $DistributionPoints) { $FailedContentObjectStatusonDistributionPoint = Get-WmiObject –NameSpace Root\SMS\Site_$SiteCode –Class SMS_DistributionDPStatus -ComputerName $SiteServer –Filter "PackageID='$($FailedContentObject.PackageID)' And Name='$($DistributionPoint)'" switch ($FailedContentObjectStatusonDistributionPoint.MessageState) { 1 { #Compliant } 2 { #In Progress } 3 { #Unknown } 4 { #Error $DistributionPointsWithErrorStatusForThisPackage.Add($DistributionPoint) | Out-Null } } } AddLogLine "Checking the status of each DP in the 'Failed State' content list, and attempting to retrigger content redistribution if it is online..." foreach ($DistributionPointWithErrorStatusForThisPackage in $DistributionPointsWithErrorStatusForThisPackage) { #Content in Error State on this DP, If we already don't know, Check to see if the DP is online if (($DistributionPointWithErrorStatusForThisPackage -like "*CMG*") -or (($OfflineDPs -notcontains $DistributionPointWithErrorStatusForThisPackage) -and (Test-Connection -Cn $DistributionPointWithErrorStatusForThisPackage -BufferSize 16 -Count 1 -ea 0 -quiet))) { AddLogLine "- $($DistributionPointWithErrorStatusForThisPackage) - Online. Triggering Content Redistribution to this host for package: $($FailedContentObject.PackageID)..." if (Refresh-SpecificDP $FailedContentObject.PackageID $DistributionPointWithErrorStatusForThisPackage) { AddLogLine "- - Success" } else { AddLogLine "- - Failure" } } else { $OfflineDPs.Add($DistributionPointWithErrorStatusForThisPackage) | Out-Null AddLogLine "- $($DistributionPointWithErrorStatusForThisPackage) - Offline. No Actions can be taken at this time." } } } AddLogLine "====================================" AddLogLine "====== Script Finished Running =====" AddLogLine "===================================="
Note: that all applications posted here are posted for use, both commercial and non-commercial, free of charge, and as such are provided as-is, without warranty of any kind whatsoever. visuaFUSION, FMSCUG or any other program listed here's author are not responsible for any damages or shortcomings that result from usage of any of these applications.