# .Synopsis Automatically document ADDS configuration .DESCRIPTION Automatically document ADDS configuration. Submits generated documentation to your Hudu instance and associates it with the Company provided by ClientName. Requires Global Keystore variables for HuduBaseDomain and HuduApiKey. .INPUTS -ClientName {{client.name}} -HuduBaseDomain {{global.HuduBaseDomain}} -HuduApiKey {{global.HuduApiKey}} .NOTES v1.0 Based on https://github.com/lwhitelock/HuduAutomation/blob/main/CyberdrainRewrite/Hudu-ADDS-Documentation.ps1 .COMPONENT Hudu Documentation .ROLE Documentation #> param ( [string] $ClientName, [string] $HuduBaseDomain, [string] $HuduApiKey ) if (!$ClientName) { write-output "Must provide -ClientName with a valid value that is identical to the name of a Company that exists in your Hudu instance. This should be the {{client.name}} value. `n" $ErrorCount += 1 } if (!$HuduBaseDomain) { write-output "Must provide -HuduBaseUrl and it must a FQDN that maps to your Hudu instance without a trailing slash. `n" $ErrorCount += 1 } if (!$HuduApiKey) { write-output "Must provide -HuduApiKey with a valid value from your Hudu instance. `n" $ErrorCount += 1 } if (!$ErrorCount -eq 0) { exit 1 } ##################################################################### # # Active Directory Details to Hudu # # Get a Hudu API Key from https://yourhududomain.com/admin/api_keys # Set the base domain of your Hudu instance without a trailing / # Client Name as it appears in Hudu $HuduAssetLayoutName = "Active Directory - AutoDoc" ##################################################################### Write-Host "Connecting to $HuduBaseDomain" #Get the Hudu API Module if not installed if (Get-Module -ListAvailable -Name HuduAPI) { Import-Module HuduAPI } else { Install-Module HuduAPI -Force Import-Module HuduAPI } #Set Hudu logon information New-HuduAPIKey $HuduAPIKey New-HuduBaseUrl $HuduBaseDomain function Get-WinADForestInformation { $Data = @{ } $ForestInformation = $(Get-ADForest) $Data.Forest = $ForestInformation $Data.RootDSE = $(Get-ADRootDSE -Properties *) $Data.ForestName = $ForestInformation.Name $Data.ForestNameDN = $Data.RootDSE.defaultNamingContext $Data.Domains = $ForestInformation.Domains $Data.ForestInformation = @{ 'Name' = $ForestInformation.Name 'Root Domain' = $ForestInformation.RootDomain 'Forest Functional Level' = $ForestInformation.ForestMode 'Domains Count' = ($ForestInformation.Domains).Count 'Sites Count' = ($ForestInformation.Sites).Count 'Domains' = ($ForestInformation.Domains) -join ", " 'Sites' = ($ForestInformation.Sites) -join ", " } $Data.UPNSuffixes = Invoke-Command -ScriptBlock { $UPNSuffixList = [PSCustomObject] @{ "Primary UPN" = $ForestInformation.RootDomain "UPN Suffixes" = $ForestInformation.UPNSuffixes -join "," } return $UPNSuffixList } $Data.GlobalCatalogs = $ForestInformation.GlobalCatalogs $Data.SPNSuffixes = $ForestInformation.SPNSuffixes $Data.Sites = Invoke-Command -ScriptBlock { $Sites = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites $SiteData = foreach ($Site in $Sites) { [PSCustomObject] @{ "Site Name" = $site.Name "Subnets" = ($site.Subnets) -join ", " "Servers" = ($Site.Servers) -join ", " } } Return $SiteData } $Data.FSMO = Invoke-Command -ScriptBlock { [PSCustomObject] @{ "Domain" = $ForestInformation.RootDomain "Role" = 'Domain Naming Master' "Holder" = $ForestInformation.DomainNamingMaster } [PSCustomObject] @{ "Domain" = $ForestInformation.RootDomain "Role" = 'Schema Master' "Holder" = $ForestInformation.SchemaMaster } foreach ($Domain in $ForestInformation.Domains) { $DomainFSMO = Get-ADDomain $Domain | Select-Object PDCEmulator, RIDMaster, InfrastructureMaster [PSCustomObject] @{ "Domain" = $Domain "Role" = 'PDC Emulator' "Holder" = $DomainFSMO.PDCEmulator } [PSCustomObject] @{ "Domain" = $Domain "Role" = 'Infrastructure Master' "Holder" = $DomainFSMO.InfrastructureMaster } [PSCustomObject] @{ "Domain" = $Domain "Role" = 'RID Master' "Holder" = $DomainFSMO.RIDMaster } } Return $FSMO } $Data.OptionalFeatures = Invoke-Command -ScriptBlock { $OptionalFeatures = $(Get-ADOptionalFeature -Filter * ) $Optional = @{ 'Recycle Bin Enabled' = '' 'Privileged Access Management Feature Enabled' = '' } ### Fix Optional Features foreach ($Feature in $OptionalFeatures) { if ($Feature.Name -eq 'Recycle Bin Feature') { if ("$($Feature.EnabledScopes)" -eq '') { $Optional.'Recycle Bin Enabled' = $False } else { $Optional.'Recycle Bin Enabled' = $True } } if ($Feature.Name -eq 'Privileged Access Management Feature') { if ("$($Feature.EnabledScopes)" -eq '') { $Optional.'Privileged Access Management Feature Enabled' = $False } else { $Optional.'Privileged Access Management Feature Enabled' = $True } } } return $Optional ### Fix optional features } return $Data } $TableHeader = "
", " | " $RawAD = Get-WinADForestInformation $ForestRawInfo = new-object PSCustomObject -property $RawAD.ForestInformation | convertto-html -Fragment | Select-Object -Skip 1 $ForestNice = $TableHeader + ($ForestRawInfo -replace $TableStyling) + $Whitespace $SiteRawInfo = $RawAD.Sites | Select-Object 'Site Name', Servers, Subnets | ConvertTo-Html -Fragment | Select-Object -Skip 1 $SiteNice = $TableHeader + ($SiteRawInfo -replace $TableStyling) + $Whitespace $OptionalRawFeatures = new-object PSCustomObject -property $RawAD.OptionalFeatures | convertto-html -Fragment | Select-Object -Skip 1 $OptionalNice = $TableHeader + ($OptionalRawFeatures -replace $TableStyling) + $Whitespace $UPNRawFeatures = $RawAD.UPNSuffixes | convertto-html -Fragment -as list| Select-Object -Skip 1 $UPNNice = $TableHeader + ($UPNRawFeatures -replace $TableStyling) + $Whitespace $DCRawFeatures = $RawAD.GlobalCatalogs | ForEach-Object { Add-Member -InputObject $_ -Type NoteProperty -Name "Domain Controller" -Value $_; $_ } | convertto-html -Fragment | Select-Object -Skip 1 $DCNice = $TableHeader + ($DCRawFeatures -replace $TableStyling) + $Whitespace $FSMORawFeatures = $RawAD.FSMO | convertto-html -Fragment | Select-Object -Skip 1 $FSMONice = $TableHeader + ($FSMORawFeatures -replace $TableStyling) + $Whitespace $ForestFunctionalLevel = $RawAD.RootDSE.forestFunctionality $DomainFunctionalLevel = $RawAD.RootDSE.domainFunctionality $domaincontrollerMaxLevel = $RawAD.RootDSE.domainControllerFunctionality $passwordpolicyraw = Get-ADDefaultDomainPasswordPolicy | Select-Object ComplexityEnabled, PasswordHistoryCount, LockoutDuration, LockoutThreshold, MaxPasswordAge, MinPasswordAge | convertto-html -Fragment -As List | Select-Object -skip 1 $passwordpolicyheader = " |
---|---|
Policy | Setting |