JustJoe

Domain-Report.ps1

Feb 16th, 2012
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # DomainReport.ps1
  2. # Emails a report of various metrics collected from every computer in the domain.
  3. # This script is intended to be run automatically, on a schedule of once a day or so,
  4. # to let us know how our domain is doing.
  5.  
  6. [string]$senderName   = "Domain Health Report"
  7. [string]$senderAddr   = "powershell@email"
  8. [string]$recptName    = "recipient name"
  9. [string]$recptAddr    = "you@email"
  10. [string]$emailSubject = "Domain Health Report"
  11. [string]$smtpServer   = ""
  12. [string]$emailBody    = ""
  13. [int]$staleCompAcctDays = 60
  14. [int]$staleUserAcctDays = 60
  15. [int]$diskFreePercentThreshold = 10
  16. [int]$SSIIndexThreshold = 7
  17.  
  18. Import-Module ActiveDirectory   # It will not hurt if the module is already loaded.
  19.  
  20. $localhost = Get-Content env:Computername
  21. $domain = Get-ADDomain
  22. $forest = Get-ADForest
  23. $allComputerAccts = Get-ADComputer -Filter * -Properties *
  24. $enabledComputerAccts = Get-ADComputer -Filter 'Enabled -eq $true' -Properties *
  25. $allUserAccts = Get-ADUser -Filter * -Properties *
  26. $enabledUserAccts = Get-ADUser -Filter 'Enabled -eq $true' -Properties *
  27.  
  28. Function Ping-Server
  29. {
  30.     param($hostName)
  31.     trap
  32.     {
  33.         $false; continue
  34.     }
  35.     $object = New-Object System.Net.NetworkInformation.Ping
  36.     $object.Send($hostName, 2000) #2000ms ping timeout
  37. }
  38.  
  39. $emailBody += "<FONT STYLE=`"font-size:30px;`">"
  40. $emailBody += "Domain Health Report"            
  41. $emailBody += "</FONT>"
  42. $emailBody += "<FONT STYLE=`"font-size:9px;`">"
  43. $emailBody += "<BR/>Report executed from $localhost at $(Get-Date)<HR/>"
  44. $emailBody += "</FONT>"
  45. $emailBody += "<FONT STYLE=`"font-family:Monospace;font-size:13px`"><BR/>"
  46. $emailBody += "<strong>Forest Root Domain:</strong> $($forest.RootDomain) ($($forest.ForestMode))<BR/>"
  47. $emailBody += "<strong>Current Domain:</strong> $($domain.Name), NetBIOS $($domain.NetBIOSName) ($($domain.DomainMode))<BR/>"
  48. $emailBody += "<BR/>"
  49. $emailBody += "<strong>Domain Controllers:</strong> $($domain.ReplicaDirectoryServers.Count) Writable, $($domain.ReadOnlyReplicaServers.Count) RODCs, $($forest.GlobalCatalogs.Count) Global Catalogs<BR/>"
  50. $emailBody += "<strong>Schema Master:</strong> $($forest.SchemaMaster)<BR/>"
  51. $emailBody += "<strong>Domain Naming Master:</strong> $($forest.DomainNamingMaster)<BR/>"
  52. $emailBody += "<strong>Infrastructure Master:</strong> $($domain.InfrastructureMaster)<BR/>"
  53. $emailBody += "<strong>RID Master:</strong> $($domain.RIDMaster)<BR/>"
  54. $emailBody += "<strong>PDC Emulator:</strong> $($domain.PDCEmulator)<BR/>"
  55. $emailBody += "<strong>Sites:</strong> $($forest.Sites)<BR/>"
  56. $emailBody += "<BR/>"
  57. $emailBody += "<strong>Computer Accounts:</strong> $($allComputerAccts.Count) found, $($enabledComputerAccts.Count) enabled<BR/>"
  58. if($allComputerAccts.Count -gt $enabledComputerAccts.Count)
  59. {
  60.     $emailBody += "<strong>Disabled Computer Accounts:</strong> "
  61.     ForEach($_ in $allComputerAccts)
  62.     {
  63.         if($_.Enabled -eq $false)
  64.         {
  65.             $emailBody += "$($_.CN)`, "
  66.         }
  67.     }
  68.     $emailBody = $emailBody -Replace "..$" # Trim off the last two characters
  69.     $emailBody += "<BR/>"
  70. }
  71. $emailBody += "<strong>Stale Computer Accounts<sup>*</sup>: </strong> "
  72. ForEach($_ in $allComputerAccts)
  73. {
  74.     if($_.PasswordLastSet -lt $((Get-Date).AddDays(-$($staleCompAcctDays))))
  75.     {
  76.         $emailBody += "$($_.CN)`, "
  77.     }
  78. }
  79. $emailBody += "<BR/><BR/>"
  80. $emailBody += "<strong>User Accounts: </strong> $($allUserAccts.Count) found, $($enabledUserAccts.Count) enabled<BR/>"
  81. if($allUserAccts.Count -gt $enabledUserAccts.Count)
  82. {
  83.     $emailBody += "<strong>Diabled User Accounts:</strong> "
  84.     ForEach($_ in $allUserAccts)
  85.     {
  86.         if($_.Enabled -eq $false)
  87.         {
  88.             $emailBody += "$($_.SAMAccountName)`, "
  89.         }      
  90.     }
  91.     $emailBody = $emailBody -Replace "..$"
  92.     $emailBody += "<BR/>"
  93. }
  94. $emailBody += "<strong>Stale User Accounts<sup>*</sup>: </strong> "
  95. ForEach($_ in $enabledUserAccts)
  96. {
  97.     $lastLogon = [DateTime]::FromFileTime($_.LastLogonTimeStamp)
  98.     if($lastLogon -lt $((Get-Date).AddDays(-$($staleUserAcctDays))))
  99.     {
  100.         $emailBody += "$($_.SAMAccountName)`, "
  101.     }
  102. }
  103. $emailBody += "</FONT><BR/><BR/>"
  104. $emailBody += "<FONT STYLE=`"font-size:9px;`">* A `"stale`" computer account is one that has not updated its machine password with AD in $staleCompAcctDays days."
  105. $emailBody += "<BR/>* A `"stale`" user account is not disabled but has not logged on to the domain in $staleUserAcctDays days."
  106. $emailBody += "</FONT>"
  107. $emailBody += "<HR/><BR/>"
  108.  
  109. ForEach($_ in $enabledComputerAccts)
  110. {
  111.     $emailBody += "<FONT STYLE=`"font-size:16px;`">"
  112.     $emailBody += "<strong>$($_.CN)</strong> <BR/>"
  113.     $emailBody += "</FONT>"
  114.     $emailBody += "<div style=`"border-width:1px;border-style:solid;margin:2px;padding:2px;`">"
  115.     $emailBody += "<FONT STYLE=`"font-family:Monospace;font-size:13px`">"
  116.     $pingNode = Ping-Server $($_.CN)
  117.     $emailBody += "<strong>Ping:</strong> "
  118.     if($pingNode.Status -ne "Success")
  119.     {
  120.         $emailBody += "<FONT STYLE=`"color:red;`"><strong>NO REPLY!</strong></FONT><BR/>"
  121.     }
  122.     else
  123.     {
  124.         $emailBody += "$($pingNode.RoundTripTime) ms reply from $($pingNode.Address)<BR/>"
  125.     }
  126.     $computerSystem = Get-WmiObject Win32_ComputerSystem -ComputerName $($_.CN)
  127.     $emailBody += "<strong>System: </strong> $($computerSystem.Manufacturer) $($computerSystem.Model)<BR/>"
  128.     $latestStabilityIndex = Get-WmiObject Win32_ReliabilityStabilityMetrics -ComputerName $($_.CN) | Select-Object -First 1 | ForEach {$_.SystemStabilityIndex}
  129.     $emailBody += "<strong>Latest SSI<sup>*</sup>: </strong>"
  130.     if($latestStabilityIndex -gt 0 -and $latestStabilityIndex -le 10)
  131.     {
  132.         if($latestStabilityIndex -lt $SSIIndexThreshold)
  133.         {
  134.             $emailBody += "<FONT STYLE=`"color:red;`"><strong>$latestStabilityIndex<BR/></strong></FONT>"
  135.         }
  136.         else
  137.         {
  138.             $emailBody += "$latestStabilityIndex<BR/>"
  139.         }      
  140.     }
  141.     else
  142.     {
  143.         $emailBody += "<FONT STYLE=`"color:red;`"><strong>NO DATA!</strong></FONT><BR/>"
  144.     }
  145.    
  146.     ## Don't want to use $log.Count here because it seems to be implemented inconsistently in the Get-Eventlog cmdlet,
  147.     ## e.g. sometimes it is null when it should be zero, and vice versa, and still other times it throws an exception
  148.     ## for no matches found.
  149.  
  150.     $emailBody += "<strong>Application Log Errors Last 24hrs: </strong>"
  151.     Try
  152.     {
  153.         $appLogErrors = Get-EventLog -Log Application -EntryType Error -After $(Get-Date).AddHours(-24) -ComputerName $($_.CN)
  154.         if($appLogErrors -eq $null)
  155.         {
  156.             $emailBody += "0<BR/>"
  157.         }
  158.         else
  159.         {
  160.             ## This technique doesn't work if $log is null. $counter goes to 1 when it should stay at 0.
  161.             $counter = 0
  162.             $appLogErrors | ForEach-Object { $counter++ }
  163.             $emailBody += "$counter<BR/>"
  164.         }
  165.     }
  166.     Catch
  167.     {
  168.         $emailBody += "<FONT STYLE=`"color:red;`"><strong>$($_.Exception.Message.ToString())</strong></FONT><BR/>"
  169.     }
  170.    
  171.     $emailBody += "<strong>System Log Errors Last 24hrs: </strong>"
  172.     Try
  173.     {
  174.         $sysLogErrors = Get-EventLog -Log System -EntryType Error -After $(Get-Date).AddHours(-24) -ComputerName $($_.CN)
  175.         if($sysLogErrors -eq $null)
  176.         {
  177.             $emailBody += "0<BR/>"
  178.         }
  179.         else
  180.         {
  181.             $counter = 0
  182.             $sysLogErrors | ForEach-Object { $counter++ }
  183.             $emailBody += "$counter<BR/>"
  184.         }
  185.  
  186.     }
  187.     Catch
  188.     {
  189.         $emailBody += "<FONT STYLE=`"color:red;`"><strong>$($_.Exception.Message.ToString())</strong></FONT><BR/>"
  190.     }
  191.    
  192.     $emailBody += "<strong>Security Audit Failures Last 24hrs: </strong>"
  193.     Try
  194.     {
  195.         $secLogErrors = Get-EventLog -Log Security -EntryType FailureAudit -After $(Get-Date).AddHours(-24) -ComputerName $($_.CN)
  196.         if($secLogErrors -eq $null)
  197.         {
  198.             $emailBody += "0<BR/>"
  199.         }
  200.         else
  201.         {
  202.             $counter = 0
  203.             $secLogErrors | ForEach-Object { $counter++ }
  204.             $emailBody += "$counter<BR/>"
  205.         }
  206.  
  207.     }
  208.     Catch
  209.     {
  210.         $emailBody += "<FONT STYLE=`"color:red;`"><strong>$($_.Exception.Message.ToString())</strong></FONT><BR/>"
  211.     }
  212.  
  213.     $emailBody += "<strong>Total RAM: </strong>$([math]::Round($computerSystem.TotalPhysicalMemory/1GB,0)) GB <BR/>"
  214.     $emailBody += "<strong>Logical Disks:</strong>"
  215.     $emailBody += "<div style=`"border-width:1px;border-style:dashed;margin:8px;padding:8px;background-color:`#dddddd`">"
  216.     $computer = $($_.CN)
  217.     ForEach($_ in $(Get-WMIObject -Query "SELECT DeviceID FROM Win32_Logicaldisk WHERE DriveType=3" -Computer $computer | ForEach { $_.DeviceID }))
  218.     {
  219.         $logicalDisk = Get-WMIObject -Query "SELECT * FROM Win32_Logicaldisk WHERE DeviceID='$_'" -Computer $computer
  220.         $freespace = [math]::Round($logicalDisk.FreeSpace/1GB,0)
  221.         $totalSize = [math]::Round($logicalDisk.Size/1GB,0)
  222.         if((($freespace/$totalSize)*100) -lt $diskFreePercentThreshold)
  223.         {
  224.             $emailBody += "<strong><FONT STYLE=`"color:red;`">$($logicalDisk.DeviceID) ($($logicalDisk.VolumeName)) $freespace GB free out of $totalSize GB </FONT></strong><BR/>"
  225.         }
  226.         else
  227.         {
  228.             $emailBody += "$($logicalDisk.DeviceID) ($($logicalDisk.VolumeName)) $freespace GB free out of $totalSize GB <BR/>"
  229.         }  
  230.     }
  231.     $emailBody += "</DIV>"
  232.     $emailBody += "</FONT></DIV><BR/><BR/>"
  233. }
  234.  
  235. $emailBody += "</FONT>"
  236. $emailBody += "<FONT STYLE=`"font-size:9px;`">* SSI = Windows System Stability Index. Configure WMI Reliability Providers across your domain via Group Policy and ensure that the RAC scheduled task is running on the machines in order to gather this data.<BR/>"
  237. $emailBody += "* The Remote Registry service must be running on remote computers in order to gather event log data."
  238. $emailBody += "</FONT>"
  239.  
  240. Send-MailMessage -From "$senderName <$senderAddr>" -To "$recptName <$recptAddr>" -Subject "$emailSubject" -Body $emailBody -SMTPServer $smtpServer -BodyAsHTML
Advertisement
Add Comment
Please, Sign In to add comment