I’m going to show you a new approach to getting deployment status out of SCCM.
Most of our readers are familiar with using SCCM Reports, or the SCCM console, to get deployment status when asked. Usually, when asked, I turn to SQL. However, I was looking at all the cmdlets that come with SCCM when I realized: There are no cmdlets dedicated to simple reporting.
As such, I took it upon myself to create a simple cmdlet that returns both summary and details of the status of an Application Deployment. I’ll include the code at the bottom of this post, but first, I’ll show you how to use it.
The name of the script is CMReporting.ps1. For now, all the required functions are within this script.
Using the Script to Get Deployment Status
To use this script, you first need to load the functions into memory by running the script.
This script must be run from the SCCM Site Server.
Here is one example on how to use it:
Get-CMAppDeploymentReport -ChooseFromGrid -DetailType Both -OutputType Text
You are first presented with a gridview list of all current app deployments. Highlight one and click “OK”.
After about 30 seconds, you’ll see a display like the following in PowerShell:
As promised, here is the code:
Function Get-WindowsErrorMessage {
[CmdletBinding()]
param (
[int]$ErrorCode ,
[string]$ErrorSource = "Windows",
[switch]$SimpleOutput
)
#This error code was generated from the Windows Exception Library
If ($ErrorSource -eq "Windows") {
$ErrorMessage = [ComponentModel.Win32Exception]$ErrorCode
}
#Write Output of Function
If ($SimpleOutput) {
Write-Output $ErrorMessage
}
Else {
Write-Output "$ErrorSource Error $($ErrorCode): $($ErrorMessage.Message)"
}
}
Function Get-CMAppDeploymentReport {
param(
[ValidateSet("Summary","Detail","Both")]
[string]$DetailLevel,
[ValidateSet("Object","Text")]
[string]$OutputType,
[int]$AssignmentID,
[switch]$ChooseFromGrid
)
#Select Deployment to Report on
if($ChooseFromGrid) {
$DeploymentList = Get-WMIObject -Namespace root\sms\site_mp1 -class SMS_DeploymentSummary -Filter "FeatureType = 1"
$SelectedDeployment = $DeploymentList | Select-Object AssignmentID, CollectionName, SoftwareName, @{Name="DeploymentTime";Expression={$([Management.ManagementDateTimeConverter]::toDateTime($_.DeploymentTime))}},@{Name="DeploymentIntent";Expression={If ($_.DeploymentIntent -eq 1){"Required"}elseif($_.DeploymentIntent -eq 2){"Available"}else{"Unknown"}}},@{Name="EnforcementDeadline";Expression={$([Management.ManagementDateTimeConverter]::toDateTime($_.EnforcementDeadline))}} | Out-GridView -OutputMode Single -Title "Select a Deployment to Report on"
$AssignmentID = $SelectedDeployment.AssignmentID
}
#Get Summary Data
$Summary = Get-WMIObject -Namespace root\sms\site_mp1 -class SMS_DeploymentSummary -Filter "AssignmentID = $AssignmentID and FeatureType = 1"
$CollectionInfo = Get-WMIObject -Namespace root\sms\site_mp1 -Class SMS_Collection -Filter "CollectionID = ""$($Summary.CollectionID)"""
If ($CollectionInfo.CollectionType -eq 2) {$CollectionType = "User"}elseif($CollectionInfo.CollectionType -eq 1){$CollectionType = "Device"}else{$CollectionType = "Other"}
$SummaryTable = $Summary |Select-Object AssignmentID, CollectionID, CollectionName, SoftwareName, @{Name="DeploymentTime";Expression={$([Management.ManagementDateTimeConverter]::toDateTime($_.DeploymentTime))}},@{Name="DeploymentIntent";Expression={If ($_.DeploymentIntent -eq 1){"Required"}elseif($_.DeploymentIntent -eq 2){"Available"}else{"Unknown"}}},@{Name="EnforcementDeadline";Expression={$([Management.ManagementDateTimeConverter]::toDateTime($_.EnforcementDeadline))}}, NumberSuccess, NumberInProgress, NumberErrors, NumberUnknown, NumberTotal, PackageID
$SummaryTitle = "Summary of Deployment for $($Summary.SoftwareName) to $($CollectionInfo.MemberCount) $($CollectionType)(s)"
$DetailTitle = "Detail for Deployment of $($Summary.SoftwareName) to $($CollectionInfo.MemberCount) $($CollectionType)(s)"
$OutputReport = New-Object -TypeName PSObject
If ($DetailLevel -eq "Summary" -or $DetailLevel -eq "Both") {
$OutputReport | Add-Member -MemberType NoteProperty -Name "SummaryTitle" -Value $SummaryTitle
$OutputReport | Add-Member -MemberType NoteProperty -Name "SummaryResults" -Value $SummaryTable
}
If ($DetailLevel -eq "Detail" -or $DetailLevel -eq "Both") {
$States = Get-WMIObject -Namespace root\sms\site_mp1 -Class "SMS_StateInformation"
#Get Detail Data
$Detail = Get-WMIObject -Namespace root\sms\site_mp1 -class SMS_AppDeploymentAssetDetails -Filter "AssignmentID = $AssignmentID"
$Devices = @()
Foreach ($Target in $Detail) {
If ($Target.AppStatusType -eq 5) {
$ErrorCode = $(Get-WMIObject -Namespace root\sms\site_mp1 -class SMS_AppDeploymentErrorAssetDetails -Filter "MachineID = $($Target.MachineID) and AssignmentID = $AssignmentID").ErrorCode
$ErrorMessage = Get-WindowsErrorMessage -ErrorCode $ErrorCode
}
Else {
$ErrorCode = ""
$ErrorMessage = ""
}
$CIComplianceInfo = Get-WmiObject -Namespace root\SMS\site_mp1 -Class SMS_CI_ComplianceHistory -Filter "ResourceID = $($Target.MachineID) and CI_ID = $($Target.AppCI)"
$Device = New-Object -TypeName PSObject
#$Device | Add-Member -MemberType NoteProperty -Name "ComplianceState" -Value "$(If ($Target.ComplianceState -eq 1){"Compliant"}elseif($Target.ComplianceState -eq 2){"Non-Compliant"}else{"Unknown"})"
$Device | Add-Member -MemberType NoteProperty -Name "Name" -Value "$($Target.MachineName)"
$Device | Add-Member -MemberType NoteProperty -Name "State" -Value "$(if ($Target.AppStatusType -eq 1) {"Success"} elseif ($Target.AppStatusType -eq 2) {"In Progress"} elseif ($Target.AppStatusType -eq 3){"Requirements Not Met"} elseif ($Target.AppStatusType -eq 4) {"Unknown"} elseif($target.AppStatusType -eq 5) {"Error"})"
#If($Device.State -eq "
$Device | Add-Member -MemberType NoteProperty -Name "ErrorCode" -Value "$ErrorCode"
$Device | Add-Member -MemberType NoteProperty -Name "ErrorMessage" -Value "$ErrorMessage"
Try {
$CIComplianceInfo = $CIComplianceInfo | Sort-Object -Property ComplianceStartDate -Descending | Select * -First 1
$Device | Add-Member -MemberType NoteProperty -Name "LastComplianceStateChange" -Value "$([Management.ManagementDateTimeConverter]::toDateTime($($CIComplianceInfo.ComplianceStartDate)))"
}
Catch {
$Device | Add-Member -MemberType NoteProperty -Name "LastComplianceStateChange" -Value ""
}
$Devices += $Device
}
$OutputReport | Add-Member -MemberType NoteProperty -Name "DetailTitle" -Value $DetailTitle
$OutputReport | Add-Member -MemberType NoteProperty -Name "DetailResults" -Value $Devices
}
If ($OutputType -eq "Object") {
Write-Output $OutputReport
}
elseif ($OutputType -eq "Text") {
If ($DetailLevel -eq "Summary" -or $DetailLevel -eq "Both"){
Write-Host ""
$OutputReport.SummaryTitle
Write-Host ""
$($OutputReport.SummaryResults | ft -AutoSize)
}
If ($DetailLevel -eq "Detail" -or $DetailLevel -eq "Both"){
Write-Host ""
$OutputReport.DetailTitle
Write-Host ""
$($OutputReport.DetailResults | Select Name, State, ErrorCode, ErrorMessage, LastComplianceStateChange -Unique | Sort-Object -Property Name | ft -AutoSize)
}
}
}