PSWinDocumentation.psm1
function Add-ToArrayAdvanced { [CmdletBinding()] param([System.Collections.ArrayList] $List, [Object] $Element, [switch] $SkipNull, [switch] $RequireUnique, [switch] $FullComparison, [switch] $Merge) if ($SkipNull -and $null -eq $Element) { return } if ($RequireUnique) { if ($FullComparison) { foreach ($ListElement in $List) { if ($ListElement -eq $Element) { $TypeLeft = Get-ObjectType -Object $ListElement $TypeRight = Get-ObjectType -Object $Element if ($TypeLeft.ObjectTypeName -eq $TypeRight.ObjectTypeName) { return } } } } else { if ($List -contains $Element) { return } } } if ($Merge) { [void] $List.AddRange($Element) } else { [void] $List.Add($Element) } } function Connect-WinService { [CmdletBinding()] param ([Object] $Credentials, [Object] $Service, [string] $Type, [switch] $Output) $Object = @() if ($Service.Use) { switch ($Type) { 'ActiveDirectory' { $CheckAvailabilityCommandsAD = Test-AvailabilityCommands -Commands 'Get-ADForest', 'Get-ADDomain', 'Get-ADRootDSE', 'Get-ADGroup', 'Get-ADUser', 'Get-ADComputer' if ($CheckAvailabilityCommandsAD -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Commands unavailable.' } return $Object } else { Write-Warning "Active Directory documentation can't be started as commands are unavailable. Check if you have Active Directory module available (part of RSAT) and try again." return } } else { } if (-not (Test-ForestConnectivity)) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'No connectivity to forest/domain.' } return $Object } else { Write-Warning 'Active Directory - No connectivity to forest/domain.' return } } else { } if ($Output) { $Object += @{Status = $true; Output = $Service.SessionName; Extended = 'Connection Established.' } return $Object } } 'Azure' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinAzure -SessionName $Service.SessionName -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Output return $OutputCommand } 'AzureAD' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinAzureAD -SessionName $Service.SessionName -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Output return $OutputCommand } 'Exchange' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Document.DocumentExchange.Configuration -AllowEmptyKeys 'Username', 'Password' if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinExchange -SessionName $Service.SessionName -ConnectionURI $Service.ConnectionURI -Authentication $Service.Authentication -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Prefix $Service.Prefix -Output return $OutputCommand } 'ExchangeOnline' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinExchange -SessionName $Service.SessionName -ConnectionURI $Service.ConnectionURI -Authentication $Service.Authentication -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Prefix $Service.Prefix -Output return $OutputCommand } 'SecurityCompliance' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinSecurityCompliance -SessionName $Service.SessionName -ConnectionURI $Service.ConnectionURI -Authentication $Service.Authentication -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Prefix $Service.Prefix -Output return $OutputCommand } 'SharePointOnline' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinSharePoint -SessionName $Service.SessionName -ConnectionURI $Service.ConnectionURI -Authentication $Service.Authentication -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Prefix $Service.Prefix -Output return $OutputCommand } 'SkypeOnline' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinSkype -SessionName $Service.SessionName -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Prefix $Service.Prefix -Output return $OutputCommand } 'MicrosoftTeams' { $CheckCredentials = Test-ConfigurationCredentials -Configuration $Credentials if ($CheckCredentials.Status -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $Service.SessionName; Extended = 'Credentials configuration is wrong.' } return $Object } else { return } } $OutputCommand = Connect-WinTeams -SessionName $Service.SessionName -Username $Credentials.Username -Password $Credentials.Password -AsSecure:$Credentials.PasswordAsSecure -FromFile:$Credentials.PasswordFromFile -MultiFactorAuthentication:$Credentials.MultiFactorAuthentication -Output return $OutputCommand } } } } function Convert-KeyToKeyValue { [CmdletBinding()] param ([object] $Object) $NewHash = [ordered] @{ } foreach ($O in $Object.Keys) { $KeyName = "$O ($($Object.$O))" $KeyValue = $Object.$O $NewHash.$KeyName = $KeyValue } return $NewHash } function Convert-TwoArraysIntoOne { [CmdletBinding()] param ($Object, $ObjectToAdd) $Value = for ($i = 0; $i -lt $Object.Count; $i++) { "$($Object[$i]) ($($ObjectToAdd[$i]))" } return $Value } function Get-ObjectKeys { param([object] $Object, [string] $Ignore) $Data = $Object.Keys | where { $_ -notcontains $Ignore } return $Data } function Get-ObjectType { [CmdletBinding()] param([Object] $Object, [string] $ObjectName = 'Random Object Name', [switch] $VerboseOnly) $ReturnData = [ordered] @{ } $ReturnData.ObjectName = $ObjectName if ($Object -ne $null) { try { $TypeInformation = $Object.GetType() $ReturnData.ObjectTypeName = $TypeInformation.Name $ReturnData.ObjectTypeBaseName = $TypeInformation.BaseType $ReturnData.SystemType = $TypeInformation.UnderlyingSystemType } catch { $ReturnData.ObjectTypeName = '' $ReturnData.ObjectTypeBaseName = '' $ReturnData.SystemType = '' } try { $TypeInformationInsider = $Object[0].GetType() $ReturnData.ObjectTypeInsiderName = $TypeInformationInsider.Name $ReturnData.ObjectTypeInsiderBaseName = $TypeInformationInsider.BaseType $ReturnData.SystemTypeInsider = $TypeInformationInsider.UnderlyingSystemType } catch { $ReturnData.ObjectTypeInsiderName = '' $ReturnData.ObjectTypeInsiderBaseName = '' $ReturnData.SystemTypeInsider = '' } } else { $ReturnData.ObjectTypeName = '' $ReturnData.ObjectTypeBaseName = '' $ReturnData.SystemType = '' $ReturnData.ObjectTypeInsiderName = '' $ReturnData.ObjectTypeInsiderBaseName = '' $ReturnData.SystemTypeInsider = '' } Write-Verbose "Get-ObjectType - ObjectTypeName: $($ReturnData.ObjectTypeName)" Write-Verbose "Get-ObjectType - ObjectTypeBaseName: $($ReturnData.ObjectTypeBaseName)" Write-Verbose "Get-ObjectType - SystemType: $($ReturnData.SystemType)" Write-Verbose "Get-ObjectType - ObjectTypeInsiderName: $($ReturnData.ObjectTypeInsiderName)" Write-Verbose "Get-ObjectType - ObjectTypeInsiderBaseName: $($ReturnData.ObjectTypeInsiderBaseName)" Write-Verbose "Get-ObjectType - SystemTypeInsider: $($ReturnData.SystemTypeInsider)" if ($VerboseOnly) { return } else { return Format-TransposeTable -Object $ReturnData } } function New-ArrayList { [CmdletBinding()] param() $List = [System.Collections.ArrayList]::new() return , $List } function Send-SqlInsert { [CmdletBinding()] param([Array] $Object, [System.Collections.IDictionary] $SqlSettings) if ($SqlSettings.SqlTableTranspose) { $Object = Format-TransposeTable -Object $Object } $SqlTable = Get-SqlQueryColumnInformation -SqlServer $SqlSettings.SqlServer -SqlDatabase $SqlSettings.SqlDatabase -Table $SqlSettings.SqlTable $PropertiesFromAllObject = Get-ObjectPropertiesAdvanced -Object $Object -AddProperties 'AddedWhen', 'AddedWho' $PropertiesFromTable = $SqlTable.Column_name if ($SqlTable -eq $null) { if ($SqlSettings.SqlTableCreate) { Write-Verbose "Send-SqlInsert - SqlTable doesn't exists, table creation is allowed, mapping will be done either on properties from object or from TableMapping defined in config" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject $CreateTableSQL = New-SqlQueryCreateTable -SqlSettings $SqlSettings -TableMapping $TableMapping } else { Write-Verbose "Send-SqlInsert - SqlTable doesn't exists, no table creation is allowed. Terminating" return "Error occured: SQL Table doesn't exists. SqlTableCreate option is disabled" } } else { if ($SqlSettings.SqlTableAlterIfNeeded) { if ($SqlSettings.SqlTableMapping) { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is allowed, but SqlTableMapping is already defined" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject } else { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is allowed, and SqlTableMapping is not defined" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject $AlterTableSQL = New-SqlQueryAlterTable -SqlSettings $SqlSettings -TableMapping $TableMapping -ExistingColumns $SqlTable.Column_name } } else { if ($SqlSettings.SqlTableMapping) { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is not allowed, SqlTableMaping is already defined" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject } else { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is not allowed, SqlTableMaping is not defined, using SqlTable Columns" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromTable -BasedOnSqlTable } } } $Queries = @(if ($CreateTableSQL) { foreach ($Sql in $CreateTableSQL) { $Sql } } if ($AlterTableSQL) { foreach ($Sql in $AlterTableSQL) { $Sql } } $SqlQueries = New-SqlQuery -Object $Object -SqlSettings $SqlSettings -TableMapping $TableMapping foreach ($Sql in $SqlQueries) { $Sql }) $ReturnData = foreach ($Query in $Queries) { try { if ($Query) { $Query Invoke-DbaQuery -SqlInstance "$($SqlSettings.SqlServer)" -Database "$($SqlSettings.SqlDatabase)" -Query $Query -ErrorAction Stop } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " "Error occured (Send-SqlInsert): $ErrorMessage" } } return $ReturnData } function Start-TimeLog { [CmdletBinding()] param() [System.Diagnostics.Stopwatch]::StartNew() } function Stop-TimeLog { [CmdletBinding()] param ([Parameter(ValueFromPipeline = $true)][System.Diagnostics.Stopwatch] $Time, [ValidateSet('OneLiner', 'Array')][string] $Option = 'OneLiner', [switch] $Continue) Begin { } Process { if ($Option -eq 'Array') { $TimeToExecute = "$($Time.Elapsed.Days) days", "$($Time.Elapsed.Hours) hours", "$($Time.Elapsed.Minutes) minutes", "$($Time.Elapsed.Seconds) seconds", "$($Time.Elapsed.Milliseconds) milliseconds" } else { $TimeToExecute = "$($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds" } } End { if (-not $Continue) { $Time.Stop() } return $TimeToExecute } } function Write-Color { <# .SYNOPSIS Write-Color is a wrapper around Write-Host. It provides: - Easy manipulation of colors, - Logging output to file (log) - Nice formatting options out of the box. .DESCRIPTION Author: przemyslaw.klys at evotec.pl Project website: https://evotec.xyz/hub/scripts/write-color-ps1/ Project support: https://github.com/EvotecIT/PSWriteColor Original idea: Josh (https://stackoverflow.com/users/81769/josh) .EXAMPLE Write-Color -Text "Red ", "Green ", "Yellow " -Color Red,Green,Yellow .EXAMPLE Write-Color -Text "This is text in Green ", "followed by red ", "and then we have Magenta... ", "isn't it fun? ", "Here goes DarkCyan" -Color Green,Red,Magenta,White,DarkCyan .EXAMPLE Write-Color -Text "This is text in Green ", "followed by red ", "and then we have Magenta... ", "isn't it fun? ", "Here goes DarkCyan" -Color Green,Red,Magenta,White,DarkCyan -StartTab 3 -LinesBefore 1 -LinesAfter 1 .EXAMPLE Write-Color "1. ", "Option 1" -Color Yellow, Green Write-Color "2. ", "Option 2" -Color Yellow, Green Write-Color "3. ", "Option 3" -Color Yellow, Green Write-Color "4. ", "Option 4" -Color Yellow, Green Write-Color "9. ", "Press 9 to exit" -Color Yellow, Gray -LinesBefore 1 .EXAMPLE Write-Color -LinesBefore 2 -Text "This little ","message is ", "written to log ", "file as well." ` -Color Yellow, White, Green, Red, Red -LogFile "C:\testing.txt" -TimeFormat "yyyy-MM-dd HH:mm:ss" Write-Color -Text "This can get ","handy if ", "want to display things, and log actions to file ", "at the same time." ` -Color Yellow, White, Green, Red, Red -LogFile "C:\testing.txt" .EXAMPLE # Added in 0.5 Write-Color -T "My text", " is ", "all colorful" -C Yellow, Red, Green -B Green, Green, Yellow wc -t "my text" -c yellow -b green wc -text "my text" -c red .NOTES CHANGELOG Version 0.5 (25th April 2018) ----------- - Added backgroundcolor - Added aliases T/B/C to shorter code - Added alias to function (can be used with "WC") - Fixes to module publishing Version 0.4.0-0.4.9 (25th April 2018) ------------------- - Published as module - Fixed small issues Version 0.31 (20th April 2018) ------------ - Added Try/Catch for Write-Output (might need some additional work) - Small change to parameters Version 0.3 (9th April 2018) ----------- - Added -ShowTime - Added -NoNewLine - Added function description - Changed some formatting Version 0.2 ----------- - Added logging to file Version 0.1 ----------- - First draft Additional Notes: - TimeFormat https://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx #> [alias('Write-Colour')] [CmdletBinding()] param ([alias ('T')] [String[]]$Text, [alias ('C', 'ForegroundColor', 'FGC')] [ConsoleColor[]]$Color = [ConsoleColor]::White, [alias ('B', 'BGC')] [ConsoleColor[]]$BackGroundColor = $null, [alias ('Indent')][int] $StartTab = 0, [int] $LinesBefore = 0, [int] $LinesAfter = 0, [int] $StartSpaces = 0, [alias ('L')] [string] $LogFile = '', [Alias('DateFormat', 'TimeFormat')][string] $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss', [alias ('LogTimeStamp')][bool] $LogTime = $true, [ValidateSet('unknown', 'string', 'unicode', 'bigendianunicode', 'utf8', 'utf7', 'utf32', 'ascii', 'default', 'oem')][string]$Encoding = 'Unicode', [switch] $ShowTime, [switch] $NoNewLine) $DefaultColor = $Color[0] if ($null -ne $BackGroundColor -and $BackGroundColor.Count -ne $Color.Count) { Write-Error "Colors, BackGroundColors parameters count doesn't match. Terminated."; return } if ($LinesBefore -ne 0) { for ($i = 0; $i -lt $LinesBefore; $i++) { Write-Host -Object "`n" -NoNewline } } if ($StartTab -ne 0) { for ($i = 0; $i -lt $StartTab; $i++) { Write-Host -Object "`t" -NoNewLine } } if ($StartSpaces -ne 0) { for ($i = 0; $i -lt $StartSpaces; $i++) { Write-Host -Object ' ' -NoNewLine } } if ($ShowTime) { Write-Host -Object "[$([datetime]::Now.ToString($DateTimeFormat))]" -NoNewline } if ($Text.Count -ne 0) { if ($Color.Count -ge $Text.Count) { if ($null -eq $BackGroundColor) { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -NoNewLine } } else { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackGroundColor[$i] -NoNewLine } } } else { if ($null -eq $BackGroundColor) { for ($i = 0; $i -lt $Color.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -NoNewLine } for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $DefaultColor -NoNewLine } } else { for ($i = 0; $i -lt $Color.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackGroundColor[$i] -NoNewLine } for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $BackGroundColor[0] -NoNewLine } } } } if ($NoNewLine -eq $true) { Write-Host -NoNewline } else { Write-Host } if ($LinesAfter -ne 0) { for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host -Object "`n" -NoNewline } } if ($Text.Count -ne 0 -and $LogFile -ne "") { $TextToFile = "" for ($i = 0; $i -lt $Text.Length; $i++) { $TextToFile += $Text[$i] } try { if ($LogTime) { Write-Output -InputObject "[$([datetime]::Now.ToString($DateTimeFormat))]$TextToFile" | Out-File -FilePath $LogFile -Encoding $Encoding -Append } else { Write-Output -InputObject "$TextToFile" | Out-File -FilePath $LogFile -Encoding $Encoding -Append } } catch { $_.Exception } } } function Clear-DataInformation { [CmdletBinding()] param([System.Collections.IDictionary] $Data, [Array] $TypesRequired, [switch] $DontRemoveSupportData, [switch] $DontRemoveEmpty) foreach ($Domain in $Data.FoundDomains.Keys) { $RemoveDomainKeys = foreach ($Key in $Data.FoundDomains.$Domain.Keys) { if ($null -eq $Data.FoundDomains.$Domain.$Key) { if (-not $DontRemoveEmpty) { $Key } continue } if ($Key -notin $TypesRequired -and $DontRemoveSupportData -eq $false) { $Key } } foreach ($Key in $RemoveDomainKeys) { $Data.FoundDomains.$Domain.Remove($Key) } } $RemoveDomains = foreach ($Domain in $Data.FoundDomains.Keys) { if ($Data.FoundDomains.$Domain.Count -eq 0) { $Domain } } foreach ($Domain in $RemoveDomains) { $Data.FoundDomains.Remove($Domain) } if ($Data.FoundDomains.Count -eq 0) { $Data.Remove('FoundDomains') } $RemoveKeys = foreach ($Key in $Data.Keys) { if ($Key -eq 'FoundDomains') { continue } if ($null -eq $Data.$Key) { if (-not $DontRemoveEmpty) { $Key } continue } if ($Key -notin $TypesRequired -and $DontRemoveSupportData -eq $false) { $Key } } foreach ($Key in $RemoveKeys) { $Data.Remove($Key) } } function Connect-WinAzure { [CmdletBinding()] param([string] $SessionName = 'Azure MSOL', [string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [switch] $Output) if (-not $MultiFactorAuthentication) { Write-Verbose "Connect-WinAzure - Running connectivity without MFA" $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } try { Connect-MsolService -Credential $Credentials -ErrorAction Stop $Connected = $true } catch { $Connected = $false $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { return @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } } else { Write-Warning "Connect-WinAzure - Failed with error message: $ErrorMessage" return } } if ($Connected -eq $false) { if ($Output) { return @{Status = $false; Output = $SessionName; Extended = 'Connection Failed.' } } else { return } } else { if ($Output) { return @{Status = $true; Output = $SessionName; Extended = 'Connection Established.' } } else { return } } } function Connect-WinAzureAD { [CmdletBinding()] param([string] $SessionName = 'Azure AD', [string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [switch] $Output) if (-not $MultiFactorAuthentication) { Write-Verbose "Connect-WinAzureAD - Running connectivity without MFA" $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } try { $Session = Connect-AzureAD -Credential $Credentials -ErrorAction Stop } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { return @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } } else { Write-Warning "Connect-WinAzureAD - Failed with error message: $ErrorMessage" return } } if (-not $Session) { if ($Output) { return @{Status = $false; Output = $SessionName; Extended = 'Connection Failed.' } } else { return } } if ($Output) { return @{Status = $true; Output = $SessionName; Extended = 'Connection Established.' } } } function Connect-WinExchange { [CmdletBinding()] param([string] $SessionName = 'Exchange', [string] $ConnectionURI, [ValidateSet("Basic", "Kerberos")][String] $Authentication = 'Kerberos', [alias('UserPrincipalName')][string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [string] $Prefix, [switch] $Output) $Object = @() if ($MultiFactorAuthentication) { Write-Verbose 'Connect-WinExchange - Using MFA option' try { Import-Module -ErrorAction Stop $((Get-ChildItem -Path $($env:LOCALAPPDATA + "\Apps\2.0\") -Filter Microsoft.Exchange.Management.ExoPowershellModule.dll -Recurse).FullName | Where-Object { $_ -notmatch "_none_" } | Select-Object -First 1) } catch { if ($Output) { return @{Status = $false; Output = $SessionName; Extended = "Connection failed. Couldn't find Exchange Online module to load." } } else { Write-Warning -Message "Connect-WinExchange - Connection failed. Couldn't find Exchange Online module to load." return } } } else { Write-Verbose 'Connect-WinExchange - Using Non-MFA option' if ($Authentication -ne 'Kerberos') { $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } else { $Credentials = $null } } $ExistingSession = Get-PSSession -Name $SessionName -ErrorAction SilentlyContinue if ($ExistingSession.Availability -contains 'Available') { foreach ($UsedSession in $ExistingSession) { if ($UsedSession.Availability -eq 'Available') { if ($Output) { $Object += @{Status = $true; Output = $SessionName; Extended = "Will reuse established session to $($Session.ComputerName)" } } else { Write-Verbose -Message "Connect-WinExchange - reusing session $($Session.ComputerName)" } $Session = $UsedSession break } } } else { if ($MultiFactorAuthentication) { Write-Verbose -Message "Connect-WinExchange - Establishing MFA Connection" $PSSessionOption = New-PSSessionOption -ProxyAccessType IEConfig try { $Session = New-ExoPSSession -UserPrincipalName $UserName -PSSessionOption $PSSessionOption $Session.Name = $SessionName } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } return $Object } else { Write-Warning -Message "Connect-WinExchange - Failed with error message: $ErrorMessage" return } } } else { Write-Verbose -Message "Connect-WinExchange - Creating Session to URI: $ConnectionURI" $SessionOption = New-PSSessionOption -SkipRevocationCheck -SkipCACheck -SkipCNCheck -Verbose:$false try { if ($Credentials) { Write-Verbose 'Connect-WinExchange - Creating new session using Credentials' $Session = New-PSSession -Credential $Credentials -ConfigurationName Microsoft.Exchange -ConnectionUri $ConnectionURI -Authentication $Authentication -SessionOption $sessionOption -Name $SessionName -AllowRedirection -ErrorAction Stop -Verbose:$false } else { Write-Verbose 'Connect-WinExchange - Creating new session without Credentials' $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ConnectionURI -Authentication $Authentication -SessionOption $sessionOption -Name $SessionName -AllowRedirection -Verbose:$false -ErrorAction Stop } } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } return $Object } else { Write-Warning "Connect-WinExchange - Failed with error message: $ErrorMessage" return } } } } if (-not $Session) { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = 'Connection failed.' } return $Object } else { return } } $CurrentVerbosePreference = $VerbosePreference; $VerbosePreference = 'SilentlyContinue' $CurrentWarningPreference = $WarningPreference; $WarningPreference = 'SilentlyContinue' if ($Prefix) { Import-Module (Import-PSSession -Session $Session -AllowClobber -DisableNameChecking -Prefix $Prefix -Verbose:$false) -Global -Prefix $Prefix } else { Import-Module (Import-PSSession -Session $Session -AllowClobber -DisableNameChecking -Verbose:$false) -Global } $VerbosePreference = $CurrentVerbosePreference $WarningPreference = $CurrentWarningPreference $CheckAvailabilityCommands = Test-AvailabilityCommands -Commands "Get-$($Prefix)MailContact", "Get-$($Prefix)Mailbox" if ($CheckAvailabilityCommands -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = 'Commands unavailable.' } return $Object } else { return } } if ($Output) { if ($Prefix) { $Object += @{Status = $true; Output = $SessionName; Extended = "Connection established $($Session.ComputerName) - prefix: $Prefix" } } else { $Object += @{Status = $true; Output = $SessionName; Extended = "Connection established $($Session.ComputerName) - prefix: n/a" } } return $Object } else { if ($Prefix) { Write-Verbose -Message "Connect-WinExchange - Connection established $($Session.ComputerName) - prefix: $Prefix" } else { Write-Verbose -Message "Connect-WinExchange - Connection established $($Session.ComputerName) - prefix: n/a" } } return $Object } function Connect-WinSecurityCompliance { [CmdletBinding()] param([string] $SessionName = 'Security and Compliance', [string] $ConnectionURI, [ValidateSet("Basic", "Kerberos")][String] $Authentication = 'Basic', [alias('UserPrincipalName')][string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [string] $Prefix, [switch] $Output) $Object = @() if ($MultiFactorAuthentication) { Write-Verbose 'Connect-WinSecurityCompliance - Using MFA option' try { Import-Module $((Get-ChildItem -Path $($env:LOCALAPPDATA + "\Apps\2.0\") -Filter Microsoft.Exchange.Management.ExoPowershellModule.dll -Recurse).FullName | ? { $_ -notmatch "_none_" } | select -First 1) } catch { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = "Connection failed. Couldn't find Exchange Online module to load." } return $Object } else { Write-Warning -Message "Connect-WinSecurityCompliance - Connection failed. Couldn't find Exchange Online module to load." return } } } else { Write-Verbose 'Connect-WinSecurityCompliance - Using Non-MFA option' if ($Authentication -ne 'Kerberos') { $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } else { $Credentials = $null } } $ExistingSession = Get-PSSession -Name $SessionName -ErrorAction SilentlyContinue if ($ExistingSession.Availability -contains 'Available') { foreach ($UsedSession in $ExistingSession) { if ($UsedSession.Availability -eq 'Available') { if ($Output) { $Object += @{Status = $true; Output = $SessionName; Extended = "Will reuse established session to $($Session.ComputerName)" } } else { Write-Verbose -Message "Connect-WinSecurityCompliance - reusing session $($Session.ComputerName)" } $Session = $UsedSession break } } } else { if ($MultiFactorAuthentication) { Write-Verbose -Message "Connect-WinSecurityCompliance - Establishing MFA Connection" $PSSessionOption = New-PSSessionOption -ProxyAccessType IEConfig try { $Session = New-ExoPSSession -UserPrincipalName $UserName -PSSessionOption $PSSessionOption $Session.Name = $SessionName } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } return $Object } else { Write-Warning -Message "Connect-WinSecurityCompliance - Failed with error message: $ErrorMessage" return } } } else { Write-Verbose -Message "Connect-WinSecurityCompliance - Creating Session to URI: $ConnectionURI" $SessionOption = New-PSSessionOption -SkipRevocationCheck -SkipCACheck -SkipCNCheck -Verbose:$false try { if ($Credentials) { Write-Verbose 'Connect-WinSecurityCompliance - Creating new session using Credentials' $Session = New-PSSession -Credential $Credentials -ConfigurationName Microsoft.Exchange -ConnectionUri $ConnectionURI -Authentication $Authentication -SessionOption $sessionOption -Name $SessionName -AllowRedirection -ErrorAction Stop -Verbose:$false } else { Write-Verbose 'Connect-WinSecurityCompliance - Creating new session without Credentials' $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ConnectionURI -Authentication $Authentication -SessionOption $sessionOption -Name $SessionName -AllowRedirection -Verbose:$false -ErrorAction Stop } } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } return $Object } else { Write-Warning "Connect-WinSecurityCompliance - Failed with error message: $ErrorMessage" return } } } } if (-not $Session) { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = 'Connection failed.' } return $Object } else { return } } $CurrentVerbosePreference = $VerbosePreference; $VerbosePreference = 'SilentlyContinue' $CurrentWarningPreference = $WarningPreference; $WarningPreference = 'SilentlyContinue' if ($Prefix) { Import-Module (Import-PSSession -Session $Session -AllowClobber -DisableNameChecking -Prefix $Prefix -Verbose:$false) -Global -Prefix $Prefix } else { Import-Module (Import-PSSession -Session $Session -AllowClobber -DisableNameChecking -Verbose:$false) -Global } $VerbosePreference = $CurrentVerbosePreference $WarningPreference = $CurrentWarningPreference $CheckAvailabilityCommands = Test-AvailabilityCommands -Commands "Get-$($Prefix)ProtectionAlert" if ($CheckAvailabilityCommands -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = 'Commands unavailable.' } return $Object } else { return } } if ($Output) { if ($Prefix) { $Object += @{Status = $true; Output = $SessionName; Extended = "Connection established $($Session.ComputerName) - prefix: $Prefix" } } else { $Object += @{Status = $true; Output = $SessionName; Extended = "Connection established $($Session.ComputerName) - prefix: n/a" } } return $Object } else { if ($Prefix) { Write-Verbose -Message "Connect-WinSecurityCompliance - Connection established $($Session.ComputerName) - prefix: $Prefix" } else { Write-Verbose -Message "Connect-WinSecurityCompliance - Connection established $($Session.ComputerName) - prefix: n/a" } } return $Object } function Connect-WinSharePoint { [CmdletBinding()] param([string] $SessionName = 'Microsoft SharePoint', [string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [alias('uri', 'url', 'ConnectionUrl')][Uri] $ConnectionURI, [switch] $Output) if (-not $MultiFactorAuthentication) { $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } try { Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking $Session = Connect-SPOService -Url $ConnectionURI -Credential $Credentials } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { return @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } } else { Write-Warning "Connect-WinSharePoint - Failed with error message: $ErrorMessage" return } } if ($Output) { return @{Status = $true; Output = $SessionName; Extended = 'Connection Established.' } } } function Connect-WinSkype { [CmdletBinding()] param([string] $SessionName = 'Microsoft Skype', [string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [switch] $Output) $Object = @() if (-not $MultiFactorAuthentication) { Write-Verbose "Connect-WinSkype - Running connectivity without MFA" $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } $ExistingSession = Get-PSSession -Name $SessionName -ErrorAction SilentlyContinue if ($ExistingSession.Availability -contains 'Available') { foreach ($UsedSession in $ExistingSession) { if ($UsedSession.Availability -eq 'Available') { if ($Output) { $Object += @{Status = $true; Output = $SessionName; Extended = "Will reuse established session to $($Session.ComputerName)" } } else { Write-Verbose -Message "Connect-WinSkype - reusing session $($Session.ComputerName)" } $Session = $UsedSession break } } } else { try { if ($MultiFactorAuthentication) { $Session = New-CsOnlineSession -UserName $Username -ErrorAction Stop } else { $Session = New-CsOnlineSession -Credential $Credentials -ErrorAction Stop } $Session.Name = $SessionName } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { return @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } } else { Write-Warning -Message "Connect-WinSkype - Failed with error message: $ErrorMessage" return } } } if (-not $Session) { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = 'Connection failed.' } return $Object } else { return } } $CurrentVerbosePreference = $VerbosePreference; $VerbosePreference = 'SilentlyContinue' $CurrentWarningPreference = $WarningPreference; $WarningPreference = 'SilentlyContinue' if ($Prefix) { Import-Module (Import-PSSession -Session $Session -AllowClobber -DisableNameChecking -Prefix $Prefix -Verbose:$false) -Global -Prefix $Prefix } else { Import-Module (Import-PSSession -Session $Session -AllowClobber -DisableNameChecking -Verbose:$false) -Global } $VerbosePreference = $CurrentVerbosePreference $WarningPreference = $CurrentWarningPreference $CheckAvailabilityCommands = Test-AvailabilityCommands -Commands "Get-$($Prefix)CsExternalAccessPolicy" if ($CheckAvailabilityCommands -contains $false) { if ($Output) { $Object += @{Status = $false; Output = $SessionName; Extended = 'Commands unavailable.' } return $Object } else { return } } if ($Output) { if ($Prefix) { $Object += @{Status = $true; Output = $SessionName; Extended = "Connection established $($Session.ComputerName) - prefix: $Prefix" } } else { $Object += @{Status = $true; Output = $SessionName; Extended = "Connection established $($Session.ComputerName) - prefix: n/a" } } return $Object } else { if ($Prefix) { Write-Verbose -Message "Connect-WinSkype - Connection established $($Session.ComputerName) - prefix: $Prefix" } else { Write-Verbose -Message "Connect-WinSkype - Connection established $($Session.ComputerName) - prefix: n/a" } } return $Object } function Connect-WinTeams { [CmdletBinding()] param([string] $SessionName = 'Microsoft Teams', [string] $Username, [string] $Password, [alias('PasswordAsSecure')][switch] $AsSecure, [alias('PasswordFromFile')][switch] $FromFile, [alias('mfa')][switch] $MultiFactorAuthentication, [switch] $Output) if (-not $MultiFactorAuthentication) { $Credentials = Request-Credentials -UserName $Username -Password $Password -AsSecure:$AsSecure -FromFile:$FromFile -Service $SessionName -Output if ($Credentials -isnot [PSCredential]) { if ($Output) { return $Credentials } else { return } } } try { $Session = Connect-MicrosoftTeams -Credential $Credentials -ErrorAction Stop } catch { $Session = $null $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Output) { return @{Status = $false; Output = $SessionName; Extended = "Connection failed with $ErrorMessage" } } else { Write-Warning "Connect-WinTeams - Failed with error message: $ErrorMessage" return } } if (-not $Session) { if ($Output) { return @{Status = $false; Output = $SessionName; Extended = 'Connection Failed.' } } else { return } } if ($Output) { return @{Status = $true; Output = $SessionName; Extended = 'Connection Established.' } } } function ConvertFrom-Color { [alias('Convert-FromColor')] [CmdletBinding()] param ([ValidateScript( { if ($($_ -in $Script:RGBColors.Keys -or $_ -match "^#([A-Fa-f0-9]{6})$" -or $_ -eq "") -eq $false) { throw "The Input value is not a valid colorname nor an valid color hex code." } else { $true } })] [alias('Colors')][string[]] $Color, [switch] $AsDecimal) $Colors = foreach ($C in $Color) { $Value = $Script:RGBColors."$C" if ($C -match "^#([A-Fa-f0-9]{6})$") { return $C } if ($null -eq $Value) { return } $HexValue = Convert-Color -RGB $Value Write-Verbose "Convert-FromColor - Color Name: $C Value: $Value HexValue: $HexValue" if ($AsDecimal) { [Convert]::ToInt64($HexValue, 16) } else { "#$($HexValue)" } } $Colors } function ConvertTo-OrderedDictionary { [CmdletBinding()] Param ([parameter(Mandatory = $true, ValueFromPipeline = $true)] $HashTable) $OrderedDictionary = [ordered]@{ } if ($HashTable -is [System.Collections.IDictionary]) { $Keys = $HashTable.Keys | Sort-Object foreach ($_ in $Keys) { $OrderedDictionary.Add($_, $HashTable[$_]) } } elseif ($HashTable -is [System.Collections.ICollection]) { for ($i = 0; $i -lt $HashTable.count; $i++) { $OrderedDictionary.Add($i, $HashTable[$i]) } } else { Write-Error "ConvertTo-OrderedDictionary - Wrong input type." } return $OrderedDictionary } function Find-TypesNeeded { [CmdletBinding()] param ($TypesRequired, $TypesNeeded) [bool] $Found = $False foreach ($Type in $TypesNeeded) { if ($TypesRequired -contains $Type) { $Found = $true break } } return $Found } function Format-PSTable { [CmdletBinding()] param ([parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)][System.Collections.ICollection] $Object, [switch] $SkipTitle, [string[]] $Property, [string[]] $ExcludeProperty, [Object] $OverwriteHeaders, [switch] $PreScanHeaders, [string] $Splitter = ';') if ($Object[0] -is [System.Collections.IDictionary]) { $Array = @(if (-not $SkipTitle) { , @('Name', 'Value') } foreach ($O in $Object) { foreach ($Name in $O.Keys) { $Value = $O[$Name] if ($O[$Name].Count -gt 1) { $Value = $O[$Name] -join $Splitter } else { $Value = $O[$Name] } , @($Name, $Value) } }) if ($Array.Count -eq 1) { , $Array } else { $Array } } elseif ($Object[0].GetType().Name -match 'bool|byte|char|datetime|decimal|double|ExcelHyperLink|float|int|long|sbyte|short|string|timespan|uint|ulong|URI|ushort') { return $Object } else { if ($Property) { $Object = $Object | Select-Object -Property $Property } $Array = @(if ($PreScanHeaders) { $Titles = Get-ObjectProperties -Object $Object } elseif ($OverwriteHeaders) { $Titles = $OverwriteHeaders } else { $Titles = $Object[0].PSObject.Properties.Name } if (-not $SkipTitle) { , $Titles } foreach ($O in $Object) { $ArrayValues = foreach ($Name in $Titles) { $Value = $O."$Name" if ($Value.Count -gt 1) { $Value -join $Splitter } elseif ($Value.Count -eq 1) { if ($Value.Value) { $Value.Value } else { $Value } } else { '' } } , $ArrayValues }) if ($Array.Count -eq 1) { , $Array } else { $Array } } } function Format-TransposeTable { [CmdletBinding()] param ([Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)][System.Collections.ICollection] $Object, [ValidateSet("ASC", "DESC", "NONE")][String] $Sort = 'NONE') begin { $i = 0 } process { foreach ($myObject in $Object) { if ($myObject -is [System.Collections.IDictionary]) { $output = New-Object -TypeName PsObject Add-Member -InputObject $output -MemberType ScriptMethod -Name AddNote -Value { Add-Member -InputObject $this -MemberType NoteProperty -Name $args[0] -Value $args[1] } if ($Sort -eq 'ASC') { $myObject.Keys | Sort-Object -Descending:$false | ForEach-Object { $output.AddNote($_, $myObject.$_) } } elseif ($Sort -eq 'DESC') { $myObject.Keys | Sort-Object -Descending:$true | ForEach-Object { $output.AddNote($_, $myObject.$_) } } else { $myObject.Keys | ForEach-Object { $output.AddNote($_, $myObject.$_) } } $output } else { $output = [ordered] @{ } $myObject | Get-Member -MemberType *Property | ForEach-Object { $output.($_.name) = $myObject.($_.name) } $output } $i += 1 } } } function Get-DataInformation { [CmdletBinding()] param([ScriptBlock] $Content, [string] $Text, [Array] $TypesRequired, [Array] $TypesNeeded) if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded $TypesNeeded) { Write-Verbose -Message $Text $Time = Start-TimeLog if ($null -ne $Content) { & $Content } $EndTime = Stop-TimeLog -Time $Time -Option OneLiner Write-Verbose "$Text - Time: $EndTime" } } function Get-FileName { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Extension Parameter description .PARAMETER Temporary Parameter description .PARAMETER TemporaryFileOnly Parameter description .EXAMPLE Get-FileName -Temporary Output: 3ymsxvav.tmp .EXAMPLE Get-FileName -Temporary Output: C:\Users\pklys\AppData\Local\Temp\tmpD74C.tmp .EXAMPLE Get-FileName -Temporary -Extension 'xlsx' Output: C:\Users\pklys\AppData\Local\Temp\tmp45B6.xlsx .NOTES General notes #> [CmdletBinding()] param([string] $Extension = 'tmp', [switch] $Temporary, [switch] $TemporaryFileOnly) if ($Temporary) { return "$($([System.IO.Path]::GetTempFileName()).Replace('.tmp','')).$Extension" } if ($TemporaryFileOnly) { return "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).$Extension" } } function Get-ObjectCount { [CmdletBinding()] param([parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)][Object]$Object) return $($Object | Measure-Object).Count } function Get-ObjectPropertiesAdvanced { [CmdletBinding()] param ([object] $Object, [string[]] $AddProperties, [switch] $Sort) $Data = @{ } $Properties = New-ArrayList $HighestCount = 0 foreach ($O in $Object) { $ObjectProperties = $O.PSObject.Properties.Name $Count = $ObjectProperties.Count if ($Count -gt $HighestCount) { $Data.HighestCount = $Count $Data.HighestObject = $O $HighestCount = $Count } foreach ($Property in $ObjectProperties) { Add-ToArrayAdvanced -List $Properties -Element $Property -SkipNull -RequireUnique } } foreach ($Property in $AddProperties) { Add-ToArrayAdvanced -List $Properties -Element $Property -SkipNull -RequireUnique } $Data.Properties = if ($Sort) { $Properties | Sort-Object } else { $Properties } return $Data } function Get-SqlQueryColumnInformation { [CmdletBinding()] param ([string] $SqlServer, [string] $SqlDatabase, [string] $Table) $Table = $Table.Replace("dbo.", '').Replace('[', '').Replace(']', '') $SqlDatabase = $SqlDatabase.Replace('[', '').Replace(']', '') $SqlDatabase = "[$SqlDatabase]" $Query = "SELECT * FROM $SqlDatabase.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '$Table'" $SqlReturn = @(try { Invoke-DbaQuery -ErrorAction Stop -ServerInstance $SqlServer -Query $Query } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " "Error occured (Get-SqlQueryColumnInformation): $ErrorMessage" }) return $SQLReturn } function Get-Types { [CmdletBinding()] param ([Object] $Types) $TypesRequired = foreach ($Type in $Types) { $Type.GetEnumValues() } return $TypesRequired } function Get-WinADForestControllers { [alias('Get-WinADDomainControllers')] <# .SYNOPSIS .DESCRIPTION Long description .PARAMETER TestAvailability Parameter description .EXAMPLE Get-WinADForestControllers -TestAvailability | Format-Table .EXAMPLE Get-WinADDomainControllers .EXAMPLE Get-WinADDomainControllers | Format-Table * Output: Domain HostName Forest IPV4Address IsGlobalCatalog IsReadOnly SchemaMaster DomainNamingMasterMaster PDCEmulator RIDMaster InfrastructureMaster Comment ------ -------- ------ ----------- --------------- ---------- ------------ ------------------------ ----------- --------- -------------------- ------- ad.evotec.xyz AD1.ad.evotec.xyz ad.evotec.xyz 192.168.240.189 True False True True True True True ad.evotec.xyz AD2.ad.evotec.xyz ad.evotec.xyz 192.168.240.192 True False False False False False False ad.evotec.pl ad.evotec.xyz False False False False False Unable to contact the server. This may be becau... .NOTES General notes #> [CmdletBinding()] param([string[]] $Domain, [switch] $TestAvailability, [switch] $SkipEmpty) try { $Forest = Get-ADForest if (-not $Domain) { $Domain = $Forest.Domains } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning "Get-WinADForestControllers - Couldn't use Get-ADForest feature. Error: $ErrorMessage" return } $Servers = foreach ($D in $Domain) { try { $DC = Get-ADDomainController -Server $D -Filter * foreach ($S in $DC) { $Server = [ordered] @{Domain = $D HostName = $S.HostName Name = $S.Name Forest = $Forest.RootDomain IPV4Address = $S.IPV4Address IPV6Address = $S.IPV6Address IsGlobalCatalog = $S.IsGlobalCatalog IsReadOnly = $S.IsReadOnly Site = $S.Site SchemaMaster = ($S.OperationMasterRoles -contains 'SchemaMaster') DomainNamingMaster = ($S.OperationMasterRoles -contains 'DomainNamingMaster') PDCEmulator = ($S.OperationMasterRoles -contains 'PDCEmulator') RIDMaster = ($S.OperationMasterRoles -contains 'RIDMaster') InfrastructureMaster = ($S.OperationMasterRoles -contains 'InfrastructureMaster') LdapPort = $S.LdapPort SslPort = $S.SslPort Pingable = $null Comment = '' } if ($TestAvailability) { $Server['Pingable'] = foreach ($_ in $Server.IPV4Address) { Test-Connection -Count 1 -Server $_ -Quiet -ErrorAction SilentlyContinue } } [PSCustomObject] $Server } } catch { [PSCustomObject]@{Domain = $D HostName = '' Name = '' Forest = $Forest.RootDomain IPV4Address = '' IPV6Address = '' IsGlobalCatalog = '' IsReadOnly = '' Site = '' SchemaMaster = $false DomainNamingMasterMaster = $false PDCEmulator = $false RIDMaster = $false InfrastructureMaster = $false LdapPort = '' SslPort = '' Pingable = $null Comment = $_.Exception.Message -replace "`n", " " -replace "`r", " " } } } if ($SkipEmpty) { return $Servers | Where-Object { $_.HostName -ne '' } } return $Servers } function New-SqlQuery { [CmdletBinding()] param ([Object] $SqlSettings, [Object] $Object, [Object] $TableMapping) $ArraySQLQueries = New-ArrayList if ($null -ne $Object) { foreach ($O in $Object) { $ArrayMain = New-ArrayList $ArrayKeys = New-ArrayList $ArrayValues = New-ArrayList if (-not $O.AddedWhen) { Add-Member -InputObject $O -MemberType NoteProperty -Name "AddedWhen" -Value (Get-Date) -Force } if (-not $O.AddedWho) { Add-Member -InputObject $O -MemberType NoteProperty -Name "AddedWho" -Value ($Env:USERNAME) -Force } $DuplicateString = [System.Text.StringBuilder]::new() foreach ($E in $O.PSObject.Properties) { $FieldName = $E.Name $FieldValue = $E.Value foreach ($MapKey in $TableMapping.Keys) { if ($FieldName -eq $MapKey) { $MapValue = $TableMapping.$MapKey $MapValueSplit = $MapValue -Split ',' if ($FieldValue -is [DateTime]) { $FieldValue = Get-Date $FieldValue -Format "yyyy-MM-dd HH:mm:ss" } if ($FieldValue -like "*'*") { $FieldValue = $FieldValue -Replace "'", "''" } Add-ToArray -List $ArrayKeys -Element "[$($MapValueSplit[0])]" if ([string]::IsNullOrWhiteSpace($FieldValue)) { Add-ToArray -List $ArrayValues -Element "NULL" } else { foreach ($ColumnName in $SqlSettings.SqlCheckBeforeInsert) { $DuplicateColumn = $ColumnName.Replace("[", '').Replace("]", '') if ($MapValueSplit[0] -eq $DuplicateColumn) { if ($DuplicateString.Length -ne 0) { $null = $DuplicateString.Append(" AND ") } $null = $DuplicateString.Append("[$DuplicateColumn] = '$FieldValue'") } } Add-ToArray -List $ArrayValues -Element "'$FieldValue'" } } } } if ($ArrayKeys) { if ($null -ne $SqlSettings.SqlCheckBeforeInsert -and $DuplicateString.Length -gt 0) { Add-ToArray -List $ArrayMain -Element "IF NOT EXISTS (" Add-ToArray -List $ArrayMain -Element "SELECT 1 FROM " Add-ToArray -List $ArrayMain -Element "$($SqlSettings.SqlTable) " Add-ToArray -List $ArrayMain -Element "WHERE $($DuplicateString.ToString())" Add-ToArray -List $ArrayMain -Element ")" } Add-ToArray -List $ArrayMain -Element "BEGIN" Add-ToArray -List $ArrayMain -Element "INSERT INTO $($SqlSettings.SqlTable) (" Add-ToArray -List $ArrayMain -Element ($ArrayKeys -join ',') Add-ToArray -List $ArrayMain -Element ') VALUES (' Add-ToArray -List $ArrayMain -Element ($ArrayValues -join ',') Add-ToArray -List $ArrayMain -Element ')' Add-ToArray -List $ArrayMain -Element "END" Add-ToArray -List $ArraySQLQueries -Element ([string] ($ArrayMain) -replace "`n", "" -replace "`r", "") } } } return $ArraySQLQueries } function New-SqlQueryAlterTable { [CmdletBinding()] param ([Object]$SqlSettings, [Object]$TableMapping, [string[]] $ExistingColumns) $ArraySQLQueries = New-ArrayList $ArrayMain = New-ArrayList $ArrayKeys = New-ArrayList foreach ($MapKey in $TableMapping.Keys) { $MapValue = $TableMapping.$MapKey $Field = $MapValue -Split ',' if ($ExistingColumns -notcontains $MapKey -and $ExistingColumns -notcontains $Field[0]) { if ($Field.Count -eq 1) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] [nvarchar](max) NULL" } elseif ($Field.Count -eq 2) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) NULL" } elseif ($Field.Count -eq 3) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) $($Field[2])" } } } if ($ArrayKeys) { Add-ToArray -List $ArrayMain -Element "ALTER TABLE $($SqlSettings.SqlTable) ADD" Add-ToArray -List $ArrayMain -Element ($ArrayKeys -join ',') Add-ToArray -List $ArrayMain -Element ';' Add-ToArray -List $ArraySQLQueries -Element ([string] ($ArrayMain) -replace "`n", "" -replace "`r", "") } return $ArraySQLQueries } function New-SqlQueryCreateTable { [CmdletBinding()] param ([Object]$SqlSettings, [Object]$TableMapping) $ArraySQLQueries = New-ArrayList $ArrayMain = New-ArrayList $ArrayKeys = New-ArrayList foreach ($MapKey in $TableMapping.Keys) { $MapValue = $TableMapping.$MapKey $Field = $MapValue -Split ',' if ($Field.Count -eq 1) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] [nvarchar](max) NULL" } elseif ($Field.Count -eq 2) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) NULL" } elseif ($Field.Count -eq 3) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) $($Field[2])" } } if ($ArrayKeys) { Add-ToArray -List $ArrayMain -Element "CREATE TABLE $($SqlSettings.SqlTable) (" Add-ToArray -List $ArrayMain -Element "ID int IDENTITY(1,1) PRIMARY KEY," Add-ToArray -List $ArrayMain -Element ($ArrayKeys -join ',') Add-ToArray -List $ArrayMain -Element ')' Add-ToArray -List $ArraySQLQueries -Element ([string] ($ArrayMain) -replace "`n", "" -replace "`r", "") } return $ArraySQLQueries } function New-SqlTableMapping { [CmdletBinding()] param([Object] $SqlTableMapping, [Object] $Object, $Properties, [switch] $BasedOnSqlTable) if ($SqlTableMapping) { $TableMapping = $SqlTableMapping } else { $TableMapping = @{ } if ($BasedOnSqlTable) { foreach ($Property in $Properties) { $FieldName = $Property $FieldNameSql = $Property $TableMapping.$FieldName = $FieldNameSQL } } else { foreach ($O in $Properties.HighestObject) { foreach ($Property in $Properties.Properties) { $FieldName = $Property $FieldValue = $O.$Property $FieldNameSQL = $FieldName.Replace(' ', '') if ($FieldValue -is [DateTime]) { $TableMapping.$FieldName = "$FieldNameSQL,[datetime],null" } elseif ($FieldValue -is [int] -or $FieldValue -is [Int64]) { $TableMapping.$FieldName = "$FieldNameSQL,[bigint]" } elseif ($FieldValue -is [bool]) { $TableMapping.$FieldName = "$FieldNameSQL,[bit]" } else { $TableMapping.$FieldName = "$FieldNameSQL" } } } } } return $TableMapping } function Test-AvailabilityCommands { param ([string[]] $Commands) $CommandsStatus = foreach ($Command in $Commands) { $Exists = Search-Command -Command $Command if ($Exists) { Write-Verbose "Test-AvailabilityCommands - Command $Command is available." } else { Write-Verbose "Test-AvailabilityCommands - Command $Command is not available." } $Exists } return $CommandsStatus } function Test-ConfigurationCredentials { [CmdletBinding()] param ([Object] $Configuration, $AllowEmptyKeys) $Object = foreach ($Key in $Configuration.Keys) { if ($AllowEmptyKeys -notcontains $Key -and [string]::IsNullOrWhiteSpace($Configuration.$Key)) { Write-Verbose "Test-ConfigurationCredentials - Configuration $Key is Null or Empty! Terminating" @{Status = $false; Output = $User.SamAccountName; Extended = "Credentials configuration $Key is Null or Empty!" } } } return $Object } function Test-ForestConnectivity { [CmdletBinding()] param() Try { $null = Get-ADForest return $true } catch { return $False } } function Add-ToArray { [CmdletBinding()] param([System.Collections.ArrayList] $List, [Object] $Element) [void] $List.Add($Element) } function Convert-Color { <# .Synopsis This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX) .Description This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX). Use it to convert your colors and prepare your graphics and HTML web pages. .Parameter RBG Enter the Red Green Blue value comma separated. Red: 51 Green: 51 Blue: 204 for example needs to be entered as 51,51,204 .Parameter HEX Enter the Hex value to be converted. Do not use the '#' symbol. (Ex: 3333CC converts to Red: 51 Green: 51 Blue: 204) .Example .\convert-color -hex FFFFFF Converts hex value FFFFFF to RGB .Example .\convert-color -RGB 123,200,255 Converts Red = 123 Green = 200 Blue = 255 to Hex value #> param([Parameter(ParameterSetName = "RGB", Position = 0)] [ValidateScript( { $_ -match '^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$' })] $RGB, [Parameter(ParameterSetName = "HEX", Position = 0)] [ValidateScript( { $_ -match '[A-Fa-f0-9]{6}' })] [string] $HEX) switch ($PsCmdlet.ParameterSetName) { "RGB" { if ($null -eq $RGB[2]) { Write-Error "Value missing. Please enter all three values seperated by comma." } $red = [convert]::Tostring($RGB[0], 16) $green = [convert]::Tostring($RGB[1], 16) $blue = [convert]::Tostring($RGB[2], 16) if ($red.Length -eq 1) { $red = '0' + $red } if ($green.Length -eq 1) { $green = '0' + $green } if ($blue.Length -eq 1) { $blue = '0' + $blue } Write-Output $red$green$blue } "HEX" { $red = $HEX.Remove(2, 4) $Green = $HEX.Remove(4, 2) $Green = $Green.remove(0, 2) $Blue = $hex.Remove(0, 4) $Red = [convert]::ToInt32($red, 16) $Green = [convert]::ToInt32($green, 16) $Blue = [convert]::ToInt32($blue, 16) Write-Output $red, $Green, $blue } } } function Get-ObjectProperties { [CmdletBinding()] param ([System.Collections.ICollection] $Object, [string[]] $AddProperties, [switch] $Sort, [bool] $RequireUnique = $true) $Properties = @(foreach ($O in $Object) { $ObjectProperties = $O.PSObject.Properties.Name $ObjectProperties } foreach ($Property in $AddProperties) { $Property }) if ($Sort) { return $Properties | Sort-Object -Unique:$RequireUnique } else { return $Properties | Select-Object -Unique:$RequireUnique } } function Get-RandomStringName { [cmdletbinding()] param([int] $Size = 31, [switch] $ToLower, [switch] $ToUpper, [switch] $LettersOnly) [string] $MyValue = @(if ($LettersOnly) { ( -join ((1..$Size) | ForEach-Object { (65..90) + (97..122) | Get-Random } | ForEach-Object { [char]$_ })) } else { ( -join ((48..57) + (97..122) | Get-Random -Count $Size | ForEach-Object { [char]$_ })) }) if ($ToLower) { return $MyValue.ToLower() } if ($ToUpper) { return $MyValue.ToUpper() } return $MyValue } function Request-Credentials { [CmdletBinding()] param([string] $UserName, [string] $Password, [switch] $AsSecure, [switch] $FromFile, [switch] $Output, [switch] $NetworkCredentials, [string] $Service) if ($FromFile) { if (($Password -ne '') -and (Test-Path $Password)) { Write-Verbose "Request-Credentials - Reading password from file $Password" $Password = Get-Content -Path $Password } else { if ($Output) { return @{Status = $false; Output = $Service; Extended = 'File with password unreadable.' } } else { Write-Warning "Request-Credentials - Secure password from file couldn't be read. File not readable. Terminating." return } } } if ($AsSecure) { try { $NewPassword = $Password | ConvertTo-SecureString -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($ErrorMessage -like '*Key not valid for use in specified state*') { if ($Output) { return @{Status = $false; Output = $Service; Extended = "Couldn't use credentials provided. Most likely using credentials from other user/session/computer." } } else { Write-Warning -Message "Request-Credentials - Couldn't use credentials provided. Most likely using credentials from other user/session/computer." return } } else { if ($Output) { return @{Status = $false; Output = $Service; Extended = $ErrorMessage } } else { Write-Warning -Message "Request-Credentials - $ErrorMessage" return } } } } else { $NewPassword = $Password } if ($UserName -and $NewPassword) { if ($AsSecure) { $Credentials = New-Object System.Management.Automation.PSCredential($Username, $NewPassword) } else { Try { $SecurePassword = $Password | ConvertTo-SecureString -asPlainText -Force -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($ErrorMessage -like '*Key not valid for use in specified state*') { if ($Output) { return @{Status = $false; Output = $Service; Extended = "Couldn't use credentials provided. Most likely using credentials from other user/session/computer." } } else { Write-Warning -Message "Request-Credentials - Couldn't use credentials provided. Most likely using credentials from other user/session/computer." return } } else { if ($Output) { return @{Status = $false; Output = $Service; Extended = $ErrorMessage } } else { Write-Warning -Message "Request-Credentials - $ErrorMessage" return } } } $Credentials = New-Object System.Management.Automation.PSCredential($Username, $SecurePassword) } } else { if ($Output) { return @{Status = $false; Output = $Service; Extended = 'Username or/and Password is empty' } } else { Write-Warning -Message 'Request-Credentials - UserName or Password are empty.' return } } if ($NetworkCredentials) { return $Credentials.GetNetworkCredential() } else { return $Credentials } } function Search-Command { [cmdletbinding()] param ([string] $CommandName) return [bool](Get-Command -Name $CommandName -ErrorAction SilentlyContinue) } 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 ($null -eq $WordDocument) { Write-Verbose ' Null' } return $WordDocument } function Get-TypesRequired { [CmdletBinding()] param ([System.Collections.IDictionary[]] $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, [System.Collections.IDictionary] $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) if ($Type -eq 'O365') { $CommandOutput = @(Connect-WinService -Type 'ExchangeOnline' -Credentials $Credentials -Service $Service -Verbose Connect-WinService -Type 'Azure' -Credentials $Credentials -Service $Service -Verbose) } else { $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 } 'O365' { $DataInformation = Get-WinO365 -TypesRequired $TypesRequired -Prefix $Service.Prefix } } 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([Xceed.Document.NET.Container] $WordDocument, [Object] $Section, [alias('Object')][Object] $Forest, [string] $Domain, [OfficeOpenXml.ExcelPackage] $Excel, [string] $SectionName, [nullable[bool]] $Sql, [bool] $ExportWord) 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 ($ExportWord) { if ($WordDocument) { if (($null -eq $Section.WordExport) -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-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 = ($Document.DocumentAD.Sections.SectionForest).Keys $ADSectionsDomain = ($Document.DocumentAD.Sections.SectionDomain).Keys foreach ($DataInformation in $DataInformationAD) { foreach ($Section in $ADSectionsForest) { if ($WordDocument) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentAD.Sections.SectionForest.$Section -Object $DataInformationAD -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAD.ExportSQL -ExportWord $Document.DocumentAD.ExportWord } else { New-DataBlock -Section $Document.DocumentAD.Sections.SectionForest.$Section -Object $DataInformationAD -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAD.ExportSQL -ExportWord $Document.DocumentAD.ExportWord } } foreach ($Domain in $DataInformationAD.FoundDomains.Keys) { foreach ($Section in $ADSectionsDomain) { if ($WordDocument) { $WordDocument = New-DataBlock -WordDocument $WordDocument -Section $Document.DocumentAD.Sections.SectionDomain.$Section -Object $DataInformationAD -Domain $Domain -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAD.ExportSQL -ExportWord $Document.DocumentAD.ExportWord } else { New-DataBlock -Section $Document.DocumentAD.Sections.SectionDomain.$Section -Object $DataInformationAD -Domain $Domain -Excel $ExcelDocument -SectionName $Section -Sql $Document.DocumentAD.ExportSQL -ExportWord $Document.DocumentAD.ExportWord } } } } 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 = ($Document.DocumentAWS.Sections).Keys $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 -ExportWord $Document.DocumentAWS.ExportWord } 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 = ($Document.DocumentExchange.Sections).Keys $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 -ExportWord $Document.DocumentExchange.ExportWord } 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 = ($Document.DocumentOffice365.Sections).Keys $TimeDataOnly = [System.Diagnostics.Stopwatch]::StartNew() $DataInformation = Get-WinServiceData -Credentials $Document.DocumentOffice365.Services.Office365.Credentials -Service $Document.DocumentOffice365.Services.Office365.ExchangeOnline -TypesRequired $TypesRequired -Type 'O365' $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 -ExportWord $Document.DocumentOffice365.ExportWord } 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 } 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)" } Export-ModuleMember -Function @('Start-Documentation') -Alias @() |