-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathGet-HybridMigrationCandidates.ps1
More file actions
416 lines (369 loc) · 18.7 KB
/
Get-HybridMigrationCandidates.ps1
File metadata and controls
416 lines (369 loc) · 18.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
<#
.SYNOPSIS
Determine mailboxes to migrate to o365 in one group based on their full access permission relationships to one another.
.DESCRIPTION
Determine mailboxes to migrate to o365 in one group based on their full access permission relationships to one another. This is meant to be run
multiple times against several seeduser accounts to help determine what groups of accounts you would want to migrate together. The first
time this is run a few global variables are populated in order to reduce the processing required in future itterations.
If you run this script without any seeduser specified then all mailboxes which no others have full access to and that are not accessing
other mailboxes via full access permission will be listed. These are the 'low hanging fruit' and generally can be migrated at any time.
.PARAMETER SeedUser
Specifying the seeduser mailbox asks the question, If you were to migrate this mailbox, which others would need to be migrated as well?
If this parameter is not specified then only mailboxes without any full access permission relationships are returned in the report.
.PARAMETER Domain
Short domain name. This is used as permissions to mailboxes are returned as '<DOMAIN>\<Username>'. If unspecified the local domain is used.
.PARAMETER AdditionalUserFilters
An array of user IDs which are ignored in the mailbox relationship calculations. These filters are extremely important to specify as one admin user mailbox
with access to every mailbox in the environment will mean that every single mailbox is associated as one group if it is not filtered ahead of time!
.LINK
http://www.the-little-things.net
.NOTES
Version
1.0.0 04/01/2016
- Initial release
Author
Zachary Loeber
.EXAMPLE
$AdminIgnoreAccts = @(
'*\admin-*',
'*\someadminuser',
'*\VeritasService'
)
.\Get-MailboxFullAccessPermission.ps1 -AdditionalUserFilters $AdminIgnoreAccts
Description
-----------
Generate a default report on the low hanging fruit for an initial migration. Filter out any results including $AdminIgnoreAccts
#>
[CmdletBinding()]
param(
[Parameter(HelpMessage = "A seed user to base permission checks upon. If not defined then only unshared singular mailboxes will be validated.")]
[string]$SeedUser,
[Parameter(Position = 1, HelpMessage = "Short domain name")]
[string]$Domain,
[Parameter(Position = 2, HelpMessage = "Additional user filters")]
[string[]]$AdditionalUserFilters = @()
)
function Get-MailboxFullAccessPermission {
<#
.SYNOPSIS
Retrieves a list of mailbox full access permissions
.DESCRIPTION
Gathers a list of users with full access permissions for a mailbox.
.PARAMETER MailboxNames
Array of mailbox names in string format.
.PARAMETER MailboxObject
One or more mailbox objects.
.PARAMETER ShowAll
Includes unresolved names (typically deleted accounts).
.PARAMETER Expand
Expands results
.PARAMETER AdditionalUserFilters
Additional user filters
.PARAMETER ExpandGroups
Tests each permission to determine if it is a group and expands it.
.PARAMETER IncludeNullResults
Includes mailboxes with all full permissions filtered out. This can be useful for finding mailboxes which are not shared.
.LINK
http://www.the-little-things.net
.NOTES
Version
1.0.0 01/25/2016
- Initial release
Author : Zachary Loeber
.EXAMPLE
Get-MailboxFullAccessPermission -MailboxName "Test User1" -Verbose
Description
-----------
Gets the send-as permissions for "Test User1" and shows verbose information.
.EXAMPLE
Get-MailboxFullAccessPermission -MailboxName 'user1' | Format-List
Description
-----------
Gets the send-as permissions for "user1" and returns the info as a format-list.
.EXAMPLE
$AdditionalUserFilters = @(
'*\user-admin',
'*\somearchivingsolutionaccount',
'*\someoldbackupaccount',
'*\unifiedmessagingadmin'
)
$Domain = 'CONTOSO' # The domain short name (ie. DOMAIN\<username>)
$perms = Get-Mailbox -ResultSize Unlimited | Get-MailboxFullAccessPermission -AdditionalUserFilters $AdditionalUserFilters -expand -expandgroup -verbose -IncludeNullResults
$groups = $perms | Sort-Object -Property FullAccess | Group-Object -Property FullAccess -AsString -AsHashTable
$standalonemailboxes = @()
Write-Host -ForegroundColor Green "The following mailboxes have full permissions on no other mailboxes."
Write-Host -ForegroundColor Green "Additionally, no other mailboxes have full access to these mailboxes."
$perms | Where {$_.FullAccess -eq $null} | Foreach {
$tmp = "$($Domain)\" + $_.MailboxAlias
if (($groups.$tmp).Count -eq 0) {
Write-Host -ForegroundColor Green " $($_.Mailbox)"
$standalonemailboxes += $_.Mailbox
}
}
Description
-----------
Queries all mailboxes full permission access and filters out results using the default filters plus several custom filters and stores the results in $perm.
The -expandgroup flag attempts to expand out full access users from groups that may be assigned to mailboxes. IncludeNullResults includes mailboxes for which
all full access permissions have been filtered out. The expand flag returns one entry for every user. Then we output to the screen all the users which
in the permissions list along with a count of mailboxes for which they have full access and save the results to $standalonemailboxes.
#>
[CmdLetBinding(DefaultParameterSetName='AsString')]
param(
[Parameter(ParameterSetName='AsString', Mandatory=$True, ValueFromPipeline=$True, Position=0, HelpMessage="Enter an Exchange mailbox name")]
[string]$MailboxName,
[Parameter(ParameterSetName='AsMailbox', Mandatory=$True, ValueFromPipeline=$True, Position=0, HelpMessage="Enter an Exchange mailbox name")]
[Microsoft.Exchange.Data.Directory.Management.Mailbox]$MailboxObject,
[Parameter(HelpMessage='Includes unresolved and other common full permission accounts.')]
[switch]$ShowAll,
[Parameter(HelpMessage="Additional user filters")]
[string[]]$AdditionalUserFilters = @(),
[Parameter(HelpMessage='Expands results.')]
[switch]$Expand,
[Parameter(HelpMessage='Expands AD groups.')]
[switch]$ExpandGroups,
[Parameter(HelpMessage='Includes mailboxes with all full permissions filtered out.')]
[switch]$IncludeNullResults
)
begin {
$FunctionName = $FunctionName
Write-Verbose "$($FunctionName): Begin"
$Mailboxes = @()
if (-not $ShowAll) {
# These are some standard user exceptions you may find in your environment
# You can supply your own list by including -ShowAll and -AdditionalUserFilters
# in the same call.
$UserExceptions = @(
'S-1-*',
"*\Organization Management",
"*\Domain Admins",
"*\Enterprise Admins",
"*\Exchange Services",
"*\Exchange Trusted Subsystem",
"*\Exchange Servers",
"*\Exchange View-Only Administrators",
"*\Exchange Admins",
"*\Managed Availability Servers",
"*\Public Folder Administrators",
"*\Exchange Domain Servers",
"*\Exchange Organization Administrators",
"NT AUTHORITY\*")
}
else {
$UserExceptions = @()
}
$UserExceptions += $AdditionalUserFilters
if ($UserExceptions.Count -gt 0) {
# If we have some user exceptions create one big regex to filter against later
$ExceptionMatches = @($UserExceptions | Foreach {[regex]::Escape($_)})
$Exceptions = '^(' + ($ExceptionMatches -join '|') + ')$'
# The regex escape will turn '*' into '\*', this next statment turns it into a match all regex of '.*'
$Exceptions = $Exceptions -replace '\\\*','.*'
}
else {
# If there are no exceptions this will fail to match anything and thus allow all results to be processed.
$Exceptions = '^()$'
}
Write-Verbose "$($FunctionName): Exceptions regex string - $exceptions"
}
process {
switch ($PSCmdlet.ParameterSetName) {
'AsStringArray' {
try {
$Mailboxes += Get-Mailbox $MailboxName -erroraction Stop
}
catch {
Write-Warning = "$($FunctionName): $_.Exception.Message"
}
}
'AsMailbox' {
$Mailboxes += @($MailboxObject)
}
}
}
end {
ForEach ($Mailbox in $Mailboxes) {
Write-Verbose "$($FunctionName): Processing Mailbox $($Mailbox.Name)"
# Initiate our array for this one mailbox to store all the full access users we end up enumerating.
$FullAccessUsers = @()
# Get all the full access permissions on a mailbox where it is not set to 'denied'
$fullperms = @($Mailbox | Get-MailboxPermission | Where {($_.AccessRights -like "*FullAccess*") -and (-not $_.Deny)})
# If we have results then continume processing
if ($fullperms.Count -gt 0) {
$fullperms | Foreach {
# Foreach permission found see if it gets filtered out in our exception list.
if ($_.User.RawIdentity -notmatch $Exceptions) {
if ($ExpandGroups) {
if ($_.User.RawIdentity -match '^(.*\\)(.*)$') {
$domstring = $matches[1]
$grpstring = $matches[2]
}
else {
$domstring = ''
$grpstring = $_.User.RawIdentity
}
try {
$groupmembers = @(Get-ADGroupMember $grpstring -Recursive)
}
catch {
$groupmembers = $null
}
if ($groupmembers -ne $null) {
Write-Verbose "$($FunctionName): $grpstring is a group with $($groupmembers.count) members..."
#foreach ($groupmember in $groupmembers) {
($groupmembers).SamAccountName | Foreach {
$memberusername = "$($domstring)$($_)"
if ($memberusername -notmatch $Exceptions) {
$FullAccessUsers += $memberusername
}
}
}
else {
Write-Verbose "$($FunctionName): $($_.User.RawIdentity) is a non-filtered user"
$FullAccessUsers += $_.User.RawIdentity
}
}
else {
$FullAccessUsers += $_.User.RawIdentity
}
}
}
if (($FullAccessUsers.Count -gt 0) -or ($IncludeNullResults)) {
$NewObjProp = @{
'Mailbox' = $Mailbox.Name
'MailboxEmail' = $Mailbox.PrimarySMTPAddress
'MailboxAlias' = $Mailbox.Alias
'FullAccess' = $null
}
$FullAccessUsers = $FullAccessUsers | Select -Unique
if ($Expand) {
if ($FullAccessUsers.Count -eq 0) {
New-Object psobject -Property $NewObjProp
}
else {
$FullAccessUsers | Foreach {
$NewObjProp.FullAccess = $_
New-Object psobject -Property $NewObjProp
}
}
}
}
else {
if ($FullAccessUsers.Count -eq 0) {
New-Object psobject -Property $NewObjProp
}
else {
$NewObjProp.FullAccess = $FullAccessUsers
New-Object psobject -Property $NewObjProp
}
}
}
}
Write-Verbose "$($FunctionName): End"
}
}
if ([string]::IsNullOrEmpty($Domain)) {
$tmp = (Get-WmiObject Win32_NTDomain).DomainName
$tmp = [string]$tmp
$Domain = $tmp.Trim()
Write-Host -ForegroundColor Yellow "Domain parameter not provided, so we are using $($Domain) instead.."
}
if (($global:Mailboxes).Count -eq 0) {
Write-Host -ForegroundColor:Cyan 'Getting all your organization mailboxes. Hang tight, this will likely take some time to complete...'
$global:Mailboxes = Get-mailbox -resultsize Unlimited
}
else {
Write-Host -ForegroundColor:Cyan 'The global mailboxes variable seems to be already populated, skipping this portion of the script.'
Write-Host -ForegroundColor:Cyan 'If you want to start from scratch nullify this variable with the following statement:'
Write-Host -ForegroundColor:Cyan ' $global:Mailboxes = $null'
Write-Host ''
Write-Host 'Press any key to continue...'
pause
}
if (($global:Perms).Count -eq 0) {
Write-Host -ForegroundColor:Cyan 'Enumerating mailbox permissions. Hang tight, this will likely take some time to complete...'
$global:Perms = $global:Mailboxes | Get-MailboxFullAccessPermission -AdditionalUserFilters $AdditionalUserFilters -expand -expandgroup -IncludeNullResults
}
else {
Write-Host -ForegroundColor:Cyan 'The global Perms variable seems to be already populated, skipping this portion of the script.'
Write-Host -ForegroundColor:Cyan 'If you want to start from scratch nullify this variable with the following statement:'
Write-Host -ForegroundColor:Cyan ' $global:Perms = $null'
Write-Host ''
Write-Host 'Press any key to continue...'
}
# Filter out permissions where there is no matching mailbox
$MailboxAliases = @(($global:Mailboxes).Alias | Foreach {"$($Domain)\$($_)"})
$FilteredPerms = $global:Perms | Where {$MailboxAliases -contains $_.FullAccess}
# get the assigned permissions by user
$groups = $FilteredPerms | Sort-Object -Property FullAccess | Group-Object -Property FullAccess -AsString -AsHashTable
if ([string]::IsNullOrEmpty($SeedUser)) {
$standalonemailboxes = @()
Write-Host -ForegroundColor Green "The following mailboxes do NOT have any full access permissions on other mailboxes."
Write-Host -ForegroundColor Green "(Additionally, no other mailboxes have full access to these either.)"
$global:Perms | Where {$_.FullAccess -eq $null} | Foreach {
$tmp = "$($Domain)\" + $_.MailboxAlias
if (($groups.$tmp).Count -eq 0) {
Write-Host -ForegroundColor Green " $($_.Mailbox)"
$standalonemailboxes += $_.Mailbox
}
}
}
else {
try {
$seeduseralias = ($global:Mailboxes | Where {$_.Name -eq $seeduser})[0].Alias
}
catch {
Write-Host -ForegroundColor Red "The seed user does not appear to have a mailbox, exiting script!"
return
}
$Global:MailboxesToMigrate = @()
$MailboxesToCheck = @($seeduseralias)
$checkedMailboxes = @()
$Iteration = 0
Do {
$Iteration++
$tempmailbox = @()
$currentmailbox = $MailboxesToCheck[0]
$checkedMailboxes += $currentmailbox
$currmailboxgroupcheck = "$($Domain)\" + $currentmailbox
$MailboxesToCheck = @()
Write-Host "Checking permissions on $currentmailbox...."
# Get the mailboxes which have full access to the seed mailbox.
$mailboxperms = @($FilteredPerms | Where {$_.MailboxAlias -eq $currentmailbox})
if ($mailboxperms.Count -gt 0) {
Write-Host -ForegroundColor Cyan "...The following users have access to $($currentmailbox):"
Foreach ($mailbox in ($mailboxperms.FullAccess)) {
$mbxout = $mailbox -replace "$($Domain)\\",''
$tempmailbox += $mbxout
Write-Host -ForegroundColor Yellow " $mbxout"
if ($groups.$mailbox -ne $null) {
Write-Host -ForegroundColor DarkCyan " -- Which also have access to the following (only going one level deep):"
$groups.$mailbox | Foreach {
Write-Host -ForegroundColor DarkCyan " ----:$($_.Mailbox)"
$tempmailbox += $_.MailboxAlias
}
}
}
}
Write-Host -ForegroundColor Cyan "$($currentmailbox) itself has access to the following mailboxes:"
$accessto = $groups.$currmailboxgroupcheck
$accessto | Foreach {
Write-Host -ForegroundColor Yellow " $($_.MailboxAlias)"
$tempmailbox += $_.MailboxAlias
}
$tempmailbox = @($tempmailbox | Select -Unique)
$Global:MailboxesToMigrate += @($tempmailbox)
$Global:MailboxesToMigrate = @($Global:MailboxesToMigrate | Select -Unique)
$Global:MailboxesToMigrate | foreach {
if ($checkedMailboxes -notcontains $_) {
$MailboxesToCheck += $_
}
}
Write-Host -ForegroundColor DarkCyan "Iteration #$($Iteration) Complete! The following mailboxes have been checked and will not be checked again:"
$checkedMailboxes | Foreach { Write-Host -ForegroundColor DarkCyan " $($_)" }
} Until ($MailboxesToCheck.Count -eq 0)
$Global:MailboxesToMigrate += $seeduseralias
$Global:MailboxesToMigrate = $Global:MailboxesToMigrate | Sort | Select -Unique
Write-Host ''
Write-Host -ForegroundColor Magenta "Based on your seed mailbox ($seeduser) you should migrate the following mailboxes as one group if possible:"
$Global:MailboxesToMigrate | Foreach { Write-Host -ForegroundColor Magenta " $($_)" }
}