Skip to content

Instantly share code, notes, and snippets.

@thegooddoctorgonzo
Last active March 25, 2022 08:33
Show Gist options
  • Save thegooddoctorgonzo/14446d428612eaa38b460bd5b3ff2e0e to your computer and use it in GitHub Desktop.
Save thegooddoctorgonzo/14446d428612eaa38b460bd5b3ff2e0e to your computer and use it in GitHub Desktop.
Find and Fix AD Computers Missing from WSUS
<# thegooddoctorgonzo
20170714
Script compares list of computers registered in WSUS to list from AD. Difference is computers missing from WSUS. Attempts to correct by eliminating reg keys from cloning computers and prompts host to check in to WSUS.
Paired with Task "Find Comps Missing From WSUS" on WSUS server
#>
Start-Transcript -Path "LOG.FILE" -Append -Force
Import-Module ActiveDirectory
#get WSUS server
$wsus = Get-WsusServer WSUSserver -PortNumber 8530
#list of comps in WSUS
$WSUSList = Get-WsusComputer -UpdateServer $wsus |Select-Object -Property FullDomainNAme | Sort-Object -Property FullDomainNAme
#put list into string array for compare
$WSUSComps = New-Object System.Collections.ArrayList
foreach($wsusCom in $WSUSList)
{
$WSUSComps.Add($wsusCom.FullDomainName)
}
#list of comps - queries several different OUs
$ADComps = Get-ADComputer -SearchBase "OU=" -Filter *
$ADComps2 = Get-ADComputer -SearchBase "OU=" -Filter *
$ADComps3 = Get-ADComputer -SearchBase "OU=" -Filter *
$ADComps4 = Get-ADComputer -SearchBase "OU=" -Filter *
$ADComps5 = Get-ADComputer -SearchBase "OU=" -Filter *
$ADComps6 = Get-ADComputer -SearchBase "OU=" -Filter *
$ADList = $ADComps1 + $ADComps2 + $ADComps3 + $ADComps4 + $ADComps5 + $ADComps6 | Select-Object -Property DNSHostName | Sort-Object -Property DNSHostName
#put list into string array for compare
$ADComputers = New-Object System.Collections.ArrayList
foreach($ADCom in $ADList)
{
$ADComputers.Add($ADCom.DNSHostName)
}
#Delta of 2 lists
$missing = $ADComputers | Where-Object {$WSUScomps -notcontains $_}
#create test for email
foreach($miss in $missing)
{
$bodyText = $bodyText + "`n" + $miss.InputObject.DNSHostName
}
$body = "Script: SCRIPT.ps1 `nTask: Find Comps Missing From WSUS on WSUS `nLog: LOG.FILE `nLog: LIST.FILE `n`n" + $bodyText
Send-MailMessage -From EMAIL -To EMAIL -SmtpServer SMTP -Subject "Find Comps Missing From WSUS Finished" -Body $body
Stop-Transcript
#Attempt to remediate computers
Start-Transcript -Path "LIST.FILE" -Force -Append
foreach ($miss in $missing)
{
if(Test-Connection -ComputerName $miss.InputObject.DNSHostName -Verbose -Count 1)
{
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock {Stop-Service -Name wuauserv -Verbose } -Verbose
#Delete reg keys
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock {Remove-ItemProperty -Name AccountDomainSid -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate -Verbose } -Verbose
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock {Remove-ItemProperty -Name PingID -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate -Verbose } -Verbose
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock {Remove-ItemProperty -Name SusClientId -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate -Verbose } -Verbose
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock {Remove-ItemProperty -Name SusClientIDValidation -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ -Verbose } -Verbose
#Delete files
$path = "\\" + $miss.InputObject.DNSHostName + "\c$\Windows\SoftwareDistribution"
Remove-Item -Path $path -Recurse -Verbose
$path = "\\" + $miss.InputObject.DNSHostName + "\c$\Windows\WindowsUpdate.log"
Remove-Item -Path $path -Verbose
#Restart update service and force check in to WSUS
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock {Start-Service -Name wuauserv -Verbose } -Verbose
Invoke-Command -ComputerName $miss.InputObject.DNSHostName -ScriptBlock { & cmd.exe /c wuauclt /resetauthorization /detectnow} -Verbose
}
}
Stop-Transcript
@thegooddoctorgonzo
Copy link
Author

Consider removing -verbose or generating output in some other way. This will make huge log files. 1000's of lines possible per host.

@dagarmon
Copy link

Hello.

I´m trying use the script adapted to my AD, but i get an error at 61 line, null or empty:

