Issue in AD Diagnosis Report

Hi i am trying to generate AD Diagnosis using dcdiag and exporting to xml. but while taking the data from xml is where the problem lies. I am following don jones method of “create html reports in powershell book”. Please check the code below and help, in my script i cant get any output for Diagnosis Module. its blank while i can get out put services. Please help me.

Import-Module ActiveDirectory
############# Fucntion for creating log file if not exist ##############

$global:logPath = $null

$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path

function New-Log($dir,$file)
{
$logDirectory = $dir
$logFolder = Get-Date -Format dd_MMM_yyyy
$logFileDate = Get-Date -uFormat “%d%m%Y_%S”
$logFileName = “$file” + “_” + “$logFileDate” + “.log”
$logFolderPath = “$logDirectory” + "" + “LOG” + "" + “$logFolder”
$logFilePath = $logFolderPath + "" +$logFileName
$logPathExistence1 = Test-Path -Path $logFolderPath
$logPathExistence2 = Test-Path -Path $logFilePath
if (!$logPathExistence1)
{
$folderCreation = New-Item $logFolderPath -Type directory
}

if (!$logPathExistence2)
{
    $fileCreation = New-Item $logFilePath -Type file 
}

$global:logPath = $logFilePath  

}

###################### Function for writing logs ############################

There are 3 types of logs(0-Info, 1-Warning, 2-Error).

Based on the log type It will appaned Date, Type and Message to log.

#############################################################################

function Write-Log($message, $type)
{
if($Type -eq 0)
{
$Date = Get-Date
$Log = “[” + $Date + “]” + "[Info] " + $Message
$Log >> $global:logPath
}
elseif($Type -eq 1)
{
$Date = Get-Date
$Log = “[” + $Date + “]” + "[Warning] " + $Message
$Log >> $global:logPath
}
elseif($Type -eq 2)
{
$Date = Get-Date
$Log = “[” + $Date + “]” + "[Error] " + $Message
$Log >> $global:logPath
}
else
{
$Date = Get-Date
$Log = “[” + $Date + “]” + "[Others] " + $Message
$Log >> $global:logPath
}
}
Import-Module $ScriptDir\EnhancedHTML2.ps1
###################### Function for Creating ServiceCheck Output Folder ############################

function Create-Output($dir)
{
$directory = $dir
$folder = Get-Date -Format dd_MMM_yyyy
$outFolderPath = “$directory” + "" + “OUTPUT” + "" + “$folder”
$pathExistence = Test-Path -Path $outFolderPath
if (!$pathExistence)
{
$folderCreation = New-Item $outFolderPath -Type directory
}
$global:outFolderPath = $outFolderPath
}

New-Log “$ScriptDir” “AD_Health_Check”

Create-Output “$ScriptDir”

###################### Function for Reading the inputs from input.conf file ############################

if (Test-Path -Path “$ScriptDir\input.conf”){
Get-Content “$ScriptDir\input.conf” | foreach-object -begin {
$h=@{}
} -process {
$k = [regex]::split($_,‘=’);
if(($k[0].CompareTo(“”) -ne 0) -and ($k[0].StartsWith(“[”) -ne $True))
{
$h.Add($k[0], $k[1])
}
}

$ComputerList=$h.Servers.Split(“,”)
$ADService=$h.ServiceNames.Split(“,”)
$To=$h.To
$From=$h.From
$Subject=$h.Subject
$Signature=$h.Signature
$SMTPMail=$h.SMTPMailServer

}else{
Write-Log “Input.conf file not exits”
Exit
}

#CSS format for the report
$Style =@"

body{
color:#333333;
font-family:calibri,Tahoma;
font-size : 10pt;
}

h1{
text-align:center;
color:#1B4F72;
}

h2{
border-top:1px solid #666666;
color:#1B4F72;
}

th{
font-weight:bold;
color:#eeeeee;
background-color:#1B4F72;
cursor:pointer;
}

.odd {background-color:#ffffff;}

.even {background-color:#dddddd;}

.paginate_enabled_next, .paginate_enabled_previous
{
cursor:pointer;
border:1px solid #222222;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px
}

.paginate_disabled_previous, .paginate_disabled_previous
{
color:#666666;
cursor:pointer;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px
}

.dataTables_info {margin-bottom:4px;}

.sectionheader {cursor:pointer;}

.secrtionheader:hover {color:red;}

.grid {width:80%}

.red{
color:red;
font-weight:bold;
}

.green{
color:green;
font-weight:bold;
}

"@

#Fucntion to get AD Services
Function Get-checkservice{
[cmdletBinding()]
param(
[Parameter(Mandatory=$True)][String]$ComputerName
)
foreach($DCservice in $ComputerList){
foreach($include in $ADService){
$SV=Get-WmiObject -Class win32_service -ComputerName $DCservice -Filter “Name=‘$include’”
$props = @{‘ServiceName’=$sv.name;
‘DisplayName’=$sv.displayname;
‘Status’=$sv.status;
‘ServerName’ =$sv.PSComputerName;}
New-Object -TypeName PSObject $props}}
}

Function Get-ADreplication{
[cmdletBinding()]
param(
[Parameter(Mandatory=$True)][String]$ComputerName
)
foreach($replication in $ComputerList){
$repinfo= repadmin /replsum * /bysrc /bydest /sort:delta
$props= @{‘DSAType’=$repinfo.DSAType;
‘HOSTNAME’=$repinfo.hostname;
‘Delta’=$repinfo.Delta;
‘Fails’=$repinfo.Fails;
‘Slash’=$repinfo.slash;
‘Total’=$repinfo.Total;
‘PctError’=$repinfo.PcTError;
‘ErrorMessage’=$repinfo.ErrorMsg;}
New-Object -TypeName PSObject $props}

}

Function Get-ADDiagnosis{

dcdiag.exe /test:dns /v /e /x:$ScriptDir\dcdiag.xml /e

[System.Xml.XmlDocument]$XD = new-object System.Xml.XmlDocument
$XD.Load(“$ScriptDir\dcdiag.xml”) | gm
ForEach ($Element in $XD.DCDIAGTestResults.DNSEnterpriseTestResults.Summary.Domain.DC)
{
ForEach ($Test in $Element){
$props= @{
‘DC’= $Element.Name
‘Authentication’=$Test.status;
‘Basic’=$Test.status;
‘Forwarders’=$Test.status;;
‘Delegation’=$Test.status;
‘DynamicUpdate’=$Test.status;
‘RecordRegistration’=$Teststatus;
‘ExternalNameResolution’=$Test.status;}}
New-Object -TypeName PSObject $props}
}

foreach($computer in $ComputerList){
try{
$reachable = $true
Write-output “Checking Connectivity to $computer”
Get-WmiObject -Class win32_bios -ComputerName $computer | Out-Null
}catch{
Write-Warning “$computer connectivity failed”
$reachable = $false
}
if($reachable){

$params = @{'As'='Table';
                'Precontent'='♦ AD Service Check';
                'EvenRowCssClass'='even';
                'OddRowCssClass'='odd';
                'MakeTableDynamic'=$True;
                'TableCssClass'='grid';
                'Properties'='ServiceName','DisplayName','Status',@{n='ServerName';e={$_.Servername}}}
    $html_Service = Get-checkservice -ComputerName $computer | ConvertTo-EnhancedHTMLFragment @params        
        
        
     $params = @{'As'='Table';
                'Precontent'='♦ AD Replication Report';
                'EvenRowCssClass'='even';
                'OddRowCssClass'='odd';
                'MakeTableDynamic'=$True;
                'TableCssClass'='grid';
                'Properties'='DSAType','HOSTNAME','Delta','Fails','Slash','Total','PCTError','ErrorMessage'}
    $html_replication = Get-ADreplication -ComputerName $computer | ConvertTo-EnhancedHTMLFragment @params      
        


    $params = @{'As'='Table';
                'Precontent'='♦ AD Diagnosis Report';
                'EvenRowCssClass'='even';
                'OddRowCssClass'='odd';
                'MakeTableDynamic'=$True;
                'TableCssClass'='grid';
                'Properties'='DC','Authentication','Basic','Forwarders','Delegation','DynamicUpdate','RecordRegistration','ExternalNameResolution'}
    $html_diagnosis = Get-ADDiagnosis | ConvertTo-EnhancedHTMLFragment @params   

#Assembling the final html report
$params = @{‘CssStyleSheet’=$Style;
‘Title’=“Server Health check”;
‘PreContent’=“Active Directory Health Check”
‘HTMLFragments’=@($html_Service,$html_replication,$html_diagnosis)
‘jQueryDataTableUri’=‘C:\html\jquerydatatable.js’;
‘jQueryUri’=‘C:\html\jQuery.js’}
$windowsHealth=ConvertTo-EnhancedHTML @params | Out-File -FilePath “$outFolderPath\AD_Health_Check.html”
}}

I found a few errors in your Get-ADDiagnostics function. The most obvious is the missing or extra ; within the hashtable. However, the bigger issue was with how you were accessing the elements in the XML. The status for each test was in an element under the “Test” property. Also, each test type needed to be accessed via an array index.

Final note, I added a test to see if the xml file existed, and deleted it, if it did. (If it exists the output from dcdiag fails. I finally added the “/S:DCNAME” parameter to dcdiag so you can run this from something other than a DC. (You could use “Get-ADDomainController” to get this programatically rather than manually code it).

Here is what I came up with. Let me know if anything needs clarification.

Function Get-ADDiagnosis{
    $ScriptDir = "C:\Scripts"
    
    If (Test-Path $ScriptDir\dcdiag.xml) {
        Remote-Item $ScriptDir\dcdiag.xml
    }

    dcdiag.exe /test:dns /v /e /x:$ScriptDir\dcdiag.xml /S:DCSERVER /e
    
    [System.Xml.XmlDocument]$XD = new-object System.Xml.XmlDocument
    $XD.Load("$ScriptDir\dcdiag.xml")

    ForEach ($Element in $XD.DCDIAGTestResults.DNSEnterpriseTestResults.Summary.Domain.DC)
    {
        $props= @{
            'DC'= $Element.Name
            'Authentication'=$Element.Test.Status[0];
            'Basic'=$Element.Test.Status[1];
            'Forwarders'=$Element.Test.Status[2];
            'Delegation'=$Element.Test.Status[3];
            'DynamicUpdate'=$Element.Test.Status[4];
            'RecordRegistration'=$Element.Test.Status[5];
            'ExternalNameResolution'=$Element.Test.Status[6]
        }
        New-Object -TypeName PSObject $props
    }
}

Also, what are these all about???
‘Precontent’=':diamonds:
Remove the ‘diamond symbol’ to make sure that is not causing issues.
Yet. it just may be a issue when you copied and pasted here, but just to be sure.

Hi Des Davis,

I tried that, i am still getting empty output, am i missing something?

Those diamonds are html code with i have used in the code, it will come as diamond symbol before the heading like bullet points.when i paste here and post the reply those html codes are compiled

This is the xml i am trying to get the data from, when i give $Element.DC i get its value as ‘ACTIVEDIRECTORY’, but when i try your code $Element.Test.state i dont get any value in my html report

#-
#-
#-
#-
#
#
#
#
#
#
#

DCDIAGTestResults
DNSEnterpriseTestResults
Summary
Domain Name=“simlab”
DC Name=“ACTIVEDIRECTORY”
Test Name=“Authentication” Status=“PASS”
Test Name=“Basic” Status=“PASS”
Test Name=“Forwarders” Status=“FAIL”
Test Name=“Delegation” Status=“PASS”
Test Name=“DynamicUpdate” Status=“PASS”
Test Name=“RecordRegistration” Status=“PASS”
Test Name=“ExternalNameResolution” Status=“N-A”
/DC
/Domain
/Summary

Thank you des davis, your answer helped me, now its working.