core/api/EntraID/msgraph/helpers/PIM/Get-MonkeyMSGraphPIMRoleAssignment.ps1
# Monkey365 - the PowerShell Cloud Security Tool for Azure and Microsoft 365 (copyright 2022) by Juan Garrido # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. Function Get-MonkeyMSGraphPIMRoleAssignment{ <# .SYNOPSIS Get PIM role assignments .DESCRIPTION Get PIM role assignments .INPUTS .OUTPUTS .EXAMPLE .NOTES Author : Juan Garrido Twitter : @tr1ana File Name : Get-MonkeyMSGraphPIMRoleAssignment Version : 1.0 .LINK https://github.com/silverhack/monkey365 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Scope="Function")] [CmdletBinding()] [OutputType([System.Collections.Generic.List[System.Management.Automation.PsObject]])] Param () try{ $new_arg = @{ APIVersion = 'beta'; } #Set Job params If($O365Object.isConfidentialApp){ $jobParam = @{ ScriptBlock = { Get-MonkeyMsGraphMFAUserDetail -UserId $_}; Arguments = $new_arg; Runspacepool = $O365Object.monkey_runspacePool; ReuseRunspacePool = $true; Debug = $O365Object.VerboseOptions.Debug; Verbose = $O365Object.VerboseOptions.Verbose; MaxQueue = $O365Object.nestedRunspaces.MaxQueue; BatchSleep = $O365Object.nestedRunspaces.BatchSleep; BatchSize = $O365Object.nestedRunspaces.BatchSize; } } Else{ If($O365Object.useOldAADAPIForUsers){ If($O365Object.canRequestMFAForUsers){ $jobParam = @{ ScriptBlock = { Get-MonkeyGraphAADUser -UserId $_ }; Runspacepool = $O365Object.monkey_runspacePool; ReuseRunspacePool = $true; Debug = $O365Object.VerboseOptions.Debug; Verbose = $O365Object.VerboseOptions.Verbose; MaxQueue = $O365Object.nestedRunspaces.MaxQueue; BatchSleep = $O365Object.nestedRunspaces.BatchSleep; BatchSize = $O365Object.nestedRunspaces.BatchSize; } } Else{ #Set job params $jobParam = @{ ScriptBlock = { Get-MonkeyMSGraphUser -UserId $_ -BypassMFACheck}; Arguments = $new_arg; Runspacepool = $O365Object.monkey_runspacePool; ReuseRunspacePool = $true; Debug = $O365Object.VerboseOptions.Debug; Verbose = $O365Object.VerboseOptions.Verbose; MaxQueue = $O365Object.nestedRunspaces.MaxQueue; BatchSleep = $O365Object.nestedRunspaces.BatchSleep; BatchSize = $O365Object.nestedRunspaces.BatchSize; } } } Else{ If($O365Object.auth_tokens.MSGraph.clientId -eq (Get-WellKnownAzureService -AzureService MicrosoftGraph)){ #Set job params $jobParam = @{ ScriptBlock = { Get-MonkeyMsGraphMFAUserDetail -UserId $_}; Arguments = $new_arg; Runspacepool = $O365Object.monkey_runspacePool; ReuseRunspacePool = $true; Debug = $O365Object.VerboseOptions.Debug; Verbose = $O365Object.VerboseOptions.Verbose; MaxQueue = $O365Object.nestedRunspaces.MaxQueue; BatchSleep = $O365Object.nestedRunspaces.BatchSleep; BatchSize = $O365Object.nestedRunspaces.BatchSize; } } Else{ #Set job params $jobParam = @{ ScriptBlock = { Get-MonkeyMSGraphUser -UserId $_ -BypassMFACheck}; Arguments = $new_arg; Runspacepool = $O365Object.monkey_runspacePool; ReuseRunspacePool = $true; Debug = $O365Object.VerboseOptions.Debug; Verbose = $O365Object.VerboseOptions.Verbose; MaxQueue = $O365Object.nestedRunspaces.MaxQueue; BatchSleep = $O365Object.nestedRunspaces.BatchSleep; BatchSize = $O365Object.nestedRunspaces.BatchSize; } } } } #Set generic list $allroleAssignments = [System.Collections.Generic.List[System.Management.Automation.PsObject]]::new() #Get PIM role assignments $msg = @{ MessageData = "Getting Role management policy from PIM"; callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'info'; InformationAction = $O365Object.InformationAction; Tags = @('EntraIDPIMInfo'); } Write-Information @msg $policyAssignments = Get-MonkeyMSGraphPIMRoleManagementPolicyAssignment #Get role templates $msg = @{ MessageData = "Getting Role templates from PIM"; callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'info'; InformationAction = $O365Object.InformationAction; Tags = @('EntraIDPIMInfo'); } Write-Information @msg $roleTemplates = Get-MonkeyMSGraphDirectoryRoleTemplate #Get all policies $p = @{ ScriptBlock = { Get-MonkeyMSGraphPIMRoleManagementPolicy -InputObject $_.policyId }; Runspacepool = $O365Object.monkey_runspacePool; ReuseRunspacePool = $true; Debug = $O365Object.VerboseOptions.Debug; Verbose = $O365Object.VerboseOptions.Verbose; MaxQueue = $O365Object.nestedRunspaces.MaxQueue; BatchSleep = $O365Object.nestedRunspaces.BatchSleep; BatchSize = $O365Object.nestedRunspaces.BatchSize; } @($policyAssignments).ForEach( { $policy = $_; $settings = $policy | Invoke-MonkeyJob @p $policy | Add-Member -MemberType NoteProperty -Name settings -Value $settings #Get role $role = @($roleTemplates).Where({$_.id -eq $policy.roleDefinitionId}) if($role.Count -gt 0){ $roleObject = $role | New-MonkeyPIMRoleObject $roleObject.policy = $policy; [void]$allroleAssignments.Add($roleObject); } Start-Sleep -Milliseconds 500; } ); #Get Active role assignment $msg = @{ MessageData = "Getting active role assignments from PIM"; callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'info'; InformationAction = $O365Object.InformationAction; Tags = @('EntraIDPIMInfo'); } Write-Information @msg $activeRoleAssignments = Get-MonkeyMSGraphPIMActiveRoleAssignment #Group objects $active_objects = $activeRoleAssignments | Group-Object -Property roleDefinitionId foreach($activeRole in $active_objects){ #Get the role $myRole = $allroleAssignments.Where({$_.id -eq $activeRole.Name}) | Select-Object -First 1 If($null -ne $myRole){ $msg = @{ MessageData = ("Getting active role assignments for {0}" -f $myRole.Name); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'info'; InformationAction = $O365Object.InformationAction; Tags = @('EntraIDPIMInfo'); } Write-Information @msg #update object $myRole.activeAssignment.isUsed = $true; $myRole.roleInUse = $true; $activeMembers = $activeRole.Group | Select-Object principalId,startDateTime,endDateTime,assignmentType,memberType -ErrorAction Ignore if($null -ne $activeMembers){ #Set array $allUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() $allServicePrincipals = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() #Get ids $ids = $activeMembers | Select-Object -ExpandProperty principalId $identities = Get-MonkeyMSGraphDirectoryObjectById -Ids $ids #Get groups $groups = @($identities).Where({$_.'@odata.type' -match '#microsoft.graph.group'}) #Get users $users = @($identities).Where({$_.'@odata.type' -match '#microsoft.graph.user'}) #Get service Principals $allSP = @($identities).Where({$_.'@odata.type' -match '#microsoft.graph.servicePrincipal'}) #get Real members foreach($grp in $groups){ $objMetadata = @($activeMembers).Where({$_.principalId -eq $grp.id}) | Select-Object * -First 1 -ErrorAction Ignore $groupMember = Get-MonkeyMSGraphGroupTransitiveMember -GroupId $grp.id -Parents @($grp.id) if($groupMember){ $ids = @($groupMember).Where({$_.'@odata.type' -match '#microsoft.graph.user'}) | Select-Object -ExpandProperty Id #Invoke job $members = $ids | Invoke-MonkeyJob @jobParam if($members){ foreach($member in @($members)){ if($null -ne $objMetadata){ $member | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $member | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $member | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $member | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allUsers.Add($member) } } #Get Service Principals $sps = @($groupMember).Where({$_.'@odata.type' -match '#microsoft.graph.servicePrincipal'}) foreach($sp in $sps){ if($null -ne $objMetadata){ $sp | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $sp | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $sp | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $sp | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allServicePrincipals.Add($sp); } } } #Add users $ids = $users| Select-Object -ExpandProperty Id #Invoke job $members = $ids | Invoke-MonkeyJob @jobParam if($null -ne $members){ foreach($member in @($members)){ $objMetadata = @($activeMembers).Where({$_.principalId -eq $member.id}) | Select-Object * -First 1 -ErrorAction Ignore if($null -ne $objMetadata){ $member | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $member | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $member | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $member | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allUsers.Add($member) } } #Populate Service principals foreach($sp in @($allSP)){ $objMetadata = @($activeMembers).Where({$_.principalId -eq $sp.id}) | Select-Object * -First 1 -ErrorAction Ignore if($null -ne $objMetadata){ $sp | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $sp | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $sp | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $sp | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allServicePrincipals.Add($sp) } #Populate Groups $myRole.activeAssignment.groups = $groups; #Get effective users and remove duplicate members $uniqueUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() $alluniqueUsers = $allUsers | Sort-Object -Property Id -Unique -ErrorAction Ignore if($null -ne $alluniqueUsers){ foreach($usr in @($alluniqueUsers)){ [void]$uniqueUsers.Add($usr); } } #Populate members $myRole.activeAssignment.users = $uniqueUsers; #Populate Service Principals $myRole.activeAssignment.servicePrincipals = $allServicePrincipals; #Count objects $myRole.activeAssignment.totalActiveMembers = ($myRole.activeAssignment.users.Count + $myRole.activeAssignment.servicePrincipals.Count) #Get duplicate users if($allUsers.Count -gt 0){ $myRole.activeAssignment.duplicateUsers = Get-MonkeyDuplicateObjectsByProperty -ReferenceObject $allUsers -Property Id } Else{ #Set empty collection $myRole.activeAssignment.duplicateUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() } } Else{ $myRole.activeAssignment.totalActiveMembers = 0; $myRole.activeAssignment.duplicateUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() } } } #Get eligible assignments $msg = @{ MessageData = "Getting eligible role assignments from PIM"; callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'info'; InformationAction = $O365Object.InformationAction; Tags = @('EntraIDPIMInfo'); } Write-Information @msg $eligibleRoleAssignments = Get-MonkeyMSGraphPIMEligibleRoleAssignment #Group objects $eligible_objects = $eligibleRoleAssignments | Group-Object -Property roleDefinitionId foreach($eligibleRole in $eligible_objects){ #Get the role $myRole = $allroleAssignments.Where({$_.id -eq $eligibleRole.Name}) | Select-Object -First 1 If($null -ne $myRole){ $msg = @{ MessageData = ("Getting eligible role assignments for {0}" -f $myRole.Name); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'info'; InformationAction = $O365Object.InformationAction; Tags = @('EntraIDPIMInfo'); } Write-Information @msg #update object $myRole.eligibleAssignment.isUsed = $true; $myRole.roleInUse = $true; #$ids = $eligibleRole.Group | Select-Object -ExpandProperty principalId -ErrorAction Ignore $eligibleMembers = $eligibleRole.Group | Select-Object principalId,startDateTime,endDateTime,assignmentType,memberType -ErrorAction Ignore If($null -ne $eligibleMembers){ #Set array $allUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() $allServicePrincipals = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() #Get ids $ids = $eligibleMembers | Select-Object -ExpandProperty principalId $identities = Get-MonkeyMSGraphDirectoryObjectById -Ids $ids #Get groups $groups = @($identities).Where({$_.'@odata.type' -match '#microsoft.graph.group'}) #Get users $users = @($identities).Where({$_.'@odata.type' -match '#microsoft.graph.user'}) #Get service Principals $allSP = @($identities).Where({$_.'@odata.type' -match '#microsoft.graph.servicePrincipal'}) #get Real members foreach($grp in $groups){ $objMetadata = @($eligibleMembers).Where({$_.principalId -eq $grp.id}) | Select-Object * -First 1 -ErrorAction Ignore $groupMember = Get-MonkeyMSGraphGroupTransitiveMember -GroupId $grp.id -Parents @($grp.id) if($groupMember){ $ids = @($groupMember).Where({$_.'@odata.type' -match '#microsoft.graph.user'}) | Select-Object -ExpandProperty Id #Invoke job $members = $ids | Invoke-MonkeyJob @jobParam if($members){ foreach($member in @($members)){ if($null -ne $objMetadata){ $member | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $member | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $member | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $member | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allUsers.Add($member) } } #Get Service Principals $sps = @($groupMember).Where({$_.'@odata.type' -match '#microsoft.graph.servicePrincipal'}) foreach($sp in $sps){ if($null -ne $objMetadata){ $sp | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $sp | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $sp | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $sp | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allServicePrincipals.Add($sp); } } } #Add users $ids = $users| Select-Object -ExpandProperty Id #Invoke job $members = $ids | Invoke-MonkeyJob @jobParam if($null -ne $members){ foreach($member in @($members)){ $objMetadata = @($eligibleMembers).Where({$_.principalId -eq $member.id}) | Select-Object * -First 1 -ErrorAction Ignore if($null -ne $objMetadata){ $member | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $member | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $member | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $member | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allUsers.Add($member) } } #Populate Service principals foreach($sp in @($allSP)){ $objMetadata = @($eligibleMembers).Where({$_.principalId -eq $sp.id}) | Select-Object * -First 1 -ErrorAction Ignore if($null -ne $objMetadata){ $sp | Add-Member -MemberType NoteProperty -Name startDateTime -Value $objMetadata.startDateTime $sp | Add-Member -MemberType NoteProperty -Name endDateTime -Value $objMetadata.endDateTime $sp | Add-Member -MemberType NoteProperty -Name assignmentType -Value $objMetadata.assignmentType $sp | Add-Member -MemberType NoteProperty -Name memberType -Value $objMetadata.memberType } [void]$allServicePrincipals.Add($sp) } #Populate Groups $myRole.eligibleAssignment.groups = $groups; #Get effective users and remove duplicate members $uniqueUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() $alluniqueUsers = $allUsers | Sort-Object -Property Id -Unique -ErrorAction Ignore if($null -ne $alluniqueUsers){ foreach($usr in @($alluniqueUsers)){ [void]$uniqueUsers.Add($usr); } } #Populate members $myRole.eligibleAssignment.users = $uniqueUsers; #Populate Service Principals $myRole.eligibleAssignment.servicePrincipals = $allServicePrincipals; #Count objects $myRole.eligibleAssignment.totalEligibleMembers = ($myRole.eligibleAssignment.users.Count + $myRole.eligibleAssignment.servicePrincipals.Count) #Get duplicate users if($allUsers.Count -gt 0){ $myRole.eligibleAssignment.duplicateUsers = Get-MonkeyDuplicateObjectsByProperty -ReferenceObject $allUsers -Property Id } Else{ #Set empty collection $myRole.eligibleAssignment.duplicateUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() } } Else{ $myRole.eligibleAssignment.totalEligibleMembers = 0; $myRole.eligibleAssignment.duplicateUsers = [System.Collections.Generic.List[System.Management.Automation.PSObject]]::new() } #Calculate eligible and active members $myRole.totalMembers = $myRole.eligibleAssignment.totalEligibleMembers + $myRole.activeAssignment.totalActiveMembers } } #return data $allroleAssignments } Catch{ $msg = @{ MessageData = $_; callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'verbose'; InformationAction = $O365Object.InformationAction; Verbose = $O365Object.verbose; Debug = $O365Object.debug; Tags = @('EntraIDPIMError'); } Write-Verbose @msg } } |