functions/Invoke-PasswordStateReport.ps1

Function Invoke-PasswordStateReport {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '', Justification = 'Not a password just an ID')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUserNameAndPassWordParams', '', Justification = 'UserID and *PasswordListID* are not a user and not a password')]
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'All')]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Position = 0, HelpMessage = "Possible values: 1-49")]
        [ValidateScript( {
                if ($_ -notmatch '^([0-9]|[1-4][0-9])$') {
                    throw "Given ReportID '$_' is not a valid ReportID. Please specify a correct ReportID from 1-49. You can get all possible ReportIDs and their purpose with 'Invoke-PasswordStateReport -ShowReportIDs' or 'Invoke-PasswordStateReport -ShowAllReportIDs' for a list"
                }
                else {
                    $true
                }
            })]
        [int32]$ReportID,
        [Parameter(ParameterSetName = 'Specific', ValueFromPipelineByPropertyName, Position = 0)][string]$UserID,
        [Parameter(ParameterSetName = 'Specific', ValueFromPipelineByPropertyName, Position = 1)][string]$SecurityGroupName,
        [Parameter(ParameterSetName = 'Specific', ValueFromPipelineByPropertyName, Position = 2, HelpMessage = "Possible values are 0 for current month, 1 for the past 30 days, and then any other integer representing the quantity of months.")]
        [AllowNull()]
        [Alias('Duration')]
        [Nullable[Int32][]]
        $DurationInMonth,
        [Parameter(ValueFromPipelineByPropertyName, Position = 1, HelpMessage = "SiteID 0 = Default site 'Internal'")]
        [AllowNull()]
        [Nullable[Int32][]]
        $SiteID = 0,
        [Parameter(ParameterSetName = 'Specific', ValueFromPipelineByPropertyName, Position = 3)]
        [AllowNull()]
        [Nullable[Int32][]]
        $PasswordListIDs,
        [Parameter(ParameterSetName = 'Specific', ValueFromPipelineByPropertyName, Position = 4)][switch]$QueryExpiredPasswords,
        [Parameter(ValueFromPipelineByPropertyName, Position = 2)][switch]$ShowReportIDs,
        [Parameter(ValueFromPipelineByPropertyName, Position = 3)][switch]$ShowAllReportIDs
    )

    begin {
        $col_ReportIDs = [ordered]@{
            "User Reports"     = [ordered]@{
                "1"  = "What passwords can a user see?"
                "2"  = "What passwords does a user still know?"
                "3"  = "What has a user been doing lately?"
                "4"  = "What Failed login attempts have there been?"
                "5"  = "Who hasn't logged in recently?"
                "6"  = "Who has one or more Security Administrator roles?"
                "7"  = "What Remote Sessions has a user been doing lately?"
                "8"  = "What user accounts are currently disabled?"
                "9"  = "What user accounts are set to expire?"
                "10" = "Which users have logged in using the Emergency Access account?"
                "11" = "What user account impersonation has been occurring?"
                "41" = "What authentication option is applied for each user?"
            }
            "Passwords"        = [ordered]@{
                "12" = "What passwords have failed Heartbeat?"
                "13" = "What passwords have failed Reset?"
                "14" = "What passwords require checkout?"
                "15" = "What passwords are currently checked out?"
                "16" = "What passwords require a Reason to be specified for access?"
                "17" = "What passwords are expiring soon?"
                "18" = "What passwords have recently been reset?"
                "19" = "What password values have been reused?"
                "20" = "What passwords have not been used lately?"
                "21" = "What Passwords are not being synced?"
                "36" = "Show Passwords configured for resets and their dependencies"
                "22" = "Passwords Strength Compliance Status"
                "35" = "Have I Been Pwned Compromises"
            }
            "Permissions"      = [ordered]@{
                "23" = "What permissions exist (all users and security groups)?"
                "24" = "What permissions exist for a user?"
                "25" = "What Permissions exist for a Security Group?"
                "26" = "What permissions have changed recently?"
                "43" = "What permissions exist for all shared password records?"
                "44" = "What permissions exist for all Host Folders?"
                "27" = "Who has been approved access to passwords recently?"
                "28" = "Who has been denied access to passwords recently?"
                "37" = "How many Administrators are there for each Shared Password List?"
                "38" = "How many Administrators are there for each Password Folder?"
            }
            "Activity"         = [ordered]@{
                "29" = "Remote Session Launcher Activity"
                "30" = "Browser Extension Activity"
                "31" = "Mobile Client Activity"
                "32" = "API Activity"
                "33" = "Self Destruct Activity"
                "34" = "Passive High Availability Module Activity"
            }
            "Document Reports" = [ordered]@{
                "45" = "What documents have been uploaded into Password Folders?"
                "46" = "What documents have been uploaded into Password Lists?"
                "47" = "What documents have been uploaded into Password records?"
                "48" = "What documents have been uploaded into Host Folders?"
                "49" = "What documents have been uploaded into Host records?"
            }
            "Misc Reports"     = [ordered]@{
                "39" = "Where are Privileged Account Credentials currently being used?"
                "40" = "What security groups exist, and who are their members?"
                "42" = "What Host records exist in Passwordstate?"
            }
        }
        # Generate a hashtable with all values from the nested hashtable
        $col_AllReportIDs = [ordered]@{ }
        foreach ($Key in $col_ReportIDs.Keys) {
            foreach ($SubKey in $col_ReportIDs[$Key].Keys) {
                $col_AllReportIDs.Add($SubKey, $col_ReportIDs[$Key][$SubKey])
            }
        }
        # if -ShowAllReportIDs is applied, show a full list of the hashtable values
        If ($PSBoundParameters.ContainsKey('ShowAllReportIDs')) {
            $ReportIDs = $col_AllReportIDs
        }
        # if -ShowReportIDs is applied, show a a structured list with categories of the hashtable values
        ElseIf ($PSBoundParameters.ContainsKey('ShowReportIDs')) {
            $ReportIDs = $col_ReportIDs
        }
        else {
            $ReportIDs = $null
        }
    }
    process {
        # If -ShowReportIDs or -ShowAllReportIDs was specified, output the overview and return the table from this function
        if ($ReportIDs) {
            return $ReportIDs
        }
        # Use default report for all permissions if no ReportID was specified
        If (!($PSBoundParameters.ContainsKey('ReportID'))) {
            throw "Error: No ReportID specified, please specify a valid ReportID from 1-49. You can get all possible ReportIDs and their purpose with 'Invoke-PasswordStateReport -ShowReportIDs' or 'Invoke-PasswordStateReport -ShowAllReportIDs' for a list"
        }
        if ($ReportID) {
            # Get the name for the report id
            [string]$ReportName = $col_AllReportIDs."$($ReportID)"
            Switch ($PSCmdlet.ParameterSetName) {
                'All' {
                    If ($null -ne $SiteID) {
                        $BuildURL = [string]$ReportID + '?'
                        $BuildURL += "SiteID=$([System.Web.HttpUtility]::UrlEncode($SiteID))&"
                    }
                    else {
                        $BuildURL = $ReportID
                    }
                }
                'Specific' {
                    $BuildURL = [string]$ReportID + '?'
                    If ($UserID) { $BuildURL += "UserID=$([System.Web.HttpUtility]::UrlEncode($UserID))&" }
                    If ($SecurityGroupName) { $BuildURL += "SecurityGroupName=$([System.Web.HttpUtility]::UrlEncode($SecurityGroupName))&" }
                    If ($null -ne $SiteID) { $BuildURL += "SiteID=$([System.Web.HttpUtility]::UrlEncode($SiteID))&" }
                    If ($null -ne $DurationInMonth) { $BuildURL += "Duration=$([System.Web.HttpUtility]::UrlEncode($DurationInMonth))&" }
                    If ($null -ne $PasswordListIDs) { $BuildURL += "PasswordListIDs=$([System.Web.HttpUtility]::UrlEncode($PasswordListIDs))&" }
                    If ($QueryExpiredPasswords.IsPresent) { $BuildURL += "QueryExpiredPasswords=$([System.Web.HttpUtility]::UrlEncode($QueryExpiredPasswords))&" }
                }
            }
            if ($BuildURL) {
                $BuildURL = $BuildURL -Replace ".$"
                $uri = "/api/reporting/$($BuildURL)"
            }
            if ($PSCmdlet.ShouldProcess("Running report '$ReportName' (ID '$ReportID') for Site '$SiteID'. Specific options: User = '$UserID', SecurityGroup = '$SecurityGroupName', Duration = '$DurationInMonth', PasswordListIDs = '$PasswordListIDs', QueryExpiredPasswords = '$QueryExpiredPasswords'")) {
                Try {
                    $output = Get-PasswordStateResource -uri $uri -method GET -ErrorAction Stop
                }
                Catch {
                    Throw $_.Exception
                }
            }
        }
    }
    end {
        if ($output) {
            return $output
        }
    }
}