Functions/Test-ADDomainControllerDiagnostic.ps1
<# .SYNOPSIS Health test of Active Directory Domain Controllers by using the built-in and trusted "dcdiag.exe" command line tool. .DESCRIPTION This function uses Windows PowerShell Remoting to connect to all specified Active Directory Domain Controllers. Inside the session, dcdiag is executed with best practice parameter values. The result is then parsed into Windows PowerShell custom objects. .PARAMETER ComputerName The list of Domain Controllers to test. Aliases are defined to accept pipeline input from the result of the Active Directory built-in cmdlets. .PARAMETER Credential Optionally, provide credentials to create the PowerShell Remoting session. .INPUTS System.String. You can pipe an array of strings representing the computer names. .OUTPUTS ActiveDirectoryFever.DiagnosticResult. A collection of result objects. One object per test. .EXAMPLE C:\> Test-ADDomainControllerDiagnostic -ComputerName LON-DC1.contoso.com Run the diagnostic test against one Domain Controller. .EXAMPLE C:\> Test-ADDomainControllerDiagnostic -ComputerName LON-DC1.contoso.com -Credential (Get-Credential) Run the diagnostic test against one Domain Controller by using custom credentials. .EXAMPLE C:\> Test-ADDomainControllerDiagnostic -ComputerName LON-DC1, LON-DC2 | Where-Object { -not $_.Result } Run the diagnostic test against two Domain Controllers and filter failed tests. .EXAMPLE C:\> Get-ADDomainController | Test-ADDomainControllerDiagnostic Run the diagnostic test on the current enumerated Domain Controller. .EXAMPLE C:\> Get-ADDomain -Identity "corp.contoso.com" | Test-ADDomainControllerDiagnostic Run the diagnostic test on all writable and read-only Domain Controllers in the "corp.contoso.com" domain. .EXAMPLE C:\> Get-ADForest -Identity "contoso.com" | Test-ADDomainControllerDiagnostic Run the diagnostic test on all Global Catalog Domain Controllers in the "contoso.com" forest. .NOTES Author : Claudio Spizzi License : MIT License .LINK https://github.com/claudiospizzi/ActiveDirectoryFever #> function Test-ADDomainControllerDiagnostic { [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [Alias('HostName', 'DNSHostName', 'ReplicaDirectoryServers', 'GlobalCatalogs')] [String[]] $ComputerName, [Parameter(Mandatory=$false)] [PSCredential] $Credential = $null ) begin { $Jobs = @() # Define the alternate credentials hash table $CredentialParameter = @{} if($Credential -ne $null) { $CredentialParameter['Credential'] = $Credential } } process { # For each provided computer name, use it as target to start the dcdiag # command inside a remoting session and as a job. This allows parallel # executing of all dcdiag commands. foreach ($ComputerNameTarget in $ComputerName) { Write-Verbose -Message "Start Job to execute 'dcdiag.exe /v /c /Skip:OutboundSecureChannels' on $ComputerNameTarget with PowerShell Remoting..." $Jobs += Invoke-Command -ComputerName $ComputerNameTarget -ScriptBlock { Write-Output (dcdiag.exe /v /c /Skip:OutboundSecureChannels) } @CredentialParameter -AsJob -JobName $ComputerNameTarget } } end { Write-Verbose -Message 'Wait for all Jobs to complete.' # Wait for all jobs to complete $Jobs = $Jobs | Wait-Job # Iterate all child jobs (one child job per domain controller) foreach ($Job in $Jobs) { try { if ($Job.State -eq 'Completed') { # Fill name and domain with location $Name = $Job.Name.Split('.', 2)[0] $Domain = $(try { $Job.Name.Split('.', 2)[1] } catch { '' }) # Receive result (and error, if occured) $Result = $Job | Receive-Job -ErrorAction Stop # Iterating all lines for ($Line = 0; $Line -lt $Result.length; $Line++) { # Correct wrong line breaks if ($Result[$Line] -match '^\s{9}.{25} (\S+) (\S+) test$') { $Result[$Line] = $Result[$Line] + ' ' + $Result[$Line + 2].Trim() } # Verify test start line if ($Result[$Line] -match '^\s{6}Starting test: \S+$') { $LineStart = $Line } # Verify test end line if ($Result[$Line] -match '^\s{9}.{25} (\S+) (\S+) test (\S+)$') { # Create a custom result object with custom type $DiagnosticResult = New-Object -TypeName PSObject -Property @{ Name = $Name Domain = $Domain Target = $Matches[1] Test = $Matches[3] Result = $Matches[2] -eq 'passed' Data = $Result[$LineStart..$Line] -join [System.Environment]::NewLine } $DiagnosticResult.PSTypeNames.Insert(0, 'ActiveDirectoryFever.DiagnosticResult') Write-Output $DiagnosticResult } } } else { $Job | Receive-Job -ErrorAction Stop | Out-Null } } catch { Write-Error -Message "Failed to execute diagnistic test.`r`n$_" -Exception $_.Exception -TargetObject $Job.Location } } # Cleanup jobs $Job | Remove-Job -ErrorAction SilentlyContinue } } |