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."