Dargslan.WinADTools.psm1
|
<# .SYNOPSIS Active Directory query toolkit — user search, group membership, OU browser, password expiry reporting, and stale object detection .DESCRIPTION Part of the Dargslan Windows Admin Toolkit collection. More tools and resources at https://dargslan.com Free Cheat Sheets: https://dargslan.com/cheat-sheets .LINK https://dargslan.com .LINK https://github.com/Dargslan/powershell-admin-scripts #> function Get-ADHealthReport { <# .SYNOPSIS Quick Active Directory environment health check .DESCRIPTION Reports domain controller status, replication health, user statistics, and identifies stale objects. Part of Dargslan.WinADTools — https://dargslan.com #> [CmdletBinding()] param([int]$StaleDays = 90, [switch]$Json) Import-Module ActiveDirectory -ErrorAction SilentlyContinue if (-not (Get-Module ActiveDirectory -ErrorAction SilentlyContinue)) { Write-Warning "ActiveDirectory module not available. Install RSAT or run on a DC."; return } $domain = Get-ADDomain $report = [ordered]@{ Domain = [PSCustomObject]@{ Name = $domain.DNSRoot; NetBIOS = $domain.NetBIOSName; Forest = $domain.Forest; FunctionalLevel = $domain.DomainMode; PDCEmulator = $domain.PDCEmulator; InfrastructureMaster = $domain.InfrastructureMaster } DomainControllers = Get-ADDomainController -Filter * | Select-Object Name, IPv4Address, Site, OperatingSystem, IsGlobalCatalog, IsReadOnly, Enabled UserStats = [PSCustomObject]@{ TotalUsers = (Get-ADUser -Filter * | Measure-Object).Count EnabledUsers = (Get-ADUser -Filter {Enabled -eq $true} | Measure-Object).Count DisabledUsers = (Get-ADUser -Filter {Enabled -eq $false} | Measure-Object).Count LockedOut = (Search-ADAccount -LockedOut | Measure-Object).Count PasswordExpired = (Search-ADAccount -PasswordExpired | Measure-Object).Count NeverExpires = (Search-ADAccount -PasswordNeverExpires | Measure-Object).Count StaleUsers = (Get-ADUser -Filter {Enabled -eq $true} -Properties LastLogonDate | Where-Object { $_.LastLogonDate -and $_.LastLogonDate -lt (Get-Date).AddDays(-$StaleDays) } | Measure-Object).Count } GroupStats = [PSCustomObject]@{ TotalGroups = (Get-ADGroup -Filter * | Measure-Object).Count EmptyGroups = (Get-ADGroup -Filter * | Where-Object { (Get-ADGroupMember $_ -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0 } | Measure-Object).Count } Replication = Get-ADReplicationPartnerMetadata -Target $domain.DNSRoot -ErrorAction SilentlyContinue | Select-Object Server, Partner, LastReplicationAttempt, LastReplicationSuccess, ConsecutiveReplicationFailures } if ($Json) { return $report | ConvertTo-Json -Depth 3 } Write-Host "`n [AD Health Report: $($report.Domain.Name)]" -ForegroundColor Cyan $report.Domain | Format-List $report.UserStats | Format-List $report.DomainControllers | Format-Table Name, IPv4Address, Site, IsGlobalCatalog -AutoSize return $report } Export-ModuleMember -Function * |