... f(Test-Connection -ComputerName $miss.InputObject.DNSHostName -Verbos ...

  •                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException
    • FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand

I have write $miss and is´t null

¿what it´s happend?

Thanks.

@thegooddoctorgonzo
Copy link
Author

Hello.

I´m trying use the script adapted to my AD, but i get an error at 61 line, null or empty:

... f(Test-Connection -ComputerName $miss.InputObject.DNSHostName -Verbos ...

  •                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException
    • FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand

I have write $miss and is´t null

¿what it´s happend?

Thanks.

What is the output of Write $miss | select * ?

@dagarmon
Copy link

I solved writing dates to file y getting dates from file:

write $missing > perdidos.txt
$complist = Get-Content "C:\perdidos.txt"

I´m sure that the problem it´s with the data type.
Thanks.

@dagarmon
Copy link

Hello.
I´m trying use the script adapted to my AD, but i get an error at 61 line, null or empty:
... f(Test-Connection -ComputerName $miss.InputObject.DNSHostName -Verbos ...

  •                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException
    • FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand

I have write $miss and is´t null
¿what it´s happend?
Thanks.

What is the output of Write $miss | select * ?

Nothing.
$missing have a list with the computer names. I don´t understand why $miss it´s empty.
Thanks.

@thegooddoctorgonzo
Copy link
Author

weird. what is the output of Write $missing[0] | select * ?

@dagarmon
Copy link

weird. what is the output of Write $missing[0] | select * ?

I´m execute:

Write $missing[0] | select *
Write $missing[12] | select *
Write $missing[1200] | select *
Write $missing[5000] | select *

and i get:

_Length

34_

@dagarmon
Copy link

Length

34

weird. what is the output of Write $missing[0] | select * ?

I´m execute:

Write $missing[0] | select * Write $missing[12] | select * Write $missing[1200] | select * Write $missing[5000] | select *

and i get:

_Length

34_

Length

34

@thegooddoctorgonzo
Copy link
Author

for all of them its 34? anything in $WSUSComps or $adcomputers? and $missing has a list of computer names?

@dagarmon
Copy link

Hi.

This is part of the scripts:

_
.
.
.
$WSUSComps = New-Object System.Collections.ArrayList
foreach($wsusCom in $WSUSList)
{
$WSUSComps.Add($wsusCom.FullDomainName)
write $wsusCom >> wsusCom.txt
}

write $WSUSComps > WSUSComps.txt
.
.
.
$ADList = Get-ADComputer -Filter 'enabled -eq $true' &lt;#| Where {($.LastLogonDate -lt (Get-Date).AddDays(-30)) -and ($.LastLogonDate -ne $NULL)} #>| Select-Object -Property DNSHostName | Sort-Object -Property DNSHostName

write $ADList > ADList.txt

#put list into string array for compare
$ADComputers = New-Object System.Collections.ArrayList
foreach($ADCom in $ADList)
{
$ADComputers.Add($ADCom.DNSHostName)
write $ADCom >> ADCom.txt
}

write $adcomputers > adcomputers.txt

#Delta of 2 lists
#$missing = New-Object System.Collections.ArrayList
$missing = ($ADComputers | Where-Object {$WSUScomps -notcontains $})
write $missing > perdidos.txt
.
.
.
foreach ($miss in $missing)
{
Write $miss | select *
Write "Computer: " $miss
if(Test-Connection -ComputerName $miss -Quiet -Count 1 -ErrorAction SilentlyContinue)
{
Write "Computer with connection " $miss
}
}
.
.
.

and i get:

_.
.
.
7135
7136
7137
7138
La transcripción se ha detenido. El archivo de salida es C:\SCRIPTS\WSUS_PS\LogFile.log
La transcripción ha comenzado. El archivo de salida es ListFile.log

Length

95964
95964
95964
95964
Computer:
Test-Connection : No se puede validar el argumento del parámetro 'ComputerName'. El argumento es null o está vacío. Proporcione un argumento que no sea null o que no esté vacío e intente
ejecutar el comando de nuevo.
En C:\SCRIPTS\WSUS_PS\FindFixCompsMissingFromWSUS.ps1: 130 Carácter: 35

  • if(Test-Connection -ComputerName $miss -Quiet -Count 1 -ErrorActi ...
    
  •                                  ~~~~~
    
    • CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException
    • FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand

Computer:
Test-Connection : No se puede validar el argumento del parámetro 'ComputerName'. El argumento es null o está vacío. Proporcione un argumento que no sea null o que no esté vacío e intente
ejecutar el comando de nuevo.
En C:\SCRIPTS\WSUS_PS\FindFixCompsMissingFromWSUS.ps1: 130 Carácter: 35

  • if(Test-Connection -ComputerName $miss -Quiet -Count 1 -ErrorActi ...
    
  •                                  ~~~~~
    
    • CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException
    • FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand

Computer:
.
.
._

The file "perdidos.txt" have a list with the computer of AD that not are in WSUS (it´s correct):

ComputerXXX.domain.es
ComputerXXX.domani.es
....

Thanks.

@thegooddoctorgonzo
Copy link
Author

Yes I think you are right that it is a problem with the data type of $miss. Maybe try $miss.toString() or [string]$miss. Maybe the list needs quotes around each string?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment