forked from michevnew/PowerShell
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Role_assignments_Inventory.ps1
162 lines (142 loc) · 9.5 KB
/
Role_assignments_Inventory.ps1
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
#Requires -Version 3.0
[CmdletBinding()] #Make sure we can use -Verbose
Param([switch]$IncludeRoleGroups,[switch]$IncludeUnassignedRoleGroups,[switch]$IncludeDelegatingAssingments)
#Simple function to check for existing Exchange Remote PowerShell session or establish a new one
function Check-Connectivity {
#Make sure we are connected to Exchange Remote PowerShell
Write-Verbose "Checking connectivity to Exchange Remote PowerShell..."
if (!$session -or ($session.State -ne "Opened")) {
try { $script:session = Get-PSSession -InstanceId (Get-AcceptedDomain | select -First 1).RunspaceId.Guid -ErrorAction Stop }
catch {
try {
#Failing to detect an active session, try connecting to ExO via Basic auth...
$script:session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential (Get-Credential) -Authentication Basic -AllowRedirection -ErrorAction Stop
Import-PSSession $session -ErrorAction Stop | Out-Null
}
catch { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop }
}
}
#As the function is called every once in a while, use it to trigger some artifical delay in order to prevent throttling
Start-Sleep -Milliseconds 500
return $true
}
#Enumerate all Role Groups that have no management role assignments
function getEmptyRoleGroups {
$ERGoutput = @()
$ERG = @(Get-RoleGroup | ? {!($_.RoleAssignments)})
if ($ERG.Count) {
$ERG | % {
$ERGobj = New-Object psobject
$ERGobj | Add-Member -MemberType NoteProperty -Name DisplayName -Value $_.Id
$ERGobj | Add-Member -MemberType NoteProperty -Name AssignmentType -Value "N/A"
$ERGobj | Add-Member -MemberType NoteProperty -Name AssigneeName -Value $_.Id #($_.Members -join ",")
$ERGobj | Add-Member -MemberType NoteProperty -Name Assignee -Value $_.ExchangeObjectId.Guid #($_.Members -join ",")
$ERGobj | Add-Member -MemberType NoteProperty -Name AssigneeType -Value "RoleGroup"
$ERGobj | Add-Member -MemberType NoteProperty -Name AssignedRoles -Value "N/A"
$ERGoutput += $ERGobj
}
return $ERGoutput
}
else { return }
}
#Find the user matching a given DisplayName. If multiple entries are returned, use the -RoleAssignee parameter to determine the correct one. If unique entry is found, return UPN, otherwise return DisplayName
function getUPN ($user,$role) {
$UPN = @(Get-User $user -ErrorAction SilentlyContinue | ? {(Get-ManagementRoleAssignment -Role $role -RoleAssignee $_.SamAccountName -ErrorAction SilentlyContinue)})
if ($UPN.Count -ne 1) { return $user }
if ($UPN) { return $UPN.UserPrincipalName }
else { return $user }
}
#Find the group matching a given DisplayName. If multiple entries are returned, use the -RoleAssignee parameter to determine the correct one. If unique entry is found, return the email address if present, or GUID. Otherwise return DisplayName
function getGroup ($group,$role) {
$grp = @(Get-Group $group -ErrorAction SilentlyContinue | ? {(Get-ManagementRoleAssignment -Role $role -RoleAssignee $_.SamAccountName -ErrorAction SilentlyContinue)})
if ($grp.Count -ne 1) { return $group }
if ($grp) {
if ($grp.WindowsEmailAddress.ToString()) { return $grp.WindowsEmailAddress.ToString() }
else { return $grp.Guid.Guid.ToString() }
}
else { return $group }
}
#List all Role assignments in the organization, including Delegating ones if the corresponding parameter is invoked
function Get-RoleAssignmentsReport {
Param
(
#Specify whether to include Role Group entries in the output
[Switch]$IncludeRoleGroups,
#Specify whether to include delegating Role assingments in the output
[Switch]$IncludeDelegatingAssingments)
$output = @()
#If $IncludeDelegatingAssingments is specified, return the delegating assignments
#-RoleAssigneeType filtering works for single values only, filter client-side
if (!$IncludeDelegatingAssingments) { $RoleAssignments = @(Get-ManagementRoleAssignment -GetEffectiveUsers -Delegating:$false | ? {$_.RoleAssigneeType -notmatch "RoleAssignmentPolicy|PartnerLinkedRoleGroup"}) }
else { $RoleAssignments = @(Get-ManagementRoleAssignment -Delegating:$true | ? {$_.RoleAssigneeName -ne "Organization Management"}) }
#override for on-premises due to the -Delegating parameter issue
if ($session.ComputerName -ne "outlook.office365.com") { $RoleAssignments = @(Get-ManagementRoleAssignment -GetEffectiveUsers | ? {$_.RoleAssigneeType -notmatch "RoleAssignmentPolicy|PartnerLinkedRoleGroup"}) }
$PercentComplete = 0; $count = 1;
foreach ($ra in $RoleAssignments) {
#Progress message
$ActivityMessage = "Processing role assignment $($ra.Name). Please wait..."
$StatusMessage = ("Processing {0} of {1}: {2}" -f $count, @($RoleAssignments).count, $ra.Guid.Guid.ToString())
$PercentComplete = ($count / @($RoleAssignments).count * 100)
Write-Progress -Activity $ActivityMessage -Status $StatusMessage -PercentComplete $PercentComplete
$count++
#Since we are using the -GetEffectiveUsers parameter, the number of entries will be huge. And since for each entry we do a Get-User or Get-Group, add some anti-throttling controls via Check-Connectivity
if ($count /50 -is [int]) {
Start-Sleep -Seconds 1
}
#Process each Role assignment entry
if ($ra.EffectiveUserName -eq "All Group Members" -and $ra.AssignmentMethod -eq "Direct") {
#Only list the "parent" entry when it's not a Role Group or when -IncludeRoleGroups is $true
if (($ra.RoleAssigneeType -ne "RoleGroup") -or $IncludeRoleGroups) {
$raobj = New-Object psobject
$raobj | Add-Member -MemberType NoteProperty -Name DisplayName -Value $ra.RoleAssigneeName
$raobj | Add-Member -MemberType NoteProperty -Name AssignmentType -Value $ra.AssignmentMethod
$raobj | Add-Member -MemberType NoteProperty -Name AssigneeName -Value $ra.RoleAssigneeName
$raobj | Add-Member -MemberType NoteProperty -Name Assignee -Value (getGroup $ra.RoleAssignee $ra.Role)
$raobj | Add-Member -MemberType NoteProperty -Name AssigneeType -Value $ra.RoleAssigneeType
$raobj | Add-Member -MemberType NoteProperty -Name AssignedRoles -Value (&{If ($IncludeDelegatingAssingments) { "Delegating - " + $ra.Role } else {$ra.Role}})
$output += $raobj
}
}
else {
#User role assignments
$raobj = New-Object psobject
$raobj | Add-Member -MemberType NoteProperty -Name DisplayName -Value $ra.RoleAssigneeName
$raobj | Add-Member -MemberType NoteProperty -Name AssignmentType -Value $ra.AssignmentMethod
$raobj | Add-Member -MemberType NoteProperty -Name AssigneeName -Value $ra.EffectiveUserName
$raobj | Add-Member -MemberType NoteProperty -Name Assignee -Value (getUPN $ra.EffectiveUserName $ra.Role)
$raobj | Add-Member -MemberType NoteProperty -Name AssigneeType -Value "User"
$raobj | Add-Member -MemberType NoteProperty -Name AssignedRoles -Value (&{If ($IncludeDelegatingAssingments) { "Delegating - " + $ra.Role } else {$ra.Role}})
$output += $raobj
}
}
#return the output
return $output
}
###########################
# MAIN SCRIPT STARTS HERE #
###########################
#Initialize the parameters
if (!$IncludeRoleGroups -and $IncludeUnassignedRoleGroups) {
$IncludeUnassignedRoleGroups = $false
Write-Verbose "The parameter -IncludeUnassignedRoleGroups can only be used when -IncludeRoleGroups is specified as well, ignoring..."
}
#Check if we are connected to Exchange PowerShell
if (!(Check-Connectivity)) { return }
#Get role assignments
Write-Verbose "Processing Role Assignments..."
$output = Get-RoleAssignmentsReport -IncludeRoleGroups:$IncludeRoleGroups
#Get delegating role assignments
if ($IncludeDelegatingAssingments -and ($session.ComputerName -eq "outlook.office365.com")) {
Write-Verbose "Processing Delegating Role Assignments..."
$output += @(Get-RoleAssignmentsReport -IncludeDelegatingAssingments -IncludeRoleGroups:$IncludeRoleGroups)
}
#For completeness, return entries for Role Groups with no assignments
if ($IncludeRoleGroups -and $IncludeUnassignedRoleGroups) {
Write-Verbose "Processing 'empty' Role Groups..."
$output += @(getEmptyRoleGroups)
}
#Dump the raw output to a CSV file
$output #| Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_RoleAssignments.csv" -NoTypeInformation -Encoding UTF8 -UseCulture
#Transform the output and return it to the console. Group assignments by individual user/group
$global:varRoleAssignments = $output | group Assignee | select @{n="DisplayName";e={($_.Group.AssigneeName | sort -Unique)}},@{n="Identifier";e={$_.Name}},@{n="ObjectType";e={($_.Group.AssigneeType | sort -Unique) -join ","}},@{n="AssignmentType";e={($_.Group.AssignmentType | sort -Unique) -join ","}},@{n="Roles";e={($_.Group.AssignedRoles | sort -Unique) -join ","}} | sort DisplayName
$global:varRoleAssignments | ft