59 How to view windows update (WSUS) summary report of left systems

In the below PowerShell script:-

  1. Name and save the script as “Get-Windows_Update_failed_left_system.PS1”.
  2.  Run the script from the PowerShell console.
  3. The output will be displayed on the PowerShell console.

Note:

Only change the path that is highlighted below in bold with your folder path.

In case of any hurdle, please Contact Us
 <#  
    .SYNOPSIS  
        Gets Patching Summary Report and Detail Report for a specific month's security patches  for all servers or a particular group.
        
    .DESCRIPTION
        Summary Report contains the status(such as installed, failed, needed and pending reboot) for approved security patches of the month. It shows the machine counts of each status for each KB.
        Detail Report  lists all the machines that are needed/failed on  the KBs of the month.

        
    .NOTES  
        Author: InfotechFusion
        Last update: 10/2021
        Script required PowerShell Module "PoshWSUS" to work.  The module is imported from fileshare. For more info about the module: https://www.powershellgallery.com/packages/PoshWSUS
           
        
    .EXAMPLE
        Get-WSUSReport -Month 2019-09

        The above script gets the Patching Summary Report and Detail Report. They are saved to .\WSUSReport\2019-09\ for patches of Sep.2019 as no Group is specified.
        ***Report only includes  servers that sync with WSUS in the last 7 days(defalut value) if the LastSyncDay variable is not specified.

     .EXAMPLE
        Get-WSUSReport -Month 2019-09 -$LastSyncDay 3

        The above script gets the Patching Summary Report and Detail Report. They are saved to .\WSUSReport\2019-09\ for patches of Sep.2019 as no Group is specified.
        ***Report only includes  servers that sync with WSUS in the last 3 days.


    .EXAMPLE
        Get-WSUSReport -Month 2019-09 -Group Production

        The above script gets the Patching Summary Report and Detail Report. They are saved to .\WSUSReport\2019-09\Production as group "production" is specified. There are two more group options, "DMZ" and "Development" 
        ***LastSyncTime cannot be used while group is specified. 
 #> 



[CmdletBinding()]
Param
(
	[parameter(Position=0, Mandatory=$true)]
	[string]$Month,
    [parameter(Position=1, Mandatory=$false)]
    [ValidateSet('Production', 'DMZ', 'Development','Lab','AllServers')]
    [string]$Group,
    [parameter(Position=1, Mandatory=$false)]
    [int]$LastSyncDay

)

#Define Variables
$Server = 'windowsupdate.Infotechfusion.com'
$path =  ".\WSUSReports\$month"   
$ExcludeState = "NotApplicable" ,"Installed", "Unknown"
$KBs = @()

# $LastSyncTime  default is 7 days if $LastSyncDay is not specified
if($LastSyncDay){$LastSyncTime = (Get-Date).AddDays(-($LastSyncDay))}
else{$LastSyncTime  = (Get-Date).AddDays(-7)}

#$Month = "2019-09"
#Group = "Production"



#Import module and connect to WSUS
Import-Module  C:\ps\PoshWSUS
$null = Connect-PSWSUSServer -WsusServer $Server  -Port 8530



#check if the pathe exist, if not create it
if (Test-Path 'WSUSReports')
    {   if (Test-Path ".\WSUSReports\$month"){} 
        else{$null = New-Item -ItemType directory ".\WSUSReports\$month"}
    }
else 
{$null = New-Item -ItemType directory '.\WSUSReports'; $null = New-Item -ItemType directory ".\WSUSReports\$month"}
    




#get all approved security patches for servers
Write-Progress "Getting Approved Security Patches"
$ApprovedPatches = Get-PSWSUSUpdate -Update $month | where {$_.IsApproved -eq "True" -and $_.UpdateClassificationTitle -like "*Security*"} 



################################### Patching Summary  Report  ##################################
Write-Progress "Getting Patching Stats Summary"
If($Group)
{
    #create subfolder for the group
    $path = ".\WSUSReports\$month\$Group"
    if (!(Test-Path $path)){$null = New-Item -ItemType directory $path}
        if($group -eq "lab"){$TargetGroup = "Laboratory"}
        else{$TargetGroup = "Servers-$Group"}
    $Patches = $ApprovedPatches | Get-PSWSUSUpdateSummaryPerGroup -GroupName $TargetGroup 

}
else
{
    $Group = "AllServers"
    #For AllServer, Report only includes  servers that are synced with WSUS in the last X days, X defined as $LastSyncTime
    $Patches =  $ApprovedPatches | Get-PSWSUSUpdateSummary  -ComputerScope (New-PSWSUSComputerScope -FromLastSyncTime $LastSyncTime)
}

Write-Progress "Exporting Monthly Patching Summary Report"
# Write-host "Reports are saved to $path"
$Patches | Select UpdateTitle,UpdateKB,Installed,Needed,Failed,PendingReboot | sort UpdateTitle| Export-Csv -NoTypeInformation "$path\$month-PatchingReport-Summary-$Group-$((get-date).toString('yyyy-MM-dd')).csv"



################################### Patching Report for  Individual  KB ##########################


#getting all KBs with at least one needed or failed
Foreach($patch in $Patches)
{
    If($patch.Failed -ne "0" -or $patch.needed -ne "0")
    {
        $KBs    += $patch.UpdateKB 
    }
}

$KBs = $KBs | sort -Unique


Write-Progress "Exporting Computer list of each needed KB"   
Foreach ($KB in $KBs)
{
    If($Group -eq "AllServers")
    {
        #For AllServer, Report only includes  servers that are synced with WSUS in the last X days, X defined as $LastSyncTime
        $KBReport = Get-PSWSUSClientPerUpdate -Update $KB  -ComputerScope  (New-PSWSUSComputerScope -IncludeSubGroups -ExcludedInstallationState $ExcludeState   -FromLastSyncTime $LastSyncTime )  | where {$_.UpdateTitle -like "*Server*"}`
    }
    else
    {
        $KBReport = Get-PSWSUSClientPerUpdate -Update $KB -GroupName $TargetGroup | where {$_.UpdateInstallationState -ne "NotApplicable " -and $_.UpdateInstallationState -ne "installed" -and $_.UpdateInstallationState -ne "Unknown"}
    }
  
$KBReport |select Computername, UpdateKB,UpdateInstallationState,UpdateTitle | sort Computername| Export-Csv -NoTypeInformation "$path\$month-PatchingReport-Detail-$Group-$((get-date).toString('yyyy-MM-dd')).csv" -Append


#$KBReport | select Computername, UpdateKB,UpdateInstallationState,UpdateTitle | sort Computername| Export-Csv -NoTypeInformation "$path\KB$KB-$group-$((get-date).toString('yyyy-MM-dd')).csv"
}

$output = Import-Csv "$path\$month-PatchingReport-Detail-$Group-$((get-date).toString('yyyy-MM-dd')).csv"  
$num = ($output.computername | sort -Unique).count 
write-host "Computers missing $month 's updates : $num "


if($group -eq 'Development')
{
$output.computername |  ? {$_ -notlike "*RWC1BINF*"}| sort name |Sort -Unique |   Out-File Patching-$Group-VMs.txt
}
else
{

$output.computername | sort name |Sort -Unique |   Out-File Patching-$Group-VMs.txt
}