Monitor-Active-Directory-Servers
This article is about PowerShell and the tasks I use it for.
This is a handy script I use to monitor servers in Active Directory. Note that you will need to change OU=SERVEROU,DC=CONTOSCO,DC=COM to whatever your Server OU is and you will need to provide your own Discord webhook. (Slack and Teams work similarly.)
<#server-watch.ps1
27Sep2023 I wanted an improved way to get alerts when servers go offline
The old script took input from a text file. This one uses AD to get the list of servers when it starts. It will run in a loop
for a day, then end. So it should be scheduled to run once daily. That way when a new server is being set up, it gets ignored
until the next day (since there are likely to be several reboots during the initial configuration).
#>
#Log management - optional
#. C:\bin\manage-logs.ps1 $MyInvocation.MyCommand.Name
$thisscript=$MyInvocation.MyCommand.Name
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 #Server 2016 and before
$serversou="OU=Your Servers,DC=CONTOSO,DC=COM"
$uriDiscord = "https://discord.com/api/webhooks/[your webhook here]"
$serverlist=@()
$responses=@{}
$alerts=@{}
$acceptableofflinesec=120
$minbetweenalerts=120
$endat=(Get-Date).AddDays(1)
function sendAlert
{
Param($message)
Write-Output "Running sendAlert`nMessage:`n$message"
$Body = "$message`n`nMonitor on " + $env:computername +" by "+$thisscript+"`n"
$payload = [PSCustomObject]@{
content = $Body
}
try {
Invoke-RestMethod -uri $uriDiscord -Method Post -body ($payload|ConvertTo-Json) -ContentType 'Application/Json' | Out-Null
}catch{
Write-Error (Get-Date) ": Update to webhook went wrong..."
}
}
Get-ADComputer -Filter * -SearchBase $serversou|%{
$servername=$_.DNSHostName
#echo "$(Get-Date) Processing $(echo $_.Name)"
If (-not $servername){
echo "$(Get-Date) No DNS Entry for $(echo $_.Name)"
}Else{
$serverlist+=$_.DNSHostName
}
If (($servername) -and (-not $responses[$_.DNSHostName])){
#echo "$(Get-Date) No existing entry for $servername set to -365 days"
$responses[$_.DNSHostName]=(Get-Date).AddDays(-365)
}
}
Get-ADDomainController -Filter *|%{
$servername=$_.HostName
#echo "$(Get-Date) Processing $(echo $_.Name)"
If (-not $servername){
echo "$(Get-Date) No DNS Entry for $(echo $_.Name)"
}Else{
$serverlist+=$_.HostName
}
If (($servername) -and (-not $responses[$_.HostName])){
#echo "$(Get-Date) No existing entry for $servername set to -365 days"
$responses[$_.HostName]=(Get-Date).AddDays(-365)
}
}
while ((Get-Date) -lt $endat){
$job=Test-Connection -ComputerName $serverlist -BufferSize 16 -Count 1 -AsJob
$results=Receive-Job $job -Wait
#$results;
foreach ($this in $results){
If ($this.StatusCode -eq 0){
$responses[$this.Address]=Get-Date
}
}
foreach ($server in $responses.keys){
$elaspedsec=((Get-Date) - $responses[$server]).TotalSeconds
#echo "$(Get-Date) $server elasped: $elaspedsec - last response: $(echo $responses[$server])"
if ($elaspedsec -gt $acceptableofflinesec){
#echo "$(Get-Date) Server: $server has not responded within $acceptableofflinesec seconds. Elasped: $(((Get-Date) - $responses[$server]))"
if (!($alerts[$server])){
$alerts[$server]=(Get-Date).AddMinutes(- $minbetweenalerts)
#echo "$(Get-Date) Server: $server did not have a last alert defined. Set to: $(echo $alerts[$server])"
}
if (((Get-Date) - $alerts[$server]).TotalMinutes -gt $minbetweenalerts){
echo "$(Get-Date) Alert needed for $server - no response since $($responses[$server]) Last alert $($alerts[$server])"
$alerts[$server]=Get-Date
sendAlert "Server: $server has not responded since $($responses[$server])"
}Else{
#echo "$(Get-Date) Alert for $server is recent, not sending another"
}
}Else{
#echo "$(Get-Date) $server has responded recently - last response: $elaspedsec"
}
}
Start-Sleep -Seconds 5
}
echo "$(Get-Date) Finished."