Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Patch AD Computers for NotPetya. Supports multiple runs to skip previously patched machines and provides detailed logging objects.
#Requires -Modules PoshRSJob, ActiveDirectory
# create this file as read-Only before running script
$SourceFile = "C:\perfc"
$ServerFilter = {enabled -eq $True -and DnsHostName -like "*" -and operatingSystem -like "*windows*"}
$SearchBase = "dc=adatum,dc=com"
$LogFile = "C:\NotPetyaPatch.xml"
$Throttle = 40
$StartDate = Get-Date
$Results = [System.Collections.ArrayList]::new()
$Vaccinated = [System.Collections.ArrayList]::new()
$PreviousResults = Import-Clixml -Path $LogFile -ErrorAction SilentlyContinue
Foreach($PreviousResult in $PreviousResults){
if($PreviousResult.Vaccinated -eq $true){
$null = $Results.Add($PreviousResult)
$null = $Vaccinated.Add($PreviousResult.Server.SID.Value)
}
}
$Results | Select-Object ComputerName, Vaccinated, Date | Format-Table
$Servers = Get-ADComputer -filter $ServerFilter -SearchBase $SearchBase | Where-Object {$_.SID.Value -notin $Vaccinated}
$Servers | Start-RSJob -Name {$_.DnsHostName} -Throttle $Throttle -ScriptBlock {
$Server = $_
$ComputerName = $Server.DnsHostName
$SourceFile = $using:SourceFile
$AdminShare = '\\{0}\C$' -f $ComputerName
$DestinationFiles = @(
Join-Path -Path $AdminShare -ChildPath '\Windows\perfc'
Join-Path -Path $AdminShare -ChildPath '\Windows\perfc.dat'
Join-Path -Path $AdminShare -ChildPath '\Windows\perfc.dll'
)
$Result = [PSCustomObject]@{
Server = $Server
ComputerName = $ComputerName
PathAvailable = $false
Vaccinated = "Unknown"
Errors = [System.Collections.ArrayList]::new()
CopyResults = [System.Collections.ArrayList]::new()
Date = Get-Date
}
if (-not (Test-Path -Path $AdminShare)) {
return $Result
}
$Result.PathAvailable = $True
foreach($DestinationFile in $DestinationFiles){
$DestinationResult = [PSCustomObject]@{
DestinationFile = $DestinationFile
FileAlreadyExists = $false
CopyAttempted = $false
CopySuccessful = $false
}
if (Test-Path -Path $DestinationFile) {
$DestinationResult.FileAlreadyExists = $true
$DestinationResult.CopySuccessful = $true
$null = $Result.CopyResults.Add($DestinationResult)
continue
}
try {
$DestinationResult.CopyAttempted = $True
$Null = Copy-Item -Path $SourceFile -destination $DestinationFile -ErrorAction Stop
}
catch {
$null = $Result.Errors.Add($_)
$null = $Result.CopyResults.Add($DestinationResult)
continue
}
if (Test-Path -Path $DestinationFile) {
$DestinationResult.CopySuccessful = $true
}
$null = $Result.CopyResults.Add($DestinationResult)
}
if($false -in $Result.CopyResults.CopySuccessful){
$Result.Vaccinated = $false
}
else{
$Result.Vaccinated = $true
}
return $Result
} | Wait-RSJob | Receive-RSJob | ForEach-Object {
$null = $Results.Add($_)
$_ | Select-Object ComputerName, Vaccinated
} | Format-Table
$VaccinatedTotal = $Results.Where({$_.vaccinated -eq $True}).Count
$VaccinatedThisRun = $VaccinatedTotal - $Vaccinated.Count
$EndDate = Get-Date
" "
"Results"
"---------------------------"
"Previously Vaccinated: {0}" -f $Vaccinated.Count
"Vaccinated This Run: {0}" -f $VaccinatedThisRun
"Vaccinated Total: {0}" -f $VaccinatedTotal
"Failed: {0}" -f $Results.Where({$_.vaccinated -eq $false}).Count
"Unknown: {0}" -f $Results.Where({$_.vaccinated -like "Unknown"}).Count
"Start Date: {0}" -f $StartDate
"End Date: {0}" -f $EndDate
"Run time: {0}" -f ($EndDate - $StartDate)
Get-RSJob | Remove-RSJob -Force
$Results | Export-Clixml -Path $LogFile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment