Share via


Powershell: Generating WSUS Reports

In a large environment the WSUS report can take a while to generate and even then it requires you to flip through what could be thousands of pages just to view which computers are missing what.

Figuring out a way to generate a CSV report that would display all the computers in a given WSUS group along with any updates they were missing. With some help from some Powershell Guru's you can build a script together that generates a report. 

Overview

The script can be run from any directory and will drop a CSV named after the group you queried in the same directory as the script. 

The user is prompted with a menu that has three options.

  • Option 1 List WSUS Groups found on your WSUS server.
  • Option 2 Pulls all the computers and their update information from the group specified. (Ex. Servers)
  • The script will query your WSUS server directly to pull the latest information. (Dependent on your WSUS server and clients communicating properly for accurate information)
  • Option 3 Quit

Examples:

Code:

001.####################################################################

002.#  #

003.# Author: Christopher Cardenas  #

004.# Creation Date: 9/5/2015  #

005.# Last Modified: 06/23/2015  #

006.#  #

007.#  *Modified for release to TechNet Wiki Articles.  #

008.#  #

009.#  #

010.#  #

011.#  #

012.####################################################################

013.#######################################################################################################################################

014.# The following section was taken from http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/09/23/a-self-elevating-#powershell-script.aspx

015.# This section is used to ensure we are running the script "As Administrator" so we don't get access denied errors when we #run

016.# commands that require administrator permissions.

017.# Get the ID and security principal of the current user account

018.$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()

019.$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)

020.# Get the security principal for the Administrator role

021.$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator

022.# Check to see if we are currently running "as Administrator"

023.if ($myWindowsPrincipal.IsInRole($adminRole))

024.{

025. # We are running "as Administrator" - so change the title and background color to indicate this

026. $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"

027. $Host.UI.RawUI.BackgroundColor = "DarkBlue"

028. clear-host

029.}

030.else

031.{

032. # We are not running "as Administrator" - so relaunch as administrator

033. # Create a new process object that starts PowerShell

034. $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";

035. # Specify the current script path and name as a parameter

036. $newProcess.Arguments = $myInvocation.MyCommand.Definition + " -Step $Step";

037. # Indicate that the process should be elevated

038. $newProcess.Verb = "runas";

039. # Start the new process

040. [System.Diagnostics.Process]::Start($newProcess);

041. # Exit from the current, unelevated, process

042. exit

043.}

044.#######################################################################################################################################

045.$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

046.Set-Location $MyDir

047.[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | Out-Null

048.$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer('GSSCCM2',$False,8530) #Change to SCCM server name

049. 

050.$computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

051.$updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope

052.#Exclude the following states from update list

053.$updatescope.ExcludedInstallationStates = 'NotApplicable','Unknown','Installed'

054. 

055.#Create Forward and Reverse lookup

056.$groups = @{}

057.$dataHolder = @()

058.$wsus.GetComputerTargetGroups() | ForEach {$groups[$_.Name]=$_.id;$groups[$_.ID]=$_.name}

059. 

060.Do {

061.$keepRunning = $true

062.Write-Host "

063.----------MENU----------------------------

064.1 = List WSUS Groups

065.2 = Pull Updates For Entire WSUS Group

066.3 = Quit

067.------------------------------------------"

068.$choice1 = read-host -prompt "Select number & press enter:"

069. 

070.Switch ($choice1) {

071."1" {$wsus.GetComputerTargetGroups().Name}

072."2" {

073. $DataHolder = @()

074. $computerscope4 = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

075. $updatescope4 = New-Object Microsoft.UpdateServices.Administration.UpdateScope

076. #Only list updates that are needed

077. $updatescope4.ExcludedInstallationStates = 'NotApplicable','Unknown','Installed'

078. #Only list updates that are approved

079. $updatescope4.ApprovedStates = [Microsoft.UpdateServices.Administration.ApprovedStates]::LatestRevisionApproved;

080.  

081. $TargetGroup = Read-Host -prompt "Please enter a group name:"

082. 

083. $pcgroup = @($wsus.GetComputerTargets($computerscope4) | Where {$_.ComputerTargetGroupIds -eq $groups[$TargetGroup]}) | Select -expand Id

084. 

085. $pcinfo = $wsus.GetSummariesPerComputerTarget($updatescope4,$computerscope4) | Where {$pcgroup -Contains $_.ComputerTargetID} | ForEach {

086. $computerscope2 = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

087. $computerscope2.NameIncludes = $wsus.GetComputerTarget(([guid]$_.ComputerTargetId)).FullDomainName

088.  

089. $pcupSum = ($wsus.GetSummariesPerUpdate($updatescope4,$computerscope2) | ForEach-Object {($wsus.GetUpdate($_.UpdateId).Title)})

090.  

091.  

092. $data = New-Object PSObject -Property @{

093. "Client" = $wsus.GetComputerTarget(([guid]$_.ComputerTargetId)).FullDomainName

094. "IP Address" = $wsus.GetComputerTarget(([guid]$_.ComputerTargetId)).IPAddress

095. "Group" = $wsus.GetComputerTarget(([guid]$_.ComputerTargetId)).RequestedTargetGroupName

096. "Updates" = ($_.NotInstalledCount + $_.DownloadedCount)

097. "Failed" = $_.FailedCount

098. "LastSync" = $wsus.GetComputerTarget(([guid]$_.ComputerTargetId)).LastReportedStatusTime

099. "Titles" = $pcupSum | Out-String

100. }

101.  

102. $DataHolder += $data | Select Client,"IP Address",Group,Updates,Failed,LastSync,Titles | Where {$_.Updates -ne "0"}

103. 

104. }

105. #Display table in PS Window. Commented out due to being too large of a table to display properly.

106. #$DataHolder | Select Client,"IP Address",Group,Updates,Failed,LastSync,Titles| Sort LastSync -Descending |

107. #Format-Table -Wrap -Autosize @{L="Last Sync with WSUS";E={$_.LastSync};align='left'},@{L="Host Name";E={$_.Client};align='center'},"IP Address",@{L="WSUS Group";E={$_.Group};align='center'},@{L="# Needed";E={$_.Updates};align='center'},@{L="Failed";E={$_.Failed};align='center'},@{L="Updates Titles";E={$_.Titles};align='left'}

108.  

109. #Create CSV

110. $DataHolder | Select LastSync,Client,"IP Address",Group,Updates,Failed,Titles | Sort LastSync -Descending | Export-Csv "$TargetGroup.csv" -NoTypeInformation

111. #Display GridView Popup

112. $DataHolder | Select LastSync,Client,"IP Address",Group,Updates,Failed,Titles | Sort LastSync -Descending | Out-GridView -Title $TargetGroup

113. 

114. $DataHolder= @()

115. $pcupSum = ""

116. }

117."3" {$keepRunning = $False

118. exit 

119. }

120.}

121.} while ($keepRunning -eq $true)

Requirements:

  • Powershell 2.0 or higher
  • WSUS Server