Recently when I checked the status of my Content distributions in the Monitoring node of the ConfigMgr console, I noticed some where the compliance was not reporting as 100%. This means there was a failure in the distribution which needs to be addressed, usually by redistributing. However, ConfigMgr does not notify you of such distributions failures, which means you have to check in the console, or the status messages or the log files to find out. It will retry a distribution up to 100 times, but after that I guess it just remains in a failed state.
So I wrote a Powershell script that will check for failed distributions, and give me various info such as the package name, type and ID, the distribution point where the failure occurred and the reason for the failure. It can be run in a PS console window, but can also send results by email, which makes it useful to be run regularly as a scheduled task, so you can monitor for distribution failures and take the necessary action to remedy them.
Here’s an example:
After running the script I can see that there are some distributions where the content hash failed to be validated, not an uncommon error. A redistribution should fix that. There is also an OS Image package that looks like it couldn’t talk to the distribution point, and given the date it’s given up trying.
If I choose the -SendEmail switch, it will send me a nice (?) neon-green HTML report 🙂
Even though it is designed for failed distributions, it will also report on distributions that are active, basically anything not yet in the successful state, so you could use it to view the progress of current distributions too.
For example, this time using the -GridView switch, I can see some Software Update Packages that are currently being distributed, and some that failed. Since the failures are very recent, ConfigMgr will try to redistribute those packages. If they remain in the failed state over time, then it needs investigating.
Configure the Script
All parameters in the script are non-mandatory, so set the defaults if you don’t want to enter them each time:
$SiteCode – Your ConfigMgr Site Code
$SiteServer – Your ConfigMgr Site Server
$From – the From email address
$To – the To email address
$Smtpserver – Your Smtp server name
$Subject – The email subject
The Script
<# .SYNOPSIS Checks for failed or incomplete package distributions in ConfigMgr .DESCRIPTION This script checks for any package distributions that are not in the successful state, and return the results either into the console window or by email in an HTML table. The following fields are returned: - Package Name - PackageID - Package Type - Distribution Point Name - Distribution State - Status Message - Last Update Time It can be run as a scheduled task to monitor for failed distributions. Data is retrieved from WMI on the Site Server. .PARAMETER SiteCode Your ConfigMgr SiteCode .PARAMETER SiteServer Your ConfigMgr Site Server .PARAMETER SendEmail Use this switch to send results by email. Console output is the default. .PARAMETER GridView Use this switch to output results to Powershell's GridView. Console output is the default. .PARAMETER From If sending email, the From address .PARAMETER To If sending email, the To address .PARAMETER SmtpServer If sending email, the Smtp server name .PARAMETER Subject If sending email, the email subject .EXAMPLE .\Get-CMFailedDistributions.ps1 Checks for unsuccesful package distributions and returns the results to the console window. .EXAMPLE .\Get-CMFailedDistributions.ps1 -SendEmail Checks for unsuccesful package distributions and sends the results by email using the default parameters. .EXAMPLE .\Get-CMFailedDistributions.ps1 -SiteCode XYZ -SiteServer sccmserver02 -SendEmail -To bill.gates@microsoft.com Checks for unsuccesful package distributions and sends the results by email using specified parameters. .NOTES Script name: Get-CMFailedDistributions.ps1 Author: Trevor Jones Contact: @trevor_smsagent DateCreated: 2015-05-12 Link: https://smsagent.wordpress.com Credits: MessageIDs from Dan Richings http://www.danrichings.com/?p=166 #> [CmdletBinding()] param ( [Parameter(Mandatory=$False)] [string]$SiteCode = "ABC", [Parameter(Mandatory=$False)] [string]$SiteServer = "sccmserver-01", [parameter(Mandatory=$False)] [switch]$SendEmail, [parameter(Mandatory=$False)] [switch]$GridView, [parameter(Mandatory=$False)] [string]$From = "ConfigMgr@contoso.com", [parameter(Mandatory=$False)] [string]$To = "ConfigMgr_Admins@contoso.com", [parameter(Mandatory=$False)] [string]$SmtpServer = "mysmtpserver", [parameter(Mandatory=$False)] [string]$Subject = "ConfigMgr Failed Distributions" ) #region Functions function New-Table ( $Title, $Topic1, $Topic2, $Topic3, $Topic4, $Topic5, $Topic6, $Topic7 ) { Add-Content $msgfile "<style>table {border-collapse: collapse;font-family: ""Trebuchet MS"", Arial, Helvetica, sans-serif;}" Add-Content $msgfile "h2 {font-family: ""Trebuchet MS"", Arial, Helvetica, sans-serif;}" Add-Content $msgfile "th, td {font-size: 1em;border: 1px solid #1FE093;padding: 3px 7px 2px 7px;}" Add-Content $msgfile "th {font-size: 1.2em;text-align: left;padding-top: 5px;padding-bottom: 4px;background-color: #1FE093;color: #ffffff;}</style>" Add-Content $msgfile "<h2>$Title</h2>" Add-Content $msgfile "<p><table>" Add-Content $msgfile "<tr><th>$Topic1</th><th>$Topic2</th><th>$Topic3</th><th>$Topic4</th><th>$Topic5</th><th>$Topic6</th><th>$Topic7</th></tr>" } function New-TableRow ( $col1, $col2, $col3, $col4, $col5, $col6, $col7 ) { Add-Content $msgfile "<tr><td>$col1</td><td>$col2</td><td>$col3</td><td>$col4</td><td>$col5</td><td>$col6</td><td>$col7</td></tr>" } function New-TableEnd { Add-Content $msgfile "</table></p>"} #endregion # Set WQL Query $packages = @() $Query = " Select PackageID,Name,MessageState,ObjectTypeID,MessageID,LastUpdateDate from SMS_DistributionDPStatus where MessageState<>1 order by LastUpdateDate Desc " # Get unsuccessful distributions $Distributions = Get-WmiObject -ComputerName $SiteServer -Namespace root\SMS\site_$SiteCode -Query $Query foreach ($Distribution in $Distributions) { # Translate Package Type if ($Distribution.ObjectTypeID -eq "2") {$Type = "Standard Package"} if ($Distribution.ObjectTypeID -eq "14") {$Type = "OS Install Package"} if ($Distribution.ObjectTypeID -eq "18") {$Type = "OS Image Package"} if ($Distribution.ObjectTypeID -eq "19") {$Type = "Boot Image Package"} if ($Distribution.ObjectTypeID -eq "21") {$Type = "Device Setting Package"} if ($Distribution.ObjectTypeID -eq "23") {$Type = "Driver Package"} if ($Distribution.ObjectTypeID -eq "24") {$Type = "Software Updates Package"} if ($Distribution.ObjectTypeID -eq "31") {$Type = "Application Content Package"} # Translate Distribution State if ($Distribution.MessageState -eq "2") {$Status = "In Progress"} if ($Distribution.MessageState -eq "3") {$Status = "Error"} if ($Distribution.MessageState -eq "4") {$Status = "Failed"} # Translate Common MessageIDs if ($Distribution.MessageID -eq "2303") {$MSGID = "Content was successfully refreshed"} if ($Distribution.MessageID -eq "2324") {$MSGID = "Failed to access or create the content share"} if ($Distribution.MessageID -eq "2330") {$MSGID = "Content was distributed to distribution point"} if ($Distribution.MessageID -eq "2384") {$MSGID = "Content hash has been successfully verified"} if ($Distribution.MessageID -eq "2323") {$MSGID = "Failed to initialize NAL"} if ($Distribution.MessageID -eq "2354") {$MSGID = "Failed to validate content status file"} if ($Distribution.MessageID -eq "2357") {$MSGID = "Content transfer manager was instructed to send content to the distribution point"} if ($Distribution.MessageID -eq "2360") {$MSGID = "Status message 2360 unknown"} if ($Distribution.MessageID -eq "2370") {$MSGID = "Failed to install distribution point"} if ($Distribution.MessageID -eq "2371") {$MSGID = "Waiting for prestaged content"} if ($Distribution.MessageID -eq "2372") {$MSGID = "Waiting for content"} if ($Distribution.MessageID -eq "2375") {$MSGID = "Created virtual directories on the defined share or volume on the distribution point succesfully"} if ($Distribution.MessageID -eq "2380") {$MSGID = "Content evaluation has started"} if ($Distribution.MessageID -eq "2381") {$MSGID = "An evaluation task is running. Content was added to the queue"} if ($Distribution.MessageID -eq "2382") {$MSGID = "Content hash is invalid"} if ($Distribution.MessageID -eq "2383") {$MSGID = "Failed to validate the package on the distribution point. The package may not be present or may be corrupt. Please redistribute it"} if ($Distribution.MessageID -eq "2384") {$MSGID = "Package has been successfully verified on the distribution point"} if ($Distribution.MessageID -eq "2388") {$MSGID = "Failed to retrieve the package list on the distribution point. Or the package list in content library doesn't match the one in WMI. Review smsdpmon.log for more information about this failure."} if ($Distribution.MessageID -eq "2391") {$MSGID = "Failed to connect to remote distribution point"} if ($Distribution.MessageID -eq "2397") {$MSGID = "Detail will be available after the server finishes processing the messages."} if ($Distribution.MessageID -eq "2398") {$MSGID = "Content Status not found"} if ($Distribution.MessageID -eq "2399") {$MSGID = "Successfully completed the installation or upgrade of the distribution point"} if ($Distribution.MessageID -eq "8203") {$MSGID = "Failed to update package"} if ($Distribution.MessageID -eq "8204") {$MSGID = "Content is being distributed to the distribution point"} if ($Distribution.MessageID -eq "8211") {$MSGID = "Package Transfer Manager failed to update the package on the distribution point. Review PkgXferMgr.log for more information about this failure."} # Get / Set Additional info $PKGID = $Distribution.PackageID $LastUPDTime = [System.Management.ManagementDateTimeconverter]::ToDateTime($Distribution.LastUpdateDate) $PKG = Get-WmiObject -ComputerName $SiteServer -Namespace root\SMS\site_$SiteCode -Query "Select * from SMS_PackageBaseclass where PackageID = '$PKGID'" # Add to a PS object $Package = New-Object psobject Add-Member -InputObject $Package -MemberType NoteProperty -Name "Package Name" -Value $PKG.Name Add-Member -InputObject $Package -MemberType NoteProperty -Name "PackageID" -Value $Distribution.PackageID Add-Member -InputObject $Package -MemberType NoteProperty -Name "Package Type" -Value $Type Add-Member -InputObject $Package -MemberType NoteProperty -Name "Distribution Point Name" -Value $Distribution.Name Add-Member -InputObject $Package -MemberType NoteProperty -Name "Distribution State" -Value $Status Add-Member -InputObject $Package -MemberType NoteProperty -Name "Status Message" -Value $MSGID Add-Member -InputObject $Package -MemberType NoteProperty -Name "Last Update Time" -Value $LastUPDTime $packages += $package } if ($SendEmail) { # Create Tempfile to store data $msgfile = "$env:TEMP\mailmessage.txt" New-Item $msgfile -ItemType file -Force | Out-Null # Populate HTML table if ($packages -ne $null ) { $Params = @{ Title = "ConfigMgr Failed Package Distributions" Topic1 = "Package Name" Topic2 = "PackageID" Topic3 = "Package Type" Topic4 = "Distribution Point Name" Topic5 = "Distribution State" Topic6 = "Status Message" Topic7 = "Last Update Time" } New-Table @Params foreach ($item in $packages ) { $params = @{ col1 = $item.'Package Name' col2 = $item.PackageID col3 = $item.'Package Type' col4 = $item.'Distribution Point Name' col5 = $item.'Distribution State' col6 = $item.'Status Message' col7 = $item.'Last Update Time' } New-TableRow @Params } New-TableEnd # Send email or return results $mailbody = Get-Content $msgfile Send-MailMessage -From $From -To $To -SmtpServer $SmtpServer -Subject $Subject -Body "$mailbody" -BodyAsHtml # Delete tempfile Remove-Item $msgfile } Else {Write-Warning "No results were returned!"} } if ($GridView) { if ($packages -ne $null) {$packages | Out-GridView -Title "ConfigMgr Failed Package Distributions"} Else {Write-Warning "No results were returned!"} } If (!$GridView -and !$SendEmail) { if ($packages -ne $null) {$packages | ft -AutoSize} Else {Write-Warning "No results were returned!"} }
this is awesome, and just what we were looking for! 🙂 Thanks!
Hi,
is it possible to extend this script to automatically try to re-send the failed packages to it´s target DP?
Yes that’s possible. Actually I have another script that I use for that, you can find it here: https://smsagent.wordpress.com/2016/01/18/redistribute-failed-package-distributions-in-configmgr-with-powershell/. This script allows you to select which failed distributions to redistribute, but you can automate the process simply by removing the line that outputs to “out-gridview”, and be sure to specify which “states” you want to trigger a redistribution for in the WQL query on the first line. For example, “SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE State = 3 OR State = 6 or State = 8” – will redistribute only distribution failures or failed hash validations.
thanks for sharing this, works far better than a report/subscription!
really really helpful!
Glad it helps!
Thanks however i don’t receive the mail ?
In the section # Translate Distribution State
How do I create a success status?
Something like this?:
if ($Distribution.MessageState -eq “5”)
{$Status = “Success”}