Forum Discussion
Calculate Percent on Compliance SCCM Powershell by Device collection
I have a function that pulls compliance status of a software update deployment (assignment ID). I want to configure this to calculate percent of the status types (Success, Error, In Progress, Unknown) and I would also like to pull compliance status based on device collection name instead of the deployment ID as it is shown below.
What I want to accomplish is automatically take a list of device collection names and run a software update deployment which organizes each collection by compliance percent (for each status), and then receive it by email every morning.
I have several locations based on device collection, and I want to be able to differentiate which locations and devices are the problematic ones.
This method makes tracking and reporting much easier and SCCM console will not have to be launched each individual time to get reporting.
function Get-SCCMSoftwareUpdateStatus {
[CmdletBinding()]
param(
[Parameter()]
[switch] $DeploymentIDFromGUI,
[Parameter(Mandatory = $false)]
[Alias('ID', 'AssignmentID')]
[string] $DeploymentID,
[Parameter(Mandatory = $false)]
[ValidateSet('Success', 'InProgress', 'Error', 'Unknown')]
[Alias('Filter')]
[string] $Status
)
BEGIN {
$Site_Code = 'ABC'
$Site_Server = 'SYSTEMCENTERSERVERNAME'
$HasErrors = $False
if ($Status -eq 'Success') {
$StatusType = 1
}
if ($Status -eq 'InProgress') {
$StatusType = 2
}
if ($Status -eq 'Unknown') {
$StatusType = 4
}
if ($Status -eq 'Error') {
$StatusType = 5
}
}
PROCESS {
try {
if ($DeploymentID -and $DeploymentIDFromGUI) {
Write-Error "Select the DeploymentIDFromGUI or DeploymentID Parameter. Not Both"
$HasErrors = $True
throw
}
if ($DeploymentIDFromGUI) {
$ShellLocation = Get-Location
Import-Module (Join-Path $(Split-Path $env:SMS_ADMIN_UI_PATH) ConfigurationManager.psd1)
#Checking to see if module has been imported. If not abort.
if (Get-Module ConfigurationManager) {
Set-Location "$($Site_Code):\"
$DeploymentID = Get-CMSoftwareUpdateDeployment | select AssignmentID, AssignmentName | Out-GridView -OutputMode Single -Title "Select a Deployment and Click OK" | Select -ExpandProperty AssignmentID
Set-Location $ShellLocation
} else {
Write-Error "The SCCM Module wasn't imported successfully. Aborting."
$HasErrors = $True
throw
}
}
if ($DeploymentID) {
$DeploymentNameWithID = Get-WMIObject -ComputerName $Site_Server -Namespace root\sms\site_$Site_Code -class SMS_SUMDeploymentAssetDetails -Filter "AssignmentID = $DeploymentID" | select AssignmentID, AssignmentName
$DeploymentName = $DeploymentNameWithID.AssignmentName | select -Unique
} else {
Write-Error "A Deployment ID was not specified. Aborting."
$HasErrors = $True
throw
}
if ($Status) {
$Output = Get-WMIObject -ComputerName $Site_Server -Namespace root\sms\site_$Site_Code -class SMS_SUMDeploymentAssetDetails -Filter "AssignmentID = $DeploymentID and StatusType = $StatusType" | `
select DeviceName, CollectionName, @{Name = 'StatusTime'; Expression = {$_.ConvertToDateTime($_.StatusTime) }}, @{Name = 'Status' ; Expression = {if ($_.StatusType -eq 1) {'Success'} elseif ($_.StatusType -eq 2) {'InProgress'} elseif ($_.StatusType -eq 5) {'Error'} elseif ($_.StatusType -eq 4) {'Unknown'} }}
} else {
$Output = Get-WMIObject -ComputerName $Site_Server -Namespace root\sms\site_$Site_Code -class SMS_SUMDeploymentAssetDetails -Filter "AssignmentID = $DeploymentID" | `
select DeviceName, CollectionName, @{Name = 'StatusTime'; Expression = {$_.ConvertToDateTime($_.StatusTime) }}, @{Name = 'Status' ; Expression = {if ($_.StatusType -eq 1) {'Success'} elseif ($_.StatusType -eq 2) {'InProgress'} elseif ($_.StatusType -eq 5) {'Error'} elseif ($_.StatusType -eq 4) {'Unknown'} }}
}
if (-not $Output) {
Write-Error "A Deployment with ID: $($DeploymentID) is not valid. Aborting"
$HasErrors = $True
throw
}
} catch {
} finally {
if (($HasErrors -eq $false) -and ($Output)) {
Write-Output ""
Write-Output "Deployment Name: $DeploymentName"
Write-Output "Deployment ID: $DeploymentID"
Write-Output ""
Write-Output $Output | Sort-Object Status
}
}
}
END {}
}
10 Replies
- farismalaebIron Contributor
Hi,
I had a small question just to confirm that I understand your question, so what you need is to get the result for all the deployment packages which listed in the following line
$DeploymentID = Get-CMSoftwareUpdateDeployment | select AssignmentID, AssignmentName | Out-GridView -OutputMode Single -Title "Select a Deployment and Click OK" | Select -ExpandProperty AssignmentID
and get the percentage of how many deployment was success, failure ...etc
so the output will look like
Success: 40%
Error: 2%
Unknown: 50%
and so on, Yes?!
- NAN2019Copper Contributor
1) Yes. I would like to show a clear percentage of each status (for example: Success 12% , 40% failed), for the Software update deployment.
2) The 2nd request was to take the specific software update deployment and run it against device collection names. Maybe the device collection could either be in a for-each statement or if its possible to take the device collection name itself and do it. So in a sense I would have:
Chicago - 75% success, 25% failed, 0% In progress, 0% failed
Cleveland - 25% success, 25% failed, 50% In progress, 0% failed
Houston - 75% success, 25% failed, 0% In progress, 0% failed
Miami - 0% success, 25% failed, 25% In progress, 50% failed
And I would like it to be in a csv as well as in the txt body of an email sent every morning.
- farismalaebIron Contributor
I wrote a quick update for script, review the change and test it, I don't have a big SCCM env, but this seems to be as you want.
Function Get-AllPackages{ $AllPack = Get-CMSoftwareUpdateDeployment | select AssignmentID, AssignmentName return $AllPack } $Packages= Get-AllPackages foreach ($SinglePack in $Packages) { Write-Host "--------------" Write-Host $SinglePack.AssignmentName $packinfo=Get-SCCMSoftwareUpdateStatus -DeploymentID $SinglePack.AssignmentID $Status=$packinfo.status | Get-Unique foreach ($sinlgestatus in $Status){ Write-Host "The Status of $($sinlgestatus) for $($SinglePack.AssignmentName)" ((($packinfo | where {$_.status -like $sinlgestatus})).status.count / ($packinfo.Count -4)).tostring("P") } }
There is no change on the main function, I added extra function and some foreach loop to get the status.
Hope it helps
---------------
If the above reply answers your question, please don't forget to click on Best Response.