AzPolicyLens.Wiki.psm1
|
using module ./AzPolicyLens.Wiki.Azure.Helper.psm1 using module ./AzPolicyLens.Wiki.Encryption.Helper.psm1 using module ./AzPolicyLens.Wiki.Generic.Helper.psm1 using module ./AzPolicyLens.Wiki.Markdown.Helper.psm1 using module ./AzPolicyLens.Wiki.Pages.Helper.psm1 using module ./AzPolicyLens.Wiki.Platform.Helper.psm1 using module ./AzPolicyLens.Wiki.Utility.Helper.psm1 #region function to import previously exported environment details Function Import-AzplEnvironmentDiscovery { [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param ( [parameter(Mandatory = $true, ParameterSetName = 'EncryptionViaKeyFile', HelpMessage = 'File path for the Environment Data to import')] [parameter(Mandatory = $true, ParameterSetName = 'EncryptionViaKeyText', HelpMessage = 'File path for the Environment Data to import')] [parameter(Mandatory = $true, ParameterSetName = 'NoEncryption', HelpMessage = 'File path for the Environment Data to import')] [ValidateScript({ Test-Path -Path $_ -PathType 'Leaf' })] [string]$FilePath, [parameter(Mandatory = $true, ParameterSetName = 'EncryptionViaKeyFile', HelpMessage = 'AES Encryption key file path. Use the same key to decrypt the file if it is encrypted.')] [ValidateNotNullOrEmpty()] [string]$EncryptionKeyFilePath, [parameter(Mandatory = $true, ParameterSetName = 'EncryptionViaKeyText', HelpMessage = 'AES Encryption Key Content.')] [ValidateNotNullOrEmpty()] [string]$EncryptionKey, [parameter(Mandatory = $true, ParameterSetName = 'EncryptionViaKeyText', HelpMessage = 'AES Encryption Initialization Vector (IV) Content.')] [ValidateNotNullOrEmpty()] [string]$EncryptionIV ) #Discovery Data File names $hierarchyFileName = 'managementGroupHierarchy.json' $policyAssignmentFileName = 'policyAssignments.json' $policyInitiativeFileName = 'policyInitiatives.json' $policyDefinitionFileName = 'policyDefinitions.json' $policyExemptionFileName = 'policyExemptions.json' $policyMetadataFileName = 'policyMetadata.json' $complianceDataFileName = 'complianceData.json' $objFile = Get-Item $FilePath if ($objFile.Extension -ieq '.zip') { Write-Verbose "[$(getCurrentUTCString)]: Expanding the ZIP archive '$($objFile.FullName)'." Expand-Archive -Path $objFile.FullName -DestinationPath (Split-Path -Path $objFile.FullName -Parent) -Force $hierarchyFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $hierarchyFileName) $policyAssignmentFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $policyAssignmentFileName) $policyInitiativeFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $policyInitiativeFileName) $policyDefinitionFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $policyDefinitionFileName) $policyExemptionFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $policyExemptionFileName) $policyMetadataFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $policyMetadataFileName) $complianceDataFileFullPath = (Join-Path -Path (Split-Path -Path $objFile.FullName -Parent) -ChildPath $complianceDataFileName) $removeExtractedFile = $true } else { Throw "Unsupported file format '$($objFile.Extension)'. Only .zip files are supported for environment details import." } try { if ($($PSCmdlet.ParameterSetName) -eq 'EncryptionViaKeyFile') { Write-Verbose "[$(getCurrentUTCString)]: Decrypting the environment details using the encryption key file '$EncryptionKeyFilePath'." -Verbose $hierarchyDetails = decryptStuff -InputFilePath $hierarchyFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 $policyAssignmentDetails = decryptStuff -InputFilePath $policyAssignmentFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 $policyInitiativeDetails = decryptStuff -InputFilePath $policyInitiativeFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 $policyDefinitionDetails = decryptStuff -InputFilePath $policyDefinitionFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 $policyExemptionDetails = decryptStuff -InputFilePath $policyExemptionFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 $policyMetadataDetails = decryptStuff -InputFilePath $policyMetadataFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 $complianceDataDetails = decryptStuff -InputFilePath $complianceDataFileFullPath -KeyFilePath $EncryptionKeyFilePath | ConvertFrom-Json -depth 100 } elseif ($($PSCmdlet.ParameterSetName) -ieq 'EncryptionViaKeyText') { Write-Verbose "[$(getCurrentUTCString)]: Decrypting the environment details using the encryption key and IV text." -Verbose $hierarchyDetails = decryptStuff -InputFilePath $hierarchyFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 $policyAssignmentDetails = decryptStuff -InputFilePath $policyAssignmentFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 $policyInitiativeDetails = decryptStuff -InputFilePath $policyInitiativeFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 $policyDefinitionDetails = decryptStuff -InputFilePath $policyDefinitionFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 $policyExemptionDetails = decryptStuff -InputFilePath $policyExemptionFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 $policyMetadataDetails = decryptStuff -InputFilePath $policyMetadataFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 $complianceDataDetails = decryptStuff -InputFilePath $complianceDataFileFullPath -AESKey $EncryptionKey -AESIV $EncryptionIV | ConvertFrom-Json -depth 100 } else { Write-Verbose "[$(getCurrentUTCString)]: Importing the environment details from the file '$FilePath' as plain-text." -Verbose $hierarchyDetails = Get-Content $hierarchyFileFullPath -Raw | ConvertFrom-Json -depth 100 $policyAssignmentDetails = Get-Content $policyAssignmentFileFullPath -Raw | ConvertFrom-Json -depth 100 $policyInitiativeDetails = Get-Content $policyInitiativeFileFullPath -Raw | ConvertFrom-Json -depth 100 $policyDefinitionDetails = Get-Content $policyDefinitionFileFullPath -Raw | ConvertFrom-Json -depth 100 $policyExemptionDetails = Get-Content $policyExemptionFileFullPath -Raw | ConvertFrom-Json -depth 100 $policyMetadataDetails = Get-Content $policyMetadataFileFullPath -Raw | ConvertFrom-Json -depth 100 $complianceDataDetails = Get-Content $complianceDataFileFullPath -Raw | ConvertFrom-Json -depth 100 } # Extract the data from the output $hierarchyData = $hierarchyDetails $policyAssignmentData = $policyAssignmentDetails $policyInitiativeData = $policyInitiativeDetails $policyDefinitionData = $policyDefinitionDetails $policyExemptionData = $policyExemptionDetails $policyMetadataData = $policyMetadataDetails $complianceData = $complianceDataDetails Write-Verbose "[$(getCurrentUTCString)]: Environment Discovery Data Import." -verbose $AzplEnvironmentDetails = [ordered]@{ timeStamp = $hierarchyData.timeStamp topLevelManagementGroupName = $hierarchyData.topLevelManagementGroupName managementGroups = $hierarchyData.managementGroups subscriptions = $hierarchyData.subscriptions assignments = $policyAssignmentData.assignments initiatives = $policyInitiativeData.initiatives definitions = $policyDefinitionData.definitions exemptions = $policyExemptionData.exemptions policyMetadata = $policyMetadataData.policyMetadata builtInDefinitionInUnAssignedCustomInitiative = $policyDefinitionData.builtInDefinitionInUnAssignedCustomInitiative assignmentCompliance = $complianceData.assignmentCompliance subscriptionComplianceSummary = $complianceData.subscriptionComplianceSummary complianceSummaryByPolicyDefinitionGroup = $complianceData.complianceSummaryByPolicyDefinitionGroup additionalBuiltInPolicyMetadataConfig = $policyMetadataData.additionalBuiltInPolicyMetadataConfig roleAssignments = $policyAssignmentData.roleAssignments roleDefinitions = $policyAssignmentData.roleDefinitions } Write-Verbose "[$(getCurrentUTCString)]: Imported environment details summary:" -Verbose Write-Verbose " - Time Stamp (UTC): $($AzplEnvironmentDetails.timeStamp)" -Verbose Write-Verbose " - Top Level Management Group Name: $($AzplEnvironmentDetails.topLevelManagementGroupName)" -Verbose Write-Verbose " - Management Groups Count: $($AzplEnvironmentDetails.managementGroups.Count)" -Verbose Write-Verbose " - Subscriptions Count: $($AzplEnvironmentDetails.subscriptions.Count)" -Verbose Write-Verbose " - Assignments Count: $($AzplEnvironmentDetails.assignments.Count)" -Verbose Write-Verbose " - Initiatives Count: $($AzplEnvironmentDetails.initiatives.Count)" -Verbose Write-Verbose " - Definitions Count: $($AzplEnvironmentDetails.definitions.Count)" -Verbose Write-Verbose " - Exemptions Count: $($AzplEnvironmentDetails.exemptions.Count)" -Verbose Write-Verbose " - Policy Metadata Count: $($AzplEnvironmentDetails.policyMetadata.Count)" -Verbose Write-Verbose " - Built-in Definition in Unassigned Custom Initiative Count: $($AzplEnvironmentDetails.builtInDefinitionInUnAssignedCustomInitiative.Count)" -Verbose Write-Verbose " - Role Assignments Count: $($AzplEnvironmentDetails.roleAssignments.Count)" -Verbose Write-Verbose " - Role Definitions Count: $($AzplEnvironmentDetails.roleDefinitions.Count)" -Verbose } catch { $ExceptionDetails = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($ExceptionDetails) $ExceptionResponse = $reader.ReadToEnd(); Write-Error $ExceptionResponse Write-Error $_.ErrorDetails throw $_.Exception $AzplEnvironmentDetails = [ordered]@{} } if ($removeExtractedFile) { Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($hierarchyFileFullPath)'." -Verbose Remove-Item -Path $hierarchyFileFullPath -Force Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($policyAssignmentFileFullPath)'." -Verbose Remove-Item -Path $policyAssignmentFileFullPath -Force Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($policyInitiativeFileFullPath)'." -Verbose Remove-Item -Path $policyInitiativeFileFullPath -Force Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($policyDefinitionFileFullPath)'." -Verbose Remove-Item -Path $policyDefinitionFileFullPath -Force Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($policyExemptionFileFullPath)'." -Verbose Remove-Item -Path $policyExemptionFileFullPath -Force Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($policyMetadataFileFullPath)'." -Verbose Remove-Item -Path $policyMetadataFileFullPath -Force Write-Verbose "[$(getCurrentUTCString)]: Removing the extracted file '$($complianceDataFileFullPath)'." -Verbose Remove-Item -Path $complianceDataFileFullPath -Force } $AzplEnvironmentDetails } #endregion #region function to generate either basic or detailed documentation for the entire environment or a subset of subscriptions Function New-AzplDocumentation { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ImportNoEncryption')] [OutputType([array])] param ( [parameter(Mandatory = $true, HelpMessage = 'The page style (detailed for engineers or basic for customers).')] [ValidateSet('detailed', 'basic')] [string]$PageStyle, [parameter(Mandatory = $true, ParameterSetName = 'ImportNoEncryption_Subscription', HelpMessage = 'Optional. The subset of subscription Ids (GUID) to generate the documentation for.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyFile_Subscription', HelpMessage = 'Optional. The subset of subscription Ids (GUID) to generate the documentation for.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText_Subscription', HelpMessage = 'Optional. The subset of subscription Ids (GUID) to generate the documentation for.')] [ValidateScript({ $_ -match '(?im)^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' })] [string[]]$SubscriptionIds, [parameter(Mandatory = $true, ParameterSetName = 'ImportNoEncryption_ManagementGroup', HelpMessage = 'The Id of a child management group to generate the documentation for.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyFile_ManagementGroup', HelpMessage = 'The Id of a child management group to generate the documentation for.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText_ManagementGroup', HelpMessage = 'The Id of a child management group to generate the documentation for.')] [ValidateNotNullOrEmpty()] [string]$childManagementGroupId, [parameter(Mandatory = $true, HelpMessage = 'The output base directory.')] [ValidateScript({ Test-Path $_ -PathType 'Container' })] [string]$BaseOutputPath, [parameter(Mandatory = $true, HelpMessage = 'The title of the wiki.')] [ValidateNotNullOrEmpty()] [string]$Title, [parameter(Mandatory = $true, HelpMessage = 'The wiki style. Supported values are "ado" and "github".')] [ValidateSet('ado', 'github')] [string]$WikiStyle, [parameter(Mandatory = $false, HelpMessage = 'The warning days for the expiration of the policy exemption.')] [ValidateRange(7, 90)] [int]$ExemptionExpiresOnWarningDays = 30, [parameter(Mandatory = $false, HelpMessage = 'The warning percentage threshold for policy compliance summary.')] [ValidateRange(1, 99)] [int]$ComplianceWarningPercentageThreshold = 80, [parameter(Mandatory = $false, HelpMessage = 'The directory contains custom security control definitions.')] [ValidateScript({ Test-Path $_ -PathType 'Container' })] [string]$CustomSecurityControlPath, [parameter(Mandatory = $true, HelpMessage = 'File path for the Environment Data to import')] [ValidateScript({ Test-Path -Path $_ -PathType 'Leaf' })] [string]$DiscoveryDataImportFilePath, [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyFile', HelpMessage = 'AES Encryption key file path. This key is used to encrypt the new discovery json export file or decrypt the existing environment discovery file.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyFile_Subscription', HelpMessage = 'AES Encryption key file path. This key is used to encrypt the new discovery json export file or decrypt the existing environment discovery file.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyFile_ManagementGroup', HelpMessage = 'AES Encryption key file path. This key is used to encrypt the new discovery json export file or decrypt the existing environment discovery file.')] [ValidateNotNullOrEmpty()] [string]$EncryptionKeyFilePath, [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText', HelpMessage = 'AES Encryption Key Content.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText_Subscription', HelpMessage = 'AES Encryption Key Content.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText_ManagementGroup', HelpMessage = 'AES Encryption Key Content.')] [ValidateNotNullOrEmpty()] [string]$EncryptionKey, [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText', HelpMessage = 'AES Encryption Initialization Vector (IV) Content.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText_Subscription', HelpMessage = 'AES Encryption Initialization Vector (IV) Content.')] [parameter(Mandatory = $true, ParameterSetName = 'ImportEncryptionWithKeyText_ManagementGroup', HelpMessage = 'AES Encryption Initialization Vector (IV) Content.')] [ValidateNotNullOrEmpty()] [string]$EncryptionIV ) Write-Verbose "Environment Data will be imported from '$DiscoveryDataImportFilePath'." $importParams = @{ FilePath = $DiscoveryDataImportFilePath } if ($PSCmdlet.ParameterSetName -ilike 'ImportEncryptionWithKeyFile*') { $importParams.Add('EncryptionKeyFilePath', $EncryptionKeyFilePath) } elseif ($PSCmdlet.ParameterSetName -ilike 'ImportEncryptionWithKeyText*') { $importParams.Add('EncryptionKey', $EncryptionKey) $importParams.Add('EncryptionIV', $EncryptionIV) } $AzplEnvironmentDetails = Import-AzplEnvironmentDiscovery @importParams #Make sure all policy resources are retrieved previously in a script scoped variable $AzplEnvironmentDetails if (!$AzplEnvironmentDetails) { Throw "[$(getCurrentUTCString)]: No environment discovery data found." Exit 1 } #create script scoped variables for Policy Definition and initiative syntax validation failures $global:failedSyntaxValidationDefinitions = @() $global:failedSyntaxValidationInitiatives = @() if ($subscriptionIds.count -gt 0) { Write-Verbose "[$(getCurrentUTCString)]: subscription Ids are provided. Filtering documentation for the specified subscriptions only." -Verbose $EnvironmentDiscoveryData = filterDiscoveryData -SubscriptionIds $subscriptionIds -environmentDetails $AzplEnvironmentDetails } elseif ($childManagementGroupId.length -gt 0) { Write-Verbose "[$(getCurrentUTCString)]: Child management group ID is provided. Filtering documentation for the specified child management group and its descendants." -Verbose $EnvironmentDiscoveryData = filterDiscoveryData -ChildManagementGroupId $childManagementGroupId -environmentDetails $AzplEnvironmentDetails } else { Write-Verbose "[$(getCurrentUTCString)]: No subscription Ids or child management group ID provided. Generating documentation for all subscriptions in the environment." -Verbose $EnvironmentDiscoveryData = $AzplEnvironmentDetails } # generate wiki page file names $wikiFileMapping = newWikiPageMapping -discoveryData $EnvironmentDiscoveryData -BaseOutputPath $BaseOutputPath -WikiStyle $WikiStyle -Title $Title -PageStyle $PageStyle -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) #Delete existing wiki content (so there are no orphaned pages for resources no longer exist) Write-Verbose "[$(getCurrentUTCString)]: Deleting existing wiki content in '$BaseOutputPath'." -Verbose removeExistingWikiFiles -WikiDirectory $BaseOutputPath -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) $detailedPagesCommonParams = @{ WikiFileMapping = $wikiFileMapping EnvironmentDiscoveryData = $EnvironmentDiscoveryData PageStyle = $PageStyle Verbose = ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) } #Get unique policy categories from assigned initiatives $uniqueAssignedPolicyInitiativeCategories = getUniqueCategoriesFromAssignedInitiatives -EnvironmentDiscoveryData $EnvironmentDiscoveryData #Generate Markdown page for custom security controls if ($PSBoundParameters.ContainsKey('CustomSecurityControlPath')) { #Get list of custom security control files $CustomSecurityControlFileSchemaFilePath = Join-Path -Path $PSScriptRoot -ChildPath 'AzPolicyLens.Wiki.Custom.Security.Control.schema.json' $CustomSecurityControlFileConfig = getCustomSecurityControlFileConfig -FilePath $CustomSecurityControlPath -schemaFilePath $CustomSecurityControlFileSchemaFilePath Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the custom security controls defined in '$CustomSecurityControlPath'." -Verbose $customSecurityControlPages = newCustomSecurityControlPage @detailedPagesCommonParams -CustomSecurityControlFileConfig $CustomSecurityControlFileConfig -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold } #Generate Markdown pages for built-in security controls Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($EnvironmentDiscoveryData.policyMetadata.count) built-in security controls (policy metadata) that have been discovered." -Verbose $policyMetadataPages = newPolicyMetadataPage -WikiFileMapping $wikiFileMapping -EnvironmentDiscoveryData $EnvironmentDiscoveryData -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold #Generate Markdown pages for policy definitions Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($EnvironmentDiscoveryData.definitions.count) policy definitions that have been discovered." -Verbose $definitionPages = newPolicyDefinitionPage @detailedPagesCommonParams #Generate Markdown pages for policy initiatives Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($EnvironmentDiscoveryData.initiatives.count) policy initiatives that have been discovered." -Verbose if ($PSBoundParameters.ContainsKey('CustomSecurityControlPath')) { $initiativePages = newPolicyInitiativePage @detailedPagesCommonParams -CustomSecurityControlFileConfig $CustomSecurityControlFileConfig } else { $initiativePages = newPolicyInitiativePage @detailedPagesCommonParams } #Generate Markdown pages for policy assignments Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($EnvironmentDiscoveryData.assignments.count) policy assignments that have been discovered." -Verbose $assignmentPages = newPolicyAssignmentPage @detailedPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold if ($EnvironmentDiscoveryData.exemptions.Count -gt 0) { #Generate Markdown pages for policy exemptions Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($EnvironmentDiscoveryData.exemptions.count) policy exemptions that have been discovered." -Verbose $exemptionPages = newPolicyExemptionPage @detailedPagesCommonParams -ExpiresOnWarningDays $ExemptionExpiresOnWarningDays } else { Write-Verbose "[$(getCurrentUTCString)]: No policy exemptions found in the environment. Skipping individual exemption page generation." $exemptionPages = @() } #Generate Markdown pages for subscriptions Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($EnvironmentDiscoveryData.subscriptions.count) subscriptions that have been discovered." -Verbose $subscriptionPages = newSubscriptionPage @detailedPagesCommonParams -ExemptionExpiresOnWarningDays $ExemptionExpiresOnWarningDays -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold #Generate Markdown pages for policy categories Write-Verbose "[$(getCurrentUTCString)]: Start Generating Markdown files for the $($uniqueAssignedPolicyInitiativeCategories.count) unique policy categories from assigned initiatives." -Verbose $policyCategoryPageParams = @{ WikiFileMapping = $wikiFileMapping EnvironmentDiscoveryData = $EnvironmentDiscoveryData uniqueAssignedPolicyInitiativeCategories = $uniqueAssignedPolicyInitiativeCategories ComplianceWarningPercentageThreshold = $ComplianceWarningPercentageThreshold Verbose = ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) } if ($PSBoundParameters.ContainsKey('CustomSecurityControlPath')) { $policyCategoryPageParams.Add('CustomSecurityControlFileConfig', $CustomSecurityControlFileConfig) } $policyCategoryPages = newPolicyCategoryPage @policyCategoryPageParams $summaryPagesCommonParams = @{ wikiFileMapping = $wikiFileMapping EnvironmentDiscoveryData = $EnvironmentDiscoveryData Title = $Title PageStyle = $PageStyle Verbose = ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) } #Generate detailed main summary Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating main $PageStyle summary Markdown file." -Verbose if ($SubscriptionIds.count -gt 0) { $mainSummaryPage = newMainSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold -uniqueAssignedPolicyInitiativeCategories $uniqueAssignedPolicyInitiativeCategories -SubscriptionIds $SubscriptionIds } elseif ($null -ne $childManagementGroupId) { $mainSummaryPage = newMainSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold -uniqueAssignedPolicyInitiativeCategories $uniqueAssignedPolicyInitiativeCategories -ChildManagementGroupId $childManagementGroupId } else { $mainSummaryPage = newMainSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold -uniqueAssignedPolicyInitiativeCategories $uniqueAssignedPolicyInitiativeCategories } #Generate assignment summary Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Policy Assignment summary Markdown file." -Verbose $assignmentSummaryPage = newAssignmentSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold #Generate assignment initiative Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Policy Initiative summary Markdown file." -Verbose $initiativeSummaryPage = newInitiativeSummaryPage @summaryPagesCommonParams #Generate assignment definition Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Policy Definition summary Markdown file." -Verbose $definitionSummaryPage = newDefinitionSummaryPage @summaryPagesCommonParams if ($PageStyle -ieq 'detailed') { #Generate security control summary Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Security Control summary Markdown file." -Verbose if ($PSBoundParameters.ContainsKey('CustomSecurityControlPath')) { $securityControlSummaryPage = newSecurityControlSummaryPage @summaryPagesCommonParams -CustomSecurityControlFileConfig $CustomSecurityControlFileConfig } else { $securityControlSummaryPage = newSecurityControlSummaryPage @summaryPagesCommonParams } } #Generate policy category summary Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Policy Category summary Markdown file." -Verbose $policyCategorySummaryPage = newPolicyCategorySummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold -uniqueAssignedPolicyInitiativeCategories $uniqueAssignedPolicyInitiativeCategories #Generate subscription Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Subscription summary Markdown file." -Verbose $subscriptionSummaryPage = newSubscriptionSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold #Generate analysis Markdown page #This page must be generated after the policy definition and initiative detailed pages because it needs the summary data for definition and initiative syntax validation results. Write-Verbose "[$(getCurrentUTCString)]: Start Generating Policy Analysis summary Markdown file." -Verbose if ($PSBoundParameters.ContainsKey('CustomSecurityControlPath')) { $analysisSummaryPage = newAnalysisSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold -CustomSecurityControlFileConfig $CustomSecurityControlFileConfig } else { $analysisSummaryPage = newAnalysisSummaryPage @summaryPagesCommonParams -ComplianceWarningPercentageThreshold $ComplianceWarningPercentageThreshold } if ($EnvironmentDiscoveryData.exemptions.Count -gt 0) { #Generate exemption Markdown page Write-Verbose "[$(getCurrentUTCString)]: Start Generating Policy Exemption summary Markdown file." -Verbose $exemptionSummaryPage = newExemptionSummaryPage @summaryPagesCommonParams -ExpiresOnWarningDays $ExemptionExpiresOnWarningDays } else { Write-Verbose "[$(getCurrentUTCString)]: No policy exemptions found in the environment. Skipping exemption summary page generation." $exemptionSummaryPage = @() } if ($WikiStyle -ieq 'github') { #Generate GitHub wiki sidebar Write-Verbose "[$(getCurrentUTCString)]: Start Generating GitHub wiki sidebar and footer Markdown files." -Verbose $githubSidebarParams = @{ WikiFileMapping = $wikiFileMapping Title = $Title EnvironmentDiscoveryData = $EnvironmentDiscoveryData CustomSecurityControlFileConfig = $customSecurityControlPages PageStyle = $PageStyle Verbose = ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) } $sidebarFilePath = newGitHubWikiSidebar @githubSidebarParams $footerFilePath = newGitHubWikiFooter -WikiFileMapping $wikiFileMapping -TimeStamp $EnvironmentDiscoveryData.TimeStamp } else { Write-Verbose "[$(getCurrentUTCString)]: Skipping GitHub wiki sidebar generation as WikiStyle is not 'github'." -Verbose } #Tidy up - Remove global variables Remove-Variable -Name failedSyntaxValidationDefinitions -Scope Global -ErrorAction SilentlyContinue Remove-Variable -Name failedSyntaxValidationInitiatives -Scope Global -ErrorAction SilentlyContinue Write-Output "[$(getCurrentUTCString)]: The following Markdown files for main summary page are generated." foreach ($p in $mainSummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy assignment summary page are generated." foreach ($p in $assignmentSummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy initiative summary page are generated." foreach ($p in $initiativeSummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy definition summary page are generated." foreach ($p in $definitionSummaryPage) { Write-Output " - $p" } if ($PageStyle -ieq 'detailed') { Write-Output "[$(getCurrentUTCString)]: The following Markdown files for security control summary page are generated." foreach ($p in $securityControlSummaryPage) { Write-Output " - $p" } } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy category summary page are generated." foreach ($p in $policyCategorySummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy exemption summary page are generated." foreach ($p in $exemptionSummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy subscription summary page are generated." foreach ($p in $subscriptionSummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for policy analysis summary page are generated." foreach ($p in $analysisSummaryPage) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Subscriptions are generated." foreach ($p in $subscriptionPages) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Policy Assignments are generated." foreach ($p in $assignmentPages) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Policy Initiatives are generated." foreach ($p in $initiativePages) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Policy Definitions are generated." foreach ($p in $definitionPages) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Policy Exemptions are generated." foreach ($p in $exemptionPages) { Write-Output " - $p" } Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Policy Metadata are generated." foreach ($p in $policyMetadataPages) { Write-Output " - $p" } if ($customSecurityControlPages) { Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Custom Security Controls are generated." foreach ($p in $customSecurityControlPages) { Write-Output " - $p" } } if ($policyCategoryPages) { Write-Output "[$(getCurrentUTCString)]: The following Markdown files for Policy Categories are generated." foreach ($p in $policyCategoryPages) { Write-Output " - $p" } } if ($WikiStyle -ieq 'github') { Write-Output "[$(getCurrentUTCString)]: The GitHub wiki sidebar and footer files have been successfully generated." Write-Output " - $sidebarFilePath" Write-Output " - $footerFilePath" } Write-Output "[$(getCurrentUTCString)]: The Policy documentation have been successfully generated for Management Group '$($AzplEnvironmentDetails.topLevelManagementGroupName)'." } #endregion |