Overview

This process will allow you to automate deployment of required WSUS updates in your SCCM environment that were missed by your Software Update ADR. A built in SCCM SQL report can indicate which WSUS software updates are required, but not deployed in an environment.

Utilizing my two other functions, HTML Email Report and SCCM Report to Array, you can help automate the process of detecting these updates and re-injecting them into the proper Software Update Groups which target the computers requiring them.

Fundamentals

At its core, the idea here is to automate running this report and to do something with the values that are returned. For example we can choose the report we want to target:


$ReportPath="/ConfigMgr_DGM/Software Updates - B Deployment Management/Management 2 - Updates required but not deployed"

And then choose the same parameters that we would have chosen int he GUI above;



$inputParams = @{
    "CollID"="DGM00084";
    "UpdateClass"="Security Updates";
    "Vendor"="Microsoft";
}

and then using my SQL to Array function we can store the report results as an array:


$array = Get-DMGSCCMSQLReport -inputParams $inputParams `
                               -ReportServerUrl $ReportServerUrl `
                               -ReportPath $ReportPath `
                               -ProviderMachineName $ProviderMachineName `
                               -Sitecode $Sitecode

These returned results are easily be passed into the next phase where they are automatically injected into the proper Software Update Group:


$updates = $array
$undeployedupdates=$updates | %{Get-CMSoftwareUpdate -ArticleId $_.update -Fast | ?{$_.nummissing -ge 1}} 
$PilotSoftwareUpdategroup=Get-CMSoftwareUpdateGroup -Name "Desired Software Update Group* nnn"
$undeployedupdates | %{Add-CMSoftwareUpdateToGroup -SoftwareUpdateId $_.CI_ID -SoftwareUpdateGroupName "SVR - 2 - Production Servers Updates - All other Products* nnn"}

You can then choose the Software Update Group you want these automatically injected inside of:


#Multiple Arrays
Get-DMGEmailReport `
    -Arrays $OutputArrays `
    -ReportTitle "Updates Required but Not Deployed Report" `
    -from "SCCMSQLReports@corporation.com" `
    -To "c-dmaiolo@corporation.com" `
    -subject "SCCM Report: Required But Not Deployed (Not Superseded, Not Expired, Not Security Only)"

For this example let’s choose to also have the results first emailed out utilizing my HTML Email Function. This generates an email, indicating which updates were included:

required but not deployed

PowerShell Invocation


Import-Module \\scriptserver\scripts\DMGSCCM\Get-DMGSCCMSQLReport\Get-DMGSCCMSQLReport.psm1 -Force
Import-Module \\scriptserver\scripts\Get-DMGEmailReport\Get-DMGEmailReport.psm1 -Force

#Set Universal Parameters for this Report
$ReportServerUrl="http://sccmsqlrserver/ReportServer"
$ReportPath="/ConfigMgr_DGM/Software Updates - B Deployment Management/Management 2 - Updates required but not deployed"

#Create Some Arrays Of Data To Display in Report. You can create as many as you want.
$OutputArrays = @()
$ProviderMachineName = "sccmsqlrserver.corp.corporation.com"
$Sitecode = "DGM"

Set-Location $Sitecode":"

#Array1
$inputParams = @{
    "CollID"="DGM00084";
    "UpdateClass"="Security Updates";
    "Vendor"="Microsoft";
}

$array = Get-DMGSCCMSQLReport -inputParams $inputParams `
                               -ReportServerUrl $ReportServerUrl `
                               -ReportPath $ReportPath `
                               -ProviderMachineName $ProviderMachineName `
                               -Sitecode $Sitecode
Set-Location $Sitecode":"  
Write-Host "Gonna take a while..."                                          
$arrayresult = $array | %{Get-CMSoftwareUpdate -ArticleId $_.Details_Table0_Title -Fast| ?{$_.nummissing -ge 1 -and $_.IsExpired -eq $FALSE -and $_.isSuperseded -eq $FALSE -and $_.LocalizedDisplayName -notlike "*Security Only*"}} | `
                               Select ArticleID,LocalizedDisplayName,NumMissing,NumPresent,IsSuperseded,IsExpired -Unique | Sort-Object -Descending -Property NumMissing

$output = [PSCustomObject] @{
'Message' = "These are all of the Windows Updates that are required but not deplyoyed for All Servers.";
'Title' = "All Production Servers with Maintenanace Window (Security Updates): Required But Not Deployed";
'Color' = "Red";
'Array' = $arrayresult
}

if ($output.Array -ne $NULL){$OutputArrays+=$output}


#Array2
$inputParams = @{
    "CollID"="DGM00084";
    "UpdateClass"="Critical Updates";
    "Vendor"="Microsoft";
}

$array = Get-DMGSCCMSQLReport -inputParams $inputParams `
                               -ReportServerUrl $ReportServerUrl `
                               -ReportPath $ReportPath `
                               -ProviderMachineName $ProviderMachineName `
                               -Sitecode $Sitecode

Set-Location $Sitecode":"                                               
Write-Host "Gonna take a while..."                                          
$arrayresult = $array | %{Get-CMSoftwareUpdate -ArticleId $_.Details_Table0_Title -Fast| ?{$_.nummissing -ge 1 -and $_.IsExpired -eq $FALSE -and $_.isSuperseded -eq $FALSE -and $_.LocalizedDisplayName -notlike "*Security Only*"}} | `
                               Select ArticleID,LocalizedDisplayName,NumMissing,NumPresent,IsSuperseded,IsExpired -Unique | Sort-Object -Descending -Property NumMissing

$output = [PSCustomObject] @{
'Message' = "These are all of the Windows Updates that are required but not deplyoyed for All Servers.";
'Title' = "All Production Servers with Maintenanace Window (Security Updates): Required But Not Deployed";
'Color' = "Red";
'Array' = $arrayresult
}

if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Array3
$inputParams = @{
    "CollID"="DGM00085";
    "UpdateClass"="Security Updates";
    "Vendor"="Microsoft";
}

$array = Get-DMGSCCMSQLReport -inputParams $inputParams `
                               -ReportServerUrl $ReportServerUrl `
                               -ReportPath $ReportPath `
                               -ProviderMachineName $ProviderMachineName `
                               -Sitecode $Sitecode

Set-Location $Sitecode":"                                               
Write-Host "Gonna take a while..."                                          
$arrayresult = $array | %{Get-CMSoftwareUpdate -ArticleId $_.Details_Table0_Title -Fast| ?{$_.nummissing -ge 1 -and $_.IsExpired -eq $FALSE -and $_.isSuperseded -eq $FALSE -and $_.LocalizedDisplayName -notlike "*Security Only*"}} | `
                               Select ArticleID,LocalizedDisplayName,NumMissing,NumPresent,IsSuperseded,IsExpired -Unique | Sort-Object -Descending -Property NumMissing

$output = [PSCustomObject] @{
'Message' = "These are all of the Windows Updates that are required but not deplyoyed for All Servers.";
'Title' = "All Production Servers with Maintenanace Window (Security Updates): Required But Not Deployed";
'Color' = "Red";
'Array' = $arrayresult
}

if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Array4
$inputParams = @{
    "CollID"="DGM00085";
    "UpdateClass"="Critical Updates";
    "Vendor"="Microsoft";
}

$array = Get-DMGSCCMSQLReport -inputParams $inputParams `
                               -ReportServerUrl $ReportServerUrl `
                               -ReportPath $ReportPath `
                               -ProviderMachineName $ProviderMachineName `
                               -Sitecode $Sitecode

Set-Location $Sitecode":"                                               
Write-Host "Gonna take a while..."                                          
$arrayresult = $array | %{Get-CMSoftwareUpdate -ArticleId $_.Details_Table0_Title -Fast| ?{$_.nummissing -ge 1 -and $_.IsExpired -eq $FALSE -and $_.isSuperseded -eq $FALSE -and $_.LocalizedDisplayName -notlike "*Security Only*"}} | `
                               Select ArticleID,LocalizedDisplayName,NumMissing,NumPresent,IsSuperseded,IsExpired -Unique | Sort-Object -Descending -Property NumMissing

$output = [PSCustomObject] @{
'Message' = "These are all of the Windows Updates that are required but not deplyoyed for All Servers.";
'Title' = "All Production Servers with Maintenanace Window (Security Updates): Required But Not Deployed";
'Color' = "Red";
'Array' = $arrayresult
}

if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Multiple Arrays
Get-DMGEmailReport `
    -Arrays $OutputArrays `
    -ReportTitle "Updates Required but Not Deployed Report" `
    -from "SCCMSQLReports@corporation.com" `
    -To "c-dmaiolo@corporation.com" `
    -subject "SCCM Report: Required But Not Deployed (Not Superseded, Not Expired, Not Security Only)"

Overview

I created this script, Get-DMGSCCMNewDeployments, to allow you to send out an email report of new SCCM deployments in your environment. This script uses native SCCM methods to build an automated report that sends an easy to read “what was deployed this week” report out to SCCM administrators.

Methodology

The report is compiled one array at a time, then combined into an array of arrays that is fed into my HTML email script.

Generating an Automated Report

This report loops through all of the available deployments that were created within the last seven days and emails the results to an email address:

If you would like to change the date range, simply update the values -MinDaysOld and -MaxDaysOld in the array element that is in the invocation function when calling the script:


'Array' = Get-DMGSCCMNewDeployments -MinDaysOld 0 -MaxDaysOld 7 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0 -FeatureType Baseline -ProviderMachineName $ProviderMachineName -Sitecode $Sitecode;

PowerShell Invocation Function


Import-Module \\scriptserver\scripts\Get-DMGEmailReport\Get-DMGEmailReport.psm1 -Force
Import-Module \\scriptserver\Scripts\DMGSCCM\Get-DMGSCCMNewDeployments\Get-DMGSCCMNewDeployments.psm1 -Force

#Create Some Arrays Of Data To Display in Report. You can create as many as you want.
$OutputArrays = @()
$ProviderMachineName = "SCCMSERVER.corp.corporation.com" #Enter Your SCCM Server Here
$Sitecode = "NNN" #Enter Your Site Code Here
   
#Array1
$output = [PSCustomObject] @{
'Message' = "These are all of the new Task Sequence deployments, and the collections they were deployed to, that were created within the last seven days. As a reminder, Task Sequences should not be used to deploy applications outside of an Operating System deployment.";
'Title' = "Task Sequence Deployments`: New This Week!";
'Color' = "Red";
'Array' = Get-DMGSCCMNewDeployments -MinDaysOld 0 -MaxDaysOld 7 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0 -FeatureType TaskSequence -ProviderMachineName $ProviderMachineName -Sitecode $Sitecode;
}
if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Array2
$output = [PSCustomObject] @{
'Message' = "These are all of the new Package deployments, and the collections they were deployed to, that were created within the last seven days. As a reminder, packages have been depreciated in SCCM, in favor of using Applications.";
'Title' = "Package Deployments`: New This Week!";
'Color' = "Red";
'Array' = Get-DMGSCCMNewDeployments -MinDaysOld 0 -MaxDaysOld 7 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0 -FeatureType Package -ProviderMachineName $ProviderMachineName -Sitecode $Sitecode;
}
if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Array3
$output = [PSCustomObject] @{
'Message' = "These are all of the new Application deployments, and the collections they were deployed to, that were created within the last seven days.";
'Title' = "Application Deployments`: New This Week!";
'Color' = "Black";
'Array' = Get-DMGSCCMNewDeployments -MinDaysOld 0 -MaxDaysOld 7 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0 -FeatureType Application -ProviderMachineName $ProviderMachineName -Sitecode $Sitecode;
}
if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Array4
$output = [PSCustomObject] @{
'Message' = "These are all of the new Windows Update deployments, and the collections they were deployed to, that were created within the last seven days.";
'Title' = "Windows Update Deployments`: New This Week!";
'Color' = "Black";
'Array' = Get-DMGSCCMNewDeployments -MinDaysOld 0 -MaxDaysOld 7 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0 -FeatureType Update -ProviderMachineName $ProviderMachineName -Sitecode $Sitecode;
}
if ($output.Array -ne $NULL){$OutputArrays+=$output}

