Active Directory configuration report

‘Sup PSHomies,

Last blog I talked about how to create a AD configuration snapshot. I saved the AD Configuration using the Export-Clixml cmdlet. As promised here’s the follow up: How to create a report from the saved snapshot.

I’m a fan of HTML for reporting purposes. In the past I’ve dabbled in creating reports using XML in combination with CSS. The challenge was creating a well-defined XML file. If you’ve ever had the idea of using Export-Clixml to combine with CSS then you’re in for a disappointment! ConvertTo-HTML is a better fit for reporting. Having said that, creating a well-defined XML file can also be a challenge. As luck would have it there’s a mini-series on the subject, check it out if you want to go down that route.

My favorite way of creating HTML reports these days is using PScribo, brought to us  by Iain Brighton. I saw him demonstrate the module at the PowerShell Conference in Stockholm on youtube. PScribo sure makes creating reports easier! PScribo supports different output formats:

  • HTML
  • Word
  • Text
  • XML

You can also edit the style of your document. To get a better impression of all the possibilities have a look at the video. The module has enough examples to help you get started. Before you know it you’ll be hooked!

Here’s the script:

<#
Author: I.C.A. Strachan
Version:
Version History:
Purpose: Create PScribo Report of saved AD Configuration
#>
[CmdletBinding()]
Param(
$snapshotDate= '29032016'
)
#PScribo link: https://github.com/iainbrighton/PScribo
Import-Module PScribo -Verbose:$false
#Get ADSnapshot
$SavedADSnapshot = Import-Clixml .\export\dsa\ADReport-$($snapshotDate).xml
$reportAD = Document "AD snapshot report - $($snapshotDate)" {
GlobalOption -ForceUppercaseSection -EnableSectionNumbering -PageSize A4 -Margin 24
BlankLine -Count 20
Paragraph "Active Directory snapshot report - $($snapshotDate)" -Style Title
BlankLine -Count 20
PageBreak
TOC -Name 'Table of Contents'
PageBreak
Section -Style Heading1 'Forest Information' {
$ADForest = [Ordered]@{
Name = $($SavedADSnapshot.ForestInformation.Name)
RootDomain = $($SavedADSnapshot.ForestInformation.RootDomain)
ForestMode = $($SavedADSnapshot.ForestInformation.ForestMode.ToString())
Domains = $($SavedADSnapshot.ForestInformation.Domains)
}
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0 -Hashtable $ADForest
}
Section -Style Heading1 'Domain Information' {
$ADDomain = [Ordered]@{
NetBIOSName = $($SavedADSnapshot.DomainInformation.NetBIOSName)
DomainMode = $($SavedADSnapshot.DomainInformation.DomainMode.ToString())
DistinguishedName = $($SavedADSnapshot.DomainInformation.DistinguishedName)
DomainSID = $($SavedADSnapshot.DomainInformation.DomainSID)
}
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0 -Hashtable $ADDomain
}
Section -Style Heading1 'FSMO Roles' {
$SavedADSnapshot.ForestInformation |
Select-Object DomainNamingMaster,SchemaMaster |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0
Blankline
$SavedADSnapshot.DomainInformation |
Select-Object PDCEmulator,InfrastructureMaster,RIDMaster |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0
}
Section -Style Heading1 'Global Catalogs' {
$GCs = $SavedADSnapshot.ForestInformation |
Select-Object -ExpandProperty GlobalCatalogs
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0 -InputObject $GCs
}
Section -Style Heading1 'Domain Controllers' {
$SavedADSnapshot.DomainControllers |
Select-Object Name,OperatingSystem,IPv4Address,Site |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0
}
Section -Style Heading1 'Default Domain Password Policy' {
$SavedADSnapshot.DefaultPassWordPoLicy |
Select-Object ComplexityEnabled,LockoutDuration,LockoutObservationWindow,LockoutThreshold,
MaxPasswordAge,MinPasswordAge,MinPasswordLength,PasswordHistoryCount,ReversibleEncryptionEnabled |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0
}
Section -Style Heading1 'Domain Administrators' {
$SavedADSnapshot.DomainAdministrators |
Select-Object Name,DistinguishedName |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -Width 0
}
Section -Style Heading1 'Organizational Units' {
$SavedADSnapshot.OrganizationalUnits |
Select-Object Name,DistinguishedName |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -Width 0
}
Section -Style Heading1 'Sites & Subnets' {
Section -Style Heading2 'Sites' {
$SavedADSnapshot.Sites |
Select-Object Name,Description,DistinguishedName |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -List -Width 0
}
Section -Style Heading2 'Sitelinks' {
$SavedADSnapshot.SiteLinks |
Select-Object Name,Cost,ReplicationFrequencyInMinutes |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -Width 0
}
Section -Style Heading2 'Subnets' {
$SavedADSnapshot.Subnets |
Select-Object Name,Site |
Table -Name 'AutofitWidth-AutofitCell-NoHighlighting' -Width 0
}
}
}
#Render report in HTML format
$reportAD | Export-Document -Path .\export\dsa -Format Html

