Wednesday, November 29, 2017

Detect current PDC and notify if it changes.

I've harped on Windows Time before and I assume it will plague me until the day I die.  We (once again) are seeing issues with time sync in our domain.  I "think" I finally got things stable but in the interim I wanted to keep an active eye on our PDC so I know if it moved to a different domain controller. 

I created the below script to do that for me.   I set a recurring scheduled task that fires every 15 minutes on my task engine server.   The script uses a fixed PDC but could be tweaked to track it if it moves.  I simply wanted an "idiot light" that annoyed me if the PDC wasn't where I expected it to be.  The first 4 alerts come as detected, then it backs off to once every hour.

Edit it as needed before running.

Param(
      [Switch]$Console = $false                            #--[ Set to true to enable local console result display. Defaults to false ]--
)

<#==============================================================================
         File Name : Get-PDC.ps1
   Original Author : Kenneth C. Mazie (kcmjr AT kcmjr.com)
                   :
       Description : The domain PDC is determined using DNS SRV records and is then
                   : compared to a preset.  If they don't match an email is sent.
                   :
             Notes : Normal operation is with no command line options.  Run from a
                   : recurring scheduled task every 15 minutes or as desired.  Outbound
                   : email messages are sent every 15 minutes first hour, then once an hour
                   : until the expected PDC is restored or the script is edited.
                   :
         Arguments : Command line options for testing:
                   : - "-console $true" will enable local console echo
                   :
          Warnings : None
                   :  
             Legal : Public Domain. Modify and redistribute freely. No rights reserved.
                   : SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
                   : ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
                   :
           Credits : Code snippets and/or ideas came from many sources including but
                   :   not limited to the following:
                   :
    Last Update by : Kenneth C. Mazie    
   Version History : v1.0 - 10-26-17 - Original
    Change History : v1.1 - 11-13-17 - Edited console output.  Changed count method.
                   : v1.2 - 11-27-17 - Added AD module import
                   : v1.3 - 11-18-17 - Changed PDC detection method.
                           #>               
                   $CurrentVersion = 1.3                             <#--[ Denotes current version
                   :
==============================================================================#>
#Requires -version 4

Clear-Host
Import-Module ActiveDirectory
$Script:Recipient = "me@mydomain.com"                                 #--[ Email recipient address goes here ]--
$Script:Subject = 'PDC Change Detected'
$Script:MailServer = '10.10.5.5'                                      #--[ Mail server IP goes here ]--
$Script:MailFrom = 'Powershell@mydomain.com'                          #--[ Email sender goes here ]--
$ScriptName = ($MyInvocation.MyCommand.Name).split(".")[0]
$Script:LogFile = $PSScriptRoot+"\"+$ScriptName+"_{0:MM-dd-yyyy_HHmmss}.log" -f (Get-Date)
$Script:FlagFile = "$PSScriptRoot\$ScriptName.flag"
$Domain = ""
$Count = 0
$ExpectedName = "dc01"                                                #--[ Expected PDC name goes here ]--
$ExpectedIP = "10.10.5.100"                                           #--[ Expected PDC IP goes here ]--

#--[ Get Domain ]-------------------------------------------------------------

While ($Domain -eq ""){
      $Domain = (Get-ADDomain).DNSroot
      Sleep -millisec 500
      $Count++
}

#--[ Read data file to determine what to do ]---------------------------------
If (Test-Path -Path $Script:FlagFile -PathType Leaf -ErrorAction SilentlyContinue){
    $Script:ErrorCount = [int](Get-Content -Path $Script:FlagFile  -ErrorAction SilentlyContinue)
 }Else{
    $Script:ErrorCount = 0
    Add-Content $Script:FlagFile -Value $Script:ErrorCount
}

#[array]$Lookup = (nslookup -type=SRV _ldap._tcp.pdc._msdcs.$Domain)
#$PDCname = ($Lookup[8].split('.'))[0]
#$PDCip = (($Lookup[8].split('='))[1]).trim()

$FSMO = Get-ADDomain | Select-Object DistinguishedName, SchemaMaster, DomainNamingMaster, InfrastructureMaster, PDCEmulator, RIDMaster 
$DetectedName = ($FSMO.PDCEmulator).Split(".")[0]
$DetectedIP = (Test-Connection $PDC -count 1 | select Ipv4Address).Ipv4Address

If ($Console){
    Write-Host "Previous Errors  :"$Script:ErrorCount -ForegroundColor Yellow 
    Write-Host "Expected PDC     : $ExpectedName" -ForegroundColor cyan
    Write-Host "Expected IP      : $ExpectedIP" -ForegroundColor cyan
    Write-Host "Detected PDC     : $DetectedName" -ForegroundColor yellow
    write-host "Detected IP      : $DetectedIP" -ForegroundColor yellow
}   

$Script:Message = @()
$Script:Message += '<html><br><font face="verdana,arial,sans-serif" color=red><strong>---===¦ ATTENTION ¦===---</strong></font><hr><br>
<strong>A change was detected in the normally assigned domain PDC.</strong><br>
<ul><li>Domain name           : <strong>'+$Domain+'</strong></li></ul>
<ul>
<li>Expected PDC DNS name : <strong>'+$ExpectedName+'</strong></li>
<li>Expected PDC IP       : <strong>'+$ExpectedIP+'</strong></li>
</ul><ul>
<li>Detected PDC DNS name : <strong>'+$DetectedName+'</strong></li>
<li>Detected PDC IP       : <strong>'+$DetectedIP+'</strong></li>
</ul>
- This check is run every 15 minutes to detect the domain PDC.<br
- Due to the way time services are configured in the domain, changes to which domain controller holds the role can affect time sync.<br>
- If this change was intentional, no harm done, however this alert will continue until stopped or the proper DC is selected/detected as PDC.<br>
- To minimize email spam, after the first 4 alerts emails will go out once per hour.<br>
- Script executed from and must be paused on : '+$env:computername+'
'

If (($PDCname -eq $TargetName) -and ($PDCip -eq $TargetIP)){
    remove-item -Path $Script:FlagFile -Force -Confirm:$false
    Add-Content $Script:FlagFile -Value "0"
    If ($Console){Write-Host "`nValues Match.  Resetting Error Count"`n -ForegroundColor Green }
}Else{   
    remove-item -Path $Script:FlagFile -Force -Confirm:$false
    Add-Content $Script:FlagFile -Value (($Script:ErrorCount -as [int]) + 1)
    $Script:Message += '
    <br>Running error count $Script:ErrorCount
    </HTML>
    '
    IF (($Script:ErrorCount -le 4) -or (!($Script:ErrorCount%4))){
        $SMTP = new-object System.Net.Mail.SmtpClient($Script:MailServer)
        $Email = New-Object System.Net.Mail.MailMessage
          $Email.Body = $Script:Message
          $Email.IsBodyHtml = $true
          $Email.To.Add($Script:Recipient)
          $Email.From = $Script:MailFrom
          $Email.Subject = $Script:Subject
        $SMTP.Send($Email)
          $Email.Dispose()
          $SMTP.Dispose()     
        $Script:ErrorCount = [int](Get-Content -Path $Script:FlagFile  -ErrorAction SilentlyContinue)
        If ($Console){Write-Host "New Error Count  :"$Script:ErrorCount`n -ForegroundColor Yellow}
    }
}



No comments:

Post a Comment