#Array5
$output = [PSCustomObject] @{
'Message' = "These are all of the new Configuration Baseline deployments, and the collections they were deployed to, that were created within the last seven days.";
'Title' = "Configuration Baseline Deployments`: New This Week!";
'Color' = "Black";
'Array' = Get-DMGSCCMNewDeployments -MinDaysOld 0 -MaxDaysOld 7 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0 -FeatureType Baseline -ProviderMachineName $ProviderMachineName -Sitecode $Sitecode;
}
if ($output.Array -ne $NULL){$OutputArrays+=$output}


#Multiple Arrays
Get-DMGEmailReport `
    -Arrays $OutputArrays `
    -ReportTitle "Last Seven Days SCCM Deployments Report" `
    -from "SCCMDeployments@corporation.com" `
    -To "serverteam@corporation.com","desktopteam@corporation.com","ddinh@corporation.com" `
    -subject "This Week's New SCCM Deployments"

PowerShell Function


<#
.SYNOPSIS
  Generates an array of SCCM objects that are new deployments
.NOTES
  Version:        1.0
  Author:         David Maiolo
  Creation Date:  2018-01-10
  Purpose/Change: Initial script development

#>

#---------------------------------------------------------[Initialisations]--------------------------------------------------------

function Get-DMGSCCMNewDeployments {
    param(
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        [ValidateRange(1,10000)]
        [Int] $MaxDaysOld,
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        [ValidateRange(0,10000)]
        [Int] $MinDaysOld,
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        [ValidateRange(0,1)]
        [Float] $PercentSuccessThreshold,
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        [ValidateRange(0,10000)]
        [int] $NumberOfTargetedThreshold,

        [Parameter(Position=2,Mandatory=$false,ValueFromPipeline=$true)]
        [ValidateSet("Application","Package","Update","Baseline","TaskSequence")]
        [String]$FeatureType,

        [Parameter(Position=3,Mandatory=$true,ValueFromPipeline=$true)]
        [String]$ProviderMachineName,

        [Parameter(Position=4,Mandatory=$true,ValueFromPipeline=$true)]
        [ValidateLength(3,3)]
        [String]$Sitecode

    )

    #Check which feature type was selected and convert to the number Get-CMDeployments uses
    if([bool]($MyInvocation.BoundParameters.Keys -contains 'FeatureType')){
           switch ($FeatureType)
           {
               'Application' {$FeatureTypeOutput=1}
               'Package' {$FeatureTypeOutput=2}
               'Update' {$FeatureTypeOutput=5}
               'Baseline' {$FeatureTypeOutput=6}
               'TaskSequence' {$FeatureTypeOutput=7}
           }
    }

    #Connect to SCCM
    # Import the ConfigurationManager.psd1 module
    $module = "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
    if((Get-Module ConfigurationManager) -eq $null) {
        Write-Host Importing $module ...
        Import-Module $module -Force
    }

    # Connect to the site's drive if it is not already present
    if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
        $NewPSDrive = New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName
    }

    # Set the current location to be the site code.
    Set-Location "$($SiteCode):\"

    #Get date for comparison
    $MaxDaysOldAgo=(Get-Date).AddDays(-$MaxDaysOld)
    $MinDaysOldAgo=(Get-Date).AddDays(-$MinDaysOld)

    Write-Host "Processing $($FeatureType)s..."

    #Get deployment matching featuretype and date range
    if ($FeatureType){
        $DeploymentsNewerThanDaysAgo = Get-CMDeployment | Where-Object {$_.DeploymentTime -gt $MaxDaysOldAgo -and $_.DeploymentTime -lt $MinDaysOldAgo -and $_.FeatureType -eq $FeatureTypeOutput}
    }else{
        $DeploymentsNewerThanDaysAgo = Get-CMDeployment | Where-Object {$_.DeploymentTime -gt $MaxDaysOldAgo -and $_.DeploymentTime -lt $MinDaysOldAgo}
    }

    #Created a Calculated Value of the Percentage of Succesful Deployments and add additional Properties
    $DMGSCCMNewDeployments = $DeploymentsNewerThanDaysAgo | Select-Object -Property `
        @{Name = 'Deployment Name'; Expression = {$_.ApplicationName}},`
        @{Name = 'Deployed To'; Expression = {$_.CollectionName}},`
        @{Name = 'Deployment Time'; Expression = {$_.DeploymentTime}},`
        @{Name = 'Percent Success'; Expression = {[math]::Round(($_.Properties.NumberSuccess/$_.Properties.NumberTargeted),2)*100}},`
        @{Name = 'Number Targeted'; Expression = {$_.Properties.NumberTargeted}},`
        @{Name = 'Success'; Expression = {$_.Properties.NumberSuccess}},`
        @{Name = 'In Progress'; Expression = {$_.Properties.NumberInProgress}},`
        @{Name = 'Unknowns'; Expression = {$_.Properties.NumberUnknown}}

    #Calculate where the percent success than the supplied values
    $DMGSCCMNewDeployments = $DMGSCCMNewDeployments | Where-Object {$_."Percent Success" -le ($PercentSuccessThreshold*100) -and $_."Number Targeted" -gt $NumberOfTargetedThreshold} | Sort-Object -Property 'Deployment Name'

    #Return the array
    return $DMGSCCMNewDeployments

}

Overview

This script will allow you to take a standard SCCM SQL Report and output the report, automatically, to either a .CSV file or to an array for use in a pipeline.

Workflow

This standard SCCM SQL report can be run which would allow you to see all of the software updates that are required but not deployed via WSUS.

Software Updates – Updates required but not deployed

Simply running the report gives you an indication of what variables are required to run this report. When fed into this function, the report will run automatically with these values chosen and the results can be either output to the pipeline as an array or to a .CSV file for easy emailing.


Import-Module \\scriptserver\scripts\DMGSCCM\Get-DMGSCCMSQLReport\Get-DMGSCCMSQLReport.psm1 -Force


#Set Universal Parameters for this Report
$ReportServerUrl="http://sccmsqlrserver/ReportServer"
$ReportPath="/ConfigMgr_DGM/Software Updates - B Deployment Management/Management 2 - Updates required but not deployed" #Include your report path here - this is a sample only

#Create Array Of Data To Display in Report.
$OutputArrays = @()
$ProviderMachineName = "sccmsqlrserver.corp.corporation.com" #enter your sccm sql server here
$Sitecode = "DGM" #enter your site code here

Set-Location $Sitecode":"

#Array1
$inputParams = @{
    "CollID"="DGM00084"; #These are sample values
    "UpdateClass"="Security Updates";
    "Vendor"="Microsoft";
}

$array = Get-DMGSCCMSQLReport -inputParams $inputParams `
                               -ReportServerUrl $ReportServerUrl `
                               -ReportPath $ReportPath `
                               -ProviderMachineName $ProviderMachineName `
                               -Sitecode $Sitecode
Set-Location $Sitecode":"  

#Generate Array with All Production Servers with Maintenance Window (Security Updates): Required But Not Deployed                                        
$arrayresult = $array | %{Get-CMSoftwareUpdate -ArticleId $_.Details_Table0_Title -Fast| ?{$_.nummissing -ge 1 -and $_.IsExpired -eq $FALSE -and $_.isSuperseded -eq $FALSE -and $_.LocalizedDisplayName -notlike "*Security Only*"}} | `
                               Select ArticleID,LocalizedDisplayName,NumMissing,NumPresent,IsSuperseded,IsExpired -Unique | Sort-Object -Descending -Property NumMissing

As you can see in the example, we take the results from a standard SQL report, transform them into an array as $array, and simultaneously pipe them to Get-CMSoftwareUpdate for further processing as $arrayresult.

Logging Results

This function has standard capabilities to output its status a log file which is fully compatible with CMTrace.exe

PowerShell Function


<#
.SYNOPSIS
  Generates an array of a SCCM SQL Report
.NOTES
  Version:        1.0
  Author:         David Maiolo
  Creation Date:  2018-01-11
  Purpose/Change: Initial script development

#>

#---------------------------------------------------------[Initialisations]--------------------------------------------------------
 function Get-DMGSCCMSQLReport
 {
    param(
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        $inputParams,
        [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)]
        $ReportServerUrl,
        [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$true)]
        $ReportPath,
        [Parameter(Position=3,Mandatory=$true,ValueFromPipeline=$true)]
        [String]$ProviderMachineName,
        [Parameter(Position=4,Mandatory=$true,ValueFromPipeline=$true)]
        [String]$Sitecode
    )


    #Set Logging Varibales
    $invocation = (Get-Variable MyInvocation -Scope 1).Value
    $ScriptDirectory = Split-Path $invocation.MyCommand.Path
    $ScriptName = ($MyInvocation.MyCommand.Name)+".psm1"
    $LogName = ($MyInvocation.MyCommand.Name)+".log"
    $LogFile = Join-Path $ScriptDirectory $LogName
    $ScriptFile = Join-Path $ScriptDirectory $ScriptName
    $ReportDate = Get-Date 

    #Set CSV Output Variables
    $CSVOutputName = ($MyInvocation.MyCommand.Name)+".csv"
    $CSVOutputFile = Join-Path $ScriptDirectory $CSVOutputName

    #Log Start of Function
    New-DMGCMTraceLog -message ("Starting Logging for $ScriptName") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile

    #Connect to SCCM
    # Import the ConfigurationManager.psd1 module
    $module = "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
    if((Get-Module ConfigurationManager) -eq $null) {
        Write-Host Importing $module ...
        Import-Module $module -Force
    }

    # 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):\"


    # add assembly 
    Add-Type -AssemblyName "Microsoft.ReportViewer.WinForms, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"

    # if the path exists, will error silently and continue 
    New-Item -ItemType Directory -Path $baseFolder -ErrorAction SilentlyContinue | Out-Null

    $rv = New-Object Microsoft.Reporting.WinForms.ReportViewer

    # report Server Properties 
    $rv.ServerReport.ReportServerUrl = $ReportServerUrl
    $rv.ServerReport.ReportPath = $ReportPath
    $rv.ProcessingMode = "Remote"

    # set up report parameters 
    $params = $null

    #create an array based on how many incoming parameters 
    $params = New-Object 'Microsoft.Reporting.WinForms.ReportParameter[]' $inputParams.Count

    $i = 0 
    foreach ($p in $inputParams.GetEnumerator()) 
    { 
        $params[$i] = New-Object Microsoft.Reporting.WinForms.ReportParameter($p.Name, $p.Value, $true) 
        $i++ 
    } 

    # set the parameters 
     Write-Host "Setting Parameters..."
    $rv.ServerReport.SetParameters($params) 
    $rv.ShowParameterPrompts = $false 
    $rv.RefreshReport() 
    $rv.ServerReport.Refresh()

    Write-Host "The Parameters Were Applied..."

    # set rendering parameters 
    $mimeType = $null 
    $encoding = $null 
    $extension = $null 
    $streamids = $null 
    $warnings = $null

    # render the SSRS report in CSV 
    $bytes = $null 
    $bytes = $rv.ServerReport.Render("CSV", 
    $null, 
    [ref] $mimeType, 
    [ref] $encoding, 
    [ref] $extension, 
    [ref] $streamids, 
    [ref] $warnings)

    Set-Location C:\

    # save the report to a file
    $fileStream = New-Object System.IO.FileStream($CSVOutputFile, [System.IO.FileMode]::OpenOrCreate) 
    $fileStream.Write($bytes, 0, $bytes.Length) 
    $fileStream.Close()

    New-DMGCMTraceLog -message ("File Exported`: $CSVOutputFile") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile

    # Re-import file and remove first three lines

    get-content -LiteralPath $CSVOutputFile|
        select -Skip 3 |
        set-content "$CSVOutputFile-temp"
    move "$CSVOutputFile-temp" $CSVOutputFile -Force
    #Log Sent Email
    New-DMGCMTraceLog -message ("File Imported (First 3 Lines Removed)`: $CSVOutputFile") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile

    $Finalvalues = Import-CSV -LiteralPath $CSVOutputFile

    #Log End Of Function
    New-DMGCMTraceLog -message ("End Logging for $ScriptName") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile

    return $Finalvalues

}

