PowerShell Mailbox Delegate Enumeration Script

<#
.SYNOPSIS
Returns delegate access to all mailboxes within a specified OU.
.DESCRIPTION
Returns delegate access to all mailboxes within a specified OU.  Where groups are delegated they are expanded and the members are listed.
.PARAMETER OrganizationalUnit
This will check all the mailboxes within a specified OrganizationalUnit.
.PARAMETER SubOrganizationalUnit
If this parameter is specified only the mailboxes in this OU will be checked as non-delegates.
.PARAMETER NonDelegated
If this switch is specified all mailboxes that have no delegates and are not themselves delegates will be listed.
.EXAMPLE
bob.holness@countdown.com | .\Update-SendAsPermissions.ps1
.NOTES
NAME : Report-DelegatePermissions

V1.0 Initial Version
#>
[cmdletbinding(DefaultParameterSetName="None")]
param
(
    [Parameter(
        ParameterSetName="OrganizationalUnit",
        Mandatory=$true,
        HelpMessage="Please pass a valid organizational unit.")
    ]
    [String]$OrganizationalUnit, 
    [Parameter(
        ParameterSetName="OrganizationalUnit",
        Mandatory=$true,
        HelpMessage="Please pass a valid NetBIOS Domain Name.")
    ] 
    [string]$DomainName="countdown.com",
    [String]$SubOrganizationalUnit="",
    [switch]$NonDelegated    
)

BEGIN
{
}
PROCESS
{
    function Return-GroupMemberDetails
    {
        <#
        .SYNOPSIS
        This function will recursively list the details of each member of a passed group.
        .DESCRIPTION
        This function will recursively list the details of each member of a passed group.
        .PARAMETER $OutDetail
        This is a hashtable containing the passed output details of the group being enumerated.
        .PARAMETER $Group
        This is the group which needs it's membership enumerating.
        #>

        param
        (
        [Parameter(
            Mandatory=$true)]
            [PSObject]$OutDetail,
        [Parameter(
            Mandatory=$true)]
            [System.DirectoryServices.DirectoryEntry]$Group
        )     
        $objMemberOutput=New-Object -typename PSObject        
        $objMemberOutput | Add-Member NoteProperty "DisplayName" $OutDetail.DisplayName
        $objMemberOutput | Add-Member NoteProperty "EmailAddress" $OutDetail.EmailAddress
        $objMemberOutput | Add-Member NoteProperty "DelegatedUser" $OutDetail.DelegatedUser
        $objMemberOutput | Add-Member NoteProperty "AccessRights" $OutDetail.AccessRights
        $objMemberOutput | Add-Member NoteProperty "ExtendedRights" $OutDetail.ExtendedRights
        $objMemberOutput | Add-Member NoteProperty "Group" $OutDetail.Group
        $objMemberOutput | Add-Member NoteProperty "Memberof" $OutDetail.MembeOf
        $objMemberOutput | Add-Member NoteProperty "MailEnabled" $OutDetail.MailEnabled
        $objMemberOutput | Add-Member NoteProperty "Message" $OutDetail.Message
        
        $objMemberOutput.MemberOf=$DomainNetbiosName+"\"+$Group.SamAccountName
        foreach($MemberDN in $Group.Member)
        {
            $MemberObject=[adsi]("LDAP://"+$MemberDN)
            $objMemberOutput.EmailAddress=([string]$MemberObject.mail)
            if (($MemberObject.mail -ne $null) -and ($MemberObject.mail -ne ""))
            {
                $objMemberOutput.MailEnabled=$true
            }
            #Only process users and groups (skip computer objects)
            if ($MemberObject.objectClass -contains "group")
            {
                $objMemberOutput.DelegatedUser=$DomainNetbiosName+"\"+$MemberObject.SamAccountName
                $objMemberOutput.Group = $true
                Return-GroupMemberDetails $objMemberOutput $MemberObject
                Write-Output $objMemberOutput
            }elseif (($MemberObject.objectClass -contains "user") -and -not ($MemberObject.objectClass -contains "computer"))
            {
                $objMemberOutput.Group = $false
                $objMemberOutput.DelegatedUser=$MemberObject.UserPrincipalName.Value
                Write-Output $objMemberOutput
            }                
        }               
    }
    
    function Return-MailboxDelegationList
    {
        <#
        .SYNOPSIS
        This function returns all the users and groups delegated permissions to a mailbox.  Group memberships areenumerated recursively.
        .DESCRIPTION
        This function returns all the users and groups delegated permissions to a mailbox.  Group memberships areenumerated recursively.
        .PARAMETER $MailboxToProcess
        The mailbox object to list delegates of.
        .PARAMETER $NonDelegated
        If this switch is specified only mailboxes with no delegates are returned.
        .PARAMETER $Count
        This is added to the Verbose string listing the mailbox being processed.
        #>    

        param
        (
        [Parameter(
            Mandatory=$true)]
            [Microsoft.Exchange.Data.Directory.Management.Mailbox]$MailboxToProcess,
            [switch]$NonDelegated, 
            [int]$Count      
        )
        
        $SamAccountNameSearchString=$DomainNetbiosName+"\"+$MailboxToProcess.SamAccountName
        $Permissions=$MailboxToProcess | Get-MailboxPermission | ?{($_.IsInherited -eq $False) -and -not ($_.User -like "NT AUTHORITY\SELF") -and -not ($_.User -like $SamAccountNameSearchString)}
        #Only process if there are some permissions explictly defined on the mailbox(non-inherited) and are not SELF or the owner.
        Write-Verbose "$Count to go : Processing Mailbox : $MailboxToProcess.DisplayName"
        if(((@($Permissions).Count -gt 0) -and ($Permissions -ne $Null) -and -not $NonDelegated))
        {
            foreach($SinglePermission in $Permissions)
            {
                $objOutput=New-Object -typename PSObject
                
                $objOutput | Add-Member NoteProperty "DisplayName" $MailboxToProcess.DisplayName
                $objOutput | Add-Member NoteProperty "EmailAddress" ([string]($MailboxToProcess.PrimarySMTPAddress))
                $objOutput | Add-Member NoteProperty "DelegatedUser" ""
                $objOutput | Add-Member NoteProperty "AccessRights" ([string]($SinglePermission.AccessRights))
                $objOutput | Add-Member NoteProperty "ExtendedRights" ([string]($SinglePermission.ExtendedRights))
                $objOutput | Add-Member NoteProperty "Group" $false
                $objOutput | Add-Member NoteProperty "Memberof" ""
                $objOutput | Add-Member NoteProperty "MailEnabled" $false
                $objOutput | Add-Member NoteProperty "Message" ""
 
                #Permissions are 
                $FullAccessUserSIDString=$SinglePermission.User.SecurityIdentifier.Value                               
                $objSid=New-Object System.Security.Principal.SecurityIdentifier $FullAccessUserSIDString
                $FullAccessUserName=$null                                    
                $ErrorActionPreference="SilentlyContinue"                    
                $FullAccessUserName=$objSid.Translate([System.Security.Principal.NTAccount])
                $ErrorActionPreference="Stop"
                if ($FullAccessUserName -ne $null)
                { 
                    $DelegatedObject=[adsi]("LDAP://<SID="+$FullAccessUserSIDString+">")   
                    if (($DelegatedObject.mail -ne $null) -and ($DelegatedObject.mail -ne ""))
                    {
                        $objOutput.MailEnabled=$true
                    }                                    
                    if ($DelegatedObject.objectClass -contains "group")
                    {
                        $objOutput.DelegatedUser=$FullAccessUserName.Value                     
                        $objOutput.Group=$true
                        #If it's a group pass the mailbox details and then expand the group membership
                        Return-GroupMemberDetails $objOutput $DelegatedObject
                    }elseif (($DelegatedObject.objectClass -contains "user") -and -not ($DelegatedObject.objectClass -contains "computer"))
                    {
                        $objOutput.DelegatedUser=$DelegatedObject.UserPrincipalName.ToString()
                    }
                }else
                {
                    $objOutput.DelegatedUser=$FullAccessUserSIDString
                    $objOutput.Message="Could not translate SID to a valid object"
                    
                }
                #Only process users and groups (skip computer objects)
                if ($objOutput.DelegatedUser -ne "")
                {
                    Write-Output $objOutput
                }
            }
        }elseif((((@($Permissions).Count -eq 0) -or ($Permissions -eq $Null)) -and $NonDelegated))
        {
            #If nondelegated specified only show mailboxes with no filtered delegated permissions
            $objOutput=New-Object -typename PSObject          
            $objOutput | Add-Member NoteProperty "DisplayName" $MailboxToProcess.DisplayName
            $objOutput | Add-Member NoteProperty "EmailAddress" $MailboxToProcess.PrimarySMTPAddress
            $objOutput | Add-Member NoteProperty "DelegatedUser" ""
            $objOutput | Add-Member NoteProperty "MailEnabled" $false

            $objOutput.MailEnabled=$true
            Write-Output $objOutput          
        }
    }
    if (($OrganizationalUnit -ne "") -and ($OrganizationalUnit -ne $null))
        {
            if([adsi]::exists(("LDAP://" + $OrganizationalUnit)))
            {
                $Mailboxes=Get-Mailbox -OrganizationalUnit $OrganizationalUnit -ResultSize Unlimited
                
                $Count=$Mailboxes.Count
                if ($NonDelegated)
                {
                    #If just an OU is specified get a list of mailboxes with delegations from that OU and then
                    #Get a list of all mailboxes without delegations that are not in the first list.
                    Write-Verbose "Building List of Mailboxes with Delegations"                   
                    $DelegatedEMailAddresses = $Mailboxes |  % {Return-MailboxDelegationList $_ -Count:$Count;$Count-=1} | Select -expandproperty EmailAddress
                    Write-Verbose "Return list of Mailboxes with no delegations that are not in the list of mailboxes with delegations."
                    if ($SubOrganizationalUnit -ne "")
                    {
                        #If a valid subou is specified as well, use the subou as the source for the mailboxes
                        #without delegations (this will be a lot faster if you're only interested
                        #in users in a small OU without delegations and who are not delegated to.
                        if([adsi]::exists(("LDAP://" + $SubOrganizationalUnit)))
                        {
                            $Mailboxes=Get-Mailbox -OrganizationalUnit $SubOrganizationalUnit -ResultSize Unlimited
                        }else
                        {
                            Write-Error "Invalid SubOrganizationalUnit specified."
                        }
                    }                    
                    $Count=$Mailboxes.Count
                    $Mailboxes |  % {Return-MailboxDelegationList -nonDelegated $_ -Count:$Count;$Count-=1} | ? {-not ($DelegatedEmailAddresses -contains $_.EmailAddress)}
                    ##>
                }else
                {
                    $Mailboxes |  % {Return-MailboxDelegationList $_ -Count:$Count;$Count-=1}
                }
            }else
            {
                Write-Error "Invalid OrganizationalUnit specified."
            }
        }
 }