Earlier today, I ran across a computer with a broken trust relationship. I don’t know how long this machine had set there – in a corner – alone – afraid to authenticate with the nearest DC. I took pity on the little guy and helped him get back on his feet.
As always, the broken trust relationship issue boils down to a password mismatch between the computer and the domain. It isn’t that the computer forgot the password (though that would be embarrassing if it did). Instead, this problem is usually the result of IT error (such as a duplicated name or an accidental reset). I list many reasons and a remote way to fix broken trust relationships on this page.
8 is the loneliest number.
I became curious on how many other machines in my domain are in this same sad/confused state. Turns out, I had 8 of them – 7 of which I was able to fix remotely! Most of these machines were open lab computers. These labs often have a spare or two (which explains why these weren’t reported to our helpdesk).
Below, you will find a PowerShell script that will let you check your domain for broken trust computers. It works by looking for a system NETLOGON event ID 5722 on each DC. This event ID contains a computer name that failed to authenticate. The user running this script should be delegated the Event Log Reader permission on your domain controllers. This can be accomplished by adding the user to the built in AD security group: Event Log Readers.
Import-Module ActiveDirectory
Import-Module Microsoft.PowerShell.Management
$DateToStartSearch = (Get-Date).AddDays(-1)
$SMTPServer = ''
$From = ''
$To = ''
$Subject = 'Broken Trust - Image or rejoin to the domain'
$DCS = Get-ADDomainController -Filter * | Select HostName | sort Hostname
Clear-Variable NetLogonErrors -ErrorAction SilentlyContinue
foreach ($DC in $DCS){
$NetLogonErrors += (Get-EventLog -LogName System -Source NETLOGON -ComputerName $DC.HostName -InstanceId 5722 -After $DateToStartSearch |
select -ExpandProperty ReplacementStrings).trimend('$')
}
$NetLogonErrors = $NetLogonErrors | select -Unique | sort
$NetLogonErrors = $NetLogonErrors | Where-Object { $_ -ne "%%5" }
$NetLogonErrorsObjects = New-Object -TypeName PSObject -Property @{ComputerName = $NetLogonErrors}
foreach ($NetLogonErrorsObject in $NetLogonErrorsObjects.ComputerName){
if (((Get-ADComputer -Identity $NetLogonErrorsObject -Properties * | select -ExpandProperty PasswordLastSet) -gt $DateToStartSearch) -eq $False){
Send-MailMessage -SmtpServer $SMTPServer -From $From -to $To -Subject $Subject -Body $NetLogonErrorsObject
}
}
To use this script, you will need to set the configure the first few lines at the top. The first line sets the earliest the script will search. If you run the script once per day, you do not need to change the first line. If you set it to run once per week, change the value from -1 to -7. The next three lines are needed to send an email alert. The final $Subject line can be changed if you prefer a different email subject.
Once you fix a machine, it should not generate an email on the next regular script run. This is accomplished by comparing the $DatetoStartSearch value to the last time that machine changed it’s password. If you run the script manually, repaired machines may generate an email because that $DatetoStartSearch value will be refreshed again. If you wish to run this manually, comment out the first line on any sequential executions.
This page and show script is broken.
I had issues too – here is the script I’m using now (put your servers in a text file list and ID it in line 1):
$Computers = Get-Content -Path ./domain_controllers.txt
foreach ($computer in $computers) {
Get-WinEvent -ComputerName $computer -FilterHashtable @{logname=’System’; id=5722} -MaxEvents 10 | select TimeCreated,Message | Out-String
}
BTW, I run this script once per week (manually), and I get an error every time I run it. But after the error, I immediately run it again and it completes with no errors (not sure why either, but at least it works on the second try every time, lol).
I get an error when I try running this:
You cannot call a method on a null-valued expression.
At line:15 char:5
+ $NetLogonErrors += (Get-EventLog -LogName System -Source NETLOGON …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Does the user that you are using to run this script have permission to read the SYSTEM event log?
Sorry for the double post last time! The first one failed and then when the second one went through, I saw both go through :-S…
Yep, I’m running the script as a domain admin, however, I was running it from an RSAT box and not directly from the server. I remoted in to one of our DCs and tried running it again (as a domain admin). I’m getting these errors:
You cannot call a method on a null-valued expression.
At line:16 char:5
+ $NetLogonErrors += (Get-EventLog -LogName System -Source NETLOGON …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Get-EventLog : No matches found
At line:16 char:25
+ … nErrors += (Get-EventLog -LogName System -Source NETLOGON -ComputerNa …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-EventLog], ArgumentException
+ FullyQualifiedErrorId : GetEventLogNoEntriesFound,Microsoft.PowerShell.Commands.GetEventLogCommand
I get an error when I try running it:
You cannot call a method on a null-valued expression.
At line:15 char:5
+ $NetLogonErrors += (Get-EventLog -LogName System -Source NETLOGON …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cool. Sometimes I’d find broken trusts indirectly when using a function I made to find failed logons. If I noticed a machine account causing a bunch of logon failures, I’d know to look into it for a broken trust. This method (event) is much more efficient at that.
One minor suggestion I have is to use Get-WinEvent instead of Get-EventLog — it’s newer, faster, makes coffee, etc. It’s a bit different to use (e.g. FilterHashtable), but worthwhile to learn.
And since I brought it up, here’s a pastebin for that failed logon function I made some rainy day. May it be useful to you someday:
https://pastebin.com/2gW1fuqC
Great tips! And thanks for that function!
Very nice PowerShell script.
Is there a way to run it on a specific OU and it’s sub OUs instead of the entire domain?
Any way to consolidate the email report to one email with all Host names, rather than one email per host name?
regards,
Stephen
I’ll answer the 2nd question first. To email all host names, change
Send-MailMessage -SmtpServer $SMTPServer -From $From -to $To -Subject $Subject -Body $NetLogonErrorsObject
to
Send-MailMessage -SmtpServer $SMTPServer -From $From -to $To -Subject $Subject -Body $NetLogonErrorsObjects.ComputerName