Get-WannaCryPatchStatus.ps1
<#PSScriptInfo
.VERSION 1.3 .AUTHOR mike@riston.me .RELEASENOTES Fixed logic error and added more information in help section. .DESCRIPTION Bulk of the script from : <<<<<<<<<<<< Version 1.08.00 @KieranWalsh May 2017 Computer Talk LTD Thanks to https://github.com/TLaborde, and https://www.facebook.com/BlackV for notifying me about missing patches. >>>>>>>>>>>> Infinite thanks to @KieranWalsh for the huge help and all of the hard work. #> function Get-WannaCryPatchStatus { <# .SYNOPSIS Queries computers in your domain for the status of their protection state against WCry .DESCRIPTION Bulk of the script from : <<<<<<<<<<<< Version 1.08.00 @KieranWalsh May 2017 Computer Talk LTD Thanks to https://github.com/TLaborde, and https://www.facebook.com/BlackV for notifying me about missing patches. >>>>>>>>>>>> Infinite thanks to @KieranWalsh for the huge help and all of the hard work. .PARAMETER patch_location_5 Path to the Windows XP .EXE update file you wish to invoke on remote computer. .PARAMETER patch_location_6 Path to the Windows 7 .MSU update file you wish to invoke on remote computer. .PARAMETER patch_location_10 Path to the Windows 10 .MSU update file you wish to invoke on remote computer. .EXAMPLE Get-WannaCryPatchStatus -patch_location_5 '\\server\wcry_xp_patch.exe' -patch_location_6 '\\server\wcry_win7_patch.msu' -patch_location_7 '\\server\wcry_win10_patch.msu' .EXAMPLE Get-WannaCryPatchStatus -patch_location_5 '\\server\wcry_xp_patch.exe' -patch_location_6 '\\server\wcry_win7_patch.msu' -patch_location_7 '\\server\wcry_win10_patch.msu' -ForceFullDomainScan Ignores the Offline Computers log from previous scan(s) and forces a full domain scan #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'Path to the Windows XP .EXE update file you wish to invoke on remote computer.')] [System.String] $patch_location_5, [Parameter(Mandatory = $true, Position = 1, HelpMessage = 'Path to the Windows 7 .MSU update file you wish to invoke on remote computer.')] [System.String] $patch_location_6, [Parameter(Mandatory = $true, Position = 2, HelpMessage = 'Path to the Windows 10 .MSU update file you wish to invoke on remote computer.')] [System.String] $patch_location_10, [Parameter(Mandatory = $false, Position = 3)] [Switch] $ForceFullDomainScan = $false ) $OffComputers = @() $CheckFail = @() $Patched = @() $Unpatched = @() $log = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath "WannaCry patch state for $($ENV:USERDOMAIN).log" $offlinelog = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath "WannaCry patch state for $($ENV:USERDOMAIN)-OfflineComputers.log" $Patches = @('KB4012212', 'KB4012213', 'KB4012214', 'KB4012215', 'KB4012216', 'KB4012217', 'KB4012598', 'KB4013429', 'KB4015217', 'KB4015438', 'KB4015549', 'KB4015550', 'KB4015551', 'KB4015552', 'KB4015553', 'KB4016635', 'KB4019215', 'KB4019216', 'KB4019264', 'KB4019472') $WindowsComputers = (Get-ADComputer -Filter { (OperatingSystem -Like 'Windows*') -and (OperatingSystem -notlike '*Windows 10*') -and (Enabled -eq $true) }).Name| Sort-Object if (Test-Path $log) { #Log Exists, move. Move-Item -Path $log -Destination "$($log)_old_$(Get-Date -Format yyyy-MM-dd.HH.mm.ss).log" } if (Test-Path $offlinelog) { #Offline Files log exists. Run against this instead of AD to save time. #Disable this line to run another 'full scan' of your domain. if (!$ForceFullDomainScan) { $WindowsComputers = Get-Content $offlinelog } #Log Exists, move. Move-Item -Path $offlinelog -Destination "$($offlinelog)_old_$(Get-Date -Format yyyy-MM-dd.HH.mm.ss).log" } "WannaCry patch status $(Get-Date -Format 'yyyy-MM-dd HH:mm')`tComputerName`tPatchStatus`tLogFile" |Out-File -FilePath $log $ComputerCount = $WindowsComputers.count "There are $ComputerCount computers to check" $loop = 0 foreach($Computer in $WindowsComputers) { $ThisComputerPatches = @() $loop ++ "$loop of $ComputerCount `t$Computer" try { $null = Test-Connection -ComputerName $Computer -Count 1 -ErrorAction Stop try { $Hotfixes = Get-HotFix -ComputerName $Computer -ErrorAction Stop $Patches | ForEach-Object -Process { if($Hotfixes.HotFixID -contains $_) { $ThisComputerPatches += $_ } } } catch { $CheckFail += $Computer "***`t$Computer `tUnable to gather hotfix information" |Out-File -FilePath $log -Append continue } If($ThisComputerPatches) { "`t$Computer is patched with $($ThisComputerPatches -join (','))" |Out-File -FilePath $log -Append $Patched += $Computer } Else { $Unpatched += $Computer "*****`t$Computer IS UNPATCHED! *****`tInvoking Patch Installation. Log will be created if not-XP`t\\$Computer\c$\scripts\wcry_patch_install.evtx" |Out-File -FilePath $log -Append $version = (Get-WmiObject -ComputerName $Computer -Class Win32_OperatingSystem).Version New-Item \\$computer\c$\scripts -ItemType Directory -Force if ($version -like '5*') { $FileToRun = $patch_location_5 $KB = '4012598' Copy-Item $FileToRun -Destination "\\$Computer\c$\scripts\wcry_patch_KB4012598.exe" #-Verbose #read-host go line 68? PsExec.exe -s \\$Computer cmd /c 'C:\scripts\wcry_patch_KB4012598.exe' /quiet } if ($version -like '6*') { $FileToRun = $patch_location_6 $KB = '4012212' Copy-Item $FileToRun -Destination "\\$Computer\c$\scripts\Win7_KB4012212.msu" #-Verbose #read-host go line 77? PsExec.exe -s \\$Computer cmd /c wusa.exe 'C:\scripts\Win7_KB4012212.msu' /quiet /norestart /log:"C:\scripts\wcry_patch_install.evtx" } if ($version -like '10*') { $FileToRun = $patch_location_10 $KB = '4013429' Copy-Item $FileToRun -Destination "\\$Computer\c$\scripts\Win10_KB4013429.msu" #-Verbose #read-host go line 87? PsExec.exe -s \\$Computer cmd /c wusa.exe 'C:\scripts\Win10_KB4013429.msu' /quiet /norestart /log:"C:\scripts\wcry_patch_install.evtx" } } } catch { $OffComputers += $Computer "****`t$Computer `tUnable to connect." |Out-File -FilePath $log -Append $Computer | Out-File -FilePath $offlinelog -Append } } ' ' "Summary for domain: $ENV:USERDNSDOMAIN" "Unpatched ($($Unpatched.count)):" |Out-File -FilePath $log -Append $Unpatched -join (', ') |Out-File -FilePath $log -Append '' |Out-File -FilePath $log -Append "Patched ($($Patched.count)):" |Out-File -FilePath $log -Append $Patched -join (', ') |Out-File -FilePath $log -Append '' |Out-File -FilePath $log -Append "Off/Untested($(($OffComputers + $CheckFail).count)):"|Out-File -FilePath $log -Append ($OffComputers + $CheckFail | Sort-Object)-join (', ')|Out-File -FilePath $log -Append "Of the $($WindowsComputers.count) windows computers in active directory, $($OffComputers.count) were off, $($CheckFail.count) couldn't be checked, $($Unpatched.count) were unpatched and $($Patched.count) were successfully patched." 'Full details in the log file.' try { Start-Process -FilePath notepad++ -ArgumentList $log } catch { Start-Process -FilePath notepad.exe -ArgumentList $log } } |