I’ve recently discovered markdown. If you’re comfortable creating HTML documents, then MD shouldn’t be much of a challenge ;-). BTW if you’re looking for a good MD reader, vscode has you covered. VSCode is gaining momentum in the PowerShell community. I’ll admit to being hooked on ISESteroids, still,  Tobias Weltner said there will be a major update pretty soon… So who knows what this might mean?

I decided to give it a try in MD Format as well!

<#
Author: I.C.A. Strachan
Version:
Version History:
Purpose: Create MD Report of saved AD Configuration
#>
[CmdletBinding()]
Param(
$snapshotDate= '29032016'
)
#Get ADSnapshot
$SavedADSnapshot = Import-Clixml .\export\dsa\ADReport-$($snapshotDate).xml
#MDReport Title
$MDReport = "# Active Directory snapshot report - $($snapshotDate)`n"
#region Get Forest Information
$ADForest = @"
# Forest Information
| | |
|---|---|
|Name | $($SavedADSnapshot.ForestInformation.Name) |
|RootDomain | $($SavedADSnapshot.ForestInformation.RootDomain) |
|ForestMode | $($SavedADSnapshot.ForestInformation.ForestMode.ToString()) |
|Domains | $($SavedADSnapshot.ForestInformation.Domains) |
"@
$MDReport += $ADForest
#endregion
#region Domain Information
$ADDomain = @"
# Domain Information
| | |
|---|---|
|NetBIOSName | $($SavedADSnapshot.DomainInformation.NetBIOSName) |
|DomainMode | $($SavedADSnapshot.DomainInformation.DomainMode.ToString()) |
|DistinguishedName | $($SavedADSnapshot.DomainInformation.DistinguishedName) |
|DomainSID | $($SavedADSnapshot.DomainInformation.DomainSID) |
"@
$MDReport += $ADDomain
#endregion
#region Default Password Policy
$ADPasswordPolicy = @"
# Default Password Policy
| | |
|---|---|
|ComplexityEnabled | $($SavedADSnapshot.DefaultPassWordPoLicy.ComplexityEnabled) |
|DistinguishedName | $($SavedADSnapshot.DefaultPassWordPoLicy.DistinguishedName) |
|LockoutDuration | $($SavedADSnapshot.DefaultPassWordPoLicy.LockoutDuration) |
|LockoutObservationWindow | $($SavedADSnapshot.DefaultPassWordPoLicy.LockoutObservationWindow) |
|LockoutThreshold | $($SavedADSnapshot.DefaultPassWordPoLicy.LockoutThreshold) |
|MaxPasswordAge | $($SavedADSnapshot.DefaultPassWordPoLicy.MaxPasswordAge) |
|MinPasswordAge | $($SavedADSnapshot.DefaultPassWordPoLicy.MinPasswordAge) |
|MinPasswordLength | $($SavedADSnapshot.DefaultPassWordPoLicy.MinPasswordLength) |
|PasswordHistoryCount | $($SavedADSnapshot.DefaultPassWordPoLicy.PasswordHistoryCount) |
|ReversibleEncryptionEnabled | $($SavedADSnapshot.DefaultPassWordPoLicy.ReversibleEncryptionEnabled) |
"@
$MDReport += $ADPasswordPolicy
#endregion
#region FSMO Roles
$ADFSMORoles = @"
# FSMO Roles
| | |
|---|---|
|DomainNamingMaster| $($SavedADSnapshot.ForestInformation.DomainNamingMaster) |
|SchemaMaster | $($SavedADSnapshot.ForestInformation.SchemaMaster) |
|PDCEmulator | $($SavedADSnapshot.DomainInformation.PDCEmulator) |
|RIDMaster | $($SavedADSnapshot.DomainInformation.RIDMaster) |
|InfrastructureMaster | $($SavedADSnapshot.DomainInformation.InfrastructureMaster) |
"@
$MDReport += $ADFSMORoles
#endregion
#region Global Catalogs
$ADGCs = @"
# Global Catalogs
|Global Catalogs |
|---|
$(
$SavedADSnapshot.ForestInformation.GlobalCatalogs |
ForEach-Object {
"|$_|`n"
}
)
"@
$MDReport += $ADGCs
#endregion
#region Domain Controllers
$ADDCs = @"
# Domain Controllers
|Name|OperatingSystem|IPv4Address|Site|
|---|---|---|---|
$(
$SavedADSnapshot.DomainControllers |
ForEach-Object {
"|$($_.Name)|$($_.OperatingSystem)|$($_.IPv4Address)|$($_.Site)|`n"
}
)
"@
$MDReport += $ADDCs
#endregion
#region Domain Administrators
$ADDomainAdmins = @"
# Domain Administrators
|Name|DistinguishedName|
|---|---|
$(
$SavedADSnapshot.DomainAdministrators |
ForEach-Object {
"|$($_.Name)|$($_.DistinguishedName)|`n"
}
)
"@
$MDReport += $ADDomainAdmins
#endregion
#region Sites & Subnets
$ADSitesSubnets = @"
# Sites & Subnets
## Sites
|Name|Description|DistinguishedName|
|---|---|---|
$(
$SavedADSnapshot.Sites |
ForEach-Object {
"|$($_.Name)|$($_.Description)|$($_.DistinguishedName)|`n"
}
)
## Sitelinks
|Name|Cost|ReplicationFrequencyInMinutes |
|---|---|---|
$(
$SavedADSnapshot.SiteLinks |
ForEach-Object {
"|$($_.Name)|$($_.Cost)|$($_.ReplicationFrequencyInMinutes)|`n"
}
)
## Subnets
|Name|Site|
|---|---|
$(
$SavedADSnapshot.Subnets |
ForEach-Object {
"|$($_.Name)|$($_.Site)|`n"
}
)
"@
$MDReport += $ADSitesSubnets
#endregion
#region Organizational Units
$ADOUs = @"
# Organizational Units
|Name|DistinguishedName|
|---|---|
$(
$SavedADSnapshot.OrganizationalUnits |
ForEach-Object {
"|$($_.Name)|$($_.DistinguishedName)|`n"
}
)
"@
#$MDReport += $ADOUs
#endregion
#Save MDReport
$MDReport | Out-File ".\export\dsa\AD snapshot report - $($snapshotDate).md" -Encoding utf8 -Force

Not bad…

MD Format ADConfiguration

MD format has a small footprint which could be interesting. MD files can be converted to other formats. Doug Finke has an excellent vscode extension to render md files in pdf, word or html, using PanDoc.

PScribo is definitely worth a try! MD is also an option. Generating reports in Powershell just got easier thanks to Iain & Doug! Great addition guys! Keep up the good work!

Hope it’s worth something to you

Ttyl,

Urv

Advertisement

3 thoughts on “Active Directory configuration report

  1. Pingback: Active Directory Operations Test | pshirwin

  2. Pingback: Powershell Reporting using Pscribo Part 1 -Getting the XML | Wei-Yen Tan’s IT Journal

  3. Pingback: AD Operation Validation class | pshirwin

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s