ADAudit.psm1
|
Function Export-ADConfig { <# .SYNOPSIS Exports the configuration of an Active Directory forest to an XML file. .DESCRIPTION The Export-ADConfig cmdlet retrieves the AD configuration via the Get-ADConfig cmdlet and then exports it to an XML file. If the -AsGoldConfig switch is used, the file is prefixed GoldConfig-, otherwise the prefix is ADConfig-. .PARAMETER InputObject The AD configuration to export. If not provided Get-ADConfig is executed to retrieve the current config. .PARAMETER Path Specify the path for the export file. If not specified, the file is either ADConfig-<currentdate>.xml or GoldConfig-<currentdate>.xml depending on whether -AsgoldConfig is specified. .PARAMETER AsGoldConfig Use to export to a file named GoldConfig-<currentdate>.xml. .EXAMPLE Export-ADConfig Retrieves the current AD configuration and exports it to a file named ADReport-<date>.xml. .EXAMPLE Export-ADConfig -AsGoldConfig Retrieves the current AD configuration and exports it to a file named GoldConfig-<date>.xml. .EXAMPLE Get-ADConfig | Export-ADConfig -AsGoldConfig Exports a previously retrieved AD configuration to a file named GoldConfig-<date>.xml. #> [cmdletbinding(DefaultParameterSetName='Default')] Param( [Parameter(ParameterSetName='Path')] [Parameter(ParameterSetName='AsGoldConfig')] [Parameter(ParameterSetName='Default')] [Parameter(Position = 0, ValueFromPipeline)] [object] $InputObject = (Get-ADConfig), [Parameter(ParameterSetName='Path')] [string] $Path, [Parameter(ParameterSetName='AsGoldConfig')] [switch] $AsGoldConfig ) Begin { If ($AsGoldConfig) { $ReportPrefix = 'GoldConfig' } Else { $ReportPrefix = 'ADReport' } if (-not $Path) { $Path = "$ReportPrefix-$(Get-Date -format yyyy-MM-dd).xml" } } Process { $InputObject | Export-Clixml -Path $Path -Encoding UTF8 } } Function Get-ADConfig { <# .SYNOPSIS Retrieves the configuration of an Active Directory forest. .DESCRIPTION The Get-ADConfig cmdlet retrieves various configuration information about Active Directory and returns that information as a PowerShell ojbect. It uses cmdlets such as: Get-ADRootDSE, Get-ADForest, Get-ADDomain, Get-ADDomainController, Get-ADTrust etc. to gather information. The primary purpose of this tool is to gather a single and detailed snapshot of the configuration of an Active Directory forest to use to validate the future health of that forest. .EXAMPLE Get-ADConfig Retrieves the current configuration of Active Directory and returns it as a PowerShell object. #> [cmdletbinding()] Param() $ADDomain = Get-ADDomain #HashTable to save ADReport [pscustomobject]@{ RootDSE = (Get-ADRootDSE) ForestInformation = (Get-ADForest) DomainInformation = $ADDomain DomainControllers = (Get-ADDomainController -Filter *) DomainTrusts = (Get-ADTrust -Filter *) DefaultPassWordPoLicy = (Get-ADDefaultDomainPasswordPolicy) AuthenticationPolicies = (Get-ADAuthenticationPolicy -LDAPFilter '(name=AuthenticationPolicy*)') AuthenticationPolicySilos = (Get-ADAuthenticationPolicySilo -Filter 'Name -like "*AuthenticationPolicySilo*"') CentralAccessPolicies = (Get-ADCentralAccessPolicy -Filter *) CentralAccessRules = (Get-ADCentralAccessRule -Filter *) ClaimTransformPolicies = (Get-ADClaimTransformPolicy -Filter *) ClaimTypes = (Get-ADClaimType -Filter *) DomainAdministrators = (Get-ADGroup -Identity $('{0}-512' -f $ADDomain.domainSID) | Get-ADGroupMember -Recursive) OrganizationalUnits = (Get-ADOrganizationalUnit -Filter *) OptionalFeatures = (Get-ADOptionalFeature -Filter *) Sites = (Get-ADReplicationSite -Filter *) Subnets = (Get-ADReplicationSubnet -Filter *) SiteLinks = (Get-ADReplicationSiteLink -Filter *) LDAPDNS = (Resolve-DnsName -Name "_ldap._tcp.$($ADDomain.DNSRoot)" -Type srv) | Sort-Object nametarget, name, type KerberosDNS = (Resolve-DnsName -Name "_kerberos._tcp.$($ADDomain.DNSRoot)" -Type srv) | Sort-Object nametarget, name, type } } Function Test-ActiveDirectory { <# .SYNOPSIS Runs Pester tests to validate whether the Active Directory configuration and health matches the previously recorded known-good state of the configuration. .DESCRIPTION .. .PARAMETER ADSnapshotFile Optional: The path to a snapshot of Active Directory that you want to validate against the Gold config. If not provided, a current config is retrieved at runtime via the Get-ADConfig cmdlet. .PARAMETER ADGoldFile The path to the 'gold' known-good snapshot of Active Directory that you want to validate against. The cmdlet looks for a file named ADGoldConfig-*.xml in the current directory .PARAMETER Tag Optional: Only run checks with one of these Pester tags (e.g. 'Forest','Domain','Password', 'Sites','Subnets','Sitelinks','ADHC'). If not specified, all checks are run. .PARAMETER ExcludeTag Optional: Skip checks with one of these Pester tags. For example, use -ExcludeTag ADHC to skip the live health checks (NLTest/DCDiag/RepAdmin/ports/services/DNS) and only compare configuration. .EXAMPLE Test-ActiveDirectory Compares the current Active Directory configuration against the most recent GoldConfig-*.xml file found in the current directory and reports any differences. .EXAMPLE Test-ActiveDirectory -ExcludeTag ADHC Compares configuration only, skipping the live health checks (useful when running from a host that isn't a domain member/controller, or doesn't have the AD administrative tools installed). #> [CmdletBinding()] Param( [string] $ADSnapshotFile, [string] $ADGoldFile = (Get-ChildItem (Join-Path $Pwd 'GoldConfig-*.xml') | Select-Object -Last 1).fullname, [string[]] $Tag, [string[]] $ExcludeTag ) $Container = New-PesterContainer -Path (Join-Path $PSScriptRoot '../ActiveDirectory.Checks.ps1') -Data @{ ADSnapshotFile = $ADSnapshotFile ADGoldFile = $ADGoldFile } $PesterConfig = New-PesterConfiguration $PesterConfig.Run.Container = $Container $PesterConfig.Run.PassThru = $true # Pester v6 fails a -ForEach that resolves to $null/empty unless the It also carries # -AllowNullOrEmptyForEach. ActiveDirectory.Checks.ps1 deliberately doesn't use that switch, so it # can also run unmodified on Pester v5 (where the switch doesn't exist). Relaxing the same behaviour # here, at the run configuration level, covers Pester v6 instead -- guarded, since this property # doesn't exist on Pester v5's configuration object and setting it there would throw. if ($PesterConfig.Run.PSObject.Properties.Name -contains 'FailOnNullOrEmptyForEach') { $PesterConfig.Run.FailOnNullOrEmptyForEach = $false } if ($Tag) { $PesterConfig.Filter.Tag = $Tag } if ($ExcludeTag) { $PesterConfig.Filter.ExcludeTag = $ExcludeTag } Invoke-Pester -Configuration $PesterConfig } |