migrate
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# Script to validate an Active Directory Domain Controller's operational status
|
||||
# Requires: ActiveDirectory PowerShell module and Domain Admin / Account Operator privileges
|
||||
|
||||
# Ensure AD Module is available
|
||||
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
|
||||
Write-Error "The ActiveDirectory module is required to run this script. Please install RSAT."
|
||||
exit
|
||||
}
|
||||
|
||||
# Set the target domain controller name
|
||||
$DCName = Read-Host "Enter the Domain Controller Name (FQDN or Hostname)"
|
||||
|
||||
try {
|
||||
# Check if the DC is online and retrievable
|
||||
Write-Host "Verifying Domain Controller existence..." -ForegroundColor Cyan
|
||||
$DC = Get-ADDomainController -Identity $DCName -ErrorAction Stop
|
||||
Write-Host "Domain Controller '$DCName' found online." -ForegroundColor Green
|
||||
|
||||
---
|
||||
|
||||
# Test Critical Services (Replaces the invalid Test-ComputerSecureChannel logic)
|
||||
Write-Host "`nChecking Critical AD Services..." -ForegroundColor Cyan
|
||||
$CriticalServices = @("NTDS", "Netlogon", "SamSs", "W32Time", "DNS")
|
||||
try {
|
||||
$Services = Get-Service -ComputerName $DCName -Name $CriticalServices -ErrorAction Stop
|
||||
foreach ($Service in $Services) {
|
||||
if ($Service.Status -eq "Running") {
|
||||
Write-Host " Service $($Service.Name) is Running." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Warning " Service $($Service.Name) is $($Service.Status)!"
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Failed to query services on '$DCName'. Check RPC/firewall settings."
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
# Check DNS Registration
|
||||
Write-Host "`nChecking DNS Registration..." -ForegroundColor Cyan
|
||||
try {
|
||||
$Test = Resolve-DnsName -Name $DC.ForceLogonDC -ErrorAction Stop
|
||||
if ($Test) {
|
||||
Write-Host "DNS registration is OK." -ForegroundColor Green
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "DNS resolution failed for '$DCName'."
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
# Check Replication Status
|
||||
Write-Host "`nChecking Replication Status..." -ForegroundColor Cyan
|
||||
try {
|
||||
$ReplicationStatuses = Get-ADReplicationStatus -DomainController $DCName -ErrorAction Stop
|
||||
$ReplFailures = 0
|
||||
|
||||
foreach ($Status in $ReplicationStatuses) {
|
||||
# 0 indicates success in AD replication cycles
|
||||
if ($Status.LastReplicationSuccess -eq 0 -or $Status.LastAttemptResult -eq "Success") {
|
||||
continue
|
||||
} else {
|
||||
Write-Warning " Replication Link Failed: Partner ($($Status.Partner)) -> Result: $($Status.LastAttemptResult)"
|
||||
$ReplFailures++
|
||||
}
|
||||
}
|
||||
|
||||
if ($ReplFailures -eq 0) {
|
||||
Write-Host "All replication links are healthy." -ForegroundColor Green
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Failed to check replication status. Ensure you have proper replication viewing permissions."
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
# Check Directory Services Event Logs for Errors
|
||||
Write-Host "`nChecking Directory Services Event Logs (Last 10 Errors)..." -ForegroundColor Cyan
|
||||
try {
|
||||
# Changed to 'Directory Service' log as it is far more relevant to DC health than 'Application'
|
||||
$ErrorEvents = Get-WinEvent -ComputerName $DCName -LogName "Directory Service" -MaxEvents 10 -FilterHashtable @{Level=2} -ErrorAction SilentlyContinue
|
||||
if ($ErrorEvents) {
|
||||
Write-Warning "Found Error Events in Directory Service Log:"
|
||||
foreach ($Event in $ErrorEvents) {
|
||||
Write-Host " Time: $($Event.TimeCreated)"
|
||||
Write-Host " ID: $($Event.Id)"
|
||||
Write-Host " Description: $($Event.Message.Substring(0, [Math]::Min(100, $Event.Message.Length)))..."
|
||||
}
|
||||
} else {
|
||||
Write-Host "No recent error events found in Directory Service log." -ForegroundColor Green
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Could not read Event Logs from '$DCName'."
|
||||
}
|
||||
|
||||
Write-Host "`n========================================="
|
||||
Write-Host "Health check completed for '$DCName'." -ForegroundColor Cyan
|
||||
|
||||
} catch {
|
||||
Write-Error "A critical error occurred: $($_.Exception.Message)"
|
||||
}
|
||||
@@ -0,0 +1,660 @@
|
||||
<#
|
||||
|
||||
.NOTES
|
||||
The script correctly performs these AD health checks:
|
||||
DNS resolution and ping connectivity
|
||||
Service status (DNS, NTDS, NetLogon)
|
||||
Disk space monitoring with color-coded alerts
|
||||
Time synchronization validation
|
||||
Comprehensive DCDiag tests (21 different tests)
|
||||
FSMO role identification
|
||||
Uptime monitoring
|
||||
The HTML report output is well-formatted with color coding for pass/warn/fail status. The script is production-ready for AD health monitoring.
|
||||
|
||||
This script is completely safe for production AD environments. It performs only read-only operations and will not cause any disruption.
|
||||
|
||||
Here's what the script does (all non-disruptive):
|
||||
|
||||
Read-Only Operations:
|
||||
DNS lookups (Resolve-DnsName)
|
||||
Network connectivity tests (Test-Connection)
|
||||
Service status queries (Get-Service)
|
||||
System information queries (Get-CimInstance)
|
||||
Time synchronization checks (w32tm /stripchart)
|
||||
DCDiag diagnostic tests (designed for production use)
|
||||
|
||||
No Changes Made:
|
||||
❌ No service restarts
|
||||
❌ No configuration modifications
|
||||
❌ No AD object changes
|
||||
❌ No registry modifications
|
||||
|
||||
Minimal Impact:
|
||||
Light network traffic from connectivity tests
|
||||
Standard WMI queries (same as monitoring tools)
|
||||
DCDiag tests are Microsoft's official diagnostic tools used regularly in production
|
||||
|
||||
Best Practices for Production:
|
||||
Run during business hours (generates useful real-time health data)
|
||||
Consider running from a management workstation rather than a DC
|
||||
The script includes progress indicators so you can monitor execution
|
||||
|
||||
This type of health check script is commonly run by AD administrators as part of routine maintenance and monitoring.
|
||||
Microsoft's DCDiag tool (which this script uses) is specifically designed for production diagnostics.
|
||||
|
||||
.SYNOPSIS
|
||||
Get-ADHealth.ps1 - Domain Controller Health Check Script.
|
||||
|
||||
.DESCRIPTION
|
||||
This script performs a list of common health checks to a specific domain, or the entire forest. The results are then compiled into a colour coded HTML report.
|
||||
|
||||
.OUTPUTS
|
||||
The results are currently only output to HTML for email or as an HTML report file, or sent as an SMTP message with an HTML body.
|
||||
|
||||
.PARAMETER DomainName
|
||||
Perform a health check on a specific Active Directory domain.
|
||||
|
||||
.PARAMETER ReportFile
|
||||
Output the report details to a file in the current directory.
|
||||
|
||||
.PARAMETER SendEmail
|
||||
Send the report via email. You have to configure the correct SMTP settings.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADHealth.ps1 -ReportFile
|
||||
Checks all domains and all domain controllers in your current forest and creates a report.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADHealth.ps1 -DomainName alitajran.com -ReportFile
|
||||
Checks all the domain controllers in the specified domain "alitajran.com" and creates a report.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADHealth.ps1 -DomainName alitajran.com -SendEmail
|
||||
Checks all the domain controllers in the specified domain "alitajran.com" and sends the resulting report as an email message.
|
||||
|
||||
.LINK
|
||||
alitajran.com/active-directory-health-check-powershell-script
|
||||
|
||||
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter( Mandatory = $false)]
|
||||
[string]$DomainName,
|
||||
|
||||
[Parameter( Mandatory = $false)]
|
||||
[switch]$ReportFile,
|
||||
|
||||
[Parameter( Mandatory = $false)]
|
||||
[switch]$SendEmail
|
||||
)
|
||||
|
||||
#...................................
|
||||
# Global Variables
|
||||
#...................................
|
||||
|
||||
$allTestedDomainControllers = [System.Collections.Generic.List[Object]]::new()
|
||||
$allDomainControllers = [System.Collections.Generic.List[Object]]::new()
|
||||
$now = Get-Date
|
||||
$date = $now.ToShortDateString()
|
||||
$reportTime = $now
|
||||
$reportFileNameTime = $now.ToString("yyyyMMdd_HHmmss")
|
||||
$reportemailsubject = "Domain Controller Health Report"
|
||||
|
||||
$smtpsettings = @{
|
||||
To = 'email@domain.com'
|
||||
From = 'adhealth@yourdomain.com'
|
||||
Subject = "$reportemailsubject - $date"
|
||||
SmtpServer = "mail.domain.com"
|
||||
Port = "25"
|
||||
#Credential = (Get-Credential)
|
||||
#UseSsl = $true
|
||||
}
|
||||
|
||||
#...................................
|
||||
# Functions
|
||||
#...................................
|
||||
|
||||
# This function gets all the domains in the forest.
|
||||
Function Get-AllDomains() {
|
||||
Write-Verbose "Running function Get-AllDomains"
|
||||
$allDomains = (Get-ADForest).Domains
|
||||
return $allDomains
|
||||
}
|
||||
|
||||
# This function gets all the domain controllers in a specified domain.
|
||||
Function Get-AllDomainControllers ($ComputerName) {
|
||||
Write-Verbose "Running function Get-AllDomainControllers"
|
||||
$allDomainControllers = Get-ADDomainController -Filter * -Server $ComputerName | Sort-Object HostName
|
||||
return $allDomainControllers
|
||||
}
|
||||
|
||||
# This function tests the domain controller against DNS.
|
||||
Function Get-DomainControllerNSLookup($ComputerName) {
|
||||
Write-Verbose "Running function Get-DomainControllerNSLookup"
|
||||
try {
|
||||
$domainControllerNSLookupResult = Resolve-DnsName $ComputerName -Type A | Select-Object -ExpandProperty IPAddress
|
||||
if ($domainControllerNSLookupResult) {
|
||||
$domainControllerNSLookupResult = 'Success'
|
||||
} else {
|
||||
$domainControllerNSLookupResult = 'Fail'
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$domainControllerNSLookupResult = 'Fail'
|
||||
}
|
||||
return $domainControllerNSLookupResult
|
||||
}
|
||||
|
||||
# This function tests the connectivity to the domain controller.
|
||||
Function Get-DomainControllerPingStatus($ComputerName) {
|
||||
Write-Verbose "Running function Get-DomainControllerPingStatus"
|
||||
if ((Test-Connection $ComputerName -Count 1 -quiet) -eq $True) {
|
||||
$domainControllerPingStatus = "Success"
|
||||
}
|
||||
else {
|
||||
$domainControllerPingStatus = 'Fail'
|
||||
}
|
||||
return $domainControllerPingStatus
|
||||
}
|
||||
|
||||
# This function tests the domain controller uptime.
|
||||
Function Get-DomainControllerUpTime($ComputerName) {
|
||||
Write-Verbose "Running function Get-DomainControllerUpTime"
|
||||
if ((Test-Connection $ComputerName -Count 1 -Quiet) -eq $True) {
|
||||
try {
|
||||
$W32OS = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction SilentlyContinue
|
||||
$timespan = (Get-Date) - $W32OS.LastBootUpTime
|
||||
[int]$uptime = "{0:00}" -f $timespan.TotalHours
|
||||
}
|
||||
catch {
|
||||
$uptime = 'CIM Failure'
|
||||
}
|
||||
}
|
||||
else {
|
||||
$uptime = 'Fail'
|
||||
}
|
||||
return $uptime
|
||||
}
|
||||
|
||||
# This function checks the time synchronization offset.
|
||||
function Get-TimeDifference($ComputerName) {
|
||||
Write-Verbose "Running function Get-TimeDifference"
|
||||
if ((Test-Connection $ComputerName -Count 1 -Quiet) -eq $True) {
|
||||
try {
|
||||
$currentTime, $timeDifference = (& w32tm /stripchart /computer:$ComputerName /samples:1 /dataonly)[-1].Trim("s") -split ',\s*'
|
||||
$diff = [double]$timeDifference
|
||||
$diffRounded = [Math]::Round($diff, 1, [MidPointRounding]::AwayFromZero)
|
||||
}
|
||||
catch {
|
||||
$diffRounded = 'Fail'
|
||||
}
|
||||
}
|
||||
else {
|
||||
$diffRounded = 'Fail'
|
||||
}
|
||||
return $diffRounded
|
||||
}
|
||||
|
||||
# This function checks the DNS, NTDS and Netlogon services.
|
||||
Function Get-DomainControllerServices($ComputerName) {
|
||||
Write-Verbose "Running function DomainControllerServices"
|
||||
$thisDomainControllerServicesTestResult = [PSCustomObject]@{
|
||||
DNSService = $null
|
||||
NTDSService = $null
|
||||
NETLOGONService = $null
|
||||
}
|
||||
|
||||
if ((Test-Connection $ComputerName -Count 1 -quiet) -eq $True) {
|
||||
if ((Get-Service -ComputerName $ComputerName -Name DNS -ErrorAction SilentlyContinue).Status -eq 'Running') {
|
||||
$thisDomainControllerServicesTestResult.DNSService = 'Success'
|
||||
}
|
||||
else {
|
||||
$thisDomainControllerServicesTestResult.DNSService = 'Fail'
|
||||
}
|
||||
if ((Get-Service -ComputerName $ComputerName -Name NTDS -ErrorAction SilentlyContinue).Status -eq 'Running') {
|
||||
$thisDomainControllerServicesTestResult.NTDSService = 'Success'
|
||||
}
|
||||
else {
|
||||
$thisDomainControllerServicesTestResult.NTDSService = 'Fail'
|
||||
}
|
||||
if ((Get-Service -ComputerName $ComputerName -Name netlogon -ErrorAction SilentlyContinue).Status -eq 'Running') {
|
||||
$thisDomainControllerServicesTestResult.NETLOGONService = 'Success'
|
||||
}
|
||||
else {
|
||||
$thisDomainControllerServicesTestResult.NETLOGONService = 'Fail'
|
||||
}
|
||||
}
|
||||
else {
|
||||
$thisDomainControllerServicesTestResult.DNSService = 'Fail'
|
||||
$thisDomainControllerServicesTestResult.NTDSService = 'Fail'
|
||||
$thisDomainControllerServicesTestResult.NETLOGONService = 'Fail'
|
||||
}
|
||||
return $thisDomainControllerServicesTestResult
|
||||
}
|
||||
|
||||
# This function runs the DCDiag tests and saves them in a variable for later processing.
|
||||
Function Get-DomainControllerDCDiagTestResults($ComputerName) {
|
||||
Write-Verbose "Running function Get-DomainControllerDCDiagTestResults"
|
||||
|
||||
# Initialize the object with all properties set to null
|
||||
$DCDiagTestResults = [PSCustomObject]@{
|
||||
ServerName = $ComputerName
|
||||
Connectivity = $null
|
||||
Advertising = $null
|
||||
FrsEvent = $null
|
||||
DFSREvent = $null
|
||||
SysVolCheck = $null
|
||||
KccEvent = $null
|
||||
KnowsOfRoleHolders = $null
|
||||
MachineAccount = $null
|
||||
NCSecDesc = $null
|
||||
NetLogons = $null
|
||||
ObjectsReplicated = $null
|
||||
Replications = $null
|
||||
RidManager = $null
|
||||
Services = $null
|
||||
SystemLog = $null
|
||||
VerifyReferences = $null
|
||||
CheckSDRefDom = $null
|
||||
CrossRefValidation = $null
|
||||
LocatorCheck = $null
|
||||
Intersite = $null
|
||||
FSMOCheck = $null
|
||||
}
|
||||
|
||||
if ((Test-Connection $ComputerName -Count 1 -quiet) -eq $True) {
|
||||
# Define an array of parameters for Dcdiag.exe
|
||||
$params = @(
|
||||
"/s:$ComputerName",
|
||||
"/test:Connectivity",
|
||||
"/test:Advertising",
|
||||
"/test:FrsEvent",
|
||||
"/test:DFSREvent",
|
||||
"/test:SysVolCheck",
|
||||
"/test:KccEvent",
|
||||
"/test:KnowsOfRoleHolders",
|
||||
"/test:MachineAccount",
|
||||
"/test:NCSecDesc",
|
||||
"/test:NetLogons",
|
||||
"/test:ObjectsReplicated",
|
||||
"/test:Replications",
|
||||
"/test:RidManager",
|
||||
"/test:Services",
|
||||
"/test:SystemLog",
|
||||
"/test:VerifyReferences",
|
||||
"/test:CheckSDRefDom",
|
||||
"/test:CrossRefValidation",
|
||||
"/test:LocatorCheck",
|
||||
"/test:Intersite",
|
||||
"/test:FSMOCheck"
|
||||
)
|
||||
|
||||
$DCDiagTest = (Dcdiag.exe @params) -split ('[\r\n]')
|
||||
|
||||
$TestName = $null
|
||||
$TestStatus = $null
|
||||
|
||||
$DCDiagTest | ForEach-Object {
|
||||
switch -Regex ($_) {
|
||||
"Starting test:" {
|
||||
$TestName = ($_ -replace ".*Starting test:").Trim()
|
||||
}
|
||||
"passed test|failed test" {
|
||||
$TestStatus = if ($_ -match "passed test") { "Passed" } else { "Failed" }
|
||||
}
|
||||
}
|
||||
if ($TestName -and $TestStatus) {
|
||||
# Set the property value directly
|
||||
$DCDiagTestResults.$TestName = $TestStatus
|
||||
$TestName = $null
|
||||
$TestStatus = $null
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# If the domain controller is not reachable, set all tests to 'Failed'
|
||||
foreach ($property in $DCDiagTestResults.PSObject.Properties.Name) {
|
||||
if ($property -ne "ServerName") {
|
||||
$DCDiagTestResults.$property = "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
return $DCDiagTestResults
|
||||
}
|
||||
|
||||
# This function checks the free space in percentage on the OS drive
|
||||
Function Get-DomainControllerOSDriveFreeSpace ($ComputerName) {
|
||||
Write-Verbose "Running function Get-DomainControllerOSDriveFreeSpace"
|
||||
if ((Test-Connection $ComputerName -Count 1 -Quiet) -eq $True) {
|
||||
try {
|
||||
$thisOSDriveLetter = (Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction Stop).SystemDrive
|
||||
$thisOSDiskDrive = Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $ComputerName -Filter "DeviceID='$thisOSDriveLetter'" -ErrorAction Stop
|
||||
$thisOSPercentFree = [math]::Round($thisOSDiskDrive.FreeSpace / $thisOSDiskDrive.Size * 100)
|
||||
}
|
||||
catch {
|
||||
$thisOSPercentFree = 'CIM Failure'
|
||||
}
|
||||
}
|
||||
else {
|
||||
$thisOSPercentFree = "Fail"
|
||||
}
|
||||
return $thisOSPercentFree
|
||||
}
|
||||
|
||||
# This function checks the free disk space on the OS drive in GB
|
||||
Function Get-DomainControllerOSDriveFreeSpaceGB ($ComputerName) {
|
||||
Write-Verbose "Running function Get-DomainControllerOSDriveFreeSpaceGB"
|
||||
if ((Test-Connection $ComputerName -Count 1 -Quiet) -eq $True) {
|
||||
try {
|
||||
$thisOSDriveLetter = (Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction Stop).SystemDrive
|
||||
$thisOSDiskDrive = Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $ComputerName -Filter "DeviceID='$thisOSDriveLetter'" -ErrorAction Stop
|
||||
# Convert bytes to GB, rounding to 2 decimal places
|
||||
$freeSpaceGB = [math]::Round($thisOSDiskDrive.FreeSpace / 1GB, 2)
|
||||
}
|
||||
catch {
|
||||
$freeSpaceGB = 'CIM Failure'
|
||||
}
|
||||
}
|
||||
else {
|
||||
$freeSpaceGB = 'Fail'
|
||||
}
|
||||
return $freeSpaceGB
|
||||
}
|
||||
|
||||
# This function generates HTML code from the results of the above functions.
|
||||
Function New-ServerHealthHTMLTableCell() {
|
||||
param( $lineitem )
|
||||
$htmltablecell = $null
|
||||
|
||||
switch ($($reportline."$lineitem")) {
|
||||
"Success" { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" }
|
||||
"Passed" { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" }
|
||||
"Pass" { $htmltablecell = "<td class=""pass"">$($reportline."$lineitem")</td>" }
|
||||
"Warn" { $htmltablecell = "<td class=""warn"">$($reportline."$lineitem")</td>" }
|
||||
"Fail" { $htmltablecell = "<td class=""fail"">$($reportline."$lineitem")</td>" }
|
||||
"Failed" { $htmltablecell = "<td class=""fail"">$($reportline."$lineitem")</td>" }
|
||||
"Could not test server uptime." { $htmltablecell = "<td class=""fail"">$($reportline."$lineitem")</td>" }
|
||||
default { $htmltablecell = "<td>$($reportline."$lineitem")</td>" }
|
||||
}
|
||||
return $htmltablecell
|
||||
}
|
||||
|
||||
if (!($DomainName)) {
|
||||
Write-Host "No domain specified, using all domains in forest" -ForegroundColor Yellow
|
||||
try {
|
||||
$allDomains = Get-AllDomains
|
||||
$reportFileName = 'forest_health_report_' + (Get-ADForest).name + '_' + $reportFileNameTime + '.html'
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to query AD Forest: $_"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "Domain name specified on cmdline" -ForegroundColor Cyan
|
||||
$allDomains = $DomainName
|
||||
$reportFileName = 'dc_health_report_' + $DomainName + '_' + $reportFileNameTime + '.html'
|
||||
}
|
||||
|
||||
foreach ($domain in $allDomains) {
|
||||
Write-Host "Testing domain" $domain -ForegroundColor Green
|
||||
$allDomainControllers = Get-AllDomainControllers $domain
|
||||
|
||||
# Force array first, then get count
|
||||
$allDomainControllers = @($allDomainControllers)
|
||||
$totalDCs = $allDomainControllers.Count
|
||||
|
||||
# Initialize counter for display
|
||||
$currentDCNumber = 0
|
||||
|
||||
foreach ($domainController in $allDomainControllers) {
|
||||
$currentDCNumber++
|
||||
$stopWatch = [system.diagnostics.stopwatch]::StartNew()
|
||||
Write-Host "Testing domain controller ($currentDCNumber of $totalDCs) $($domainController.HostName)" -ForegroundColor Cyan
|
||||
$DCDiagTestResults = Get-DomainControllerDCDiagTestResults $domainController.HostName
|
||||
|
||||
$thisDomainController = [PSCustomObject]@{
|
||||
Server = ($domainController.HostName).ToLower()
|
||||
Site = $domainController.Site
|
||||
"OS Version" = $domainController.OperatingSystem
|
||||
"IPv4 Address" = $domainController.IPv4Address
|
||||
"Operation Master Roles" = $domainController.OperationMasterRoles
|
||||
"DNS" = Get-DomainControllerNSLookup $domainController.HostName
|
||||
"Ping" = Get-DomainControllerPingStatus $domainController.HostName
|
||||
"Uptime (hours)" = Get-DomainControllerUpTime $domainController.HostName
|
||||
"OS Free Space (%)" = Get-DomainControllerOSDriveFreeSpace $domainController.HostName
|
||||
"OS Free Space (GB)" = Get-DomainControllerOSDriveFreeSpaceGB $domainController.HostName
|
||||
"Time offset (seconds)" = Get-TimeDifference $domainController.HostName
|
||||
"DNS Service" = (Get-DomainControllerServices $domainController.HostName).DNSService
|
||||
"NTDS Service" = (Get-DomainControllerServices $domainController.HostName).NTDSService
|
||||
"NetLogon Service" = (Get-DomainControllerServices $domainController.HostName).NETLOGONService
|
||||
"DCDIAG: Connectivity" = $DCDiagTestResults.Connectivity
|
||||
"DCDIAG: Advertising" = $DCDiagTestResults.Advertising
|
||||
"DCDIAG: FrsEvent" = $DCDiagTestResults.FrsEvent
|
||||
"DCDIAG: DFSREvent" = $DCDiagTestResults.DFSREvent
|
||||
"DCDIAG: SysVolCheck" = $DCDiagTestResults.SysVolCheck
|
||||
"DCDIAG: KccEvent" = $DCDiagTestResults.KccEvent
|
||||
"DCDIAG: FSMO KnowsOfRoleHolders" = $DCDiagTestResults.KnowsOfRoleHolders
|
||||
"DCDIAG: MachineAccount" = $DCDiagTestResults.MachineAccount
|
||||
"DCDIAG: NCSecDesc" = $DCDiagTestResults.NCSecDesc
|
||||
"DCDIAG: NetLogons" = $DCDiagTestResults.NetLogons
|
||||
"DCDIAG: ObjectsReplicated" = $DCDiagTestResults.ObjectsReplicated
|
||||
"DCDIAG: Replications" = $DCDiagTestResults.Replications
|
||||
"DCDIAG: RidManager" = $DCDiagTestResults.RidManager
|
||||
"DCDIAG: Services" = $DCDiagTestResults.Services
|
||||
"DCDIAG: SystemLog" = $DCDiagTestResults.SystemLog
|
||||
"DCDIAG: VerifyReferences" = $DCDiagTestResults.VerifyReferences
|
||||
"DCDIAG: CheckSDRefDom" = $DCDiagTestResults.CheckSDRefDom
|
||||
"DCDIAG: CrossRefValidation" = $DCDiagTestResults.CrossRefValidation
|
||||
"DCDIAG: LocatorCheck" = $DCDiagTestResults.LocatorCheck
|
||||
"DCDIAG: Intersite" = $DCDiagTestResults.Intersite
|
||||
"DCDIAG: FSMO Check" = $DCDiagTestResults.FSMOCheck
|
||||
"Processing Time (seconds)" = $stopWatch.Elapsed.Seconds
|
||||
}
|
||||
|
||||
$allTestedDomainControllers.Add($thisDomainController)
|
||||
}
|
||||
}
|
||||
|
||||
# Common HTML head and styles
|
||||
$htmlhead = "<html>
|
||||
<style>
|
||||
BODY { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 10pt; }
|
||||
H1 { font-size: 20px; }
|
||||
H2 { font-size: 16px; }
|
||||
H3 { font-size: 14px; }
|
||||
TABLE { border: 1px solid #ccc; border-collapse: collapse; font-size: 10pt;}
|
||||
TH { border: 1px solid #ccc; background: #f2f2f2; padding: 10px; color: #000000;}
|
||||
TD { border: 1px solid #ccc; padding: 10px; }
|
||||
td.pass { background: #6BBF59;}
|
||||
td.warn { background: #FFD966;}
|
||||
td.fail { background: #D9534F; color: #ffffff;}
|
||||
td.info { background: #5BC0DE;}
|
||||
</style>
|
||||
<body>
|
||||
<h1 align=""left"">Domain Controller Health Check Report</h1>
|
||||
<h3 align=""left"">Generated: $reportTime </h3>"
|
||||
|
||||
# Domain Controller Health Report Table Header
|
||||
$htmltableheader = "<h3>Domain Controller Health Summary</h3>
|
||||
<h3>Forest: $((Get-ADForest).Name)</h3>
|
||||
<p>
|
||||
<table style=""width: 100%; border-collapse: separate; "">
|
||||
<tr>
|
||||
<th style=""text-align: center"">Server</th>
|
||||
<th style=""text-align: center; "">Site</th>
|
||||
<th style=""text-align: center; "">OS Version</th>
|
||||
<th style=""text-align: center; "">IPv4 Address</th>
|
||||
<th style=""text-align: center; "">Operation Master Roles</th>
|
||||
<th style=""text-align: center; "">DNS</th>
|
||||
<th style=""text-align: center; "">Ping</th>
|
||||
<th style=""text-align: center; "">Uptime (hours)</th>
|
||||
<th style=""text-align: center; "">OS Free Space (%)</th>
|
||||
<th style=""text-align: center; "">OS Free Space (GB)</th>
|
||||
<th style=""text-align: center; "">Time offset (seconds)</th>
|
||||
<th style=""text-align: center; "">DNS Service</th>
|
||||
<th style=""text-align: center; "">NTDS Service</th>
|
||||
<th style=""text-align: center; "">NetLogon Service</th>
|
||||
<th style=""text-align: center; "">DCDIAG: Connectivity</th>
|
||||
<th style=""text-align: center; "">DCDIAG: Advertising</th>
|
||||
<th style=""text-align: center; "">DCDIAG: FrsEvent</th>
|
||||
<th style=""text-align: center; "">DCDIAG: DFSREvent</th>
|
||||
<th style=""text-align: center; "">DCDIAG: SysVolCheck</th>
|
||||
<th style=""text-align: center; "">DCDIAG: KccEvent</th>
|
||||
<th style=""text-align: center; "">DCDIAG: FSMO KnowsOfRoleHolders</th>
|
||||
<th style=""text-align: center; "">DCDIAG: MachineAccount</th>
|
||||
<th style=""text-align: center; "">DCDIAG: NCSecDesc</th>
|
||||
<th style=""text-align: center; "">DCDIAG: NetLogons</th>
|
||||
<th style=""text-align: center; "">DCDIAG: ObjectsReplicated</th>
|
||||
<th style=""text-align: center; "">DCDIAG: Replications</th>
|
||||
<th style=""text-align: center; "">DCDIAG: RidManager</th>
|
||||
<th style=""text-align: center; "">DCDIAG: Services</th>
|
||||
<th style=""text-align: center; "">DCDIAG: SystemLog</th>
|
||||
<th style=""text-align: center; "">DCDIAG: VerifyReferences</th>
|
||||
<th style=""text-align: center; "">DCDIAG: CheckSDRefDom</th>
|
||||
<th style=""text-align: center; "">DCDIAG: CrossRefValidation</th>
|
||||
<th style=""text-align: center; "">DCDIAG: LocatorCheck</th>
|
||||
<th style=""text-align: center; "">DCDIAG: Intersite</th>
|
||||
<th style=""text-align: center; "">DCDIAG: FSMO Check</th>
|
||||
<th style=""text-align: center; "">Processing Time (seconds)</th>
|
||||
</tr>"
|
||||
|
||||
# Domain Controller Health Report Table
|
||||
$serverhealthhtmltable = $serverhealthhtmltable + $htmltableheader
|
||||
|
||||
# This section will process through the $allTestedDomainControllers array object and create and colour the HTML table based on certain conditions.
|
||||
foreach ($reportline in $allTestedDomainControllers) {
|
||||
|
||||
if (Test-Path variable:fsmoRoleHTML) {
|
||||
Remove-Variable fsmoRoleHTML
|
||||
}
|
||||
|
||||
if (($reportline."Operation Master Roles").Count -gt 0) {
|
||||
$fsmoRoleHTML = ($reportline."Operation Master Roles" | ForEach-Object { "$_`r`n" }) -join '<br>'
|
||||
}
|
||||
else {
|
||||
$fsmoRoleHTML = 'None<br>'
|
||||
}
|
||||
|
||||
$htmltablerow = "<tr>"
|
||||
$htmltablerow += "<td>$($reportline.Server)</td>"
|
||||
$htmltablerow += "<td>$($reportline.Site)</td>"
|
||||
$htmltablerow += "<td>$($reportline."OS Version")</td>"
|
||||
$htmltablerow += "<td>$($reportline."IPv4 Address")</td>"
|
||||
$htmltablerow += "<td>$fsmoRoleHTML</td>"
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DNS" )
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "Ping")
|
||||
|
||||
if ($($reportline."Uptime (hours)") -eq "CIM Failure") {
|
||||
$htmltablerow += "<td class=""warn"">Could not test server uptime.</td>"
|
||||
}
|
||||
elseif ($($reportline."Uptime (hours)") -eq "Fail") {
|
||||
$htmltablerow += "<td class=""fail"">Fail</td>"
|
||||
}
|
||||
else {
|
||||
$hours = [int]$($reportline."Uptime (hours)")
|
||||
if ($hours -le 24) {
|
||||
$htmltablerow += "<td class=""warn"">$hours</td>"
|
||||
}
|
||||
else {
|
||||
$htmltablerow += "<td class=""pass"">$hours</td>"
|
||||
}
|
||||
}
|
||||
|
||||
$osSpace = $reportline."OS Free Space (%)"
|
||||
if ($osSpace -eq "CIM Failure") {
|
||||
$htmltablerow += "<td class=""warn"">Could not test server free space.</td>"
|
||||
}
|
||||
elseif ($osSpace -eq "Fail") {
|
||||
$htmltablerow += "<td class=""fail"">$osSpace</td>"
|
||||
}
|
||||
elseif ($osSpace -le 5) {
|
||||
$htmltablerow += "<td class=""fail"">$osSpace</td>"
|
||||
}
|
||||
elseif ($osSpace -le 30) {
|
||||
$htmltablerow += "<td class=""warn"">$osSpace</td>"
|
||||
}
|
||||
else {
|
||||
$htmltablerow += "<td class=""pass"">$osSpace</td>"
|
||||
}
|
||||
|
||||
$osSpaceGB = $reportline."OS Free Space (GB)"
|
||||
if ($osSpaceGB -eq "CIM Failure") {
|
||||
$htmltablerow += "<td class=""warn"">Could not test server free space.</td>"
|
||||
}
|
||||
elseif ($osSpaceGB -eq "Fail") {
|
||||
$htmltablerow += "<td class=""fail"">$osSpaceGB</td>"
|
||||
}
|
||||
elseif ($osSpaceGB -lt 5) {
|
||||
$htmltablerow += "<td class=""fail"">$osSpaceGB</td>"
|
||||
}
|
||||
elseif ($osSpaceGB -lt 10) {
|
||||
$htmltablerow += "<td class=""warn"">$osSpaceGB</td>"
|
||||
}
|
||||
else {
|
||||
$htmltablerow += "<td class=""pass"">$osSpaceGB</td>"
|
||||
}
|
||||
|
||||
$time = $reportline."Time offset (seconds)"
|
||||
if ($time -ge 1) {
|
||||
$htmltablerow += "<td class=""fail"">$time</td>"
|
||||
}
|
||||
else {
|
||||
$htmltablerow += "<td class=""pass"">$time</td>"
|
||||
}
|
||||
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DNS Service")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "NTDS Service")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "NetLogon Service")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Connectivity")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Advertising")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FrsEvent")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: DFSREvent")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: SysVolCheck")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: KccEvent")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FSMO KnowsOfRoleHolders")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: MachineAccount")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: NCSecDesc")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: NetLogons")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: ObjectsReplicated")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Replications")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: RidManager")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Services")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: SystemLog")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: VerifyReferences")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: CheckSDRefDom")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: CrossRefValidation")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: LocatorCheck")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: Intersite")
|
||||
$htmltablerow += (New-ServerHealthHTMLTableCell "DCDIAG: FSMO Check")
|
||||
|
||||
$processingTime = $reportline."Processing Time (seconds)"
|
||||
$htmltablerow += "<td>$processingTime</td>"
|
||||
|
||||
[array]$serverhealthhtmltable += $htmltablerow
|
||||
}
|
||||
|
||||
$serverhealthhtmltable += "</table></p>"
|
||||
$htmltail = "* DNS test is performed using Resolve-DnsName. This cmdlet is only available from Windows 2012 onwards.
|
||||
</body>
|
||||
</html>"
|
||||
|
||||
$htmlreport = $htmlhead + $serverhealthhtmltable + $htmltail
|
||||
|
||||
if ($ReportFile) {
|
||||
$htmlreport | Out-File $reportFileName -Encoding UTF8
|
||||
}
|
||||
|
||||
if ($SendEmail) {
|
||||
try {
|
||||
# Send email with both inline HTML and attachment
|
||||
$htmlreport | Out-File $reportFileName -Encoding UTF8
|
||||
Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Attachments $reportFileName -Encoding ([System.Text.Encoding]::UTF8) -ErrorAction Stop
|
||||
Write-Host "Email sent successfully." -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host "Failed to send email. Error: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Queries common user information from either Local Accounts or Active Directory.
|
||||
|
||||
.DESCRIPTION
|
||||
This script retrieves detailed information about user accounts.
|
||||
It can query local user accounts on the machine or Active Directory user accounts
|
||||
if the machine is domain-joined and the Active Directory module is available.
|
||||
|
||||
.PARAMETER UserName
|
||||
Specifies the username (SamAccountName for AD, or Name for Local) of the user
|
||||
to query. If omitted, all users based on the specified source will be listed.
|
||||
|
||||
.PARAMETER ActiveDirectory
|
||||
Use this switch to query Active Directory.
|
||||
Requires the 'ActiveDirectory' module to be installed and the machine to be
|
||||
connected to a domain. If not specified, local users are queried by default.
|
||||
|
||||
.PARAMETER IncludeGroups
|
||||
Use this switch to include group memberships for each user.
|
||||
This can take longer, especially for Active Directory.
|
||||
|
||||
.EXAMPLE
|
||||
.\GetUserInformation.ps1 -UserName "jdoe"
|
||||
|
||||
Queries information for the local user 'jdoe'.
|
||||
|
||||
.EXAMPLE
|
||||
.\GetUserInformation.ps1 -ActiveDirectory -UserName "s.smith"
|
||||
|
||||
Queries information for the Active Directory user 's.smith'.
|
||||
|
||||
.EXAMPLE
|
||||
.\GetUserInformation.ps1 -AllUsers -ActiveDirectory -IncludeGroups
|
||||
|
||||
Lists all Active Directory users with their group memberships.
|
||||
|
||||
.EXAMPLE
|
||||
.\GetUserInformation.ps1
|
||||
|
||||
Lists all local users on the machine.
|
||||
|
||||
.NOTES
|
||||
Author: ChatGPT (with improvements for clarity and robustness)
|
||||
Date: 2023-10-27
|
||||
Version: 1.1
|
||||
|
||||
For Active Directory queries:
|
||||
- Ensure you have the ActiveDirectory module installed (part of RSAT tools).
|
||||
- Your user account needs appropriate permissions to read AD objects.
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName='AllUsers')]
|
||||
param (
|
||||
[Parameter(ParameterSetName='SpecificUser', Position=0)]
|
||||
[string]$UserName,
|
||||
|
||||
[Parameter(ParameterSetName='AllUsers')]
|
||||
[switch]$AllUsers,
|
||||
|
||||
[Parameter()]
|
||||
[switch]$ActiveDirectory,
|
||||
|
||||
[Parameter()]
|
||||
[switch]$IncludeGroups
|
||||
)
|
||||
|
||||
function Get-LocalUserInformation {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[string]$TargetUsername
|
||||
)
|
||||
|
||||
Write-Host "Querying local user accounts..." -ForegroundColor Cyan
|
||||
|
||||
$users = @()
|
||||
try {
|
||||
if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey('TargetUsername')) {
|
||||
# Try to get a specific local user
|
||||
$user = Get-LocalUser -Name $TargetUsername -ErrorAction SilentlyContinue
|
||||
if ($user) {
|
||||
$users += $user
|
||||
} else {
|
||||
Write-Warning "Local user '$TargetUsername' not found."
|
||||
}
|
||||
} else {
|
||||
# Get all local users
|
||||
$users = Get-LocalUser -ErrorAction Stop
|
||||
}
|
||||
|
||||
if ($users.Count -eq 0) {
|
||||
Write-Warning "No local user accounts found matching the criteria."
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($user in $users) {
|
||||
$groups = @()
|
||||
if ($IncludeGroups) {
|
||||
try {
|
||||
# Get-LocalUser has a .Groups property in PS 5.1+
|
||||
# For older versions, one might have to iterate Get-LocalGroup and check members
|
||||
$userGroups = $user.Groups | Select-Object -ExpandProperty Name
|
||||
if ($userGroups) {
|
||||
$groups = $userGroups
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not retrieve groups for local user $($user.Name): $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
[PSCustomObject]@{
|
||||
Source = 'Local'
|
||||
Username = $user.Name
|
||||
FullName = $user.FullName
|
||||
Description = $user.Description
|
||||
Enabled = $user.Enabled
|
||||
LastLogon = 'N/A (Local)'
|
||||
EmailAddress = 'N/A (Local)'
|
||||
Department = 'N/A (Local)'
|
||||
Office = 'N/A (Local)'
|
||||
PhoneNumber = 'N/A (Local)'
|
||||
HomeDirectory = 'N/A (Local)'
|
||||
ProfilePath = 'N/A (Local)'
|
||||
Groups = if ($groups.Count -gt 0) { $groups -join ', ' } else { 'None' }
|
||||
SID = $user.SID.Value
|
||||
WhenCreated = $user.CreationTime
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "An error occurred while querying local users: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ADUserInformation {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[string]$TargetUsername
|
||||
)
|
||||
|
||||
Write-Host "Querying Active Directory user accounts..." -ForegroundColor Cyan
|
||||
|
||||
# Check if ActiveDirectory module is available
|
||||
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
|
||||
Write-Warning "The ActiveDirectory module is not installed or available."
|
||||
Write-Warning "Please install Remote Server Administration Tools (RSAT) for Active Directory Domain Services."
|
||||
Write-Warning "Cannot query Active Directory."
|
||||
return
|
||||
}
|
||||
|
||||
# Import the module if not already loaded in the current session
|
||||
if (-not (Get-Module -Name ActiveDirectory -ErrorAction SilentlyContinue)) {
|
||||
try {
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
Write-Host "ActiveDirectory module loaded successfully." -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to load ActiveDirectory module: $($_.Exception.Message)"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
$propertiesToLoad = @(
|
||||
"SamAccountName", "DisplayName", "GivenName", "Surname", "Description", "Enabled",
|
||||
"LastLogonTimestamp", "EmailAddress", "OfficePhone", "Department", "Office",
|
||||
"HomeDirectory", "ProfilePath", "SID", "WhenCreated", "PasswordLastSet"
|
||||
)
|
||||
|
||||
$adUsers = @()
|
||||
try {
|
||||
if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey('TargetUsername')) {
|
||||
# Try to get a specific AD user
|
||||
$user = Get-ADUser -Identity $TargetUsername -Properties $propertiesToLoad -ErrorAction SilentlyContinue
|
||||
if ($user) {
|
||||
$adUsers += $user
|
||||
} else {
|
||||
Write-Warning "Active Directory user '$TargetUsername' not found."
|
||||
}
|
||||
} else {
|
||||
# Get all AD users (excluding disabled or specific service accounts if desired, for now, all)
|
||||
$adUsers = Get-ADUser -Filter * -Properties $propertiesToLoad -ErrorAction Stop
|
||||
}
|
||||
|
||||
if ($adUsers.Count -eq 0) {
|
||||
Write-Warning "No Active Directory user accounts found matching the criteria."
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($adUser in $adUsers) {
|
||||
$groups = @()
|
||||
if ($IncludeGroups) {
|
||||
try {
|
||||
$userGroups = Get-ADPrincipalGroupMembership -Identity $adUser.SamAccountName | Select-Object -ExpandProperty Name
|
||||
if ($userGroups) {
|
||||
$groups = $userGroups
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not retrieve groups for AD user $($adUser.SamAccountName): $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# Convert LastLogonTimestamp from FileTime to DateTime
|
||||
$lastLogon = if ($adUser.LastLogonTimestamp) {
|
||||
[DateTime]::FromFileTime($adUser.LastLogonTimestamp)
|
||||
} else {
|
||||
"Not available" # Or "Never"
|
||||
}
|
||||
|
||||
[PSCustomObject]@{
|
||||
Source = 'Active Directory'
|
||||
Username = $adUser.SamAccountName
|
||||
FullName = $adUser.DisplayName
|
||||
Description = $adUser.Description
|
||||
Enabled = $adUser.Enabled
|
||||
LastLogon = $lastLogon
|
||||
EmailAddress = $adUser.EmailAddress
|
||||
Department = $adUser.Department
|
||||
Office = $adUser.Office
|
||||
PhoneNumber = $adUser.OfficePhone
|
||||
HomeDirectory = $adUser.HomeDirectory
|
||||
ProfilePath = $adUser.ProfilePath
|
||||
Groups = if ($groups.Count -gt 0) { $groups -join ', ' } else { 'None' }
|
||||
SID = $adUser.SID.Value
|
||||
WhenCreated = $adUser.WhenCreated
|
||||
PasswordLastSet = $adUser.PasswordLastSet
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "An error occurred while querying Active Directory users: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Main Script Logic ---
|
||||
if ($ActiveDirectory) {
|
||||
if ($UserName) {
|
||||
Get-ADUserInformation -TargetUsername $UserName
|
||||
}
|
||||
else {
|
||||
Get-ADUserInformation
|
||||
}
|
||||
} else {
|
||||
# Default to local users if -ActiveDirectory not specified
|
||||
if ($UserName) {
|
||||
Get-LocalUserInformation -TargetUsername $UserName
|
||||
}
|
||||
else {
|
||||
Get-LocalUserInformation
|
||||
}
|
||||
}
|
||||
|
||||
# How to Use the Script:
|
||||
#
|
||||
# Save: Copy the code above and save it in a file named GetUserInformation.ps1 (or any other .ps1 name) on your computer.
|
||||
#
|
||||
# Open PowerShell:
|
||||
# Right-click on the PowerShell icon and select "Run as administrator" (recommended for querying all local users, though usually not strictly necessary for just reading common info).
|
||||
# Navigate to the directory where you saved the script using cd C:\path\to\your\script.
|
||||
#
|
||||
# Execution Policy: If you haven't run PowerShell scripts before, you might need to adjust your execution policy. You can do this by running:
|
||||
#
|
||||
# Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
#
|
||||
# Confirm with Y when prompted. You can revert this later with Set-ExecutionPolicy Restricted -Scope CurrentUser.
|
||||
#
|
||||
# Run the Script:
|
||||
#
|
||||
# To list all Local Users:
|
||||
#
|
||||
# .\GetUserInformation.ps1
|
||||
#
|
||||
# To query a specific Local User (e.g., "Administrator"):
|
||||
#
|
||||
# .\GetUserInformation.ps1 -UserName "Administrator"
|
||||
#
|
||||
# To list all Active Directory Users (if domain-joined and AD module installed):
|
||||
#
|
||||
# .\GetUserInformation.ps1 -ActiveDirectory
|
||||
#
|
||||
# (Be aware this might list many users in a large domain.)
|
||||
#
|
||||
# To query a specific Active Directory User (e.g., "johndoe"):
|
||||
#
|
||||
# .\GetUserInformation.ps1 -ActiveDirectory -UserName "johndoe"
|
||||
#
|
||||
# To include Group Memberships (can be slower for many users):
|
||||
#
|
||||
# .\GetUserInformation.ps1 -ActiveDirectory -IncludeGroups -UserName "johndoe"
|
||||
#
|
||||
# or
|
||||
#
|
||||
# .\GetUserInformation.ps1 -IncludeGroups # For local users
|
||||
Reference in New Issue
Block a user