Scripts/Get-MailboxPermissions.ps1

function Get-MailboxPermissions {
<#
    .SYNOPSIS
    Retrieves delegated permissions for all mailboxes in Microsoft 365.
 
    .DESCRIPTION
    Retrieves detailed information about mailbox delegated permissions, including Full Access, Send As,
    Send on Behalf, Calendar permissions, and Inbox permissions for all mailboxes.
 
    .PARAMETER OutputDir
    Specifies the output directory for the delegated permissions report.
    Default: Output\Mailbox Permissions
 
    .PARAMETER Encoding
    Specifies the encoding of the CSV output file.
    Default: UTF8
 
    .PARAMETER UserIds
    UserIds is the UserIds parameter filtering the log entries by the account of the user who performed the actions.
 
    .PARAMETER LogLevel
    Specifies the level of logging:
    None: No logging
    Minimal: Critical errors only
    Standard: Normal operational logging
    Debug: Verbose logging for debugging purposes
    Default: Standard
     
    .EXAMPLE
    Get-MailboxPermissions
    Retrieves delegated permissions for all mailboxes and exports to a CSV file in the default directory.
         
    .EXAMPLE
    Get-MailboxPermissions -OutputDir C:\Temp -Encoding UTF32
    Retrieves delegated permissions and saves the output to C:\Temp with UTF-32 encoding.
 
    .EXAMPLE
    Get-MailboxPermissions -OutputDir "Reports" -Encoding UTF8
    Retrieves delegated permissions and saves the report in the Reports folder with UTF-8 encoding.
#>

    [CmdletBinding()]
    param (
        [string]$outputDir = "Output\Delegated Permissions",
        [string]$Encoding = "UTF8",
        [ValidateSet('None', 'Minimal', 'Standard', 'Debug')]
        [string]$LogLevel = 'Standard',
        [string[]]$UserIds
        )

    Set-LogLevel -Level ([LogLevel]::$LogLevel)
    $isDebugEnabled = $script:LogLevel -eq [LogLevel]::Debug

    $summary = @{
        TotalMailboxes = 0
        MailboxesProcessed = 0
        MailboxesWithPermissions = 0
        PermissionStats = @{
            FullAccess = 0
            SendAs = 0
            SendOnBehalf = 0
            Calendar = 0
            Inbox = 0
        }
        StartTime = Get-Date
        ProcessingTime = $null
    }

    Write-LogFile -Message "=== Starting Mailbox Permissions Collection ===" -Color "Cyan" -Level Standard
    
    if ($isDebugEnabled) {
        Write-LogFile -Message "[DEBUG] PowerShell Version: $($PSVersionTable.PSVersion)" -Level Debug
        Write-LogFile -Message "[DEBUG] Input parameters:" -Level Debug
        Write-LogFile -Message "[DEBUG] OutputDir: $outputDir" -Level Debug
        Write-LogFile -Message "[DEBUG] Encoding: $Encoding" -Level Debug
        Write-LogFile -Message "[DEBUG] LogLevel: $LogLevel" -Level Debug
        Write-LogFile -Message "[DEBUG] UserIds: $UserIds" -Level Debug
        
        $exchangeModule = Get-Module -Name ExchangeOnlineManagement -ErrorAction SilentlyContinue
        if ($exchangeModule) {
            Write-LogFile -Message "[DEBUG] ExchangeOnlineManagement Module Version: $($exchangeModule.Version)" -Level Debug
        } else {
            Write-LogFile -Message "[DEBUG] ExchangeOnlineManagement Module not loaded" -Level Debug
        }

        try {
            $connectionInfo = Get-ConnectionInformation -ErrorAction SilentlyContinue
            if ($connectionInfo) {
                Write-LogFile -Message "[DEBUG] Connection Status: $($connectionInfo.State)" -Level Debug
                Write-LogFile -Message "[DEBUG] Connection Type: $($connectionInfo.TokenStatus)" -Level Debug
                Write-LogFile -Message "[DEBUG] Connected Account: $($connectionInfo.UserPrincipalName)" -Level Debug
            } else {
                Write-LogFile -Message "[DEBUG] No active Exchange Online connection found" -Level Debug
            }
        } catch {
            Write-LogFile -Message "[DEBUG] Unable to retrieve connection information" -Level Debug
        }
    }

    $date = [datetime]::Now.ToString('yyyyMMddHHmmss') 
    $outputFile = "$($date)-MailboxDelegatedPermissions.csv"

    if (!(test-path $OutputDir)) {
        New-Item -ItemType Directory -Force -Path $OutputDir > $null
    } else {
        if (!(Test-Path -Path $OutputDir)) {
            Write-LogFile -Message "[Error] Custom directory invalid: $OutputDir" -Level Minimal -color "Red"
        }
    }

    $outputDirectory = Join-Path $outputDir $outputFile

    try {
        Get-EXOMailbox -ResultSize 1 > $null
    }
    catch {
        write-logFile -Message "[INFO] Ensure you are connected to M365 by running the Connect-M365 command before executing this script" -Color "Yellow" -Level Minimal
        Write-logFile -Message "[ERROR] An error occurred: $($_.Exception.Message)" -Color "Red" -Level Minimal
        if ($isDebugEnabled) {
            Write-LogFile -Message "[DEBUG] Connection error details:" -Level Debug
            Write-LogFile -Message "[DEBUG] Exception type: $($_.Exception.GetType().Name)" -Level Debug
            Write-LogFile -Message "[DEBUG] Full error: $($_.Exception.ToString())" -Level Debug
            Write-LogFile -Message "[DEBUG] Stack trace: $($_.ScriptStackTrace)" -Level Debug
        }
        throw
    }

    $results = @()
    Write-LogFile -Message "[INFO] Retrieving mailbox list..." -Level Standard

    if ($UserIds) {
        $userIdList = $UserIds -split ','
        Write-LogFile -Message "[INFO] Filtering mailboxes for users: $UserIds" -Level Standard
        $mailboxes = Get-EXOMailbox -ResultSize unlimited -Properties UserPrincipalName, DisplayName, GrantSendOnBehalfTo, RecipientTypeDetails | 
            Where-Object { $userIdList -contains $_.UserPrincipalName }
    } else {
        $mailboxes = Get-EXOMailbox -ResultSize unlimited -Properties UserPrincipalName, DisplayName, GrantSendOnBehalfTo, RecipientTypeDetails
    }
    
    $totalMailboxes = $mailboxes.Count
    $summary.TotalMailboxes = $mailboxes.Count
    Write-LogFile -Message "[INFO] Found $($summary.TotalMailboxes) mailboxes to process" -Level Standard
    $current = 0

    foreach ($mailbox in $mailboxes) {
        $summary.MailboxesProcessed++
        $current++
        if ($LogLevel -eq 'Standard') {
            Write-Progress -Activity "Checking delegated permissions" -Status "Processing $($mailbox.DisplayName)" -PercentComplete (($current / $totalMailboxes) * 100)
        }

        if ($isDebugEnabled) {
            Write-LogFile -Message "[DEBUG] Mailbox details:" -Level Debug
            Write-LogFile -Message "[DEBUG] Display Name: $($mailbox.DisplayName)" -Level Debug
            Write-LogFile -Message "[DEBUG] UPN: $($mailbox.UserPrincipalName)" -Level Debug
            Write-LogFile -Message "[DEBUG] Type: $($mailbox.RecipientTypeDetails)" -Level Debug
        }

        # Get Full Access permissions
        $fullAccessDetails = Get-MailboxPermission -Identity $mailbox.UserPrincipalName | 
            Where-Object {
                $_.IsInherited -eq $false -and 
                $_.User -notlike "NT AUTHORITY\SELF" -and 
                $_.User -notlike "DiscoverySearchMailbox" -and 
                $_.User -notlike "S-1-5*"
            }

        if ($isDebugEnabled) {
            $fullAccessCount = ($fullAccessDetails | Measure-Object).Count
            Write-LogFile -Message "[DEBUG] Found $fullAccessCount Full Access permissions" -Level Debug
        }

        # Get Send As permissions
        $sendAsDetails = $null
        try {
            $sendAsDetails = Get-RecipientPermission -Identity $mailbox.UserPrincipalName | 
                Where-Object {
                    $_.IsInherited -eq $false -and 
                    $_.Trustee -notlike "NT AUTHORITY\SELF" -and 
                    $_.User -notlike "DiscoverySearchMailbox" -and 
                    $_.Trustee -notlike "S-1-5*"
                }
            if ($isDebugEnabled) {
                $sendAsCount = ($sendAsDetails | Measure-Object).Count
                Write-LogFile -Message "[DEBUG] Found $sendAsCount Send As permissions" -Level Debug
            }
        }
        catch [System.Management.Automation.CommandNotFoundException] {
            if ($LogLevel -eq 'Standard') {
                Write-LogFile -Message "[WARNING] Get-RecipientPermission cmdlet not available. Skipping Send As permissions check for $($mailbox.UserPrincipalName)." -Color "Yellow" -Level Standard
            }
        }
        catch {
            if ($LogLevel -eq 'Standard') {
                Write-LogFile -Message "[WARNING] Error getting Send As permissions for $($mailbox.UserPrincipalName): $($_.Exception.Message)" -Color "Yellow" -Level Standard
            }
            if ($isDebugEnabled) {
                Write-LogFile -Message "[DEBUG] Mailbox retrieval error details:" -Level Debug
                Write-LogFile -Message "[DEBUG] Exception type: $($_.Exception.GetType().Name)" -Level Debug
                Write-LogFile -Message "[DEBUG] Full error: $($_.Exception.ToString())" -Level Debug
                Write-LogFile -Message "[DEBUG] Stack trace: $($_.ScriptStackTrace)" -Level Debug
            }
        }

        # Get Send on Behalf permissions
        $sendOnBehalfUsers = $mailbox.GrantSendOnBehalfTo | Where-Object {$_ -ne $null}

        if ($isDebugEnabled) {
            $sendOnBehalfCount = ($sendOnBehalfUsers | Measure-Object).Count
            Write-LogFile -Message "[DEBUG] Found $sendOnBehalfCount Send on Behalf permissions" -Level Debug
        }
        
        # Get Calendar Folder Permissions
        $calendarPermissions = @()
        try {
            $calendarPermissions = Get-MailboxFolderPermission -Identity "$($mailbox.UserPrincipalName):\Calendar" -ErrorAction Stop | 
                Where-Object {
                    $_.User.DisplayName -notlike "Default" -and 
                    $_.User.DisplayName -notlike "Anonymous" -and 
                    $_.User.DisplayName -notlike "NT AUTHORITY\SELF"
                }

            if ($isDebugEnabled) {
                $calendarCount = ($calendarPermissions | Measure-Object).Count
                Write-LogFile -Message "[DEBUG] Found $calendarCount Calendar permissions" -Level Debug
            }
        }
        catch {
        }

         # Get Inbox Folder Permissions
        $inboxPermissions = @()
        try {
            $inboxPermissions = Get-MailboxFolderPermission -Identity "$($mailbox.UserPrincipalName):\Inbox" -ErrorAction Stop | 
                Where-Object {
                    $_.User.DisplayName -notlike "Default" -and 
                    $_.User.DisplayName -notlike "Anonymous" -and 
                    $_.User.DisplayName -notlike "NT AUTHORITY\SELF"
                }

            if ($isDebugEnabled) {
                $inboxCount = ($inboxPermissions | Measure-Object).Count
                Write-LogFile -Message "[DEBUG] Found $inboxCount Inbox permissions" -Level Debug
            }
        }
        catch {
        }

        if ($fullAccessDetails) {
            $summary.PermissionStats.FullAccess += ($fullAccessDetails | Measure-Object).Count
        }

        if ($sendAsDetails) {
            $summary.PermissionStats.SendAs += ($sendAsDetails | Measure-Object).Count
        }

        if ($sendOnBehalfUsers) {
            $summary.PermissionStats.SendOnBehalf += ($sendOnBehalfUsers | Measure-Object).Count
        }

        if ($calendarPermissions) {
            $summary.PermissionStats.Calendar += ($calendarPermissions | Measure-Object).Count
        }

        if ($inboxPermissions) {
            $summary.PermissionStats.Inbox += ($inboxPermissions | Measure-Object).Count
        }

        $permissionEntry = [PSCustomObject]@{
            UserPrincipalName = $mailbox.UserPrincipalName
            DisplayName = $mailbox.DisplayName
            RecipientTypeDetails = $mailbox.RecipientTypeDetails
            
            # Full Access Details
            FullAccessUsers = ($fullAccessDetails | ForEach-Object {
                $user = Get-EXORecipient $_.User -ErrorAction SilentlyContinue
                if ($user) {
                    "$($user.DisplayName) ($($user.PrimarySmtpAddress))"
                } else {
                    $_.User
                }
            }) -join '; '
            FullAccessPermissions = ($fullAccessDetails | ForEach-Object { 
                $user = Get-EXORecipient $_.User -ErrorAction SilentlyContinue
                $userName = if ($user) { "$($user.DisplayName) ($($user.PrimarySmtpAddress))" } else { $_.User }
                "$userName - Rights: $($_.AccessRights -join ','), Deny: $($_.Deny), Inheritance: $($_.InheritanceType)" 
            }) -join ' | '
            
            # Send As Details
            SendAsUsers = ($sendAsDetails | ForEach-Object {
                $user = Get-EXORecipient $_.Trustee -ErrorAction SilentlyContinue
                if ($user) {
                    "$($user.DisplayName) ($($user.PrimarySmtpAddress))"
                } else {
                    $_.Trustee
                }
            }) -join '; '
            SendAsPermissions = ($sendAsDetails | ForEach-Object { 
                $user = Get-EXORecipient $_.Trustee -ErrorAction SilentlyContinue
                $userName = if ($user) { "$($user.DisplayName) ($($user.PrimarySmtpAddress))" } else { $_.Trustee }
                "$userName - Type: $($_.AccessControlType), Rights: $($_.AccessRights), Inheritance: $($_.InheritanceType)" 
            }) -join ' | '
            
            # Send on Behalf Details
            SendOnBehalfUsers = ($sendOnBehalfUsers | ForEach-Object {
                $user = Get-EXORecipient $_ -ErrorAction SilentlyContinue
                if ($user) {
                    "$($user.DisplayName) ($($user.PrimarySmtpAddress))"
                } else {
                    $_
                }
            }) -join '; '

            # Calendar Permissions
            CalendarUsers = ($calendarPermissions | ForEach-Object { 
                "$($_.User.DisplayName) ($($_.User.ADRecipient.PrimarySmtpAddress)) - $($_.AccessRights)" 
            }) -join '; '
            CalendarPermissions = ($calendarPermissions | ForEach-Object {
                "$($_.User.DisplayName): $($_.AccessRights)"
            }) -join ' | '

            # Inbox Permissions
            InboxUsers = ($inboxPermissions | ForEach-Object { 
                "$($_.User.DisplayName) ($($_.User.ADRecipient.PrimarySmtpAddress)) - $($_.AccessRights)" 
            }) -join '; '
            InboxPermissions = ($inboxPermissions | ForEach-Object {
                "$($_.User.DisplayName): $($_.AccessRights)"
            }) -join ' | '
            
            # Permission Counts
            FullAccessCount = ($fullAccessDetails | Measure-Object).Count
            SendAsCount = ($sendAsDetails | Measure-Object).Count
            SendOnBehalfCount = ($sendOnBehalfUsers | Measure-Object).Count
            CalendarPermissionCount = ($calendarPermissions | Measure-Object).Count
            InboxPermissionCount = ($inboxPermissions | Measure-Object).Count
        }            

        if ($permissionEntry.FullAccessCount -gt 0 -or 
            $permissionEntry.SendAsCount -gt 0 -or 
            $permissionEntry.SendOnBehalfCount -gt 0 -or
            $permissionEntry.CalendarPermissionCount -gt 0 -or
            $permissionEntry.InboxPermissionCount -gt 0) {
            $summary.MailboxesWithPermissions++
        }

        $results += $permissionEntry
    }

    $results | Export-Csv -Path $outputDirectory -NoTypeInformation -Encoding $Encoding

    $summary.ProcessingTime = (Get-Date) - $summary.StartTime

    Write-LogFile -Message "`n=== Mailbox Permissions Analysis Summary ===" -Color "Cyan" -Level Standard
    Write-LogFile -Message "Processing Statistics:" -Level Standard
    Write-LogFile -Message " Total Mailboxes: $($summary.TotalMailboxes)" -Level Standard
    Write-LogFile -Message " Mailboxes Processed: $($summary.MailboxesProcessed)" -Level Standard
    Write-LogFile -Message " Mailboxes with Permissions: $($summary.MailboxesWithPermissions)" -Level Standard

    Write-LogFile -Message "`nPermission Counts:" -Level Standard
    Write-LogFile -Message " Full Access: $($summary.PermissionStats.FullAccess)" -Level Standard
    Write-LogFile -Message " Send As: $($summary.PermissionStats.SendAs)" -Level Standard
    Write-LogFile -Message " Send on Behalf: $($summary.PermissionStats.SendOnBehalf)" -Level Standard
    Write-LogFile -Message " Calendar: $($summary.PermissionStats.Calendar)" -Level Standard
    Write-LogFile -Message " Inbox: $($summary.PermissionStats.Inbox)" -Level Standard

    Write-LogFile -Message "`nOutput:" -Level Standard
    Write-LogFile -Message " Output File: $outputDirectory" -Level Standard
    Write-LogFile -Message " Processing Time: $($summary.ProcessingTime.ToString('mm\:ss'))" -Color "Green" -Level Standard
}