PSWinDocumentation.psm1

function Get-DocumentPath {
    [CmdletBinding()]
    param ([System.Collections.IDictionary] $Document,
        [string] $FinalDocumentLocation)
    if ($Document.Configuration.Prettify.UseBuiltinTemplate) { $WordDocument = Get-WordDocument -FilePath "$($MyInvocation.MyCommand.Module.ModuleBase)\Templates\WordTemplate.docx" } else { if ($Document.Configuration.Prettify.CustomTemplatePath) { if ($(Test-File -File $Document.Configuration.Prettify.CustomTemplatePath -FileName 'CustomTemplatePath') -eq 0) { $WordDocument = Get-WordDocument -FilePath $Document.Configuration.Prettify.CustomTemplatePath } else { $WordDocument = New-WordDocument -FilePath $FinalDocumentLocation } } else { $WordDocument = New-WordDocument -FilePath $FinalDocumentLocation } }
    if ($WordDocument -eq $null) { Write-Verbose ' Null' }
    return $WordDocument
}
function Get-TypesRequired {
    [CmdletBinding()]
    param ([hashtable[]] $Sections)
    $TypesRequired = New-ArrayList
    $Types = 'TableData', 'ListData', 'ChartData', 'SqlData', 'ExcelData', 'TextBasedData'
    foreach ($Section in $Sections) {
        $Keys = Get-ObjectKeys -Object $Section
        foreach ($Key in $Keys) { if ($Section.$Key.Use -eq $True) { foreach ($Type in $Types) { Add-ToArrayAdvanced -List $TypesRequired -Element $Section.$Key.$Type -SkipNull -RequireUnique -FullComparison } } }
    }
    Write-Verbose "Get-TypesRequired - FinalList: $($TypesRequired -join ', ')"
    return $TypesRequired
}
function Get-WinDataFromFile {
    [cmdletbinding()]
    param([string] $FilePath,
        [string] $Type,
        [string] $FileType = 'XML')
    try {
        if (Test-Path $FilePath) {
            if ($FileType -eq 'XML') { $Data = Import-Clixml -Path $FilePath -ErrorAction Stop } else {
                $File = Get-Content -Raw -Path $FilePath
                $Data = ConvertFrom-Json -InputObject $File
            }
        } else { Write-Warning "Couldn't load $FileType file from $FilePath for $Type data. File doesn't exists." }
    } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Warning "Couldn't load $FileType file from $FilePath for $Type data. Error occured: $ErrorMessage"
    }
    return $Data
}
function Get-WinDataFromFileInChunks {
    [CmdletBinding()]
    param ([string] $FolderPath,
        [string] $FileType = 'XML',
        [Object] $Type)
    $DataInformation = @{ }
    if (Test-Path $FolderPath) {
        $Files = @(Get-ChildItem -Path "$FolderPath\*.$FileType" -ErrorAction SilentlyContinue -Recurse)
        foreach ($File in $Files) {
            $FilePath = $File.FullName
            $FieldName = $File.BaseName
            Write-Verbose -Message "Importing $FilePath as $FieldName"
            try { $DataInformation.$FieldName = Import-Clixml -Path $FilePath -ErrorAction Stop } catch {
                $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
                Write-Warning "Couldn't load $FileType file from $FilePath for $Type data to match into $FieldName. Error occured: $ErrorMessage"
            }
        }
    } else { Write-Warning -Message "Couldn't load files ($FileType) from folder $FolderPath as it doesn't exists." }
    return $DataInformation
}
function Get-WinDocumentationData {
    [CmdletBinding()]
    param ([alias("Data")][Object] $DataToGet,
        [alias("Forest")][Object] $Object,
        [string] $Domain)
    if ($null -ne $DataToGet) {
        $Type = Get-ObjectType -Object $DataToGet -ObjectName 'Get-WinDocumentationData'
        if ($Type.ObjectTypeName -eq 'ActiveDirectory') { if ("$DataToGet" -like 'Forest*') { return $Object."$DataToGet" } elseif ($DataToGet.ToString() -like 'Domain*') { return $Object.FoundDomains.$Domain."$DataToGet" } } else { return $Object."$DataToGet" }
    }
    return
}
function Get-WinDocumentationText {
    [CmdletBinding()]
    param ([string[]] $Text,
        [hashtable] $Forest,
        [string] $Domain)
    $Array = foreach ($T in $Text) {
        $T = $T.Replace('<CompanyName>', $Document.Configuration.Prettify.CompanyName)
        $T = $T.Replace('<ForestName>', $Forest.ForestInformation.Name)
        $T = $T.Replace('<ForestNameDN>', $Forest.ForestInformation.'Forest Distingushed Name')
        $T = $T.Replace('<Domain>', $Domain)
        $T = $T.Replace('<DomainNetBios>', $Forest.FoundDomains.$Domain.DomainInformation.NetBIOSName)
        $T = $T.Replace('<DomainDN>', $Forest.FoundDomains.$Domain.DomainInformation.DistinguishedName)
        $T = $T.Replace('<DomainPasswordWeakPasswordList>', $Forest.FoundDomains.$Domain.DomainPasswordDataPasswords.DomainPasswordWeakPasswordList)
        $T
    }
    return $Array
}
function Get-WinServiceData {
    [CmdletBinding()]
    param ([Object] $Credentials,
        [Object] $Service,
        [string] $Type,
        [Object] $TypesRequired)
    $CommandOutput = Connect-WinService -Type $Type -Credentials $Credentials -Service $Service -Verbose
    if ($Service.Use) {
        if ($Service.OnlineMode) {
            switch ($Type) {
                'ActiveDirectory' {
                    if ($Service.PasswordTests.Use) { $PasswordClearText = $Service.PasswordTests.PasswordFilePathClearText } else { $PasswordClearText = '' }
                    if ($Service.PasswordTests.UseHashDB) { $PasswordHashes = $Service.PasswordTests.PasswordFilePathHash } else { $PasswordHashes = '' }
                    $DataInformation = Get-WinADForestInformation -TypesRequired $TypesRequired -PathToPasswords $PasswordClearText -PathToPasswordsHashes $PasswordHashes -Verbose
                }
                'AWS' { $DataInformation = Get-WinAWSInformation -TypesRequired $TypesRequired -AWSAccessKey $Credentials.AccessKey -AWSSecretKey $Credentials.SecretKey -AWSRegion $Credentials.Region }
                'Azure' { $DataInformation = Get-WinO365Azure -TypesRequired $TypesRequired }
                'AzureAD' { }
                'Exchange' { $DataInformation = Get-WinExchangeInformation -TypesRequired $TypesRequired -Prefix $Service.Prefix }
                'ExchangeOnline' { $DataInformation = Get-WinO365Exchange -TypesRequired $TypesRequired -Prefix $Service.Prefix }
                'Teams' { }
                'SharePointOnline' { }
                'SkypeOnline' { }
            }
            if ($Service.Export.Use) {
                $Time = Start-TimeLog
                if ($Service.Export.To -eq 'File' -or $Service.Export.To -eq 'Both') {
                    Save-WinDataToFile -Export $Service.Export.Use -FilePath $Service.Export.FilePath -Data $DataInformation -Type $Type -IsOffline:$false -FileType 'XML'
                    $TimeSummary = Stop-TimeLog -Time $Time -Option OneLiner
                    Write-Verbose "Saving data for $Type to file $($Service.Export.FilePath) took: $TimeSummary"
                }
                if ($Service.Export.To -eq 'Folder' -or $Service.Export.To -eq 'Both') {
                    $Time = Start-TimeLog
                    Save-WinDataToFileInChunks -Export $Service.Export.Use -FolderPath $Service.Export.FolderPath -Data $DataInformation -Type $Type -IsOffline:$false -FileType 'XML'
                    $TimeSummary = Stop-TimeLog -Time $Time -Option OneLiner
                    Write-Verbose "Saving data for $Type to folder $($Service.Export.FolderPath) took: $TimeSummary"
                }
            }
            return $DataInformation
        } else {
            if ($Service.Import.Use) {
                $Time = Start-TimeLog
                if ($Service.Import.From -eq 'File') {
                    Write-Verbose "Loading data for $Type in offline mode from XML File $($Service.Import.Path). Hang on..."
                    $DataInformation = Get-WinDataFromFile -FilePath $Service.Import.Path -Type $Type -FileType 'XML'
                } elseif ($Service.Import.From -eq 'Folder') {
                    Write-Verbose "Loading data for $Type in offline mode from XML File $($Service.Import.Path). Hang on..."
                    $DataInformation = Get-WinDataFromFileInChunks -FolderPath $Service.Import.Path -Type $Type -FileType 'XML'
                } else { Write-Warning "Wrong option for Import.Use. Only Folder/File is supported." }
                $TimeSummary = Stop-TimeLog -Time $Time -Option OneLiner
                Write-Verbose "Loading data for $Type in offline mode from file took $TimeSummary"
                return $DataInformation
            }
        }
    }
}
function New-DataBlock {
    [CmdletBinding()]
    param([Container]$WordDocument,
        [Object] $Section,
        [alias('Object')][Object] $Forest,
        [string] $Domain,
        [OfficeOpenXml.ExcelPackage] $Excel,
        [string] $SectionName,
        [nullable[bool]] $Sql)
    if ($Section.Use) {
        if ($Domain) { $SectionDetails = "$Domain - $SectionName" } else { $SectionDetails = $SectionName }
        $TableData = Get-WinDocumentationData -DataToGet $Section.TableData -Object $Forest -Domain $Domain
        $ExcelData = Get-WinDocumentationData -DataToGet $Section.ExcelData -Object $Forest -Domain $Domain
        $ListData = Get-WinDocumentationData -DataToGet $Section.ListData -Object $Forest -Domain $Domain
        $SqlData = Get-WinDocumentationData -DataToGet $Section.SqlData -Object $Forest -Domain $Domain
        $TextBasedData = Get-WindocumentationData -DataToGet $Section.TextBasedData -Object $Forest -Domain $Domain
        $ChartData = (Get-WinDocumentationData -DataToGet $Section.ChartData -Object $Forest -Domain $Domain)
        if ($ChartData) {
            if ($Section.ChartKeys -is [string]) {
                if ($Section.ChartKeys -eq 'Keys' -and $Section.ChartValues -eq 'Values') {
                    $ChartKeys = (Convert-KeyToKeyValue $ChartData).Keys
                    $ChartValues = (Convert-KeyToKeyValue $ChartData).Values
                } else {
                    $ChartKeys = (Convert-KeyToKeyValue $ChartData)."$($Section.ChartKeys)"
                    $ChartValues = (Convert-KeyToKeyValue $ChartData)."$($Section.ChartValues)"
                }
            } elseif ($Section.ChartKeys -is [Array]) {
                $ChartKeys = (Convert-TwoArraysIntoOne -Object $ChartData.($Section.ChartKeys[0]) -ObjectToAdd $ChartData.($Section.ChartKeys[1]))
                $ChartValues = ($ChartData.($Section.ChartValues))
            } else { }
        }
        $TocText = (Get-WinDocumentationText -Text $Section.TocText -Forest $Forest -Domain $Domain)
        $TableTitleText = (Get-WinDocumentationText -Text $Section.TableTitleText -Forest $Forest -Domain $Domain)
        $Text = (Get-WinDocumentationText -Text $Section.Text -Forest $Forest -Domain $Domain)
        $ChartTitle = (Get-WinDocumentationText -Text $Section.ChartTitle -Forest $Forest -Domain $Domain)
        $ListBuilderContent = (Get-WinDocumentationText -Text $Section.ListBuilderContent -Forest $Forest -Domain $Domain)
        $TextNoData = (Get-WinDocumentationText -Text $Section.TextNoData -Forest $Forest -Domain $Domain)
        if ($WordDocument -and (($null -eq $Section.WordExport -and $Section.Use -eq $true) -or ($Section.WordExport -eq $true))) {
            Write-Verbose "Generating WORD Section for [$SectionDetails]"
            New-WordBlock -WordDocument $WordDocument -TocGlobalDefinition $Section.TocGlobalDefinition-TocGlobalTitle $Section.TocGlobalTitle -TocGlobalSwitches $Section.TocGlobalSwitches -TocGlobalRightTabPos $Section.TocGlobalRightTabPos -TocEnable $Section.TocEnable -TocText $TocText -TocListLevel $Section.TocListLevel -TocListItemType $Section.TocListItemType -TocHeadingType $Section.TocHeadingType -TableData $TableData -TableDesign $Section.TableDesign -TableTitleMerge $Section.TableTitleMerge -TableTitleText $TableTitleText -TableMaximumColumns $Section.TableMaximumColumns -TableColumnWidths $Section.TableColumnWidths -Text $Text -TextNoData $TextNoData -EmptyParagraphsBefore $Section.EmptyParagraphsBefore -EmptyParagraphsAfter $Section.EmptyParagraphsAfter -PageBreaksBefore $Section.PageBreaksBefore -PageBreaksAfter $Section.PageBreaksAfter -TextAlignment $Section.TextAlignment -ListData $ListData -ListType $Section.ListType -ListTextEmpty $Section.ListTextEmpty -ChartEnable $Section.ChartEnable -ChartTitle $ChartTitle -ChartKeys $ChartKeys -ChartValues $ChartValues -ListBuilderContent $ListBuilderContent -ListBuilderType $Section.ListBuilderType -ListBuilderLevel $Section.ListBuilderLevel -TextBasedData $TextBasedData -TextBasedDataAlignment $Section.TextSpecialAlignment
        }
        if ($Excel -and $Section.ExcelExport) {
            if ($Section.ExcelWorkSheet -eq '') { $WorkSheetName = $SectionDetails } else { $WorkSheetName = (Get-WinDocumentationText -Text $Section.ExcelWorkSheet -Forest $Forest -Domain $Domain) }
            if ($ExcelData) {
                Write-Verbose "Generating EXCEL Section for [$SectionDetails]"
                $ExcelWorksheet = Add-ExcelWorksheetData -ExcelDocument $Excel -ExcelWorksheetName $WorkSheetName -DataTable $ExcelData -AutoFit -AutoFilter -PreScanHeaders
            }
        }
        if ($Sql -and $Section.SQLExport -and $SqlData) {
            Write-Verbose "Sending [$SectionDetails] to SQL Server"
            $SqlQuery = Send-SqlInsert -Object $SqlData -SqlSettings $Section -Verbose
            foreach ($Query in $SqlQuery) { Write-Color @script:WriteParameters -Text '[i] ', 'MS SQL Output: ', $Query -Color White, White, Yellow }
        }
    }
    if ($WordDocument) { return $WordDocument } else { return }
}
function Save-WinDataToFile {
    [cmdletbinding()]
    param([nullable[bool]] $Export,
        [string] $Type,
        [Object] $Data,
        [string] $FilePath,
        [switch] $IsOffline,
        [string] $FileType = 'XML')
    if ($IsOffline) {
        Write-Verbose "Save-WinDataToFile - Exporting $Type data to $FileType to path $FilePath skipped. Running in offline mode."
        return
    }
    if ($Export) {
        if ($FilePath) {
            $Split = Split-Path -Path $FilePath
            if (-not (Test-Path -Path $Split)) { New-Item -ItemType Directory -Force -Path $Split > $null }
            Write-Verbose "Save-WinDataToFile - Exporting $Type data to $FileType to path $FilePath"
            if ($FileType -eq 'XML') {
                try { $Data | Export-Clixml -Path $FilePath -ErrorAction Stop -Encoding UTF8 } catch {
                $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
                Write-Warning "Couldn't save $FileType file to $FilePath for $Type data. Error occured: $ErrorMessage"
            }
        } else {
            try { $Data | ConvertTo-Json -ErrorAction Stop | Add-Content -Path $FilePath -Encoding UTF8 -ErrorAction Stop } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Warning "Couldn't save $FileType file to $FilePath for $Type data. Error occured: $ErrorMessage"
    }
}
}
}
}
function Save-WinDataToFileInChunks {
    [CmdletBinding()]
    param([nullable[bool]] $Export,
        [string] $Type,
        [Object] $Data,
        [string] $FolderPath,
        [switch] $IsOffline,
        [string] $FileType = 'XML')
    foreach ($Key in $Data.Keys) {
        $FilePath = [IO.Path]::Combine($FolderPath, "$Key.xml")
        Save-WinDataToFile -Export $Export -Type $Type -IsOffline:$IsOffline -Data $Data.$Key -FilePath $FilePath -FileType $FileType
    }
}
$Script:DataBehaviorActiveDirectory = [ordered] @{ForestInformation = @{OnlineRequired = $true }
    ForestFSMO = @{OnlineRequired = $true }
    ForestGlobalCatalogs = @{OnlineRequired = $true }
    ForestOptionalFeatures = @{OnlineRequired = $true }
    ForestUPNSuffixes = @{OnlineRequired = $true }
    ForestSPNSuffixes = @{OnlineRequired = $true }
    ForestSites = @{OnlineRequired = $true }
    ForestSites1 = @{OnlineRequired = $false }
    ForestSites2 = @{OnlineRequired = $false }
    ForestSubnets = @{OnlineRequired = $true }
    ForestSubnets1 = @{OnlineRequired = $true }
    ForestSubnets2 = @{OnlineRequired = $true }
    ForestSiteLinks = @{OnlineRequired = $true }
    DomainRootDSE = @{OnlineRequired = $true }
    DomainRIDs = @{OnlineRequired = $true }
    DomainAuthenticationPolicies = @{OnlineRequired = $true }
    DomainAuthenticationPolicySilos = @{OnlineRequired = $true }
    DomainCentralAccessPolicies = @{OnlineRequired = $true }
    DomainCentralAccessRules = @{OnlineRequired = $true }
    DomainClaimTransformPolicies = @{OnlineRequired = $true }
    DomainClaimTypes = @{OnlineRequired = $true }
    DomainFineGrainedPolicies = @{OnlineRequired = $true }
    DomainFineGrainedPoliciesUsers = @{OnlineRequired = $true }
    DomainFineGrainedPoliciesUsersExtended = @{OnlineRequired = $true }
    DomainGUIDS = @{OnlineRequired = $true }
    DomainDNSSRV = @{OnlineRequired = $true }
    DomainDNSA = @{OnlineRequired = $true }
    DomainInformation = @{OnlineRequired = $true }
    DomainControllers = @{OnlineRequired = $true }
    DomainFSMO = @{OnlineRequired = $true }
    DomainDefaultPasswordPolicy = @{OnlineRequired = $true }
    DomainGroupPolicies = @{OnlineRequired = $true }
    DomainGroupPoliciesDetails = @{OnlineRequired = $true }
    DomainGroupPoliciesACL = @{OnlineRequired = $true }
    DomainOrganizationalUnits = @{OnlineRequired = $true }
    DomainOrganizationalUnitsBasicACL = @{OnlineRequired = $true }
    DomainOrganizationalUnitsExtended = @{OnlineRequired = $true }
    DomainContainers = @{OnlineRequired = $true }
    DomainTrusts = @{OnlineRequired = $true }
    DomainGroupsFullList = @{OnlineRequired = $true }
    DomainGroups = @{OnlineRequired = $true }
    DomainGroupsMembers = @{OnlineRequired = $true }
    DomainGroupsMembersRecursive = @{OnlineRequired = $true }
    DomainGroupsSpecial = @{OnlineRequired = $true }
    DomainGroupsSpecialMembers = @{OnlineRequired = $true }
    DomainGroupsSpecialMembersRecursive = @{OnlineRequired = $true }
    DomainGroupsPriviliged = @{OnlineRequired = $true }
    DomainGroupsPriviligedMembers = @{OnlineRequired = $true }
    DomainGroupsPriviligedMembersRecursive = @{OnlineRequired = $true }
    DomainUsersFullList = @{OnlineRequired = $true }
    DomainUsers = @{OnlineRequired = $true }
    DomainUsersCount = @{OnlineRequired = $true }
    DomainUsersAll = @{OnlineRequired = $true }
    DomainUsersSystemAccounts = @{OnlineRequired = $true }
    DomainUsersNeverExpiring = @{OnlineRequired = $true }
    DomainUsersNeverExpiringInclDisabled = @{OnlineRequired = $true }
    DomainUsersExpiredInclDisabled = @{OnlineRequired = $true }
    DomainUsersExpiredExclDisabled = @{OnlineRequired = $true }
    DomainAdministrators = @{OnlineRequired = $true }
    DomainAdministratorsRecursive = @{OnlineRequired = $true }
    DomainEnterpriseAdministrators = @{OnlineRequired = $true }
    DomainEnterpriseAdministratorsRecursive = @{OnlineRequired = $true }
    DomainComputersFullList = @{OnlineRequired = $true }
    DomainComputersAll = @{OnlineRequired = $true }
    DomainComputersAllCount = @{OnlineRequired = $true }
    DomainComputers = @{OnlineRequired = $true }
    DomainComputersCount = @{OnlineRequired = $true }
    DomainServers = @{OnlineRequired = $true }
    DomainServersCount = @{OnlineRequired = $true }
    DomainComputersUnknown = @{OnlineRequired = $true }
    DomainComputersUnknownCount = @{OnlineRequired = $true }
    DomainPasswordDataUsers = @{OnlineRequired = $true }
    DomainPasswordDataPasswords = @{OnlineRequired = $true }
    DomainPasswordDataPasswordsHashes = @{OnlineRequired = $true }
    DomainPasswordClearTextPassword = @{OnlineRequired = $true }
    DomainPasswordClearTextPasswordEnabled = @{OnlineRequired = $true }
    DomainPasswordClearTextPasswordDisabled = @{OnlineRequired = $true }
    DomainPasswordLMHash = @{OnlineRequired = $true }
    DomainPasswordEmptyPassword = @{OnlineRequired = $true }
    DomainPasswordWeakPassword = @{OnlineRequired = $true }
    DomainPasswordWeakPasswordEnabled = @{OnlineRequired = $true }
    DomainPasswordWeakPasswordDisabled = @{OnlineRequired = $true }
    DomainPasswordWeakPasswordList = @{OnlineRequired = $true }
    DomainPasswordDefaultComputerPassword = @{OnlineRequired = $true }
    DomainPasswordPasswordNotRequired = @{OnlineRequired = $true }
    DomainPasswordPasswordNeverExpires = @{OnlineRequired = $true }
    DomainPasswordAESKeysMissing = @{OnlineRequired = $true }
    DomainPasswordPreAuthNotRequired = @{OnlineRequired = $true }
    DomainPasswordDESEncryptionOnly = @{OnlineRequired = $true }
    DomainPasswordDelegatableAdmins = @{OnlineRequired = $true }
    DomainPasswordDuplicatePasswordGroups = @{OnlineRequired = $true }
    DomainPasswordHashesWeakPassword = @{OnlineRequired = $true }
    DomainPasswordHashesWeakPasswordEnabled = @{OnlineRequired = $true }
    DomainPasswordHashesWeakPasswordDisabled = @{OnlineRequired = $true }
    DomainPasswordStats = @{OnlineRequired = $true }
}
$Script:Document = [ordered]@{Configuration = [ordered] @{Prettify = @{CompanyName = 'Evotec'
            UseBuiltinTemplate = $true
            CustomTemplatePath = ''
            Language = 'en-US'
        }
        Options = @{OpenDocument = $false
            OpenExcel = $false
        }
        DisplayConsole = @{ShowTime = $false
            LogFile = "$ENV:TEMP\PSWinDocumentationTesting.log"
            TimeFormat = 'yyyy-MM-dd HH:mm:ss'
        }
        Debug = @{Verbose = $false }
    }
    DocumentAD = [ordered] @{Enable = $true
        ExportWord = $true
        ExportExcel = $true
        FilePathWord = "$Env:USERPROFILE\Desktop\PSWinDocumentation-Report.docx"
        FilePathExcel = "$Env:USERPROFILE\Desktop\PSWinDocumentation-Report.xlsx"
        Sections = [ordered] @{SectionForest = [ordered] @{SectionTOC = [ordered] @{Use = $true
                    TocGlobalDefinition = $true
                    TocGlobalTitle = 'Table of content'
                    TocGlobalRightTabPos = 15
                    PageBreaksAfter = 1
                }
                SectionForestIntroduction = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'Scope'
                    TocListLevel = 0
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    Text = "This document provides a low-level design of roles and permissions for" + " the IT infrastructure team at <CompanyName> organization. This document utilizes knowledge from" + " AD General Concept document that should be delivered with this document. Having all the information" + " described in attached document one can start designing Active Directory with those principles in mind." + " It's important to know while best practices that were described are important in decision making they" + " should not be treated as final and only solution. Most important aspect is to make sure company has full" + " usability of Active Directory and is happy with how it works. Making things harder just for the sake of" + " implementation of best practices isn't always the best way to go."
                    TextAlignment = 'Both'
                    PageBreaksAfter = 1
                }
                SectionForestSummary = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Forest Summary'
                    TocListLevel = 0
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestInformation
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = "Forest Summary"
                    Text = "Active Directory at <CompanyName> has a forest name <ForestName>." + " Following table contains forest summary with important information:"
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest Summary'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestInformation
                }
                SectionForestFSMO = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestFSMO
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = 'FSMO Roles'
                    Text = 'Following table contains FSMO servers'
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest FSMO'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestFSMO
                }
                SectionForestOptionalFeatures = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestOptionalFeatures
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = 'Optional Features'
                    Text = 'Following table contains optional forest features'
                    TextNoData = "Following section should have table containing forest features. However no data was provided."
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest Optional Features'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestOptionalFeatures
                }
                SectionForestUPNSuffixes = [ordered] @{Use = $true
                    Text = "Following UPN suffixes were created in this forest:"
                    TextNoData = "No UPN suffixes were created in this forest."
                    ListType = 'Bulleted'
                    ListData = [PSWinDocumentation.ActiveDirectory]::ForestUPNSuffixes
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest UPN Suffixes'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestUPNSuffixes
                }
                SectionForesSPNSuffixes = [ordered] @{Use = $true
                    Text = "Following SPN suffixes were created in this forest:"
                    TextNoData = "No SPN suffixes were created in this forest."
                    ListType = 'Bulleted'
                    ListData = [PSWinDocumentation.ActiveDirectory]::ForestSPNSuffixes
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest SPN Suffixes'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSPNSuffixes
                }
                SectionForestSites1 = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Sites'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestSites1
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Forest Sites list can be found below"
                    ExcelExport = $false
                    ExcelWorkSheet = 'Forest Sites 1'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSites1
                }
                SectionForestSites2 = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestSites2
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Forest Sites list can be found below"
                    EmptyParagraphsBefore = 1
                    ExcelExport = $false
                    ExcelWorkSheet = 'Forest Sites 2'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSites2
                }
                SectionForestSites = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest Sites'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSites
                }
                SectionForestSubnets1 = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Subnets'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestSubnets1
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Table below contains information regarding relation between Subnets and sites"
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest Subnets 1'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSubnets1
                }
                SectionForestSubnets2 = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestSubnets2
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Table below contains information regarding relation between Subnets and sites"
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest Subnets 2'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSubnets2
                }
                SectionForestSiteLinks = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Site Links'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    TableData = [PSWinDocumentation.ActiveDirectory]::ForestSiteLinks
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Forest Site Links information is available in table below"
                    ExcelExport = $true
                    ExcelWorkSheet = 'Forest Site Links'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::ForestSiteLinks
                }
            }
            SectionDomain = [ordered] @{SectionPageBreak = [ordered] @{Use = $True
                    PageBreaksBefore = 1
                }
                SectionDomainStarter = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Domain <Domain>'
                    TocListLevel = 0
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                }
                SectionDomainIntroduction = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Domain Summary'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    Text = "Following domain exists within forest <ForestName>:"
                    ListBuilderContent = "Domain <DomainDN>", 'Name for fully qualified domain name (FQDN): <Domain>', 'Name for NetBIOS: <DomainNetBios>'
                    ListBuilderLevel = 0, 1, 1
                    ListBuilderType = 'Bulleted', 'Bulleted', 'Bulleted'
                    EmptyParagraphsBefore = 0
                }
                SectionDomainControllers = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Domain Controllers'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainControllers
                    TableDesign = 'ColorfulGridAccent5'
                    TableMaximumColumns = 8
                    Text = 'Following table contains domain controllers'
                    TextNoData = ''
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DCs'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainControllers
                }
                SectionDomainFSMO = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainFSMO
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = "FSMO Roles for <Domain>"
                    Text = "Following table contains FSMO servers with roles for domain <Domain>"
                    EmptyParagraphsBefore = 1
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - FSMO'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainFSMO
                }
                SectionDomainDefaultPasswordPolicy = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Password Policies'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainDefaultPasswordPolicy
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $True
                    TableTitleText = "Default Password Policy for <Domain>"
                    Text = 'Following table contains password policies for all users within <Domain>'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DefaultPasswordPolicy'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainDefaultPasswordPolicy
                }
                SectionDomainFineGrainedPolicies = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Fine Grained Password Policies'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainFineGrainedPolicies
                    TableDesign = 'ColorfulGridAccent5'
                    TableMaximumColumns = 8
                    TableTitleMerge = $false
                    TableTitleText = "Fine Grained Password Policy for <Domain>"
                    Text = 'Following table contains fine grained password policies'
                    TextNoData = "Following section should cover fine grained password policies. " + "There were no fine grained password polices defined in <Domain>. There was no formal requirement to have " + "them set up."
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Password Policy (Grained)'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainFineGrainedPolicies
                }
                SectionDomainGroupPolicies = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Group Policies'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainGroupPolicies
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Following table contains group policies for <Domain>"
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - GroupPolicies'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupPolicies
                }
                SectionDomainGroupPoliciesDetails = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Group Policies Details'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainGroupPoliciesDetails
                    TableMaximumColumns = 6
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Following table contains group policies for <Domain>"
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - GroupPolicies Details'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupPoliciesDetails
                }
                SectionDomainGroupPoliciesACL = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - GroupPoliciesACL'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupPoliciesACL
                }
                SectionDomainDNSSrv = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - DNS A/SRV Records'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainDNSSRV
                    TableMaximumColumns = 10
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Following table contains SRV records for Kerberos and LDAP"
                    EmptyParagraphsAfter = 1
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DNSSRV'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainDNSSRV
                }
                SectionDomainDNSA = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainDNSA
                    TableMaximumColumns = 10
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Following table contains A records for Kerberos and LDAP"
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DNSA'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainDNSA
                }
                SectionDomainTrusts = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Trusts'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainTrusts
                    TableMaximumColumns = 6
                    TableDesign = 'ColorfulGridAccent5'
                    Text = "Following table contains trusts established with domains..."
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DomainTrusts'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainTrusts
                }
                SectionDomainOrganizationalUnits = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Organizational Units'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainOrganizationalUnits
                    TableDesign = 'ColorfulGridAccent5'
                    TableMaximumColumns = 4
                    Text = "Following table contains all OU's created in <Domain>"
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - OrganizationalUnits'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainOrganizationalUnits
                }
                SectionDomainPriviligedGroup = [ordered] @{Use = $False
                    TocEnable = $True
                    TocText = 'General Information - Priviliged Groups'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsPriviliged
                    TableDesign = 'ColorfulGridAccent5'
                    Text = 'Following table contains list of priviliged groups and count of the members in it.'
                    ChartEnable = $True
                    ChartTitle = 'Priviliged Group Members'
                    ChartData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsPriviliged
                    ChartKeys = 'Group Name', 'Members Count'
                    ChartValues = 'Members Count'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - PriviligedGroupMembers'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsPriviliged
                }
                SectionDomainUsers = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Domain Users in <Domain>'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    PageBreaksBefore = 1
                    Text = 'Following section covers users information for domain <Domain>. '
                }
                SectionDomainUsersCount = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Users Count'
                    TocListLevel = 2
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainUsersCount
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = 'Users Count'
                    Text = "Following table and chart shows number of users in its categories"
                    ChartEnable = $True
                    ChartTitle = 'Users Count'
                    ChartData = [PSWinDocumentation.ActiveDirectory]::DomainUsersCount
                    ChartKeys = 'Keys'
                    ChartValues = 'Values'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - UsersCount'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersCount
                }
                SectionDomainAdministrators = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Domain Administrators'
                    TocListLevel = 2
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainAdministratorsRecursive
                    TableDesign = 'ColorfulGridAccent5'
                    Text = 'Following users have highest priviliges and are able to control a lot of Windows resources.'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DomainAdministrators'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainAdministratorsRecursive
                }
                SectionEnterpriseAdministrators = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Enterprise Administrators'
                    TocListLevel = 2
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainEnterpriseAdministratorsRecursive
                    TableDesign = 'ColorfulGridAccent5'
                    Text = 'Following users have highest priviliges across Forest and are able to control a lot of Windows resources.'
                    TextNoData = 'No Enterprise Administrators users were defined for this domain.'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - EnterpriseAdministrators'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainEnterpriseAdministratorsRecursive
                }
                SectionDomainComputers = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Computer Objects in <Domain>'
                    TocListLevel = 1
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading1'
                    PageBreaksBefore = 1
                    Text = 'Following section covers computers information for domain <Domain>. '
                }
                DomainComputers = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Computers'
                    TocListLevel = 2
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainComputers
                    TableDesign = 'ColorfulGridAccent5'
                    Text = 'Following client computers are created in <Domain>.'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DomainComputers'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainComputers
                }
                DomainComputersCount = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainComputersCount
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = 'Computers Count'
                    Text = "Following table and chart shows number of computers and their versions"
                    ChartEnable = $True
                    ChartTitle = 'Computers Count'
                    ChartData = [PSWinDocumentation.ActiveDirectory]::DomainComputersCount
                    ChartKeys = 'System Name', 'System Count'
                    ChartValues = 'System Count'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DomainComputersCount'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainComputersCount
                    EmptyParagraphsBefore = 1
                }
                DomainServers = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Servers'
                    TocListLevel = 2
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainServers
                    TableDesign = 'ColorfulGridAccent5'
                    Text = 'Following client computers are created in <Domain>.'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DomainComputers'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainServers
                }
                DomainServersCount = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainServersCount
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = 'Servers Count'
                    Text = "Following table and chart shows number of servers and their versions"
                    ChartEnable = $True
                    ChartTitle = 'Servers Count'
                    ChartData = [PSWinDocumentation.ActiveDirectory]::DomainServersCount
                    ChartKeys = 'System Name', 'System Count'
                    ChartValues = 'System Count'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - DomainServersCount'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainServersCount
                    EmptyParagraphsBefore = 1
                }
                DomainComputersUnknown = [ordered] @{Use = $true
                    TocEnable = $True
                    TocText = 'General Information - Unknown Computer Objects'
                    TocListLevel = 2
                    TocListItemType = 'Numbered'
                    TocHeadingType = 'Heading2'
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainComputersUnknown
                    TableDesign = 'ColorfulGridAccent5'
                    Text = 'Following client computers are not asisgned to clients or computers in <Domain>.'
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - ComputersUnknown'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainComputersUnknown
                }
                DomainComputersUnknownCount = [ordered] @{Use = $true
                    TableData = [PSWinDocumentation.ActiveDirectory]::DomainComputersUnknownCount
                    TableDesign = 'ColorfulGridAccent5'
                    TableTitleMerge = $true
                    TableTitleText = 'Unknown Computers Count'
                    Text = "Following table and chart shows number of unknown object computers in domain."
                    ExcelExport = $false
                    ExcelWorkSheet = '<Domain> - ComputersUnknownCount'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainComputersUnknownCount
                    EmptyParagraphsBefore = 1
                }
                SectionExcelDomainOrganizationalUnitsBasicACL = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - OU ACL Basic'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainOrganizationalUnitsBasicACL
                }
                SectionExcelDomainOrganizationalUnitsExtended = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - OU ACL Extended'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainOrganizationalUnitsExtended
                }
                SectionExcelDomainUsers = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Users'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsers
                }
                SectionExcelDomainUsersAll = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Users All'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersAll
                }
                SectionExcelDomainUsersSystemAccounts = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Users System'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersSystemAccounts
                }
                SectionExcelDomainUsersNeverExpiring = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Never Expiring'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersNeverExpiring
                }
                SectionExcelDomainUsersNeverExpiringInclDisabled = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Never Expiring incl Disabled'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersNeverExpiringInclDisabled
                }
                SectionExcelDomainUsersExpiredInclDisabled = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Expired incl Disabled'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersExpiredInclDisabled
                }
                SectionExcelDomainUsersExpiredExclDisabled = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Expired excl Disabled'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersExpiredExclDisabled
                }
                SectionExcelDomainUsersFullList = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Users List Full'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainUsersFullList
                }
                SectionExcelDomainComputersFullList = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Computers List'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainComputersFullList
                }
                SectionExcelDomainGroupsFullList = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Groups List'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsFullList
                }
                SectionExcelDomainGroupsRest = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Groups'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroups
                }
                SectionExcelDomainGroupsSpecial = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Groups Special'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsSpecial
                }
                SectionExcelDomainGroupsPriviliged = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Groups Priv'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsPriviliged
                }
                SectionExcelDomainGroupMembers = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Members'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsMembers
                }
                SectionExcelDomainGroupMembersSpecial = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Members Special'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsSpecialMembers
                }
                SectionExcelDomainGroupMembersPriviliged = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Members Priv'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsPriviligedMembers
                }
                SectionExcelDomainGroupMembersRecursive = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Members Rec'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsMembersRecursive
                }
                SectionExcelDomainGroupMembersSpecialRecursive = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Members RecSpecial'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsSpecialMembersRecursive
                }
                SectionExcelDomainGroupMembersPriviligedRecursive = [ordered] @{Use = $true
                    ExcelExport = $true
                    ExcelWorkSheet = '<Domain> - Members RecPriv'
                    ExcelData = [PSWinDocumentation.ActiveDirectory]::DomainGroupsPriviligedMembersRecursive
                }
            }
        }
    }
}
$Script:O365SKU = @{"O365_BUSINESS_ESSENTIALS" = "Office 365 Business Essentials"
    "O365_BUSINESS_PREMIUM" = "Office 365 Business Premium"
    "DESKLESSPACK" = "Office 365 (Plan K1)"
    "DESKLESSWOFFPACK" = "Office 365 (Plan K2)"
    "LITEPACK" = "Office 365 (Plan P1)"
    "EXCHANGESTANDARD" = "Office 365 Exchange Online Only"
    "STANDARDPACK" = "Enterprise Plan E1"
    "STANDARDWOFFPACK" = "Office 365 (Plan E2)"
    "ENTERPRISEPACK" = "Enterprise Plan E3"
    "ENTERPRISEPACKLRG" = "Enterprise Plan E3"
    "ENTERPRISEWITHSCAL" = "Enterprise Plan E4"
    "STANDARDPACK_STUDENT" = "Office 365 (Plan A1) for Students"
    "STANDARDWOFFPACKPACK_STUDENT" = "Office 365 (Plan A2) for Students"
    "ENTERPRISEPACK_STUDENT" = "Office 365 (Plan A3) for Students"
    "ENTERPRISEWITHSCAL_STUDENT" = "Office 365 (Plan A4) for Students"
    "STANDARDPACK_FACULTY" = "Office 365 (Plan A1) for Faculty"
    "STANDARDWOFFPACKPACK_FACULTY" = "Office 365 (Plan A2) for Faculty"
    "ENTERPRISEPACK_FACULTY" = "Office 365 (Plan A3) for Faculty"
    "ENTERPRISEWITHSCAL_FACULTY" = "Office 365 (Plan A4) for Faculty"
    "ENTERPRISEPACK_B_PILOT" = "Office 365 (Enterprise Preview)"
    "STANDARD_B_PILOT" = "Office 365 (Small Business Preview)"
    "VISIOCLIENT" = "Visio Pro Online"
    "POWER_BI_ADDON" = "Office 365 Power BI Addon"
    "POWER_BI_INDIVIDUAL_USE" = "Power BI Individual User"
    "POWER_BI_STANDALONE" = "Power BI Stand Alone"
    "POWER_BI_STANDARD" = "Power-BI Standard"
    "PROJECTESSENTIALS" = "Project Lite"
    "PROJECTCLIENT" = "Project Professional"
    "PROJECTONLINE_PLAN_1" = "Project Online"
    "PROJECTONLINE_PLAN_2" = "Project Online and PRO"
    "ProjectPremium" = "Project Online Premium"
    "ECAL_SERVICES" = "ECAL"
    "EMS" = "Enterprise Mobility Suite"
    "RIGHTSMANAGEMENT_ADHOC" = "Windows Azure Rights Management"
    "MCOMEETADV" = "PSTN conferencing"
    "SHAREPOINTSTORAGE" = "SharePoint storage"
    "PLANNERSTANDALONE" = "Planner Standalone"
    "CRMIUR" = "CMRIUR"
    "BI_AZURE_P1" = "Power BI Reporting and Analytics"
    "INTUNE_A" = "Windows Intune Plan A"
    "PROJECTWORKMANAGEMENT" = "Office 365 Planner Preview"
    "ATP_ENTERPRISE" = "Exchange Online Advanced Threat Protection"
    "EQUIVIO_ANALYTICS" = "Office 365 Advanced eDiscovery"
    "AAD_BASIC" = "Azure Active Directory Basic"
    "RMS_S_ENTERPRISE" = "Azure Active Directory Rights Management"
    "AAD_PREMIUM" = "Azure Active Directory Premium"
    "MFA_PREMIUM" = "Azure Multi-Factor Authentication"
    "STANDARDPACK_GOV" = "Microsoft Office 365 (Plan G1) for Government"
    "STANDARDWOFFPACK_GOV" = "Microsoft Office 365 (Plan G2) for Government"
    "ENTERPRISEPACK_GOV" = "Microsoft Office 365 (Plan G3) for Government"
    "ENTERPRISEWITHSCAL_GOV" = "Microsoft Office 365 (Plan G4) for Government"
    "DESKLESSPACK_GOV" = "Microsoft Office 365 (Plan K1) for Government"
    "ESKLESSWOFFPACK_GOV" = "Microsoft Office 365 (Plan K2) for Government"
    "EXCHANGESTANDARD_GOV" = "Microsoft Office 365 Exchange Online (Plan 1) only for Government"
    "EXCHANGEENTERPRISE_GOV" = "Microsoft Office 365 Exchange Online (Plan 2) only for Government"
    "SHAREPOINTDESKLESS_GOV" = "SharePoint Online Kiosk"
    "EXCHANGE_S_DESKLESS_GOV" = "Exchange Kiosk"
    "RMS_S_ENTERPRISE_GOV" = "Windows Azure Active Directory Rights Management"
    "OFFICESUBSCRIPTION_GOV" = "Office ProPlus"
    "MCOSTANDARD_GOV" = "Lync Plan 2G"
    "SHAREPOINTWAC_GOV" = "Office Online for Government"
    "SHAREPOINTENTERPRISE_GOV" = "SharePoint Plan 2G"
    "EXCHANGE_S_ENTERPRISE_GOV" = "Exchange Plan 2G"
    "EXCHANGE_S_ARCHIVE_ADDON_GOV" = "Exchange Online Archiving"
    "EXCHANGE_S_DESKLESS" = "Exchange Online Kiosk"
    "SHAREPOINTDESKLESS" = "SharePoint Online Kiosk"
    "SHAREPOINTWAC" = "Office Online"
    "YAMMER_ENTERPRISE" = "Yammer for the Starship Enterprise"
    "EXCHANGE_L_STANDARD" = "Exchange Online (Plan 1)"
    "MCOLITE" = "Lync Online (Plan 1)"
    "SHAREPOINTLITE" = "SharePoint Online (Plan 1)"
    "OFFICE_PRO_PLUS_SUBSCRIPTION_SMBIZ" = "Office ProPlus"
    "EXCHANGE_S_STANDARD_MIDMARKET" = "Exchange Online (Plan 1)"
    "MCOSTANDARD_MIDMARKET" = "Lync Online (Plan 1)"
    "SHAREPOINTENTERPRISE_MIDMARKET" = "SharePoint Online (Plan 1)"
    "OFFICESUBSCRIPTION" = "Office ProPlus"
    "YAMMER_MIDSIZE" = "Yammer"
    "DYN365_ENTERPRISE_PLAN1" = "Dynamics 365 Customer Engagement Plan Enterprise Edition"
    "ENTERPRISEPREMIUM_NOPSTNCONF" = "Enterprise E5 (without Audio Conferencing)"
    "ENTERPRISEPREMIUM" = "Enterprise E5 (with Audio Conferencing)"
    "MCOSTANDARD" = "Skype for Business Online Standalone Plan 2"
    "PROJECT_MADEIRA_PREVIEW_IW_SKU" = "Dynamics 365 for Financials for IWs"
    "STANDARDWOFFPACK_IW_STUDENT" = "Office 365 Education for Students"
    "STANDARDWOFFPACK_IW_FACULTY" = "Office 365 Education for Faculty"
    "EOP_ENTERPRISE_FACULTY" = "Exchange Online Protection for Faculty"
    "EXCHANGESTANDARD_STUDENT" = "Exchange Online (Plan 1) for Students"
    "OFFICESUBSCRIPTION_STUDENT" = "Office ProPlus Student Benefit"
    "STANDARDWOFFPACK_FACULTY" = "Office 365 Education E1 for Faculty"
    "STANDARDWOFFPACK_STUDENT" = "Microsoft Office 365 (Plan A2) for Students"
    "DYN365_FINANCIALS_BUSINESS_SKU" = "Dynamics 365 for Financials Business Edition"
    "DYN365_FINANCIALS_TEAM_MEMBERS_SKU" = "Dynamics 365 for Team Members Business Edition"
    "FLOW_FREE" = "Microsoft Flow Free"
    "POWER_BI_PRO" = "Power BI Pro"
    "O365_BUSINESS" = "Office 365 Business"
    "DYN365_ENTERPRISE_SALES" = "Dynamics Office 365 Enterprise Sales"
    "RIGHTSMANAGEMENT" = "Rights Management"
    "PROJECTPROFESSIONAL" = "Project Professional"
    "VISIOONLINE_PLAN1" = "Visio Online Plan 1"
    "EXCHANGEENTERPRISE" = "Exchange Online Plan 2"
    "DYN365_ENTERPRISE_P1_IW" = "Dynamics 365 P1 Trial for Information Workers"
    "DYN365_ENTERPRISE_TEAM_MEMBERS" = "Dynamics 365 For Team Members Enterprise Edition"
    "CRMSTANDARD" = "Microsoft Dynamics CRM Online Professional"
    "EXCHANGEARCHIVE_ADDON" = "Exchange Online Archiving For Exchange Online"
    "EXCHANGEDESKLESS" = "Exchange Online Kiosk"
    "SPZA_IW" = "App Connect"
    "WINDOWS_STORE" = "Windows Store for Business"
    "MCOEV" = "Microsoft Phone System"
    "VIDEO_INTEROP" = "Polycom Skype Meeting Video Interop for Skype for Business"
    "SPE_E5" = "Microsoft 365 E5"
    "SPE_E3" = "Microsoft 365 E3"
    "ATA" = "Advanced Threat Analytics"
    "MCOPSTN2" = "Domestic and International Calling Plan"
    "FLOW_P1" = "Microsoft Flow Plan 1"
    "FLOW_P2" = "Microsoft Flow Plan 2"
    "POWERAPPS_VIRAL" = "Microsoft PowerApps Plan 2"
}
$Script:Services = @{OnPremises = [ordered] @{Credentials = [ordered] @{Username = ''
            Password = ''
            PasswordAsSecure = $true
            PasswordFromFile = $true
        }
        ActiveDirectory = [ordered] @{Use = $true
            OnlineMode = $true
            Import = @{Use = $false
                From = 'Folder'
                Path = "$Env:USERPROFILE\Desktop\PSWinDocumentation"
            }
            Export = @{Use = $false
                To = 'Folder'
                FolderPath = "$Env:USERPROFILE\Desktop\PSWinDocumentation"
                FilePath = "$Env:USERPROFILE\Desktop\PSWinDocumentation\PSWinDocumentation.xml"
            }
            Prefix = ''
            SessionName = 'ActiveDirectory'
            PasswordTests = @{Use = $false
                PasswordFilePathClearText = 'C:\Support\GitHub\PSWinDocumentation\Ignore\Passwords.txt'
                UseHashDB = $false
                PasswordFilePathHash = 'C:\Support\GitHub\PSWinDocumentation\Ignore\Passwords-Hashes.txt'
            }
        }
    }
}
$Script:ServicesAWS = @{Amazon = [ordered] @{Credentials = [ordered] @{AccessKey = ''
            SecretKey = ''
            Region = 'eu-west-1'
        }
        AWS = [ordered] @{Use = $true
            OnlineMode = $true
            Import = @{Use = $false
                From = 'Folder'
                Path = "$Env:USERPROFILE\Desktop\PSWinDocumentation"
            }
            Export = @{Use = $false
                To = 'Folder'
                FolderPath = "$Env:USERPROFILE\Desktop\PSWinDocumentation"
                FilePath = "$Env:USERPROFILE\Desktop\PSWinDocumentation\PSWinDocumentation.xml"
            }
            Prefix = ''
            SessionName = 'AWS'
        }
    }
}
$Script:ServicesO365 = @{Office365 = [ordered] @{Credentials = [ordered] @{Username = 'przemyslaw.klys@evotec.pl'
            Password = 'C:\Support\Important\Password-O365-Evotec.txt'
            PasswordAsSecure = $true
            PasswordFromFile = $true
        }
        Azure = [ordered] @{Use = $true
            OnlineMode = $true
            Import = @{Use = $false
                From = 'Folder'
                Path = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365Azure"
            }
            Export = @{Use = $false
                To = 'Folder'
                FolderPath = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365Azure"
                FilePath = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365Azure\PSWinDocumentation.xml"
            }
            ExportXML = $false
            FilePathXML = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365Azure.xml"
            Prefix = ''
            SessionName = 'O365Azure'
        }
        AzureAD = [ordered] @{Use = $true
            OnlineMode = $true
            Import = @{Use = $false
                From = 'Folder'
                Path = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365AzureAD"
            }
            Export = @{Use = $false
                To = 'Folder'
                FolderPath = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365AzureAD"
                FilePath = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365AzureAD\PSWinDocumentation.xml"
            }
            ExportXML = $false
            FilePathXML = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365AzureAD.xml"
            SessionName = 'O365AzureAD'
            Prefix = ''
        }
        ExchangeOnline = [ordered] @{Use = $true
            OnlineMode = $true
            Import = @{Use = $false
                From = 'Folder'
                Path = "$Env:USERPROFILE\Desktop\PSWinDocumentation"
            }
            Export = @{Use = $false
                To = 'Folder'
                FolderPath = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365ExchangeOnline"
                FilePath = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365ExchangeOnline\PSWinDocumentation.xml"
            }
            ExportXML = $false
            FilePathXML = "$Env:USERPROFILE\Desktop\PSWinDocumentation-O365ExchangeOnline.xml"
            Authentication = 'Basic'
            ConnectionURI = 'https://outlook.office365.com/powershell-liveid/'
            Prefix = 'O365'
            SessionName = 'O365Exchange'
        }
    }
}
$script:WriteParameters = @{ShowTime = $true
    LogFile = ""
    TimeFormat = "yyyy-MM-dd HH:mm:ss"
}
function Start-Documentation {
    [CmdletBinding()]
    param ([System.Collections.IDictionary] $Document)
    $TimeTotal = [System.Diagnostics.Stopwatch]::StartNew()
    Test-Configuration -Document $Document
    if ($Document.DocumentAD.Enable) {
        if ($null -eq $Document.DocumentAD.Services) {
            $Document.DocumentAD.Services = ($Script:Services).Clone()
            $Document.DocumentAD.Services.OnPremises.ActiveDirectory.PasswordTests = @{Use = $Document.DocumentAD.Configuration.PasswordTests.Use
                PasswordFilePathClearText = $Document.DocumentAD.Configuration.PasswordTests.PasswordFilePathClearText
                UseHashDB = $Document.DocumentAD.Configuration.PasswordTests.UseHashDB
                PasswordFilePathHash = $Document.DocumentAD.Configuration.PasswordTests.PasswordFilePathHash
            }
        }
        Start-DocumentationAD -Document $Document
    }
    if ($Document.DocumentAWS.Enable) {
        if ($null -eq $Document.DocumentAWS.Services) {
            $Document.DocumentAWS.Services = ($Script:ServicesAWS).Clone()
            $Document.DocumentAWS.Services.Amazon.Credentials.AccessKey = $Document.DocumentAWS.Configuration.AWSAccessKey
            $Document.DocumentAWS.Services.Amazon.Credentials.SecretKey = $Document.DocumentAWS.Configuration.AWSSecretKey
            $Document.DocumentAWS.Services.Amazon.Credentials.Region = $Document.DocumentAWS.Configuration.AWSRegion
        }
        Start-DocumentationAWS -Document $Document
    }
    if ($Document.DocumentOffice365.Enable) {
        if ($null -eq $Document.DocumentOffice365.Services) {
            $Document.DocumentOffice365.Services = ($Script:ServicesO365).Clone()
            $Document.DocumentOffice365.Services.Office365.Credentials = [ordered] @{Username = $Document.DocumentOffice365.Configuration.O365Username
                Password = $Document.DocumentOffice365.Configuration.O365Password
                PasswordAsSecure = $Document.DocumentOffice365.Configuration.O365PasswordAsSecure
                PasswordFromFile = $Document.DocumentOffice365.Configuration.O365PasswordFromFile
            }
            $Document.DocumentOffice365.Services.Office365.Azure.Use = $Document.DocumentOffice365.Configuration.O365AzureADUse
            $Document.DocumentOffice365.Services.Office365.Azure.Prefix = ''
            $Document.DocumentOffice365.Services.Office365.Azure.SessionName = 'O365Azure'
            $Document.DocumentOffice365.Services.Office365.AzureAD.Use = $Document.DocumentOffice365.Configuration.O365AzureADUse
            $Document.DocumentOffice365.Services.Office365.AzureAD.SessionName = 'O365AzureAD'
            $Document.DocumentOffice365.Services.Office365.AzureAD.Prefix = ''
            $Document.DocumentOffice365.Services.Office365.ExchangeOnline.Use = $Document.DocumentOffice365.Configuration.O365ExchangeUse
            $Document.DocumentOffice365.Services.Office365.ExchangeOnline.Authentication = $Document.DocumentOffice365.Configuration.O365ExchangeAuthentication
            $Document.DocumentOffice365.Services.Office365.ExchangeOnline.ConnectionURI = $Document.DocumentOffice365.Configuration.O365ExchangeURI
            $Document.DocumentOffice365.Services.Office365.ExchangeOnline.Prefix = ''
            $Document.DocumentOffice365.Services.Office365.ExchangeOnline.SessionName = $Document.DocumentOffice365.Configuration.O365ExchangeSessionName
        }
        Start-DocumentationO365 -Document $Document
    }
    $TimeTotal.Stop()
    Write-Verbose "Time total: $($TimeTotal.Elapsed)"
}
function Start-DocumentationAD {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Document)
    $TimeDataOnly = [System.Diagnostics.Stopwatch]::StartNew()
    $TypesRequired = Get-TypesRequired -Sections $Document.DocumentAD.Sections.SectionForest, $Document.DocumentAD.Sections.SectionDomain
    $DataInformationAD = Get-WinServiceData -Credentials $Document.DocumentAD.Services.OnPremises.Credentials -Service $Document.DocumentAD.Services.OnPremises.ActiveDirectory -TypesRequired $TypesRequired -Type 'ActiveDirectory'
    $TimeDataOnly.Stop()
    $TimeDocuments = [System.Diagnostics.Stopwatch]::StartNew()
    if ($Document.DocumentAD.ExportExcel -or $Document.DocumentAD.ExportWord -or $Document.DocumentAD.ExportSQL) {
        if ($Document.DocumentAD.ExportWord) { $WordDocument = Get-DocumentPath -Document $Document -FinalDocumentLocation $Document.DocumentAD.FilePathWord }
        if ($Document.DocumentAD.ExportExcel) { $ExcelDocument = New-ExcelDocument }
        $ADSectionsForest = Get-ObjectKeys -Object $Document.DocumentAD.Sections.SectionForest
        $ADSectionsDomain = Get-ObjectKeys -Object $Document.DocumentAD.Sections.SectionDomain
        foreach ($DataInformation in $DataInformationAD) {
            foreach ($Section in $ADSectionsForest) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentAD.Sections.SectionForest.$Section -Object $DataInformationAD -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAD.ExportSQL }
            foreach ($Domain in $DataInformationAD.FoundDomains.Keys) { foreach ($Section in $ADSectionsDomain) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentAD.Sections.SectionDomain.$Section -Object $DataInformationAD -Domain $Domain -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAD.ExportSQL } }
        }
        if ($Document.DocumentAD.ExportWord) { $FilePath = Save-WordDocument -WordDocument $WordDocument -Language $Document.Configuration.Prettify.Language -FilePath $Document.DocumentAD.FilePathWord -Supress $True -OpenDocument:$Document.Configuration.Options.OpenDocument }
        if ($Document.DocumentAD.ExportExcel) { $ExcelData = Save-ExcelDocument -ExcelDocument $ExcelDocument -FilePath $Document.DocumentAD.FilePathExcel -OpenWorkBook:$Document.Configuration.Options.OpenExcel }
    }
    $TimeDocuments.Stop()
    Write-Verbose "Time to gather data: $($TimeDataOnly.Elapsed)"
    Write-Verbose "Time to create documents: $($TimeDocuments.Elapsed)"
}
function Start-DocumentationAWS {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Document)
    $TimeDataOnly = [System.Diagnostics.Stopwatch]::StartNew()
    $DataSections = Get-ObjectKeys -Object $Document.DocumentAWS.Sections
    $TypesRequired = Get-TypesRequired -Sections $Document.DocumentAWS.Sections
    $DataInformation = Get-WinServiceData -Credentials $Document.DocumentAWS.Services.Amazon.Credentials -Service $Document.DocumentAWS.Services.Amazon.AWS -TypesRequired $TypesRequired -Type 'AWS'
    $TimeDataOnly.Stop()
    $TimeDocuments = [System.Diagnostics.Stopwatch]::StartNew()
    if ($DataInformation.Count -gt 0) {
        if ($Document.DocumentAWS.ExportWord) { $WordDocument = Get-DocumentPath -Document $Document -FinalDocumentLocation $Document.DocumentAWS.FilePathWord }
        if ($Document.DocumentAWS.ExportExcel) { $ExcelDocument = New-ExcelDocument }
        foreach ($Section in $DataSections) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentAWS.Sections.$Section -Forest $DataInformation -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAWS.ExportSQL }
        if ($Document.DocumentAWS.ExportWord) { $FilePath = Save-WordDocument -WordDocument $WordDocument -Language $Document.Configuration.Prettify.Language -FilePath $Document.DocumentAWS.FilePathWord -Supress $True -OpenDocument:$Document.Configuration.Options.OpenDocument }
        if ($Document.DocumentAWS.ExportExcel) { $ExcelData = Save-ExcelDocument -ExcelDocument $ExcelDocument -FilePath $Document.DocumentAWS.FilePathExcel -OpenWorkBook:$Document.Configuration.Options.OpenExcel }
    } else { Write-Warning "There was no data to process AWS documentation. Check configuration." }
    $TimeDocuments.Stop()
    Write-Verbose "Time to gather data: $($TimeDataOnly.Elapsed)"
    Write-Verbose "Time to create documents: $($TimeDocuments.Elapsed)"
}
function Start-DocumentationExchange {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Document)
    $DataSections = Get-ObjectKeys -Object $Document.DocumentExchange.Sections
    $TypesRequired = Get-TypesRequired -Sections $Document.DocumentExchange.Sections
    $TimeDataOnly = [System.Diagnostics.Stopwatch]::StartNew()
    $DataInformation = Get-WinServiceData -Credentials $Document.DocumentExchange.Services.OnPremises.Credentials -Service $Document.DocumentExchange.Services.OnPremises.Exchange -TypesRequired $TypesRequired -Type 'Exchange'
    $TimeDataOnly.Stop()
    $TimeDocuments = [System.Diagnostics.Stopwatch]::StartNew()
    if ($DataInformation.Count -gt 0) {
        if ($Document.DocumentExchange.ExportWord) { $WordDocument = Get-DocumentPath -Document $Document -FinalDocumentLocation $Document.DocumentExchange.FilePathWord }
        if ($Document.DocumentExchange.ExportExcel) { $ExcelDocument = New-ExcelDocument }
        foreach ($Section in $DataSections) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentExchange.Sections.$Section -Forest $DataInformation -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentExchange.ExportSQL }
        if ($Document.DocumentExchange.ExportWord) { $FilePath = Save-WordDocument -WordDocument $WordDocument -Language $Document.Configuration.Prettify.Language -FilePath $Document.DocumentExchange.FilePathWord -Supress $True -OpenDocument:$Document.Configuration.Options.OpenDocument }
        if ($Document.DocumentExchange.ExportExcel) { $ExcelData = Save-ExcelDocument -ExcelDocument $ExcelDocument -FilePath $Document.DocumentExchange.FilePathExcel -OpenWorkBook:$Document.Configuration.Options.OpenExcel }
    } else { Write-Warning "There was no data to process Exchange documentation. Check configuration." }
    $TimeDocuments.Stop()
    Write-Verbose "Time to gather data: $($TimeDataOnly.Elapsed)"
    Write-Verbose "Time to create documents: $($TimeDocuments.Elapsed)"
}
function Start-DocumentationO365 {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Document)
    $TypesRequired = Get-TypesRequired -Sections $Document.DocumentOffice365.Sections
    $DataSections = Get-ObjectKeys -Object $Document.DocumentOffice365.Sections
    $TimeDataOnly = [System.Diagnostics.Stopwatch]::StartNew()
    $DataAzure = Get-WinServiceData -Credentials $Document.DocumentOffice365.Services.Office365.Credentials -Service $Document.DocumentOffice365.Services.Office365.Azure -TypesRequired $TypesRequired -Type 'Azure'
    $DataExchangeOnline = Get-WinServiceData -Credentials $Document.DocumentOffice365.Services.Office365.Credentials -Service $Document.DocumentOffice365.Services.Office365.ExchangeOnline -TypesRequired $TypesRequired -Type 'ExchangeOnline'
    $DataInformation = [ordered]@{ }
    if ($null -ne $DataAzure -and $DataExchangeOnline.Count -gt 0) { $DataInformation += $DataAzure }
    if ($null -ne $DataExchangeOnline -and $DataExchangeOnline.Count -gt 0) { $DataInformation += $DataExchangeOnline }
    $TimeDataOnly.Stop()
    $TimeDocuments = [System.Diagnostics.Stopwatch]::StartNew()
    if ($DataInformation.Count -gt 0) {
        if ($Document.DocumentOffice365.ExportWord) { $WordDocument = Get-DocumentPath -Document $Document -FinalDocumentLocation $Document.DocumentOffice365.FilePathWord }
        if ($Document.DocumentOffice365.ExportExcel) { $ExcelDocument = New-ExcelDocument }
        foreach ($Section in $DataSections) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentOffice365.Sections.$Section -Forest $DataInformation -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentOffice365.ExportSQL }
        if ($Document.DocumentOffice365.ExportWord) { $FilePath = Save-WordDocument -WordDocument $WordDocument -Language $Document.Configuration.Prettify.Language -FilePath $Document.DocumentOffice365.FilePathWord -Supress $True -OpenDocument:$Document.Configuration.Options.OpenDocument }
        if ($Document.DocumentOffice365.ExportExcel) { $ExcelData = Save-ExcelDocument -ExcelDocument $ExcelDocument -FilePath $Document.DocumentOffice365.FilePathExcel -OpenWorkBook:$Document.Configuration.Options.OpenExcel }
    } else { Write-Warning "There was no data to process Office 365 documentation. Check configuration." }
    $TimeDocuments.Stop()
    Write-Verbose "Time to gather data: $($TimeDataOnly.Elapsed)"
    Write-Verbose "Time to create documents: $($TimeDocuments.Elapsed)"
}
function Test-Configuration {
    [CmdletBinding()]
    param ([System.Collections.IDictionary] $Document)
    [int] $ErrorCount = 0
    $Script:WriteParameters = $Document.Configuration.DisplayConsole
    $Keys = Get-ObjectKeys -Object $Document -Ignore 'Configuration'
    foreach ($Key in $Keys) {
        $ErrorCount += Test-File -File $Document.$Key.FilePathWord -FileName 'FilePathWord' -Skip:(-not $Document.$Key.ExportWord)
        $ErrorCount += Test-File -File $Document.$Key.FilePathExcel -FileName 'FilePathExcel' -Skip:(-not $Document.$Key.ExportExcel)
    }
    if ($ErrorCount -ne 0) { Exit }
}
function Test-File {
    [CmdletBinding()]
    param ([string] $File,
        [string] $FileName,
        [switch] $Require,
        [switch] $Skip)
    [int] $ErrorCount = 0
    if ($Skip) { return $ErrorCount }
    if ($File -ne '') {
        if ($Require) {
            if (Test-Path $File) { return $ErrorCount } else {
                Write-Color @Script:WriteParameters '[e] ', $FileName, " doesn't exists (", $File, "). It's required if you want to use this feature." -Color Red, Yellow, Yellow, White
                $ErrorCount++
            }
        }
    } else {
        $ErrorCount++
        Write-Color @Script:WriteParameters '[e] ', $FileName, " was empty. It's required if you want to use this feature." -Color Red, Yellow, White
    }
    return $ErrorCount
}
Export-ModuleMember -Function @('Start-Documentation') -Alias @()