Overview

At times, SCCM client machines may lose the ability to communicate properly with the SCCM site server due to Kerberos authentication errors. You will see these errors in Deployment Statuses or other times invoking PowerShell scripts on remote clients.

This script attempts to invoke a generic script remotely on an imported set of SCCM clients and determine if there is a Kerberos authentication error:

 Invoke-Command -ComputerName $h -ScriptBlock { Test-Connection SCCMSERVER -Quiet -Count 1 } -ErrorAction Stop 

If the invocation returns the exception error System.Management.Automation.Remoting.PSRemotingTransportException you can assume there is an error and we can remotely instruct a CLI through WinRM:

 $command = "C:\ADMIN`\PSTools\PsExec.exe \\$h /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`"" 

Therefor it is a prerequisite that you have PsExec.exe in the C:\ADMIN\PSTools\ directory of the PC before running the script, as shown above.

The script will also try to resolve DNS issues that may be related to the error.

Fixing Kerberos Errors on an Imported List of Computers

You can import a generic list of computers via a CSV that is in the following format:

 Fix-DGMKerberosError –CSV \\Pathto\the.csv 

Logging Output

The function outputs its progress to a log file and is fully compatible with CMTrace.exe.

PowerShell Function

 
<#
.Synopsis
   Fix SCCM Kerberos Errors
.DESCRIPTION
   The tool, Fix-DMGKerberosError.ps1 was written by David Maiolo which will attempt to fix Kerberos Authentican Issues on remote computers.
.EXAMPLE
   Fix-DMGKerberosError -CSVFile kerberos_error_import.csv
.EXAMPLE
   Fix-DMGKerberosError -Hostname LT061222
#>


function LogIt
{
  param (
  [Parameter(Mandatory=$true)]
  $message,
  [Parameter(Mandatory=$true)]
  $component,
  [Parameter(Mandatory=$true)]
  $type )

  switch ($type)
  {
    1 { $type = "Info" }
    2 { $type = "Warning" }
    3 { $type = "Error" }
    4 { $type = "Verbose" }
  }

  if (($type -eq "Verbose") -and ($Global:Verbose))
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    Write-Host $message
  }
  elseif ($type -ne "Verbose")
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    if ($type -eq 'Info') { Write-Host $message }
    if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
    if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
    

  }
  if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type }
  if ($type -eq 'Error') { $Global:ScriptStatus = $type }

  if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB)
  {
    $log = $Global:LogFile
    Remove-Item ($log.Replace(".log", ".lo_"))
    Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force
  }
} 

function GetScriptDirectory
{
  $invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $invocation.MyCommand.Path
} 

function Fix-DMGKerberosError
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 1')]
                   [ValidateScript({(Test-Path $_)})]
                   $CSVFile,
        # Param2 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 2')]
                   [ValidateScript({(Get-ADComputer -Identity $_).objectclass -eq 'computer' })]
                   [String]$Hostname
    )

    Begin
    {
        $path = (get-item -Path .).FullName 
        
        if ($CSVFile -ne $null){
            Write-Host Importing $CSVFile...
            $csv = import-csv "$CSVFile"
        }else{
            $csv = [PSCustomObject]@{
                Hostname = $Hostname}
        }
        Write-Host ==========================================
        Write-Host SCCM Kerberos Remote Execution Fix Tool
        Write-Host ==========================================
        Write-Host "v0.1 (2017-12-20) by dmaiolo"
        LogIt -message ("Starting Logging for Fix-DMGKerberosError") -component "Main()" -type 1 
    }
    Process
    {
    

    $computers = @();
        
    $csv | foreach-object {
        $h = $_.Hostname
    

        if(Test-Connection -ComputerName $h -Count 1 -Quiet){

            Write-Host "$h`: Invoking Generic Command (Test-Connection SCCMSERVER -Quiet -Count 1)..."
            Try{
                Invoke-Command -ComputerName $h -ScriptBlock { Test-Connection SCCMSERVER -Quiet -Count 1 } -ErrorAction Stop
                LogIt -message ("$h`: Generic Command (Test-Connection SCCMSERVER -Quiet -Count 1) Ran Succesfully. No Fix Required.") -component "Main()" -type 1
            }
            Catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
                LogIt -message ("$h`: Kerberos Issue Detected. Fix Required") -component "Main()" -type 2
                Write-Host "$h`: Attempting to Repair WinRM for Kerberos Authentication..."
                $command = "C:\ADMIN`\PSTools\PsExec.exe \\$h /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`""
                if($expression = Invoke-Expression -Command:"$command" -ErrorAction Stop) {
                    LogIt -message ("$h`: WinRM Repair Ran Succesfully for Kerberos Authentication") -component "Main()" -type 1
                    }
                else{
                    LogIt -message ("$h`: WinRM Repair NOT Succesfull for Kerberos Authentication") -component "Main()" -type 3
                    LogIt -message ("$h`: Attempting DNS Repair by running PsExec for ipconfig /registerdns against the IP Address... ") -component "Main()" -type 1
                    try{
                        $IPv4AddressPinged = (Test-Connection -ComputerName $h -Count 1 -ErrorAction SilentlyContinue).IPV4Address.IPAddressToString
                        LogIt -message ("$h`: Found a valid IP Address To Invoke-Expression against ($IPv4AddressPinged).") -component "Main()" -type 1
                        $RealHostName = (Resolve-DnsName $IPv4AddressPinged).NameHost
                        LogIt -message ("$h`: Your DNS has accociated $h to $IPv4AddressPinged, but it acually belongs to $RealHostName. This is part of your problem.") -component "Main()" -type 1
                        
                    }
                    catch{
                        LogIt -message ("$h`: No Valid IP Address for this host could be determined.") -component "Main()" -type 3
                        $RealHostName = $false
                        $IPv4AddressPinged = $false
                    }
                    if ($IPv4AddressPinged){
                        $command2 = "C:\ADMIN\PSTools\PsExec.exe \\$IPv4AddressPinged /s /accepteula /nobanner cmd /c `"ipconfig /registerdns`""
                        if(Invoke-Expression -Command:"$command2"){
                            LogIt -message ("$h`: ($RealHostName) Succesfully Ran $command2.") -component "Main()" -type 1
                            Write-Host "$h`: ($RealHostName) Attempting to Repair WinRM for Kerberos Authentication against IP Address ($IPv4AddressPinged)..."
                            $command3 = "C:\ADMIN`\PSTools\PsExec.exe \\$IPv4AddressPinged /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`""
                            if($expression2 = Invoke-Expression -Command:"$command3" -ErrorAction Stop) {
                                LogIt -message ("$h`: ($RealHostName) WinRM Repair Ran Succesfully for Kerberos Authentication against IP Address ($IPv4AddressPinged)") -component "Main()" -type 1
                            }
                            else{
                                LogIt -message ("$h`: ($RealHostName) WinRM Repair NOT Succesfull for Kerberos Authentication against IP Address ($IPv4AddressPinged)") -component "Main()" -type 3
                               }
                        }
                        else{
                            LogIt -message ("$h`: ($RealHostName) Unable to Run $command2.") -component "Main()" -type 3
                        }
                    }
                 }
            }
            Catch{
                LogIt -message ("$h`: Generic Command (Test-Connection SCCMSERVER -Quiet -Count 1) Ran Into a Non-Kerberos Issue. Fix Unknown.") -component "Main()" -type 3
            }

        }
        else{
            LogIt -message ("$h`: is offline.") -component "Main()" -type 2
        }
       }
    }
    End
    {
       Write-Host ===============================================================
       Write-Host Log File of Results Generated at $Global:LogFile VIEW WITH CMTRACE.EXE
       LogIt -message ("Ending Logging for Fix-DMGKerberosError") -component "Main()" -type 1
    }
}

$VerboseLogging = "true"
[bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging)
#$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGKerberosError_$(Get-Date -Format dd-MM-yyyy).log"
$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGKerberosError.log"
$Global:MaxLogSizeInKB = 10240
$Global:ScriptName = 'Fix-DMGKerberosError.ps1' 
$Global:ScriptStatus = 'Success'

Overview

I developed this tool, Fix-DMGSCCMWUAPolicy.ps1,to help you mitigate WUA Policy issues that result in error 0x80004005 on the client-side WUAHandler.log file. This tool will attempt to resolve those issues.

Troubleshooting Error 0x80004005

When you deploy software updates, you add the updates to a SUG and then deploy the SUG to your clients. When you create the deployment, the update policy is sent to client computers, and the update content files are downloaded from a DP to the local cache on the client computer. The updates are then available for installation. After the deployment and the deployment policy have been created on the server, clients receive the policy on the next policy evaluation cycle. However, group policy issues can sometimes block these policies.

Root Cause of WSUS Error 0x80004005

If you receive error 0x80004005 in your WUAHandler.log file, then Group policy is likely overriding the local policy, not allowing the workstation to be patched or updated.

Resolution to WSUS Error 0x80004005

If you have this error, a few steps need to be carried out to resolve. The below script will automate this task against remotely against a set of imported computers. If the fix is not required, the utility will pass on to the next computer in the CSV file.

The utility will create a log file which is compatible with the CMTrace.exe tool.

log_file

PowerShell Script: Fix-DMGSCCMWUAPolicy.ps1


<#
.Synopsis
   Fix the WUA Policy Locally On The Client
.DESCRIPTION
   The tool, Fix-DMGSCCMWUAPolicy.ps1 was written by David Maiolo and will automatically fix WUA Policies
.EXAMPLE
   Fix-DMGSCCMWUAPolicy -CSVFile sccm_import.csv
.EXAMPLE
   Fix-DMGSCCMWUAPolicy -Hostname WORKSTATION01
#>


function New-DGMLogFile
{
  param (
  [Parameter(Mandatory=$true)]
  $message,
  [Parameter(Mandatory=$true)]
  $component,
  [Parameter(Mandatory=$true)]
  $type )

  switch ($type)
  {
    1 { $type = "Info" }
    2 { $type = "Warning" }
    3 { $type = "Error" }
    4 { $type = "Verbose" }
  }

  if (($type -eq "Verbose") -and ($Global:Verbose))
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    Write-Host $message
  }
  elseif ($type -ne "Verbose")
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    if ($type -eq 'Info') { Write-Host $message }
    if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
    if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
    

  }
  if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type }
  if ($type -eq 'Error') { $Global:ScriptStatus = $type }

  if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB)
  {
    $log = $Global:LogFile
    Remove-Item ($log.Replace(".log", ".lo_"))
    Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force
  }
} 

function GetScriptDirectory
{
  $invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $invocation.MyCommand.Path
} 

