Reporting on SCCM Application Deployment Progress with Powershell

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”.

selectdeployment

 

After about 30 seconds, you’ll see a display like the following in PowerShell:

 

output

As promised, here is the code:

 


Function Get-WindowsErrorMessage {

    [CmdletBinding()]

    param (
        $ErrorCode ,
        $ErrorSource = "Windows",
        $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")]
        $DetailLevel,
        [ValidateSet("Object","Text")]
        $OutputType,
        $AssignmentID,
        $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)
        }
    }


}


 

 

 

By |2018-12-19T14:26:46+00:00December 19th, 2018|PowerShell, SCCM, Uncategorized|0 Comments

About the Author:

steve bowman

Model Technology

Let us help you get your end point and data center strategy on cruise control!  Ask about our Calibration Assessment.

CONTACT US

  • 12125 Woodcrest Executive Drive, Ste. 204 Creve Coeur, MO 63141
  • (314) 254-4138
  • sales@model-technology.com

RECENT TWEETS