AzReports.psm1

#Region '.\Private\CheckAzContext.ps1' 0
function CheckAzContext {
    if (-not (Get-AzContext).Account) {
        Connect-AzAccount
    }
}
#EndRegion '.\Private\CheckAzContext.ps1' 6
#Region '.\Private\CheckPath.ps1' 0
function CheckPath {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.IO.FileInfo]
        $Path,

        [string]
        $Extension,

        [switch]
        $Force
    )

    if ($Extension) {
        if ($Path.Extension -ne $Extension) {
            throw "File extension must be $( $Extension )!"
        }
    }

    if (Test-Path -Path $Path.DirectoryName) {
        if (Test-Path -Path $Path.FullName) {
            if ($Force) {
                [void](Remove-Item -Path $Path.FullName -Force)
            } else {
                throw "$( $Path.FullName ) already exists, pass -Force to overwrite!"
            }
        }
    } else {
        [void](New-Item -Path $Path.DirectoryName -ItemType Directory -Force)
    }
}
#EndRegion '.\Private\CheckPath.ps1' 33
#Region '.\Public\New-AzReportsPolicyAssignment.ps1' 0
#requires -Modules ImportExcel

function New-AzReportsPolicyAssignment {
    <#
    .SYNOPSIS
        Creates an Excel spreadsheet report with the details for Azure Policy Assignment
    .DESCRIPTION
        Creates an Excel spreadsheet report with the details for Azure Policy Assignment
    .EXAMPLE
        PS C:\> New-AzReportsPolicyAssignment -Path .\temp\SecurityCenterBuiltIn.xlsx -Name SecurityCenterBuiltIn -Force
 
        Creates a report of the Azure Policy Assignment and if the Path already exists it overwrites it.
    .INPUTS
        None
    .OUTPUTS
        Excel Spreadsheet
    #>

    [CmdletBinding()]
    param(
        # Path to create the Excel report. Must end with '.xlsx'.
        [Parameter(Mandatory)]
        [System.IO.FileInfo]
        $Path,

        [string]
        $Name,

        # Do not automatically open the generated Excel spreadsheet.
        [switch]
        $NoInvoke,

        # Overwrite existing Excel spreadsheet.
        [switch]
        $Force
    )
    $InformationPreference = 'Continue'
    $env:SuppressAzurePowerShellBreakingChangeWarnings = 'true'

    try {
        CheckAzContext

        CheckPath -Path $Path -Extension '.xlsx' -Force:$Force -ErrorAction Stop

        if ($Name) {
            $policyAssignments = Get-AzPolicyAssignment -Name $Name
        } else {
            $policyAssignments = Get-AzPolicyAssignment
        }

        $objects = @()

        foreach ( $policyAssignment in $policyAssignments) {
            if ($policyAssignment.Properties.Parameters) {
                $objects += GetPolicyAssignmentParameters -PolicyAssignment $policyAssignment
            } else {
                Write-Information "Policy Assignment: $( $policyAssignment.Properties.DisplayName ) - has no parameters."

                $objects += [PSCustomObject]@{
                    Name             = $policyAssignment.Name
                    'Display Name'   = $policyAssignment.Properties.DisplayName
                    Scope            = $policyAssignment.Properties.Scope
                    'Parameter Name' = $null
                    Value            = $null
                }
            }
        }

        $excelSplat = @{
            Path          = $Path
            WorksheetName = 'PolicyAssignment'
            TableStyle    = 'Medium2'
            AutoSize      = $true
            FreezeTopRow  = $true
            Style         = $excelStyle
            PassThru      = $true
        }

        $excel = $objects |
            Sort-Object -Property Category, Name |
            Export-Excel @excelSplat

        $workSheet = $excel.Workbook.Worksheets[$excelSplat.WorksheetName]

        Set-ExcelRow -Worksheet $workSheet -Row 1 -Bold -HorizontalAlignment Center

        Set-ExcelColumn -Worksheet $workSheet -Column 1 -AutoSize
        Set-ExcelColumn -Worksheet $workSheet -Column 2 -AutoSize
        Set-ExcelColumn -Worksheet $workSheet -Column 3 -AutoSize
        Set-ExcelColumn -Worksheet $workSheet -Column 4 -AutoSize
        Set-ExcelColumn -Worksheet $workSheet -Column 5 -AutoSize

        if ($NoInvoke) {
            Close-ExcelPackage -ExcelPackage $excel
        } else {
            Close-ExcelPackage -ExcelPackage $excel -Show
        }
    } catch {
        throw $PSItem
    }
}
#EndRegion '.\Public\New-AzReportsPolicyAssignment.ps1' 101
#Region '.\Public\New-AzReportsPolicyDefinition.ps1' 0
#requires -Modules ImportExcel