function Fix-DMGSCCMWUAPolicy
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 1')]
                   [ValidateScript({(Test-Path $_)})]
                   $CSVFile,
        # Param2 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 2')]
                   [ValidateScript({(Get-ADComputer -Identity $_).objectclass -eq 'computer' })]
                   [String]$Hostname
    )

    Begin
    {
        $path = (get-item -Path .).FullName 
        
        if ($CSVFile -ne $null){
            Write-Host Importing $CSVFile...
            $csv = import-csv "$CSVFile"
        }else{
            $csv = [PSCustomObject]@{
                Hostname = $Hostname}
        }
        Write-Host ==========================================
        Write-Host SCCM WUA Policy Error 0`x80070002 Fix Tool
        Write-Host ==========================================
        Write-Host "v0.1 (2017-12-20) by dmaiolo"
        New-DGMLogFile -message ("Starting Logging for Fix-DMGSCCMWUAPolicy") -component "Main()" -type 1 
    }
    Process
    {
    

    $computers = @();
        
    $csv | foreach-object {
        $h = $_.Hostname
    

        if(Test-Connection -ComputerName $h -Count 1 -Quiet){


            $g = $null
            $resultsfile = $null

            $resultsfile = "\\$h\c$\Windows\CCM\Logs\WUAHandler.log"
            #$resultsfile = "\\cs-msc\public\Temp\Noah\WUAHandler.log"
            $logLines = @()

            Write-Host $h`: Loading $resultsfile ...
            if (Test-Path $resultsfile){
                $g = Get-Content  $resultsfile -ErrorAction Stop
            }else{
                New-DGMLogFile -message ("$h`: $resultsfile Does Not Exist") -component "Main()" -type 3
            }
            
            $lastLine = $g.Length
            $WUAPolicyErrorFound = $false
            Write-Host $h`: Size of File`: $lastLine Lines

            for($i = $lastLine-1; $i -ge 0; $i--)
            {
                #if ($g[$i] -contains "*0x80004005*") { 
                #    Write-Host $g[$i]
                #    $WUAPolicyErrorFound = $true
                #    break
                $g[$i] -match '(?:.*)(0x80004005)' | out-null
                    #$logLines += ($h + ': ' + $matches[1] + ' on ' + $matches[3] + ' at ' + $matches[2])
                    if ($matches -ne $null){
                        if ($matches[1] -eq "0x80004005") { 
                            $WUAPolicyErrorFound = $true
                            break 
                        }
                    }
               
            }

            if($WUAPolicyErrorFound){
                New-DGMLogFile -message ("$h`: Unable to read existing WUA Group Policy object. 0x80004005. Fix requred.") -component "Main()" -type 2
                $sourcefile = "\\$h\c$\Windows\System32\GroupPolicy\Machine\Registry.pol"
                #$destinationfile = "\\$($h)\c$\Windows\System32\GroupPolicy\Registry_$(Get-Date -Format dd-MM-yyyy).pol"

                Write-Host "$h`: Removing $sourcefile..."
                if (Test-Path $sourcefile){
                    try{
                        Remove-Item -Path $sourcefile -Force
                        New-DGMLogFile -message ("$h`: Removed Policy File`: $sourcefile.") -component "Main()" -type 1
                    }
                    catch{
                        New-DGMLogFile -message ("$h`: Could NOT Remove Policy File`: $sourcefile.") -component "Main()" -type 3
                    }
                }else{
                    New-DGMLogFile -message ("$h`: File Does Not Exist`: $sourcefile.") -component "Main()" -type 3
                }

                Write-Host $h`: Sleeping 5 Seconds...
                sleep 5

                Write-Host "$h`: Running GPUdate `/Force..."
                Try{
                    Invoke-Command -ComputerName $h -ScriptBlock { gpupdate /force } -ErrorAction Stop
                    New-DGMLogFile -message ("$h`: GPUpdate /Force Ran Succesfully") -component "Main()" -type 1
                }
                Catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
                    New-DGMLogFile -message ("$h`: GPUpdate /Force Did NOT Run Succesfully (errorcode 0x80090322 occurred while using Kerberos authentication: An unknown security error occurred.)") -component "Main()" -type 3
                    try {
                        $command = "C:\ADMIN`\PSTools\PsExec.exe \\$h /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`""
                        Invoke-Expression -Command:"$command"
                        New-DGMLogFile -message ("$h`: WinRM Repair Ran Succesfully") -component "Main()" -type 1
                        }
                    catch{
                        New-DGMLogFile -message ("$h`: WinRM Repair NOT Succesfull") -component "Main()" -type 3
                    }
                }
                Catch{
                    New-DGMLogFile -message ("$h`: GPUpdate /Force Did NOT Run Succesfully (generic error)") -component "Main()" -type 3
                }

                Write-Host $h`: Sleeping 5 Seconds...
                sleep 5

                Write-Host "$h`: Updating the SCCM Store Policy..."
                Try{
                    Invoke-Command -ComputerName $h -ScriptBlock { 
                        $strAction = "{00000000-0000-0000-0000-000000000108}"

                        $WMIPath = "\\" + $Using:h + "\root\ccm:SMS_Client" 
                        $SMSwmi = [wmiclass] $WMIPath 
                        [Void]$SMSwmi.TriggerSchedule($strAction)
                     } -ErrorAction Stop
                    New-DGMLogFile -message ("$h`: Update of the SCCM Store Policy Was Succesful") -component "Main()" -type 1
                }
                Catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
                    New-DGMLogFile -message ("$h`: Update of the SCCM Store Policy Was NOT Succesful (errorcode 0x80090322 occurred while using Kerberos authentication: An unknown security error occurred.)") -component "Main()" -type 3
                }
                Catch{
                    New-DGMLogFile -message ("$h`: Update of the SCCM Store Policy Was NOT Succesful (generic error)") -component "Main()" -type 3
                }

            }else{
                New-DGMLogFile -message ("$h`: No WUA Group Policy Object Errors Found. No Fix requred.") -component "Main()" -type 1
            }

        }
        else{
            New-DGMLogFile -message ("$h`: is offline.") -component "Main()" -type 2
        }
       }
    }
    End
    {
       Write-Host ===============================================================
       Write-Host Log File of Results Generated at $Global:LogFile VIEW WITH CMTRACE.EXE
       New-DGMLogFile -message ("Ending Logging for Fix-DMGSCCMWUAPolicy") -component "Main()" -type 1
    }
}

$VerboseLogging = "true"
[bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging)
#$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGSCCMWUAPolicy_$(Get-Date -Format dd-MM-yyyy).log"
$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGSCCMWUAPolicy.log"
$Global:MaxLogSizeInKB = 10240
$Global:ScriptName = 'Fix-DMGSCCMWUAPolicy.ps1' 
$Global:ScriptStatus = 'Success'

Overview

I developed this tool, Fix-DMGSCCMStateMessage.ps1, to assit in troubleshooting SCCM “In Progress” and State Message Communication issues. If the UpdateStore.log shows that a particular windows update component is installed, but it is still in progress in the SCCM console, the State Message is likely not communicating properly to the SQL server. State messaging is a mechanism in SCCM which replicates point in time conditions on the client.

Fix-DGMSCCMStateMessage Tool

The tool will automatically update the State Message locally on the SCCM client by invoking the following two commands:


$SCCMUpdatesStore = New-Object -ComObject Microsoft.CCM.UpdatesStore
$SCCMUpdatesStore.RefreshServerComplianceState()

The tool requires the –csvfile argument, which is the path to a .CSV file containing one column, Hostname, with the computer hostnames listed in the column and can be run as in the example below.

Fix-DGMSCCMStateMessage Log File

The utility will create a log file that is compatible with the CMTrace tool, which includes the thread, time, state and component for each process.


<#
.Synopsis
   Update the State Message locally on the SCCM client
.DESCRIPTION
   The tool, Fix-DMGSCCMStateMessage.ps1 was written by David Maiolo which will automatically update the State Message locally on the SCCM client by 
   invoking the following two commands: $SCCMUpdatesStore = New-Object -ComObject Microsoft.CCM.UpdatesStore and $SCCMUpdatesStore.RefreshServerComplianceState()
.EXAMPLE
   Fix-DMGSCCMStateMessage -CSVFile state_message_import.csv
.EXAMPLE
   Fix-DMGSCCMStateMessage -Hostname WORKSTATION01
#>


function New-DGMLogFile
{
  param (
  [Parameter(Mandatory=$true)]
  $message,
  [Parameter(Mandatory=$true)]
  $component,
  [Parameter(Mandatory=$true)]
  $type )

  switch ($type)
  {
    1 { $type = "Info" }
    2 { $type = "Warning" }
    3 { $type = "Error" }
    4 { $type = "Verbose" }
  }

  if (($type -eq "Verbose") -and ($Global:Verbose))
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    Write-Host $message
  }
  elseif ($type -ne "Verbose")
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    if ($type -eq 'Info') { Write-Host $message }
    if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
    if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
    

  }
  if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type }
  if ($type -eq 'Error') { $Global:ScriptStatus = $type }

  if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB)
  {
    $log = $Global:LogFile
    Remove-Item ($log.Replace(".log", ".lo_"))
    Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force
  }
} 

function GetScriptDirectory
{
  $invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $invocation.MyCommand.Path
} 

function GetStringBetweenTwoStrings($firstString, $secondString, $importString){

    #Get content from file
    $file = $importString

    #Regex pattern to compare two strings
    $pattern = "$firstString(.*?)$secondString"

    #Perform the opperation
    $result = [regex]::Match($file,$pattern).Groups[1].Value

    #Return result
    return $result

}

