Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- .SYNOPSIS
- DELAY WSUS AUTO APPROVALS
- .DESCRIPTION
- This script delay approvals for specific target group (OU).
- The delay is customizable.
- You must run this script on your WSUS Server.
- .NOTES
- File Name : DELAY-WSUS-AUTO-APPROVALS.ps1
- Author : Igors Moskalcovs
- Version : 1.4 (2018/06/12) - added allowed classification configuration
- - made report look pretier and more informative
- - added send to email functionality
- ----------------------------------------------------------------------------------------
- Version : 1.3 (2013/03/05) - make optional validation targetgroup
- - count delay from Creation Date (if validation target group exists) else from Arrival Date of updates
- History : 1.2 (2013/02/14) - Fix
- History : 1.1 (2013/01/29) - Fix
- History : 1.0 (2013/01/22) - First Version
- #>
- ###############################################################################
- # GLOBALS
- ##################
- # WSUS Part
- # This the delay between arrival date of updates and automatic approvals
- $DELAY = [TimeSpan]30d ;
- # Only these categories and classifications are included
- $WSUS_CategoriesIncluded = @("Office 2007", "Office 2016", "Windows 7", "Windows Defender");
- $WSUS_ClassificationsIncluded = @("Critical Updates", "Definition Updates", "Security Updates", "Tools", "Update Rollups", "Updates");
- # We approve updates on this TargetGroup
- $WSUS_TargetGroup_To_Approved = "Windows 7";
- # Optional : Validation TargetGroup
- # If you don't have/want a Validation Target Group (with limited computers), set variable to null.
- #$WSUS_TargetGroup_Validation = "Validation";
- $WSUS_TargetGroup_Validation = "Updates Test Pool";
- #Email Notifications
- #Server
- $mxserver = "mx.contoso.com"
- #From
- $emailfrom = "wsus <wsus@contoso.com>"
- #Recipients
- $emailrecipients = "User <user@contoso.com>", "User2 <user2@contoso.com>", "User3 <user3@contoso.com>"
- #Subject
- $emailsubject = "Wsus Delayed Updates Report"
- #Body
- $emailbody = ""
- ##################
- # LOG, REPORT and RUN files
- $PATH_DIR = "D:\DELAY-WSUS-AUTO-APPROVALS";
- $FILENAME_LOG = "DELAY-WSUS-AUTO-APPROVALS-W7.log"
- $FILENAME_REPORTS = "DELAY-WSUS-AUTO-APPROVALS_" + $(Get-Date -format yyyy-MM-dd_HH\hmm\mss\s) + "W7.html"
- $TITLE = "DELAY WSUS AUTO APPROVALS"
- ###############################################################################
- # FUNCTIONS
- function BuildHTMLTable($report) {
- # The content
- if ($report.count -eq 0) {
- return "<h3>No updates</h3>"
- }
- else {
- # $WSUS_TargetGroup_Validation is optinal
- if ( $WSUS_TargetGroup_Validation -ne $null ) {
- $rows = "<p></p>`
- <p><h2>Status Report</b></h2><table>`
- <p></p>`
- <col width=150px> `
- <col width=150px> `
- <col width=150px> `
- <tr>`
- <th>Approved</th>`
- <th>Waiting (Delay)</th>`
- <th>Waiting (Validation)</th>`
- </tr> `
- <tr> `
- <td>" + $(($report | Where-Object -FilterScript {$_.Action -eq "Approve !"} | Measure-Object).Count) + "</td>`
- <td>" + $(($report | Where-Object -FilterScript {$_.Description -like "*days remaining"} | Measure-Object).Count) + "</td>`
- <td>" + $(($report | Where-Object -FilterScript {$_.Description -like "*must be approved first"} | Measure-Object).Count) + "</td>`
- </tr> `
- </table> `
- <p></p> `
- <p><h2>Detailed Report</h2></p>`
- <p><i>Results are sorted by arrival date</i></p>`
- <table> `
- <col> `
- <col> `
- <col> `
- <col> `
- <col> `
- <col> `
- <col> `
- <tr>`
- <th>Name</th>`
- <th>Product</th>`
- <th>Classification</th>`
- <th>Date of Arrivals</th>`
- <th>Approved on Validation Group</th>`
- <th>Action</th>`
- <th>Description</th>`
- </tr>"
- $rows += $report | Sort-Object "Date of Arrival" -descending | `
- ForEach-Object { "`
- <tr>`
- <td>" + $($_."name") + "</td>`
- <td>" + $($_."Product") + "</td>`
- <td>" + $($_."Classification") + "</td>`
- <td>" + $($_."Date of Arrival") + "</td>`
- <td style='text-align:center'>" + $($_."Approved by Validation") + "</td>`
- <td style='text-align:center'>" + $($_."Action") + "</td>`
- <td>" + $($_."Description") + "</td>`
- </tr>" }
- $rows += "</table>"
- }
- else {
- $rows = "<p></p>`
- <p><h2>Status Report</b></h2><table>`
- <p></p>`
- <col width=150px> `
- <col width=150px> `
- <col width=150px> `
- <tr>`
- <th>Approved</th>`
- <th>Waiting (Delay)</th>`
- <th>Waiting (Validation)</th>`
- </tr> `
- <tr> `
- <td>" + $(($report | Where-Object -FilterScript {$_.Action -like "Approve !"} | Measure-Object).Count) + "</td>`
- <td>" + $(($report | Where-Object -FilterScript {$_.Description -like "*days remaining"} | Measure-Object).Count) + "</td>`
- <td>" + $(($report | Where-Object -FilterScript {$_.Description -like "*must be approved first"} | Measure-Object).Count) + "</td>`
- </tr> `
- </table> `
- <p></p> `
- <p><h2>Detailed Report</h2></p>`
- <p><i>Results are sorted by arrival date</i></p>`
- <table>`
- <col>`
- <col>`
- <col>`
- <col> `
- <col> `
- <col> `
- <tr>`
- <th>Name</th>`
- <th>Product</th>`
- <th>Classification</th>`
- <th>Date of Arrivals</th>`
- <th>Action</th>`
- <th>Description</th>`
- </tr>"
- $rows += $report | Sort-Object "Date of Arrival" -descending | `
- ForEach-Object { "`
- <tr>`
- <td>" + $($_."name") + "</td>`
- <td>" + $($_."Product") + "</td>`
- <td>" + $($_."Classification") + "</td>`
- <td>" + $($_."Date of Arrival") + "</td>`
- <td style='text-align:center'>" + $($_."Action") + "</td>`
- <td>" + $($_."Description") + "</td>`
- </tr>" }
- $rows += "</table>"
- }
- }
- return $rows
- }
- function filterUpdates($updates) {
- $updates_filtered = @()
- $nb_rejected = 0
- # Get update not approved for no targetgroup
- $updates | foreach {
- if ( $_.IsApproved -eq $False ) {
- $updates_filtered += $_
- }
- }
- # Get update approved only for a specific Targetgroup
- $updates | where { $_.IsApproved -eq $True } | foreach { `
- $mark_tg_approved = $false
- $_.getUpdateApprovals() | foreach {
- if ($_.ComputerTargetGroupId -eq $tg_to_Approve.id ) {
- $mark_tg_approved = $true
- }
- }
- if ( $mark_tg_approved ) {
- $nb_rejected++
- }
- else {
- $updates_filtered += $_
- }
- }
- return ($updates_filtered, $nb_rejected)
- }
- ###############################################################################
- # CORE PROGRAM - DON'T TOUCH !!! ... Normally
- ####
- # INIT
- ####
- # init trap
- $logfile = $PATH_DIR + "\" + $FILENAME_LOG
- trap {Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Error - $_"; break}
- # get date
- $now = Get-Date
- # build filename for reports
- $report_filename = $PATH_DIR + "\" + $FILENAME_REPORTS
- $ErrorActionPreference = "Stop"
- ####
- # Log
- ####
- Add-content $logfile -value "----------------------------------------------------"
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Start"
- ####
- # Load Assembly
- ####
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Loading Assembly ... "
- [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | Out-Null
- $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer()
- # GetID of TargetGroup
- $tg_to_Approve = $wsus.GetComputerTargetGroups() | where { $_.name -eq $WSUS_TargetGroup_To_Approved }
- # $WSUS_TargetGroup_Validation is optinal
- if ( $WSUS_TargetGroup_Validation -ne $null ) {
- $tg_valid_Approve = $wsus.GetComputerTargetGroups() | where { $_.name -eq $WSUS_TargetGroup_Validation }
- }
- ####
- # Get all updates we want.
- ####
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Collect and filter updates ... "
- # building Rexgexp
- $regexpCateg = ""; $WSUS_CategoriesIncluded | foreach { $regexpCateg += "^$_$|" }
- $regexpCateg = $regexpCateg.substring(0, $regexpCateg.length - 1)
- $regexpClass = ""; $WSUS_ClassificationsIncluded | foreach { $regexpClass += "^$_$|" }
- $regexpClass = $regexpClass.substring(0, $regexpClass.length - 1)
- $allUpdates = $wsus.getUpdates()
- $updates = $allUpdates | Where {$_.ProductTitles -match $regexpCateg `
- -and $_.UpdateClassificationTitle -match $regexpClass `
- -and $_.IsDeclined -eq $False `
- -and $_.IsSuperseded -eq $False `
- -and $_.State -eq "Ready"}
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') - Total Updates : $($allUpdates.count) Useful Updates : $($updates.count)"
- ####
- # Eliminates some updates we collect
- ####
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Reject some useless updates ... "
- ($updates_filtered, $nb_rejected) = filterUpdates($updates)
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') - Total updates rejected $nb_rejected (because they are already approved) "
- ####
- # Automatic Approve
- # and construct list of each updates
- ####
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Approving updates ... "
- # Title, arrivaldate, producttitles, is not superseded, approved by validation, delay OK, action, remark
- $report = @()
- $nb_approved = 0
- $updates_filtered | foreach {
- $action = @()
- $desc = @()
- # $WSUS_TargetGroup_Validation is optinal
- if ( $WSUS_TargetGroup_Validation -ne $null ) {
- $isValidationApproved = $false
- $isDelayExceeded = $false
- if ( $_.isApproved ) {
- $_.getUpdateApprovals() | foreach {
- if ($_.ComputerTargetGroupId -eq $tg_valid_Approve.id ) {
- $isValidationApproved = $true
- $delayCount = $_.CreationDate.add($DELAY)
- $isDelayExceeded = $delayCount -lt $now
- }
- }
- }
- }
- else {
- $delayCount = $_.ArrivalDate.add($DELAY)
- $isDelayExceeded = $delayCount -lt $now
- $isValidationApproved = $true
- }
- # $WSUS_TargetGroup_Validation is optinal
- if ($isValidationApproved -or $WSUS_TargetGroup_Validation -eq $null ) {
- if ($isDelayExceeded) {
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') - Approve $($_.legacyname) "
- $nb_approved++
- $action = "(Approve !)"
- $desc = "Uncomment action in script"
- ## UNCOMMENT WHEN YOU'RE SURE
- $action="Approve !"
- $desc = "$($($now - $_.ArrivalDate).days) days after release"
- if($_.RequiresLicenseAgreementAcceptance) {$_.AcceptLicenseAgreement()}
- $_.approve(“Install”,$tg_to_Approve)
- }
- else {
- $action = "Wait"
- $desc = "$($($delayCount - $now).days) days remaining"
- }
- }
- else {
- if ( $WSUS_TargetGroup_Validation -ne $null ) {
- $action = "Wait"
- $desc = "$($tg_valid_Approve.name) must be approved first"
- }
- else {
- $action = "Wait"
- $desc = "This case never happen - send comments on script center for this script"
- }
- }
- $line = New-Object System.Object
- $line | Add-Member -type NoteProperty -name "Name" -value $_.title
- $line | Add-Member -type NoteProperty -name "Date of Arrival" -value $_.ArrivalDate.ToString("yyyy/MM/dd HH:mm:ss")
- $line | Add-Member -type NoteProperty -name "Product" -value $_.ProductTitles
- $line | Add-Member -type NoteProperty -name "Classification" -value $_.UpdateClassificationTitle
- # $WSUS_TargetGroup_Validation is optinal
- if ( $WSUS_TargetGroup_Validation -ne $null ) {
- $line | Add-Member -type NoteProperty -name "Approved by Validation" -value $isValidationApproved
- }
- $line | Add-Member -type NoteProperty -name "Action" -value $action
- $line | Add-Member -type NoteProperty -name "Description" -value $desc
- $report += $line
- }
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') - Total updates approved $nb_approved "
- ####
- # Build report
- ####
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') Building report ... "
- $HTML_head = "<!--mce:0-->";
- $HTML_style = "
- <style>`
- i, table, tr > th {`
- font-family: Tahoma, Geneva, sans-serif;`
- font-size: 10px;`
- text-align:left;`
- }`
- p {`
- font-family: Tahoma, Geneva, sans-serif;`
- font-size: 12px;`
- }`
- h1,h2,h3 {`
- font-family: Tahoma, Geneva, sans-serif;`
- }`
- tr > td {`
- text-align:left;`
- }`
- ul {`
- list-style-type: circle;`
- font-family: Tahoma, Geneva, sans-serif;`
- font-size: 12px;`
- }`
- </style>`
- "
- $HTML_body = "<H2> $TITLE - Date of report : $($now.ToString("yyyy/MM/dd HH:mm:ss"))</H2>`
- <p>Delay <b>$($DELAY.days) days</b> is set for auto approval of updates on a target group <b>$WSUS_TargetGroup_To_Approved</b></p> `
- <p>Validation group is set to : $WSUS_TargetGroup_Validation group on WSUS Server</p>`
- <p><h3>This script is taking into accout only the following updates:</h3></p>`
- <ul>`
- <li>For products matching $([system.String]::Join(",", $WSUS_CategoriesIncluded))</li>`
- <p><i> To configure, change WSUS_CategoriesIncluded script variable</i></p>`
- <li>For classification matching $([system.String]::Join(",", $WSUS_ClassificationsIncluded))</li>`
- <p><i> To configure, change WSUS_ClassificationsIncluded script variable</i></p>`
- <li>That aren't Declined</li>`
- <li>That aren't Superseded</li>`
- <li>That are marked as Needed</li>`
- <p><i>this setting is set by WSUS server, when at least one of the registered workstations reported it as needed</i></p>`
- </ul>"
- $report_html = BuildHTMLTable($report)
- $html = "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>`
- <html xmlns='http://www.w3.org/1999/xhtml'>" + `
- "<head>" + `
- "<title>" + $TITLE + "</title>" + `
- $HTML_style + `
- "</head>" + `
- "<body>" + `
- $HTML_body + `
- $report_html + `
- "</body>" + `
- "</html>"
- $html | Set-Content $report_filename
- Send-MailMessage -From $emailfrom -To $emailrecipients -Subject $emailsubject -SmtpServer $mxserver -Attachments $report_filename
- ####
- # End
- ####
- Add-content $logfile -value "$(Get-Date -format 'yyyy/MM/dd HH:mm:ss') End "
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement