Scenario: We found that using Microsoft’s spider script (the script that determines all mailbox permissions and delegates found here) was slow and would eat RAM (like Cookie Monster eats cookies) causing our Exchange servers to error out. So we developed a newer, faster, but more raw version of the spider script.
Script: Edit the global variables and then copy and paste in normal Windows Powershell. You want the scriptlet pretty and easy to read, copy and paste into PowerShell ISE. This is not meant to run as a .ps1, we like to see everything….
<#Script Notes:
0. Output of the file will display FullAccess, SendAs, SendOnBehalf, and Calendar Permissions (Reviewer,Editor, ect.)
1. Open a normal Windows Powershell with an account with Exchange Permissions (Run-As)
2. Take a list of all Exchange On-Premises Mailboxes (get-mailbox -resultsize unlimited | Select Alias | export-csv C:tempAll_mbx.csv. All we need is the alias column (keep the header alias), nothing else.
3. This script requires the ActiveDirectory Module
4. In the New-OnPremExchangeSession it will randomly select one of our Exchange servers to process the remote PowerShell Commands. After 500 mailboxes, it will randomly select another.
5. If you have to start over, open a brand new normal Windows Powershell with an account with Exchange Permission (Run-As)
End_ScriptNotes #>
#Global Variables############################################################################################
$m = import-csv “C:tempAll_Mbx.csv” #Import a list of all your Mailboxes. If you have not done this yet, feel free to run the following command inside a Exchange PowerShell: get-mailbox -resultsize unlimited | Export-csv C:tempAll_mbx.csv
$outfile = “C:tempAll_Mbx_Spider_Results.csv” #Final Spider Results Export
$report_Final = @() #Used to capture all spider rights within the script
$count = 0 #The Count starts the counter for each mailbox processed
$CounterSleep = 500 #This offset countersleep allows the script to sleep after 500 Mailboxes and pickup a new Exchange server to connect to to avoid hardware/resource problems
$ExchangeServers = “ExSrv1.domain.com”,”ExSrv2.domain.com”,”ExSrv3.domain.com” #Exchange server pool that your Powershell session with connect to after the CounterSleep hits
$domainForUsername = “domain” #Replace the domain with the domain name used for sign ins. Example: If you login is domainusername: contososteve make the value “contoso”
$dom = $env:userdomain;$usr = $env:username #Just for fun in the script
$DisplayName = ([adsi]”WinNT://$dom/$usr,user”).fullname #Just for fun in the script
#End_Global Variables############################################################################################
#This is where the MAGIC HAPPENS
#Import Module####################################################################################################
#Required for AD Permissions
Import-Module ActiveDirectory
#End_Import Module#####################################################################################################
#Functions required##################################################################################################################################
#Gets nested group members
function Get-DistributionGroupMemberRecursive ($GroupIdentity) {
$member_list = Get-DistributionGroupMember -Identity $GroupIdentity
foreach ($member in $member_list) {
if ($member.RecipientType -like ‘*Group*’) {
Get-DistributionGroupMemberRecursive -GroupIdentity $member.Identity
} else {
$member
}
}
}
#Connects to Exchange remote Powershell on servers randomly
Function New-OnPremExchangeSession(){
#close any old remote session. We don’t need it. Don’t want it.
Get-PSSession | Remove-PSSession -Confirm:$false
For ($i=60; $i -gt 1; $i–-) {
Write-Progress -Activity “$DisplayName made me fall asleep.” -SecondsRemaining $i
Start-Sleep 1
}
Do{
#get-random number for exchange server
$ex_srv = get-random $ExchangeServers
$ex_ps = “http://”+$ex_srv +”/powershell/”
#start a new remote session
“Attempting to connect to Remote Powershell on esgmtwex$ex_i”
$OnPremsession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ex_ps -Authentication Kerberos
$OnPrem = Import-PSSession $OnPremSession
#check for session
$opensession = Get-PSSession | Where {($_.Configurationname -eq “Microsoft.Exchange”) -and ($_.State -eq “Opened”)}
}While($opensession -eq $null)
}
#End_Functions##############################################################################################
#Connect to Exchange##############################################################################################################################
New-OnPremExchangeSession
#END_ConnecttoExchange##############################################################################################################################
#Loop Each Mailbox#################################################################################################################################################################
$m.alias | sort | %{
#Define InLoop Variables
$u = $_
#write-it so you can see it.
Write-host “$U – $count/$($m.count – 1)” -ForegroundColor green
$count++
If($count -eq $CounterSleep){
New-OnPremExchangeSession $OnPremCredentials
$CounterSleep = $CounterSleep + 500
“CounterSleep now set to $CounterSleep”
}
[int]$percentComplete = [int](($Count/$($M.count * 100)))
Write-Progress -Activity “Connected to $((Get-PSSession | Where {($_.Configurationname -eq “Microsoft.Exchange”) -and ($_.State -eq “Opened”)}).computername)” -PercentComplete “$percentComplete” -Status (“Processing Mailbox: $($U) – $($Count) of $($m.count – 1 )”)
“————————”
#Check Mbx
$error.clear()
$mbx = get-mailbox $u
If($error[0].exception -like “*The I/O operation has been aborted*”){“I/O Error Operation found, sleeping 3 minutes”;sleep 180; $mbx=get-mailbox $u}
If($mbx -ne $null){
#here we go!!!!!
#Collect SendOnBehalf permissions##############################################################################################
” Checking SendOnBehalf for $U”
$SendOnBehalf = $mbx.grantsendonbehalfto
If($SendOnBehalf -ne $null){
$SendOnBehalf | %{
$sob_name = $_
$sob_name = ($sob_name -split ‘/’)[-1]
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value $sob_name
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “SendOnBehalf”
$Report_final += $obj
}
}else{
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value “None”
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “SendOnBehalf”
$Report_final += $obj
}
$SendOnBehalf = $null
#End_Calendar##################################################################################################################
#Collect Calendar permissions##############################################################################################
” Checking Calendar for $U”
$cal_var = ($mbx.alias).tostring() +”:calendar”
$Calendar_Perm = get-mailboxfolderpermission $cal_Var | Where {($_.User -notlike “*Default*”) -and ($_.user -notlike “*anonymous*”)}
If($Calendar_Perm -ne $Null){
$calendar_Perm | %{
$cal_user_name = $_.user.adrecipient.name
If($cal_user_name -ne $null){
$cal_user_right = $_ | Select -ExpandProperty AccessRights
#”$Cal_user_name – $Cal_user_right”
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value $cal_user_name
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “Calendar:$cal_user_right”
$Report_final += $obj
}
}
}else{
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value None
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “Calendar”
$Report_final += $obj
}
#Clear FullAccess
$Cal_Var = $null
$Calendar_Perm = $null
$Cal_user_name = $null
$Cal_user_right = $null
#End_Calendar##################################################################################################################
#Collect SendAs permissions##############################################################################################
#This method does not perform a get-adpermission because its slow.
#Why does Microsoft want us to run slow commands when the offer faster commands.
” Checking Sendas for $U”
$SendAs_Perm = (Get-acl -path “AD:$($mbx.distinguishedname)”).access |where {($_.ActiveDirectoryRights -like “*ExtendedRight*”) -and ($_.IsInherited -like “*false*”) -and ($_.IdentityReference -like “$domainForUsername*”) -and ($_.ObjectType -eq “ab721a54-1e2f-11d0-9819-00aa0040529b”)}
#$SendAs = $mbx | Get-ADPermission | Where extendedrights -like send-as | Where User -notlike “Nt AuthoritySelf”
If($SendAs_Perm -ne $Null){
$SendAs_users = @()
$Sendas_Perm.IdentityReference.Value |%{
#Format User Name
$object = $_
$object = $object -replace “$domainForUsername\”,””
#ADCheck
$AD_Chk = Get-adobject -filter {samaccountname -eq $object}
#Write-host ” $($AD_Chk | Select name, objectclass)” -ForegroundColor yellow
#ObjectClass Check based off ADObject $AD_CHK
If($AD_Chk.objectclass -eq “User”){$SendAs_users += $AD_CHK | Select -ExpandProperty Name}
If($AD_Chk.objectclass -eq “Group”){$SendAs_users += Get-DistributionGroupMemberRecursive $($AD_Chk | Select -ExpandProperty Name) | Select -ExpandProperty Name}
$Sendas_users | select -Unique | %{
$delegate = $_
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value $delegate
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “SendAs”
$Report_final += $obj
}
}
}else{
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value None
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “SendAs”
$Report_final += $obj
}
#Clear SendAsVariables
$SendAs_Perm = $null
$Sendas_users = $null
$object = $null
$AD_Chk = $null
$delegate = $null
#End_SendAs##################################################################################################################
#Collect MBX permissions##############################################################################################
” Checking FullAccess for $U”
$FullAccess_Perm = $mbx | get-mailboxpermission | Where {($_.IsInherited -eq $false) -and ($_.User -notlike “NT Auth*”) -and ($_.Deny -eq $false)}
If($FullAccess_Perm -ne $Null){
$fullAccess_Users = @()
$fullAccess_Perm.user | %{
#$fullAccess_Perm.user.securityidentifier | %{
#Format User Name
$object = $_
$object = $object -replace “$domainForUsername\”,””
#ADCheck
#$AD_Chk = Get-adobject -filter {objectsid -eq $object}
$AD_Chk = Get-adobject -filter {samaccountname -eq $object}
#ObjectClass Check based off ADObject $AD_CHK
If($AD_Chk.objectclass -eq “User”){$FullAccess_users += $AD_CHK | Select -ExpandProperty Name}
If($AD_Chk.objectclass -eq “Group”){$FullAccess_users += Get-DistributionGroupMemberRecursive $($AD_Chk | Select -ExpandProperty Name) | Select -ExpandProperty Name}
$FullAccess_users | select -Unique | %{
$delegate = $_
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value $delegate
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “FullAccess”
$Report_final += $obj
}
}
}else{
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value None
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “FullAccess”
$Report_final += $obj
}
#Clear FullAccess
$FullAccess_Perm = $null
$FullAccess_users = $null
$object = $null
$AD_Chk = $null
$delegate = $null
#End_FullAccess##################################################################################################################
}else{
Write-Host “No Mbx for $u” -ForegroundColor Magenta
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -Name Mbx -Value $u
$obj | Add-Member -membertype noteproperty -Name Delegate -Value None
$obj | Add-Member -membertype noteproperty -Name AccessRight -Value “No_Mbx_Found”
$Report_final += $obj}
#Clear InLoop Variables.
#Wash, Rinse, Repeat
$u = $null
$mbx = $null
}
#END_Loop Each Mailbox#################################################################################################################################################################
#View the Report##################################################################################################################################################################
#$report_Final
#$report_Final | out-gridview
$Report_Final | export-csv $outfile
#View the Report##################################################################################################################################################################