function Fix-DMGSCCMStateMessage
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 1')]
                   [ValidateScript({(Test-Path $_)})]
                   $CSVFile,
        # Param2 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 2')]
                   [ValidateScript({(Get-ADComputer -Identity $_).objectclass -eq 'computer' })]
                   [String]$Hostname
    )

    Begin
    {
        $path = (get-item -Path .).FullName 
        
        if ($CSVFile -ne $null){
            Write-Host Importing $CSVFile...
            $csv = import-csv "$CSVFile"
        }else{
            $csv = [PSCustomObject]@{
                Hostname = $Hostname}
        }
        Write-Host =========================================
        Write-Host SCCM State Message Update Tool
        Write-Host =========================================
        Write-Host "dmaiolo"
        New-DGMLogFile -message ("Starting Logging for Fix-DMGSCCMStateMessage") -component "Main()" -type 1 
    }
    Process
    {
    

    $computers = @();
        
    $csv | foreach-object {
        $h = $_.Hostname
    
        if(Test-Connection -ComputerName $h -Count 1 -ErrorAction SilentlyContinue){

            Try{
               
                $g = $null               
                Invoke-Command -ComputerName $h -ScriptBlock { $SCCMUpdatesStore = New-Object -ComObject Microsoft.CCM.UpdatesStore
                                                               $SCCMUpdatesStore.RefreshServerComplianceState() } -ErrorAction Stop 
                New-DGMLogFile -message ("$h`: State Message Updated Succesfully (RefreshServerComplianceState())") -component "Main()" -type 1
                Write-Host $h`: Sleeping 5 Seconds...
                sleep 5
                $resultsfile = "\\$h\c$\Windows\CCM\Logs\UpdatesStore.log"

                $logLines = @()

                $g = Get-Content  $resultsfile -ErrorAction Stop
                $lastLine = $g.Length
                for($i = $lastLine-1; $i -ge 0; $i--)
                {
                    $g[$i] -match '<\!\[LOG\[(.*?)\]LOG.*

Overview

I developed this tool, Fix-DGMSCCMUpdateStore.ps1, to assist in fixing Windows UpdateStore Corruption (Datastore.edb) on SCCM Client Computers. On the SCCM client machine, the Windows UpdateStore Datastore.edb in Windows\Software Distribution\.. contains scan results. Over time, this may become corrupted which can stop updating from occurring on the client machine. Additionally, an error might be seen on the client application log reporting wuaueng.dll (1668) SUS20ClientDataStore: Database C:\WINDOWS\SoftwareDistribution\DataStore\DataStore.edb requires logfiles xx-yy in order to recover successfully.

Fix-DGMSCCMUpdateStore Tool

The tool ill automatically attempt to fix the Windows Update Store on an array of SCCM client computers imported via a .CSV file. When run, the tool will perform the following tasks on each computer within the .CSV:

  • Stop the Windows Update Service
  • Move SoftwareDistribution to a backup location
  • Start Windows Update Service
  • Recreate SoftwareDistribution

The tool requires the –csvfile argument, which is the path to a .CSV file containing one column, Hostname, with the hostnames listed in the column and can be run as in the example below.

Fix-DGMSCCMUpdateStore Log File

The utility will create a log file that is compatible with the CMTrace tool, which includes the thread, time, state and component for each process.


PowerShell Script: Fix-DGMSCCMUpdateStore.ps1

<# .Synopsis Fix the Windows UpdateStore on an array of SCCM clients. .DESCRIPTION The Windows UpdateStore Datastore.edb in Windows\Software Distribution\.. contains scan results. This may become corrupted. This tool will fix it on an array of computers imported. .EXAMPLE Fix-DMGSCCMUpdateStore -CSVFile .\Fix-DMGSCCMUpdateStore-Import.csv #> function New-DGMLogFile { param ( [Parameter(Mandatory=$true)] $message, [Parameter(Mandatory=$true)] $component, [Parameter(Mandatory=$true)] $type ) switch ($type) { 1 { $type = "Info" } 2 { $type = "Warning" } 3 { $type = "Error" } 4 { $type = "Verbose" } } if (($type -eq "Verbose") -and ($Global:Verbose)) { $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile) Write-Host $message } elseif ($type -ne "Verbose") { $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile) if ($type -eq 'Info') { Write-Host $message } if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow} if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red} } if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type } if ($type -eq 'Error') { $Global:ScriptStatus = $type } if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB) { $log = $Global:LogFile Remove-Item ($log.Replace(".log", ".lo_")) Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force } } function GetScriptDirectory { $invocation = (Get-Variable MyInvocation -Scope 1).Value Split-Path $invocation.MyCommand.Path } function Fix-DMGSCCMUpdateStore { [CmdletBinding()] [Alias()] [OutputType([int])] Param ( # Param1 help description [Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0, ParameterSetName='Parameter Set 1')] [ValidateScript({(Test-Path $_)})] $CSVFile, # Param2 help description [Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0, ParameterSetName='Parameter Set 2')] [ValidateScript({(Get-ADComputer -Identity $_).objectclass -eq 'computer' })] [String]$Hostname ) Begin { if ($CSVFile -ne $null){ Write-Host Importing $CSVFile... $csv = import-csv "$CSVFile" }else{ $csv = [PSCustomObject]@{ Hostname = $Hostname} } $service1 = "wuauserv" $service2 = "bits" Write-Host ========================================= Write-Host SCCM Fix Windows Update Store by dmaiolo Write-Host ========================================= Write-Host "v0.2 (2017-12-11)" New-DGMLogFile -message ("Starting Logging for Fix-DMGSCCMUpdateStore") -component "Main()" -type 1 } Process { $computers = @(); $csv | foreach-object { $h = $_.Hostname #Test if machine is online if(Test-Connection -ComputerName $h -count 2 -quiet){ Write-Host "Online: $h" -ForegroundColor Green #Stop Windows Update service try{ (get-service -ComputerName $h -Name $service1 -ErrorAction Stop).Stop() New-DGMLogFile -message ("Stopped $service1 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Stop $service1 service on $h.") -component "Main()" -type 3 } #Sleep 10 seconds to give service enough time to react Write-Host "Sleeping 5 Seconds..." Start-Sleep -s 5 #Stop BITS service try{ (get-service -ComputerName $h -Name $service2 -ErrorAction Stop).Stop() New-DGMLogFile -message ("Stopped $service2 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Stop $service2 service on $h.") -component "Main()" -type 3 } #Sleep 5 seconds to give service enough time to react Write-Host "Sleeping 5 Seconds..." Start-Sleep -s 5 #Rename the software update store $sourcepath = "\\$($h)\c$\Windows\SoftwareDistribution" $destinationpath = "\\$($h)\c$\Windows\SoftwareDistribution_$(Get-Date -Format dd-MM-yyyy)" $destinationpath2 = "\\$($h)\c$\Windows\SoftwareDistribution_$(Get-Date -Format dd-MM-yyyy)" #Appending destination path if script already run today if (Test-Path $destinationpath){ $n=0 while ((Test-Path $destinationpath2) -eq $true){ New-DGMLogFile -message ("Backup location $destinationpath2 already exists.") -component "Main()" -type 1 ++$n $destinationpath2 = $destinationpath + "-" + $n } $destinationpath = $destinationpath2 } Write-Host "Renaming $sourcepath..." try{ Move-Item -Path $sourcepath -Destination $destinationpath -Force New-DGMLogFile -message ("Renamed SoftwareDistribution to $destinationpath.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Rename SoftwareDistribution to $destinationpath.") -component "Main()" -type 3 } #Start the Windows Update service try{ (get-service -ComputerName $h -Name $service1 -ErrorAction Stop).Start() New-DGMLogFile -message ("Started $service1 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Start $service1 service on $h.") -component "Main()" -type 3 } #Start the BITS service try{ (get-service -ComputerName $h -Name $service2 -ErrorAction Stop).Start() New-DGMLogFile -message ("Started $service2 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Start $service2 service on $h.") -component "Main()" -type 3 } #Give the services 5 seconds to wake up and create new folders Start-Sleep -s 5 #Verify new folder was created Write-Host "Checking new folder recreation..." if(Test-Path("\\$($h)\c$\Windows\SoftwareDistribution")){ New-DGMLogFile -message ("\\$($h)\c$\Windows\SoftwareDistribution was recreated.") -component "Main()" -type 1 } else{ New-DGMLogFile -message ("\\$($h)\c$\Windows\SoftwareDistribution could NOT be recreated.") -component "Main()" -type 3 } } else{ #Machine is offline New-DGMLogFile -message ("Offline: $h.") -component "Main()" -type 2 } } } End { Write-Host =============================================================== Write-Host Log File of Results Generated at $path\Fix-DMGSCCMUpdateStore_$(Get-Date -Format dd-MM-yyyy).log VIEW WITH CMTRACE.EXE New-DGMLogFile -message ("Ending Logging for Fix-DMGSCCMUpdateStore") -component "Main()" -type 1 } } $VerboseLogging = "true" [bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging) $Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGSCCMUpdateStore_$(Get-Date -Format dd-MM-yyyy).log" $Global:MaxLogSizeInKB = 10240 $Global:ScriptName = 'Fix-DMGSCCMUpdateStore.ps1' $Global:ScriptStatus = 'Success'

Overview

This upgrade strategy will allow you to update your Server environment to the version of Windows Management 5.1 via SCCM. Use this recommended project management guide to help build your deployment workflow. I used this method to upgrade a 400+ server environment which completed smoothly.

Purpose

The purpose of this Deployment Strategy and Plan article is to help you define a deployment strategy and plan for a Windows Management Framework 5.1 upgrade. This article is comprised of two sections: the Deployment Strategy and the Deployment Plan. The Deployment Strategy section is used to formulate a deployment approach for Windows Management Framework 5.1. The Deployment Plan section contains recommended schedule, resource, technical, and support information necessary for successful deployment of Windows Management Framework 5.1.

About Windows Management Framework

Windows Management Framework (WMF) is the delivery mechanism that provides a management interface across the various versions of Windows and Windows Server. With the installation of WMF 5.1, increases security and feature sets will become available to our servers.

Components For Upgrade

The following components should be scheduled for upgrade during this project to version 5.1. This WMF installation adds and/or updates the following features:

  • Windows PowerShell
  • Windows PowerShell Desired State Configuration (DSC)
  • Windows PowerShell Integrated Script Environment (ISE)
  • Windows Remote Management (WinRM)
  • Windows Management Instrumentation (WMI)
  • Windows PowerShell Web Services (Management OData IIS Extension)
  • Software Inventory Logging (SIL)
  • Server Manager CIM Provider

Deployment Strategy

The Deployment Strategy section of this article provides an overview of the deployment strategy planned for Windows Management Framework 5.1. Included in the deployment strategy is recommended timeline information, a description of the deployment approach, and associated benefits, assumptions and risks.

Deployment Overview

Phases

Sites

Computers

Scheduled Dates

PRE-PILOT

Select Servers

15

October 2, 2017 – October 24, 2017

PILOT

Pilot Server Group

106

January 16, 2018 – January 31, 2018

PRODUCTION

Production Server Group

258

February 6, 2018 – February 28, 2018

Total Servers Targeted: 364

Exclusions to Upgrade

38 systems will not be targeted for the upgrade for various reasons. The exclusions include:

  • Exchange 2010 Mailbox Servers / CAS/HUB Servers (MBX) (CAS)
  • SharePoint 2007, 2010 and 2013 Servers (SPS)
  • Proxy and Application Servers (SAS)
  • SCCM Servers (SCM)
  • VMM Cluster Node, Library and Failover Name Account Servers (VMM)
  • Lync Servers (LNC)
  • Operations Manager 2016 Servers (OPS)

Deployment Phases

The Deployment Dates referenced below are the date Windows Management Framework 5.1 would attempt to begin installation on the selected servers in your environment. This does not indicate the completion date for this phase, which could take an additional 2 weeks.

Pilot Phase

Sub Phases

Sites

Computers

Deployment Date

Server 2008 R2

Pilot Server Group

23

January 16, 2018

Server 2012

Pilot Server Group

12

January 16, 2018

Server 2012 R2

Pilot Server Group

71

January 16, 2018

106

Production Phase

Sub Phases

Sites

Computers

Deployment Date

Server 2008 R2

Production Server Group

45

February 6, 2018

Server 2012

Production Server Group

188

February 6, 2018

Server 2012 R2

Production Server Group

25

February 6, 2018

258

Deployment Plan

Deployment Approach

System Center Configuration Manager (SCCM) will be used to deploy Windows Management Framework 5.1. When each phase is approached, the servers will be instructed to execute the installation in Parallel, within their maintenance window.

Because WMF 5.1 has specific installation requirements based on the Operating System, both the PILOT and PRODUCTION phase can be broken into the 2008 R2, 2012 and 2012 R2 sub phases. This is simply used for application targeting and reporting purposes, and as we can see earlier, does not require a shift in deployment date for the parent phase.

Assumptions and Risks

Assumptions

The servers targeted for deployment are assumed to be left on and connected to your corporate network during their maintenance windows. Additionally it is expected that a reboot will likely occur after the installation, during the maintenance window.

Risks

JEA endpoints and session configurations configured to use virtual accounts in WMF 5.0 will not be configured to use a virtual account after upgrading to WMF 5.1. This means that commands run in JEA sessions will run under the connecting user’s identity instead of a temporary administrator account, potentially preventing the user from running commands which require elevated privileges. To restore the virtual accounts, we would need to unregister and re-register any session configurations that use virtual accounts.

This is unlikely to be an issue in your environment.

Pilot Deployment Statistics

A sample pilot phase might be completed successfully with results broken down in the following phases

PILOT Server 2008 R2

PILOT Server 2012

PILOT Server 2012 R2

Benefits to Upgrade

PowerShell Editions

Starting with version 5.1, PowerShell is available in different editions which denote varying feature sets and platform compatibility.

Catalog Cmdlets

Two new cmdlets have been added in the Microsoft.PowerShell.Security module; these generate and validate Windows catalog files.

  • New-FileCatalog
  • Test0FileCatalog

Module Analysis Cache

Starting with WMF 5.1, PowerShell provides control over the file that is used to cache data about a module, such as the commands it exports.

Specifying module version

In WMF 5.1, using module behaves the same way as other module-related constructions in PowerShell. Previously, you had no way to specify a particular module version; if there were multiple versions present, this resulted in an error.

Engagement and Promotion Strategy

During each deployment phase, you can send an email to communicate the associated deployment phase. Members in your team may choose to notify specific application owners if they feel the need.

Testing Methods and Monitoring

The Windows Management Framework 5.1 deployment should be passed through a pre-pilot and pilot phase, where hopefully no issues would be observed. In the event an issue is determined, a rollback to the previous version can be deployed through the uninstall command on the application.

Monitoring The Deployment

Basic Monitoring

Central monitoring of the Windows Management Framework 5.1 rollout can be viewed from your computer by visiting your SCCM report server and searching for the report ‘All application deployments (basic)’.

Choose By: Application

Select Application Based on OS (Collection):

  • WMF 5.1 (For Windows Server 2008 R2)
  • WMF 5.1 (For Windows Server 2012)
  • WMF 5.1 (For Windows Server 2012 R2)

Select Collection (Application): All

The application metrics will be divided into the respective phases:

Clicking the “View Current” data for the phase will allow you to further drill down, even to the computer and user level if necessary:

The monitoring works by determining the following registry value was created:

Server 2008 R2 and Server 2012 WMF 5.1 Detection

Key: HKLM\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine

Value: PowerShellVersion [String]

Rule: Must begin with “5.1”

2012 R2 WMF 5.1 Detection

Key: HKLM\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine

Value: PowerShellVersion [String]

Rule: Must begin with “5.1”

Or

Key: HKLM\SOFTWARE\Microsoft\PowerShell\4\PowerShellEngine

Value: PowerShellVersion [String]

Rule: Must begin with “5.1”

Or

Key: HKLM\SOFTWARE\Microsoft\PowerShell\5\PowerShellEngine

Value: PowerShellVersion [String]

Rule: Must begin with “5.1”

Advanced Monitoring

To assure a technician or technical contact has as much data as possible to troubleshoot Windows Management Framework 5.1 deployment issues, compliance items and baselines were written which assess Windows PowerShell versioning directly in a baseline. To see the advanced monitoring that this baselines provide, again go to your SCCM report server and search for the report: Compliance 1.2 – Compliance Details for all CIs of a specific Baseline (report available through a special Microsoft PFE program).

Configuration Baselines Name: CB.Powershell.Version.5

Clicking ‘View Report’ will allow you to drill down and see each compliance item and reason for failure.

There are similar baselines to track all of the versions prior to the upgrade:

  • CB.Powershell.Version.4
  • CB.Powershell.Version.3
  • CB.Powershell.Version.2

Reference Documents

  • Include Your Reference Documents Here

Overview

I created this article to provide an overview of some of the most popular SCCM current, and upcoming components.

SCCM Sites and Scaling

The key driver of the type and count of sites that you use in a hierarchy is usually the number and type of devices you must support. “500 users is not enough numbers to justify a secondary site. The key decision factor is the amount of users involved.”

Stand-alone primary site

This topology is successful when your different geographic locations can be successfully served by this single primary site. To help manage network traffic, you use preferred management points and a carefully planned content infrastructure.

  • SQL Server is required.
  • Additional primary sites provide support for a higher number of clients.
  • Cannot be tiered below other primary sites.
  • Participates in database replication.

Scope of Standalone Site

  • Supports up to 250 distribution points.
  • Supports up to 15 management points
  • 175,000 total clients and devices, not to exceed:

    • 150,000 desktops (computers that run Windows, Linux, and UNIX)
    • 25,000 devices that run Mac and Windows CE 7.0
    • One of the following, depending on how your deployment supports mobile device management:

      • 50,000 devices that you manage by using on-premises MDM
      • 150,000 cloud-based devices

Central administration site with one or more child primary sites

The recommended location for all administration and reporting for the hierarchy. You would move to this topology if you require more than one primary site to support management of all your devices and users. It’s required when you need to use more than a single primary site.

  • SQL Server is required.
  • Does not process client data.
  • Does not support client assignment.
  • Not all site system roles are available.
  • Participates in database replication.

Scope of Central Administration Site

  • Supports up to 25 child primary sites
  • 700,000 desktops (computers that run Windows, Linux, and UNIX)
  • 25,000 devices that run Mac and Windows CE 7.0
  • One of the following, depending on how your deployment supports mobile device management (MDM):

    • 100,000 devices that you manage by using on-premises MDM
    • 300,000 cloud-based devices

Scope of Child Primary Site

  • Supports up to 250 secondary sites
  • Supports up to 250 distribution points.
  • Supports up to 15 management points
  • 150,000 total clients and devices

Secondary Site

Manages clients in remote locations where network bandwidth control is required.

  • SQL Server Express or a full instance of SQL Server is required. If neither is installed when the site is installed, SQL Server Express is automatically installed.
  • A management point and distribution point are automatically deployed when the site is installed.
  • Secondary sites must be direct child sites below a primary site, but can be configured to send content to other secondary sites.
  • Participates in database replication.

Scope of Secondary sites

  • Don’t support child sites.
  • Supports 1 management point
  • 15,000 desktops (computers that run Windows, Linux, and UNIX)

Other Roles and Scaling

  • Application Catalog web service point: 50,000 per installed instance (can install more than one)
  • Distribution Point: Connections from up to 4,000 clients. (250 DPs can be installed at each primary site). Supports a combined total of up to 10,000 packages and applications.
  • Fallback status point: Support up to 100,000 clients
  • Software Update Point: can support up to 25,000 clients
  • Management points: 25,000 total clients and devices

SCCM Site System Roles

SCCM uses site system roles to support operations at each site. Servers that host the Configuration Manager site are named site servers, and computers that host the other site system roles are named site system servers. The site server is also a site system server. Although we have only one site, AS1, the principal is the same.

For example, your site server could be SITESERV005PRD and a site system server would be a distribution point such as DIST002DT02.

Site Communication

Site system servers within the same site communicate with each other by using server message block (SMB), HTTP, or HTTPS, depending on the site configuration selections that you make. Because these communications are unmanaged and can occur at any time without network bandwidth control, it is important that you review your available network bandwidth before you install site system servers and configure the site system roles.

Default Site System Roles

These roles are installed automatically on the site system.

  • Configuration Manager site server: Automatically installed on the server from which you run setup when you install a central administration site or primary site
  • Configuration Manager site system: Assigned during site installation or when you add an optional site system role to another server.
  • Configuration Manager component site system role: Required to support other roles, such as a management point.
  • Configuration Manager site database server: Runs a supported version of Microsoft SQL Server
  • SMS Provider: Interface between the console and the site database

Optional Site System Roles

  • Application Catalog web service point: provides software information to the Application Catalog website from the Software Library.
  • Application Catalog website point: provides users with a list of available software from the Application Catalog.
  • Asset Intelligence synchronization point: connects to Microsoft to download Asset Intelligence catalog information. Can only be installed on the central administration site or a stand-alone primary site
  • Certificate registration point: Communicates with a server that runs the Network Device Enrollment Service to manage device certificate requests that use the Simple Certificate Enrollment Protocol (SCEP).
  • Distribution point: Contains source files for clients to download, such as application content, software packages, software updates, operating system images, and boot images. You can control content distribution by using bandwidth, throttling, and scheduling options.
  • Fallback status point: Helps you monitor client installation and identify the clients that are unmanaged because they cannot communicate with their management point.
  • Management point*: Provides policy and service location information to clients and receives configuration data from clients.
  • Endpoint Protection point: Accept the Endpoint Protection license terms and to configure the default membership for Microsoft Active Protection Service.
  • Enrollment point: Uses PKI certificates for Configuration Manager to enroll mobile devices and Mac computers, and to provision Intel AMT-based computers
  • Enrollment proxy point: Manages Configuration Manager enrollment requests from mobile devices and Mac computers.
  • Out of band service point: Provisions and configures Intel AMT-based computers
  • Reporting services point: Integrates with SQL Server Reporting Services to create and manage reports
  • Software update point: Integrates with Windows Server Update Services (WSUS) to provide software updates to clients.
  • State migration point: Stores user state data when a computer is migrated to a new operating system.
  • System Health Validator point: Validates Network Access Protection (NAP) policies
  • Microsoft Intune connector: Uses Microsoft Intune to manage mobile devices

Using the SCCM PowerShell Console

Importing the Configuration Manager PowerShell Module

Open PowerShell as an administrator


CD  C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\

import-module .ConfigurationManager.psd1 - verbosecd A

Loading PowerShell from the Configuration Manager Console

  1. Launch the Configuration Manager console. In the upper left corner, there’s a blue rectangle. Click the white arrow in the blue rectangle, and choose “Connect via Windows PowerShell”.
  2. You’ll see a prompt that contains our site code: PS NNN:\>

Optionally you can open PowerShell as administrator and CD NNN:

Update Configuration Manager PowerShell Help File

  1. update-help –module configurationmanager

Basic Cmdlets


Get-CMSite
Get-CMManagementPoint
Get-CMDistributionPoint
Get-Command –module ConfigurationManager –noun *managementpoint* #retrieve the cmdlets that have a name that contains “managementpoint.”

Example SCCM Applications that Utilize PowerShell

These are some examples of applications that I have created which utilize different SCCM PowerShell cmdlets:

Unlocking SCCM Objects

Here is a quick example of where SCCM’s cmdlets come to the rescue. Prior to 2012 SP1, objects needed to be unlocked in SQL, via the following procedure.

Unlocking in SQL

  1. Connect to your SCCM SQL Server via RDP
  2. SQL Management Studio -> CM_NNN -> New Query!
  3. select * from SEDO_LockState where LockStateID <> 0
  4. DELETE from SEDO_LockState where LockID = ‘

Unlocking Via PowerShell

Now, we can easily perform the same task with this PowerShell cmdlet that is designed to unlock objects!


Unlock-CMObject -InputObject $(Get-CMApplication -Name application_name)

Windows Management Instrumentation

Windows Management Instrumentation (WMI) is the infrastructure for management data and operations on Windows-based operating systems.

Exploring WMI on Your SCCM Server

  1. Download/Open WMI Explorer and Connect to: \\siteserver\root\SMS
  2. Browse away. There are also other namespaces to browse other than what is listed.

Testing Queries

  1. Open WBEMTEST
  2. Connect to \\siteserver\root\SMS\SITE_NNN
  3. Click ‘Query’. Here you can run the same queries that SCCM runs in collections, etc.
  4. Click Apply

SMS Provider

The SMS Provider is a Windows Management Instrumentation (WMI) provider that assigns read and write access to the Configuration Manager database at a site:

  • Each central administration site and primary site require at least one SMS Provider. You can install additional providers as needed.
  • The SMS Admins security group provides access to the SMS Provider. Configuration Manager automatically creates this group on the site server, and on each computer where you install an instance of the SMS Provider.
  • Secondary sites do not support the SMS Provider.

Configuration Manager administrative users use an SMS Provider to access information that is stored in the database. To do so, admins can use the Configuration Manager Console, Resource Explorer, tools, and custom scripts. The SMS Provider does not interact with Configuration Manager Clients. When a Configuration Manager console connects to a site, the Configuration Manager console queries WMI on the site server to locate an instance of the SMS Provider to use.

The SMS Provider helps enforce Configuration Manager security. It returns only the information that the administrative user who is running the Configuration Manager console is authorized to view.

Querying SCCM’s WMI through PowerShell

Here is a WMI query snippet to the SCCM database from the Threaded Computer Details Aggregator application I created that returns computer details


$qry = "select * from SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceID = SMS_R_System.ResourceId inner join SMS_G_System_PC_BIOS on SMS_G_System_PC_BIOS.ResourceID = SMS_R_System.ResourceId inner join SMS_G_System_LOGICAL_DISK on SMS_G_System_LOGICAL_DISK.ResourceID = SMS_R_System.ResourceId where ResourceID = '$ResourceID'"

$objComputerSystemProduct = Get-WmiObject -ComputerName $ProviderMachineName -Namespace $SCCMnameSpace -Query $qry

Endpoint Protection Overview

  • Antimalware policies
  • Windows Firewall settings
  • Windows Defender Advanced Threat Protection (1606+) (Windows 10 1607+)

Download the latest antimalware definition files, Send email notifications, use in-console monitoring, and view reports

Endpoint Protection Client

Windows 10 / Server 2016: Windows Defender is already installed. A management client for Windows Defender is installed when the Configuration Manager client installs.

Windows XP / 7 / 8 / Server 2008: Endpoint Protection client is installed with the Configuration Manager client.

Hyper-V: Endpoint Protection client can be installed on Hyper-V Host and on VM. Actions have a built-in randomized delay

  • Malware and spyware detection and remediation
  • Rootkit detection and remediation
  • Critical vulnerability assessment and automatic definition and engine updates
  • Network vulnerability detection through Network Inspection System
  • Integration with Cloud Protection Service to report malware to Microsoft.

Anti-Malware Policies

  1. Assets and Compliance -> Endpoint Protection -> Antimalware Policies
  2. Default Client Antimalware Policy OR Create Antimalware Policy

    1. Scheduled Scans Settings
    2. Scan Settings
    3. Default Actions Settings
    4. Real-time Protection Settings
    5. Exclusion Settings
    6. Advanced Settings
    7. Threat Overrides Settings
    8. Cloud Protection Service
    9. Definition Updates Settings
  3. Deploy Policy to Collection

Windows Firewall

  1. Assets and Compliance -> Endpoint Protection -> Windows Firewall Policies
  2. Create Windows Firewall Policy

    1. For Every Network Profile:

      1. Enable Windows Firewall
      2. Block all incoming connections
      3. Notify the user when Windows Firewall blocks a new program
  3. Deploy Policy to Collection

Windows Defender Advanced Threat Protection

Windows Defender ATP is a service in the Windows Security Center. By adding and deploying a client onboarding configuration file, Configuration Manager can monitor deployment status and Windows Defender ATP agent health.

  1. Logon to the Windows Defender ATP online service

    1. Endpoint Management -> System Center Configuration Manager -> Download Configuration File.zip
  2. Onboard devices for ATP

    1. Assets and Compliance > Overview > Endpoint Protection > Windows Defender ATP Policies -> Create Windows Defender ATP Policy
    2. Browse to Configuration File.zip
  3. Monitor ATP Agent

    1. Monitoring > Overview > Security -> Windows Defender ATP

      1. Windows Defender Agent Deployment Status
      2. Windows Defender ATP Agent Health (Healthy, Inactive, Etc)

Internet Based Client Management (IBCM)

Internet-based client management, or IBCM, allows you to manage clients when they are not connected to your network, but have an Internet connection. Cloud Management Gateways (CMG) and Cloud Distribution Points (CPD) are used as the cloud infrastructure to support IBCM.

IBCM Requirements

  • In order to implement IBCM into your environment, you need an Azure subscription.
  • It also requires clients and the site system servers that the clients connect to use PKI certificates

Not Supported in IBCM

  • Actual Client installation deployment over the Internet (do it manually)
  • Wake-on-LAN
  • OS deployment (you can deploy task sequences that do not deploy an OS)
  • Remote control
  • Software deployment (unless the Internet-based management point can authenticate the user in AD)
  • Roaming

How IBCM Works with a Software Update Point

  1. Scan:against this software update point.  
  2. Download: from Microsoft Update

Setting up an IBCM

Prerequisites:

  1. Site Server Must be in DMZ – UPDATE, now you have CMG (Cloud Management Gateway) and this is no longer necessary.
  2. Site systems must be connected to the Internet and must be in AD

    1. Distribution point, Software update point, etc
  3. The FQDN of site server needs to be on public DNS server as host record

Setup

  1. Create 3 certificates

    1. WEB SERVER (IIS) CERTIFICATE (Web Server Template)
    2. CLIENT CERTIFICATE (Workstation Authentication  Template)
    3. DISTRIBUTION POINT SITE SERVER CERTIFICATE (Workstation Authentication  Template)
  2. Issue 3 certificates

    1. CA Server -> Certificate Authority -> right-click Certificate Templates, click New, and then click Certificate Template to Issue -> Select all 3
  3. Configure 3 certificates

    1. CLIENT CERTIFICATE
    2. DISTRIBUTION POINT SITE SERVER CERTIFICATE
    3. WEB SERVER (IIS) CERTIFICATE
  4. Setup in SCCM

    1. Administration -> Sites and Servers -> Internet DP

      1. General -> Import Cert -> DISTRIBUTION POINT SITE SERVER CERTIFICATE.PFX
      2. General -> HTTPS and “Allow Internet-Only connections”
    2. Administration -> Sites and Servers -> Internet MP

      1. General -> HTTPS and “Allow Internet-Only connections”
      2. SCCM -> Administration –> Sites –> Right, properties
      3. client computer communication –> Choose use HTTPS or HTTP
      4. Check the “Use PKI client certificate when available
      5. Import the Root CA certificate
  5. Install Client Manually

    1. Option 1: manually add the new MP FQDN in the “Network” tab of the client property
    2. Option 2: include the Client.msi property of CCMHOSTNAME=<Internet FQDN of the MP>

Office 365 Client Management

The Office 365 client can now be deployed and managed in your SCCM console.

The O365 Dashboard (appeared in 1610)

To enable the dashboard you must first select the Office 365 ProPlus Configurations hardware inventory class:

Administration > Client Settings > Default Client Settings -> Device Settings list, click Set Classes -> Hardware Inventory Classes -> Office 365 ProPlus Configurations.

Dashboard Location: Software Library > Overview > Office 365 Client Management -> <CHOOSE COLLECTION>

  • Number of Office 365 clients
  • Office 365 client versions
  • Office 365 client languages
  • Office 365 client channels

How to Deploy Office 365 Apps (started in 1702)

  1. Software Library > Overview > Office 365 Client Management.
  2. Click Office 365 Installer in the upper-right pane.
  3. Give it Name, XML (Optional), Select the Office 365 suite, select the applications
  4. Deploy Now or Just Create Application

How to Deploy Office 365 Updates

  1. Configure WSUS

    1. Administration > Site Configuration > Sites -> WSUS Point -> Classifications tab

      1. Classification: Updates
      2. Product: Office 365 Client
  2. Enable O365 Update Client Setting

    1. Administration > Overview > Client Setting -> Software Updates -> Enable management of the Office 365 Client Agent: YES

Office 2016 vs. Office 365

Office 2016 is the traditional Office product, sold for a one-time fee. You pay once to buy a version of Office 2016 you can install on a single PC.

Office 365, on the other hand, requires you to pay a monthly or yearly fee which gives you access to the latest version of Office for as long as you pay the fee.

Mobile Device Management (MDM) with Intune

Microsoft Intune is a cloud service that provides mobile device management (MDM). There are two modes of device management, Intune standalone and Hybrid MDM with Configuration Manager.

Intune is managed in SCCM under the Cloud Services node.

In a standalone environment, the devices are managed in the Intune web console. In the hybrid environment, the devices are integrated into SCCM and would automatically be added to the All Mobile Devices collection.

Co-Management Model Released at Microsoft Ignite

A device cannot typically be managed in both. Once the device is managed in Hybrid, the Intune web console is no longer available. An exception to this is in SCCM 1710 where a new mode, co-managed, was released. This allows SCCM and Intune to both manage a Windows 10 device at the same time.

Azure Active Directory (Azure AD)

Azure Active Directory (Azure AD) is Microsoft’s multi-tenant, cloud based directory and identity management service. It can be synchronized with your on-premises AD to provide seamless login credentials while clients are on the web.

Configuration Manager Advanced Dashboard

Available through a custom Microsoft engagement is the ability to add an advanced dashboard to your SCCM reporting console.

The dashboard contains over 160 reports. Included in the dashboard are reports on

  • Asset Inventory
  • Software Update Management
  • Application Deployment
  • Compliance Settings
  • Infrastructure Monitoring
  • Site Replica
  • Content replication
  • Software Distribution
  • Clients Health
  • Servers Heath
  • SCEP

Dashboard Installation

In order to install the dashboard in your environment, the following variables need to be recorded:

A backup should then made of the SQL server database pertaining to reporting services, in addition a snapshot taken on the site server.

To install the dashboard the POPCMAD_Tool.exe was used with the variables above:

As seen above, the new report path, Advanced Dashboard, would be created which is the new root for the dashboard reports.

As an example, one dashboard now available to you would be the Client Health Statistics dashboard:

Disaster Recovery

A whitepaper for disaster recover, “System Center 2012 Configuration Manager R2 – Disaster Recovery for Entire Hierarchy and Standalone Primary Site” is available.

A copy of the whitepaper can be found here:

https://www.microsoft.com/en-us/download/details.aspx?id=44295

Most Important Disaster Recover Items

Although many topics are discussed and can be viewed in the whitepaper, of most importance to you are the ways in which SCCM can be recovered. Because Microsoft does not officially release SCCM in every release cycle, it is possible you could be on a version that can only be installed by updating an officially released version. Incremental updates can only be found on the site server with a cd.latest directory:

\\siteserver\c$\Program Files\Microsoft System Center Configuration Manager\cd.latest

Therefore, backup of this directory is crucial in order to perform an SCCM recovery. Fortunately, an automated task to backup this folder is now available in SCCM by enable backups in site maintenance at Administration > Overview > Site Configuration> Sites > (Right Click) NNN – Contoso, Inc. > Site Maintenance

Even if you have not enabled this task, it is important to understand its functionality. If you are handling these disaster recovery efforts outside of SCCM using a different backup solution, you may not need to enable this task in your environment. For example, VEEAM could be used to backup your SCCM site server:

  • SCCM Site Server siteserver: Backed up in VEEAM as the whole server
  • SCCM SQL Servers SQLSERVER1 and SQLSERVER2: Back up your SQL Servers as an application aware backup (via a volume shadow copy writer). This application aware backup allows SQL to gracefully end all SQL transactions before taking the backup.

To restore an SCCM server, open your Veeam Backup & Replication Console on your backup server VEEAMBACKUP would allow the areas to be restored as you see here in with the SQL server backups

Role Based Administration

The role-based administration model in SCCM centrally defines security access settings for all sites and site settings by using the following:

  • Security roles are assigned to administrative users to provide those users (or groups of users) permission to different Configuration Manager Objects.
  • Security scopes are used to group specific instances of objects that an administrative user is responsible to manage.
  • Collections are used to specify groups of user and device resources that the user can manage.

Each of these components are collectively combined to create the necessary security changes for user access.

Management of SCCM security is handled in Administration > Overview > Security > Administrative Users

Associating Users, Roles, Scopes and Collections Together

To get started with Role Based Administration, you will add the different user groups to the console at Administration > Overview > Security > Administrative Users. Think of these as the users that you will be dividing permissions amongst.

Next you will add a Security Role to this group. There are built-in security roles and also roles you can create, called custom roles. For this example, let’s add the built-in Read-only Analyst role to the SCCM-Report-Vieyours group:

Finally, you will add the security scopes and collections this group can view:

The security scopes are set elsewhere but only represent a name. “Securable objects” throughout SCCM are then configured to either be viewable or not viewable by this security scope.

Securable vs Non-Securable Objects

When building the security model for objects in SCCM, the idea of securable objects is important. When clicking certain objects in SCCM, you may notice a lock icon allowing the security scope to be set:


This allows the object to only be viewed by those in certain security scopes. For example, clicking the lock icon while selecting an alert subscription will allow you to limit only a specific team to see this object. Other users would not see this object within their console.

On the other hand, objects such as the alerts are non-securable and must be delineated with a security role. Security roles allows the associate objects to not be entirely hidden from a user, but can customized with what permissions apply to the object as seen in the security role properties for a custom role:

When creating new security roles, it is recommended to take one of the Built-in roles and copy it. This copy will become a custom role:

Built-in roles cannot be modified and are thought of generally as templates for custom roles.

Securable Objects managed by Security Scope

Non-Securable Objects managed by Security Role

Alert Subscriptions

Active Directory forests

Antimalware Policies

Administrative users

Applications

Alerts

Boot Images

Boundaries

Boundary groups

Computer associations

Configuration items

Default client settings

Distribution points and distribution point groups

Deployment templates

Driver packages

Device drivers

Global conditions

Exchange Server connector

Migration jobs

Migration site-to-site mappings

Operating system images

Mobile device enrollment profiles

Operating system installation packages

Security roles

Packages

Security scopes

Queries

Site addresses

Sites

Site system roles

Software metering rules

Software titles

Software Update Groups

Software updates

Software update packages

Status messages

Task sequence packages

User device affinities

Windows CE device setting items and packages

Associating Configuration Items to Dynamic Collections for Automated Remediation

Configuration Items (CI’s) are useful for detecting compliance for a multitude of events and states on the computers within the company environment. For example, configuration items could be created and combined in a Configuration Baseline (CB’s) that detect the all of the required components to be compliant for Cisco AnyConnect:

Anyone of these configuration items can be used as the query for a collection. For example, you can create collections that represent the computers that are not compliant for each of these items:

you can then target a remediation deployment to this collection, or in this example, why not combine the configuration item collections into a configuration baseline collection, much like the logic for the actual CI’s and CB’s:

Creating Dynamic Collections Based off Configuration Items

Creating a dynamic collection based off computers that fail compliance for a configuration item is as simple as creating a collection by the same name as the CI and using this custom query to target your CI. Simply replace the area boldened with the name of your CI:


select SMS_R_SYSTEM.ResyourceID,SMS_R_SYSTEM.ResyourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResyourceDomainORWorkgroup,SMS_R_SYSTEM.Client
from SMS_R_System where SMS_R_System.ResyourceID 
in (select SMS_CI_COMP.ResyourceID from SMS_CI_CurrentComplianceStatus 
as SMS_CI_COMP inner join SMS_ConfigurationItem 
as SMS_CI on SMS_CI.ci_id=SMS_CI_COMP.ci_id 
where ((SMS_CI_COMP.DisplayName = "CI.Name.Of.Yyour.CI" and SMS_CI.islatest = 1  and SMS_CI_COMP.ComplianceState != 1) ))

Antivirus Exclusions for SCCM

In order to exclude SCCM from its own System Center Endpoint Protection scans, the following AV policies should be applied under Assets and Compliance > Overview > Endpoint Protection > Antimalware Policies

  • SERVER – SCCM Site Server
  • SERVER– SCCM SQL Servers

These policies should be deployed to collections with their respective names and associated servers. To configure the exclusions, the following Microsoft article can be referenced, which will assist you in targeting SCCM current branch:

https://blogs.technet.microsoft.com/systemcenterpfe/2017/05/24/configuration-manager-current-branch-antivirus-update/

Test-DGMSCEPPathsTool

This tool, Test-DGMSCEPPaths.ps1, was written by David Maiolo which is a small utility to test the paths of folders before adding them to SCEP policies.

The tool requires the –csvfile argument, which is the path to a csv file containing one column, Path, with the paths listed in the column and can be run as in the example below.


This tool can be useful to verify input. Perhaps you find an additional “space” in your default installation directory between “Configuration” and “Manager” as in D:\Program Files\Microsoft System Center Configuration Manager\

Core Function of the Test-DGMSCEPPaths.ps1 tool

Overview

This article contains a recommended set of procedures and schedules you can follow in your environment to obtain great WSUS compliance within SCCM. I developed these best practices and helped a client implement them to improve their compliance.

Schedule

I recommend that you create a schedule in your environment to check/complete the following WSUS components/tasks.

Weekly

All Software Update Cleanup of Superseded and Expired

Software Update Groups Cleanup

Monthly

Set MaxExecutionTime on Specific SCCM Software Updates

Cleanup Packages from DPs that are not Needed at DPs

Remediate Updates that are required but not deployed

Notification of Network Segment Creation

Quarterly

Verify Packages and Applications are NOT Updated to DPs on a Schedule

Manage SCCM Deployment Threads

Manage SCCM Distribution Point Rate Limits (Time-Slice Based Throttling)

Manage SCCM Distribution Point Priority Schedules

Enable Binary Differential Replication on Deployment Packages

Project Based

Maximize Performance and Coverage of Automatic Deployment Rules

Allow Site Server and Microsoft to be used as fallback Update locations for Updates

Network Segment Creation

Overview

When a new network segment is created within your environment, be sure the new segment is communicated.

Procedure

  1. Work with your Network engineers to be included in communication when new network segments are created.

Set MaxExecutionTime on Specific SCCM Software Updates

Overview

Every update in SCCM has a maximum amount of time that it is allowed to run. If the amount of time it takes to install the update exceeds the MaxExecutionTime variable set for the update, the update will fail to install. Increasing this execution time can allow a greater installation success rate.

Procedure

  1. Run from NNN(Your SCCM Sever): Powershell:

    
    Get-CMSoftwareUpdate -name  "*Cumulative Update*" -Fast | ? {$_.MaxExecutionTime -lt '1800'} | Set-CMSoftwareUpdate -MaximumExecutionMins 30
    Get-CMSoftwareUpdate -name "*Cumulative Security Update*" -Fast | ? {$_.MaxExecutionTime -lt '1800'} | Set-CMSoftwareUpdate -MaximumExecutionMins 30
    Get-CMSoftwareUpdate -name "*Security Monthly Quality Rollup*" -Fast | ? {$_.MaxExecutionTime -lt '1800'} | Set-CMSoftwareUpdate -MaximumExecutionMins 60
    Get-CMSoftwareUpdate -name "*Security and Quality Rollup*" -Fast | ? {$_.MaxExecutionTime -lt '1800'} | Set-CMSoftwareUpdate -MaximumExecutionMins 30
    

    Examples

    Figure 1 Maximum Run Time on a Software Update

    Cleanup Packages from DPs That are Not Needed

    Overview

    Overtime, SCCM Distribution Points out will accumulate updates and applications that are no longer applicable to the particular DP. For example, if an older version of Adobe Reader were needed in 2015, leaving the installation files on the DP is using unnecessary space.

    Procedure

    1. View Active Deployments

      1. Within the SCCM Console, open Monitoring\Overview\Deployments
      2. Sort by Date Created
    2. Cross Reference Active Deployments with DP Content, And Remove Unneeded

      1. Administration\Overview\Distribution Point Groups -> Branch Distribution Groups [Right Click -> Properties]
      2. Content Tab -> Click Unneeded Updates -> Remove

    Examples

    Figure 2 Removing DP Content

    Verify That Applications are NOT Updated to DPs on a Schedule

    Overview

    Within the SCCM Console there is an option to have content automatically redistribute itself to distribution points on a schedule. When found to be enabled on content, the processes unnecessarily consumes SCCM traffic.

    Procedure

    1. Open a suspected offending application or package
    2. For example, open Software Library\Overview\Application Management\Packages\Workstations\
      System Configurations\NCI
    3. [Right Click] Properties -> Data Source -> Update Distribution points on a schedule
    4. Verify this is unchecked

    Examples

    Figure 3 Verifying content is not updated on schedule

    Manage SCCM Deployment Threads

    Overview

    SCCM controls the number of packages it will attempt to distribute at one time, and the number of distribution points it will attempt to distribute the packages to. Adjusting these controls will allow maximum throughput of traffic while maintaining throttling constraints.

    Figure 4 SCCM Content Threads

    Procedure

    1. Within the SCCM Console go to Administration\Overview\Site Configuration\Sites\XXX
    2. [Right Click] Configure Site Components -> Software Distribution
    3. Adjust Maximum Threads

    Monitoring Threads

    1. Download and Install the System Center 2012 R2 Configuration Manager Toolkit
    2. Open the DP Job Manager Tool at C:\Program Files (x86)\ConfigMgr 2012 Toolkit R2\ServerTools\DPJobMgr.exe
    3. Use the Manage Jobs tab to monitor


    Figure 5 DP Job Manager Tool

    Examples

    Figure 6 Adjusting Content Threads

    Manage DP Rate Limits (Time-Sliced Throttling)

    Overview

    Distribution Point Rate limits are a form throttling which applies to content distribution. Adjusting these throttles can help maximize performance while minimizing disruption during the workweek.

    Procedure

    1. Within the SCCM Console go to Administration\Overview\Distribution Points [Right Click DP] Properties
    2. Open the Rate Limits tab
    3. Adjust accordingly

    Examples

    Figure 7 Adjusting DP Rate Limits

    Manage SCCM Distribution Point Priority Schedules

    Overview

    Distribution schedules allow low, medium and high priority deployments to adhere to certain schedules. Adjusting these schedules can help maximize performance while minimizing disruption during the workweek.

    Procedure

    1. Within the SCCM Console go to Administration\Overview\Distribution Points [Right Click DP] Properties
    2. Open the Schedule tab
    3. Adjust accordingly

    Examples

    Figure 8 Adjusting DP Priority Schedules

    Maximize Performance and Coverage of Automatic Deployment Rules

    Overview

    When creating SCCM ADRs, it is important that no rule duplicates another, and also that combined rules do not miss any critical or security updates for an environment (such as Prod or Pilot)

    Figure 9 Optimizing ADRs in SCCM

    How Microsoft Deploys Software Updates

    Security Only Quality Update (Released every month)

    • Includes Critical and Security for That Month

    Security Monthly Quality Rollup (Released every month)

    • Includes Critical, Security and Updates*, Cumulative for Year

      * Feature patches (non-security)

    Procedure

    1. Within the SCCM Console go to Software Library\Overview\Software Updates\Automatic Deployment Rules
    2. A Deployment Packages are updated via an ADR no more frequently than necessary. For example, a pilot ADR may update weekly, whereas a Production ADR may update monthly.

    Enable Binary Differential Replication on Deployment Packages

    Overview

    Binary Differential Replication, sometimes known as “delta replication,” is used by SCCM to update package source files with a minimum of additional network traffic. This minimizes the network traffic between sites, especially when the package is large and the changes are relatively small.

    Procedure

    1. Within the SCCM Console go to Software Library\Overview\Software Updates\Deployment Packages
    2. [Right Click Package] and check Enable binary differential replication

    Examples

    Figure 10 Enabling Binary Differential Replication

    Allow Site Server and Microsoft to be used as Fallback Update Locations

    Overview

    If there is no distribution point assigned to a client, updates can fail to deploy. Allowing a fallback source to be used, which increases the chances your clients will receive their required updates.

    Procedure

    1. Within the SCCM Console go to Software Library\Overview\Software Updates\Automatic Deployment Rules
    2. Click an ADR, and then go to the Deployment Settings tab at the bottom of the screen
    3. [Right Click] Properties
    4. Open the Download Settings tab and check If software updates are not available…

    Examples

    Figure 11 Configuring Failback Sources for ADRs

    Remediate Updates That Are required but not deployed

    Overview

    There is a prebuilt SCCM report that can help identify updates that are required, but have not been distributed. I have further configured the ability automate this portion in a different project. Please see SCCM: Automate Deployment of Required Updates for more details.

    Procedure

    1. Using Internet Explorer, browse to the Reports path at http://vconscm005prd/Reports
    2. Find the report Management 2 – Updates required but not deployed and run it
    3. Collection: ‘Production Workstation’ and ‘Production Server’ (one report for each)
    4. Vendor: Microsoft
    5. Update Class: Critical and Security (one report for each)
    6. Export each report as updates_nn.csv
    7. Connect to NNN: PowerShell console and use the report to update Software Update Groups accordingly:
    
    $updates =import-csv -path updates_nn.csv
    
    $undeployedupdates=$updates | %{Get-CMSoftwareUpdate -ArticleId $_.update -Fast | ?{$_.nummissing -ge 1}} 
    $PilotSoftwareUpdategroup=Get-CMSoftwareUpdateGroup -Name "Production Servers Updates - All other Products* nnn"
    $undeployedupdates | %{Add-CMSoftwareUpdateToGroup -SoftwareUpdateId $_.CI_ID -SoftwareUpdateGroupName "Production Servers Updates - All other Products* nnn"}
    

    Examples

    Figure 12 Checking Critical Updates

    Figure 13 Checking Security Updates

    Software Update Cleanup of Superseded and Expired

    Overview

    Superseded and Expired updates need to periodically be cleaned up from Software Update Groups.

    Superseded Updates Procedure

    1. Within the SCCM Console go to Software Library\Overview\Software Updates\All Software Updates
    2. Add Criteria -> Superseded + Deployed
    3. [Right Click] Edit Membership -> Uncheck from each Deployment Package

    Expired Procedure

    1. Within the SCCM Console go to Software Library\Overview\Software Updates\All Software Updates
    2. Add Criteria -> Expired + Deployed
    3. [Right Click] Edit Membership -> Uncheck from each Deployment Package

    Examples

    Figure 14 Removing Expired Updates From SUG

    Software Update Groups Cleanup

    Overview

    Once an Update Group has been automatically created, used and replaced by a new Update Group of the same exact type, the old group can safely be deleted. This helps keep the environment clean and remove unnecessary Software Update Group deployments.

    Procuedure

    1. Within the SCCM Console go to Software Library\Overview\Software Updates\Software Update Groups
    2. Sort by Name
    3. Delete the older of identical Software Update Groups if no longer user

    Examples

    Figure 15 Deleting Old Software Update Groups