function New-AzReportsPolicyDefinition {
    <#
    .SYNOPSIS
        Creates an Excel spreadsheet report with the details for Azure Policy Definitions.
    .DESCRIPTION
        Creates an Excel spreadsheet report with the details for Azure Policy Definitions.
    .EXAMPLE
        PS C:\> New-AzReportsPolicyDefinition -Path .\BuiltInPolicies -BuiltIn -Force
 
        Creates a report of the BuiltIn Azure Policy Definitions and if the Path already exists it overwrites it.
    .EXAMPLE
        PS C:\> New-AzReportsPolicyDefinition -Path .\CustomPolicies -Custom -Force
 
        Creates a report of the custom Azure Policy Definitions and if the Path already exists it overwrites it.
    .EXAMPLE
        PS C:\> New-AzReportsPolicyDefinition -Path .\CustomPolicies
 
        Creates a report of all Azure Policy Definitions.
    .INPUTS
        None
    .OUTPUTS
        Excel Spreadsheet
    #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param(
        # Path to create the Excel report. Must end with '.xlsx'.
        [Parameter(Mandatory)]
        [Parameter(ParameterSetName = 'Default')]
        [Parameter(ParameterSetName = 'BuiltIn')]
        [Parameter(ParameterSetName = 'Custom')]
        [System.IO.FileInfo]
        $Path,

        # Only output BuiltIn Azure Policy Definitions.
        [Parameter(ParameterSetName = 'BuiltIn')]
        [switch]
        $BuiltIn,

        #Only output Custom Azure Policy Definitions.
        [Parameter(ParameterSetName = 'Custom')]
        [switch]
        $Custom,

        # Do not automatically open the generated Excel spreadsheet.
        [Parameter(ParameterSetName = 'Default')]
        [Parameter(ParameterSetName = 'BuiltIn')]
        [Parameter(ParameterSetName = 'Custom')]
        [switch]
        $NoInvoke,

        # Overwrite existing Excel spreadsheet.
        [Parameter(ParameterSetName = 'Default')]
        [Parameter(ParameterSetName = 'BuiltIn')]
        [Parameter(ParameterSetName = 'Custom')]
        [switch]
        $Force
    )
    $InformationPreference = 'Continue'

    CheckAzContext

    CheckPath -Path $Path -Extension '.xlsx' -Force:$Force

    if ($PSBoundParameters.Keys -contains 'BuiltIn') {
        $policyDefinitions = Get-AzPolicyDefinition -Builtin
    } elseif ($PSBoundParameters.Keys -contains 'Custom') {
        $policyDefinitions = Get-AzPolicyDefinition -Custom
    } else {
        $policyDefinitions = Get-AzPolicyDefinition
    }

    $objects = @()

    foreach ($policyDefinition in $policyDefinitions) {
        Write-Information "Policy Name: $($policyDefinition.Properties.DisplayName)"

        $item = [ordered]@{
            Name                     = $policyDefinition.Name
            Category                 = $policyDefinition.Properties.Metadata.category
            Type                     = $policyDefinition.Properties.PolicyType
            'Display Name'           = $policyDefinition.Properties.DisplayName
            Description              = $policyDefinition.Properties.Description
            'Resource Id'            = $policyDefinition.ResourceId
            'Available Effects'      = $policyDefinition.Properties.PolicyRule.then.effect
            'Parameter Name'         = $null
            'Parameter Type'         = $null
            'Parameter Display Name' = $null
            'Parameter Description'  = $null
            'Allowed Values'         = $null
            'Default Value'          = $null
            'Desired Value'          = $null
        }

        if ($policyDefinition.Properties.Parameters) {
            $parameters = $policyDefinition.Properties.Parameters.PSObject.Members |
                Where-Object { $_.MemberType -eq 'NoteProperty' } |
                Select-Object -ExpandProperty Name

            foreach ($parameter in $parameters) {
                Write-Information "Parameter Name: $parameter"
                $item.'Parameter Name' = $parameter
                $item.'Parameter Type' = $policyDefinition.Properties.Parameters.$parameter.type
                $item.'Parameter Display Name' = $policyDefinition.Properties.Parameters.$parameter.metadata.displayName
                $item.'Parameter Description' = $policyDefinition.Properties.Parameters.$parameter.metadata.description
                $item.'Allowed Values' = $policyDefinition.Properties.Parameters.$parameter.allowedValues -join ', '

                if ($policyDefinition.Properties.Parameters.$parameter.type -eq 'Object') {
                    $item.'Default Value' = $policyDefinition.Properties.Parameters.$parameter.defaultValue |
                        ConvertTo-Json -Compress
                } else {
                    $item.'Default Value' = $policyDefinition.Properties.Parameters.$parameter.defaultValue -join ', '
                }

                $objects += [PSCustomObject]$item
            }

        } else {
            $objects += [PSCustomObject]$item
        }
    }

    $excelStyle = New-ExcelStyle -VerticalAlignment Top

    $excelSplat = @{
        Path          = $Path
        WorksheetName = 'Policies'
        TableStyle    = 'Medium2'
        AutoSize      = $true
        FreezeTopRow  = $true
        Style         = $excelStyle
        PassThru      = $true
    }

    $excel = $objects |
        Sort-Object -Property Category, 'Display Name', 'Parameter Name' |
        Export-Excel @excelSplat

    $workSheet = $excel.Workbook.Worksheets[$excelSplat.WorksheetName]

    Set-ExcelRow -Worksheet $workSheet -Row 1 -Bold -HorizontalAlignment Center

    Set-ExcelColumn -Worksheet $workSheet -Column 1 -AutoSize -Hide
    Set-ExcelColumn -Worksheet $workSheet -Column 2 -AutoSize -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 3 -AutoSize -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 4 -Width 50 -WrapText
    Set-ExcelColumn -Worksheet $workSheet -Column 5 -Width 60 -WrapText
    Set-ExcelColumn -Worksheet $workSheet -Column 6 -AutoSize -HorizontalAlignment Left
    Set-ExcelColumn -Worksheet $workSheet -Column 7 -AutoSize -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 8 -Width 50 -WrapText -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 9 -AutoSize -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 10 -Width 50 -WrapText
    Set-ExcelColumn -Worksheet $workSheet -Column 11 -Width 50 -WrapText
    Set-ExcelColumn -Worksheet $workSheet -Column 12 -Width 50 -WrapText -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 13 -Width 50 -WrapText -HorizontalAlignment Center
    Set-ExcelColumn -Worksheet $workSheet -Column 14 -Width 50 -WrapText -HorizontalAlignment Center

    if ($NoInvoke) {
        Close-ExcelPackage -ExcelPackage $excel
    } else {
        Close-ExcelPackage -ExcelPackage $excel -Show
    }
}
#EndRegion '.\Public\New-AzReportsPolicyDefinition.ps1' 165
#Region '.\Public\New-AzReportsRegion.ps1' 0
function New-AzReportsRegion {
    <#
    .SYNOPSIS
        Creates an Markdown file report with the details for Azure Policy Assignment
    .DESCRIPTION
        Creates an Markdown file report with the details for Azure Policy Assignment
    .EXAMPLE
        PS C:\> New-AzReportsPolicyAssignment -Path .\temp\SecurityCenterBuiltIn.xlsx -Name SecurityCenterBuiltIn -Force
 
        Creates a report of the Azure Policy Assignment and if the Path already exists it overwrites it.
    .INPUTS
        None
    .OUTPUTS
        Markdown File
    #>

    [CmdletBinding()]
    param(
        # Path to create the Markdown report. Must end with '.md'.
        [System.IO.FileInfo]
        $Path,

        # Do not automatically open the generated Markdown file.
        [switch]
        $NoInvoke,

        # Overwrite existing Markdown file.
        [switch]
        $Force
    )
    CheckAzContext

    if ($Path) {
        CheckPath -Path $Path -Extension '.md' -Force:$Force
    }

    $azRegions = Get-AzLocation |
        Sort-Object -Property DisplayName

    $customAzRegions = [System.Collections.ArrayList]@()

    foreach ($azRegion in $azRegions) {
        $shortLocation = ''
        $shortLocationSubstitions = @(
            @{
                Southeast = 'SE'
            }
        )
        $displayNameComponents = $azRegion.DisplayName.Split(' ')

        foreach ($displayNameComponent in $displayNameComponents) {
            if ($shortLocationSubstitions.Keys -contains $displayNameComponent) {
                $shortLocation += $shortLocationSubstitions.$displayNameComponent
            } elseif ([Int]::TryParse($displayNameComponent, [ref]$null)) {
                $shortLocation += $displayNameComponent
            } else {
                $shortLocation += $displayNameComponent -creplace '[^A-Z]'
            }
        }

        $customAzRegions += [PSCustomObject]@{
            'Display Name'        = $azRegion.DisplayName
            Region                = $azRegion.Location
            'Region Length'       = $azRegion.Location.Length
            'Short Region'        = $shortLocation.ToLower()
            'Short Region Length' = $shortLocation.Length
        }
    }

    $headers = $customAzRegions |
        Get-Member -MemberType NoteProperty |
        Select-Object -ExpandProperty Name

    $sbTable = [System.Text.StringBuilder]'|'

    $headerPadding = @{}

    foreach ($header in $headers) {
        $headerValueLengths = $customAzRegions.'Display Name' |
            Select-Object -ExpandProperty Length -Unique |
            Sort-Object -Descending

        if ($header.Length -gt $headerValueLengths[0]) {
            $headerPadding.$header = $header.Length
        } else {
            $headerPadding.$header = $headerValueLengths[0]
        }

        $null = $sbTable.Append((' {0} |' -f $header.PadRight($headerPadding.$header, ' ')))
    }

    $null = $sbTable.AppendLine('')
    $null = $sbTable.Append('|')

    foreach ($header in $headers) {
        $null = $sbTable.Append((' {0} |' -f ''.PadRight($headerPadding.$header, '-')))
    }

    $null = $sbTable.AppendLine('')

    foreach ($customAzRegion in $customAzRegions) {
        $null = $sbTable.Append('|')

        foreach ($header in $headers) {
            $null = $sbTable.Append((' {0} |' -f $customAzRegion.$header.ToString().PadRight($headerPadding.$header, ' ')))
        }

        $null = $sbTable.AppendLine('')
    }

    if ($Path) {
        $sbTable.ToString() |
            Out-File -FilePath $Path.FullName

        if (-not $NoInvoke) {
            Invoke-Item -Path $Path.FullName
        }
    } else {
        $sbTable.ToString()
    }
}
#EndRegion '.\Public\New-AzReportsRegion.ps1' 121