From f1947f558ae6ba37567ca6a9a401f9b145552d0d Mon Sep 17 00:00:00 2001 From: Christian Bortone <49211005+xybytes@users.noreply.github.com> Date: Sat, 5 Apr 2025 19:47:28 +0200 Subject: [PATCH 1/4] Update Get-AzDomainInfo.ps1 remove error for not public blob --- Az/Get-AzDomainInfo.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Az/Get-AzDomainInfo.ps1 b/Az/Get-AzDomainInfo.ps1 index d356f59..abe0ab9 100644 --- a/Az/Get-AzDomainInfo.ps1 +++ b/Az/Get-AzDomainInfo.ps1 @@ -256,7 +256,11 @@ Function Get-AzDomainInfo # URL for listing publicly available files $uriList = "https://"+(-join ($StorageAccountName,'.blob.core.windows.net/',$_.Name))+"/?restype=container&comp=list" - $FileList = (Invoke-WebRequest -uri $uriList -Method Get -Verbose:$False).Content + try { + $FileList = (Invoke-WebRequest -Uri $uriList -Method Get -Verbose:$False).Content + } catch { + # No Action + } # Microsoft includes these characters in the response, Thanks... [xml]$xmlFileList = $FileList -replace '' From 2bf682b536e5fc2bb565fc8373dcfbce4f749189 Mon Sep 17 00:00:00 2001 From: Christian Bortone <49211005+xybytes@users.noreply.github.com> Date: Sun, 6 Apr 2025 00:48:54 -0700 Subject: [PATCH 2/4] Add role and group memberships Improve user enumeration functionality by adding user roles and group memberships. --- AzureAD/Get-AzureADDomainInfo.ps1 | 95 +++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/AzureAD/Get-AzureADDomainInfo.ps1 b/AzureAD/Get-AzureADDomainInfo.ps1 index 00772f7..96ca88c 100644 --- a/AzureAD/Get-AzureADDomainInfo.ps1 +++ b/AzureAD/Get-AzureADDomainInfo.ps1 @@ -87,14 +87,97 @@ Function Get-AzureADDomainInfo if ($Users -eq "Y"){ # Get/Write Users for each domain Write-Verbose "Getting Domain Users..." - # Base user info - $azureADUsers = Get-AzureADUser -All 1 - $azureADUsers | select DisplayName,UserPrincipalName,ObjectId,ObjectType,AccountEnabled,AgeGroup,City,CompanyName,ConsentProvidedForMinor,Country,CreationType,Department,DirSyncEnabled,FacsimileTelephoneNumber,GivenName,IsCompromised,ImmutableId,JobTitle,LastDirSyncTime,LegalAgeGroupClassification,Mail,MailNickName,Mobile,OnPremisesSecurityIdentifier,PasswordPolicies,PasswordProfile,PhysicalDeliveryOfficeName,PostalCode,PreferredLanguage,RefreshTokensValidFromDateTime,ShowInAddressList,SipProxyAddress,State,StreetAddress,Surname,TelephoneNumber,UsageLocation,UserState,UserStateChangedOn,UserType | Export-Csv -NoTypeInformation -LiteralPath $folder"\AzureAD\AzureAD_Users.CSV" - $azureADUserscount = $azureADUsers.count - Write-Verbose "`t$azureADUserscount Domain Users were found." + + $azureADUsers = Get-AzureADUser -All $true + + $entraIDRoles = Get-AzureADDirectoryRole + + $userRolesMap = @{} + foreach ($role in $entraIDRoles) { + $members = Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId + foreach ($member in $members) { + if (-not $userRolesMap.ContainsKey($member.ObjectId)) { + $userRolesMap[$member.ObjectId] = @() + } + $userRolesMap[$member.ObjectId] += $role.DisplayName + } + } - } + $azureADGroups = Get-AzureADGroup -All $true + $userGroupsMap = @{} + + foreach ($group in $azureADGroups) { + $members = Get-AzureADGroupMember -ObjectId $group.ObjectId + + foreach ($member in $members) { + if (-not $userGroupsMap.ContainsKey($member.ObjectId)) { + $userGroupsMap[$member.ObjectId] = @() + } + $userGroupsMap[$member.ObjectId] += $group.DisplayName + } + } + + $exportUsers = $azureADUsers | ForEach-Object { + $AzureADroles = $userRolesMap[$_.ObjectId] -join "; " + $AzureADgroups = if ($userGroupsMap.ContainsKey($_.ObjectId) -and $userGroupsMap[$_.ObjectId]) { + $userGroupsMap[$_.ObjectId] -join "; " + } else { + "" + } + [PSCustomObject]@{ + DisplayName = $_.DisplayName + UserPrincipalName = $_.UserPrincipalName + ObjectId = $_.ObjectId + AzureADRole = $AzureADroles + AzureADGroups = $AzureADgroups + ObjectType = $_.ObjectType + AccountEnabled = $_.AccountEnabled + AgeGroup = $_.AgeGroup + City = $_.City + CompanyName = $_.CompanyName + ConsentProvidedForMinor = $_.ConsentProvidedForMinor + Country = $_.Country + CreationType = $_.CreationType + Department = $_.Department + DirSyncEnabled = $_.DirSyncEnabled + FacsimileTelephoneNumber = $_.FacsimileTelephoneNumber + GivenName = $_.GivenName + Surname = $_.Surname + IsCompromised = $_.IsCompromised + ImmutableId = $_.ImmutableId + JobTitle = $_.JobTitle + LastDirSyncTime = $_.LastDirSyncTime + LegalAgeGroupClassification = $_.LegalAgeGroupClassification + Mail = $_.Mail + MailNickName = $_.MailNickName + Mobile = $_.Mobile + OnPremisesSecurityIdentifier = $_.OnPremisesSecurityIdentifier + PasswordPolicies = $_.PasswordPolicies + PasswordProfile = $_.PasswordProfile + PhysicalDeliveryOfficeName = $_.PhysicalDeliveryOfficeName + PostalCode = $_.PostalCode + PreferredLanguage = $_.PreferredLanguage + RefreshTokensValidFromDateTime = $_.RefreshTokensValidFromDateTime + ShowInAddressList = $_.ShowInAddressList + SipProxyAddress = $_.SipProxyAddress + State = $_.State + StreetAddress = $_.StreetAddress + TelephoneNumber = $_.TelephoneNumber + UsageLocation = $_.UsageLocation + UserState = $_.UserState + UserStateChangedOn = $_.UserStateChangedOn + UserType = $_.UserType + + } + } + + $exportUsers | Export-Csv -NoTypeInformation -LiteralPath "$folder\AzureAD\AzureAD_Users.CSV" + + $azureADUserscount = $azureADUsers.Count + Write-Verbose "`t$azureADUserscount Domain Users were found." + } + if ($Groups -eq "Y"){ # Get/Write Groups Write-Verbose "Getting Domain Groups..." From ca3a2662b06b07277a68618eef45d9e3ddd9a3b8 Mon Sep 17 00:00:00 2001 From: Christian Bortone <49211005+xybytes@users.noreply.github.com> Date: Sun, 6 Apr 2025 12:27:26 -0700 Subject: [PATCH 3/4] Update Get-AzureADDomainInfo.ps1 add comments --- AzureAD/Get-AzureADDomainInfo.ps1 | 46 +++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/AzureAD/Get-AzureADDomainInfo.ps1 b/AzureAD/Get-AzureADDomainInfo.ps1 index 96ca88c..a1396b8 100644 --- a/AzureAD/Get-AzureADDomainInfo.ps1 +++ b/AzureAD/Get-AzureADDomainInfo.ps1 @@ -45,7 +45,6 @@ Function Get-AzureADDomainInfo VERBOSE: Getting Domain Service Principals... VERBOSE: 500 service principals were enumerated. VERBOSE: All done with AzureAD tasks. - #> [CmdletBinding()] @@ -87,50 +86,78 @@ Function Get-AzureADDomainInfo if ($Users -eq "Y"){ # Get/Write Users for each domain Write-Verbose "Getting Domain Users..." - + + # List Users $azureADUsers = Get-AzureADUser -All $true + # List Directory Roles $entraIDRoles = Get-AzureADDirectoryRole + # Initialize an empty map to store user roles $userRolesMap = @{} + # Loop through each role in the Azure AD roles set foreach ($role in $entraIDRoles) { + + # Retrieve the members associated with each role $members = Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId + + # Loop through each member associated with the role foreach ($member in $members) { + + # If the user is not already in the map, initialize an empty list if (-not $userRolesMap.ContainsKey($member.ObjectId)) { $userRolesMap[$member.ObjectId] = @() } + + # Add the role name to the user's list of roles $userRolesMap[$member.ObjectId] += $role.DisplayName } } - + + # Retrieve all Azure AD groups $azureADGroups = Get-AzureADGroup -All $true + + # Initialize an empty map to store group memberships for users $userGroupsMap = @{} - + + # Loop through each group in the Azure AD groups foreach ($group in $azureADGroups) { + # Retrieve the members of each grou $members = Get-AzureADGroupMember -ObjectId $group.ObjectId + # Loop through each member of the group foreach ($member in $members) { + + # If the user is not already in the map, initialize an empty list if (-not $userGroupsMap.ContainsKey($member.ObjectId)) { $userGroupsMap[$member.ObjectId] = @() } + + # Add the group name to the user's list of groups $userGroupsMap[$member.ObjectId] += $group.DisplayName } } - + + # Create an output object for each Azure AD user with their roles and groups $exportUsers = $azureADUsers | ForEach-Object { + + # Retrieve the roles assigned to the user and join them into a single string $AzureADroles = $userRolesMap[$_.ObjectId] -join "; " + + # Retrieve the groups the user belongs to and join them into a single string $AzureADgroups = if ($userGroupsMap.ContainsKey($_.ObjectId) -and $userGroupsMap[$_.ObjectId]) { $userGroupsMap[$_.ObjectId] -join "; " } else { "" } - + + # Create a custom object to store the user's details and export them [PSCustomObject]@{ DisplayName = $_.DisplayName UserPrincipalName = $_.UserPrincipalName ObjectId = $_.ObjectId - AzureADRole = $AzureADroles - AzureADGroups = $AzureADgroups + DirectoryRoles = $AzureADroles + ADGroups = $AzureADgroups ObjectType = $_.ObjectType AccountEnabled = $_.AccountEnabled AgeGroup = $_.AgeGroup @@ -171,7 +198,8 @@ Function Get-AzureADDomainInfo } } - + + # Export to CSV $exportUsers | Export-Csv -NoTypeInformation -LiteralPath "$folder\AzureAD\AzureAD_Users.CSV" $azureADUserscount = $azureADUsers.Count From 7ad87e4dba8e7e569602e07e271eb7bd22bdd32a Mon Sep 17 00:00:00 2001 From: Christian Bortone <49211005+xybytes@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:43:47 -0700 Subject: [PATCH 4/4] RBAC Users&Groups Identify RBAC assignments for users and groups, along with their corresponding resources --- Az/Get-AzDomainInfo.ps1 | 102 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/Az/Get-AzDomainInfo.ps1 b/Az/Get-AzDomainInfo.ps1 index abe0ab9..ee5e64e 100644 --- a/Az/Get-AzDomainInfo.ps1 +++ b/Az/Get-AzDomainInfo.ps1 @@ -94,6 +94,16 @@ Function Get-AzDomainInfo HelpMessage="Dump list of Groups.")] [ValidateSet("Y","N")] [String]$Groups = "Y", + + [parameter(Mandatory=$false, + HelpMessage="Dump list of RBAC of Users")] + [ValidateSet("Y","N")] + [String]$RBACUsers = "Y", + + [parameter(Mandatory=$false, + HelpMessage="Dump list of RBAC of Groups")] + [ValidateSet("Y","N")] + [String]$RBACGroups = "Y", [parameter(Mandatory=$false, HelpMessage="Dump list of Storage Accounts.")] @@ -126,6 +136,7 @@ Function Get-AzDomainInfo [String]$LoginBypass = "N" ) + if ($LoginBypass -eq "N"){ # Check to see if we're logged in with Az $LoginStatus = Get-AzContext @@ -212,7 +223,98 @@ Function Get-AzDomainInfo Write-Verbose "`tDomain Group Users were enumerated for $groupCount groups." } + If ($RBACUsers -eq "Y") { + Write-Verbose "Getting RBAC for Users..." + + # Check Output Path + if(Test-Path $folder"\RBAC"){} + else{New-Item -ItemType Directory $folder"\RBAC" | Out-Null} + + + # Define the user object + $adusers = Get-AzADUser + + # Initialize an array to hold the role assignment information + $roleAssignmentsInfo = @() + + foreach ($aduser in $adusers) { + + # Ensure the ObjectId is valid (non-null) + if ($aduser.Id) { + + # Retrieve role assignments for the user using their ObjectId + $roleAssignments = Get-AzRoleAssignment -PrincipalId $aduser.Id + + # Loop through each role assignment to fetch the role definition name + foreach ($roleAssignment in $roleAssignments) { + + # Ensure the RoleDefinitionId exists + if ($roleAssignment.RoleDefinitionId) { + $roleDef = Get-AzRoleDefinition -Id $roleAssignment.RoleDefinitionId + + # Create a custom object + $roleAssignmentsInfo += [PSCustomObject]@{ + UserPrincipalName = $aduser.UserPrincipalName + RoleAssignmentName = $roleDef.Name + Scope = $roleAssignment.Scope + } + } + } + } + } + + # Print the results in a table format + $roleAssignmentsInfo | Export-Csv -NoTypeInformation -LiteralPath $folder"\RBAC\RBAC_Users.CSV" + + Write-Verbose "`t$($roleAssignmentsInfo.Count) role were enumerated for users" + } + + If ($RBACGroups -eq "Y") { + Write-Verbose "Getting RBAC for Groups..." + + # Check Output Path + if(Test-Path $folder"\RBAC"){} + else{New-Item -ItemType Directory $folder"\RBAC" | Out-Null} + + # Get all Azure AD groups + $adgroups = Get-AzADGroup + + # Initialize an array to hold the role assignment information + $roleAssignmentsInfo = @() + foreach ($adgroup in $adgroups) { + + # Ensure the Id is valid (non-null/empty) + if ($adgroup.Id) { + + # Retrieve role assignments for the group using their Id + $roleAssignments = Get-AzRoleAssignment -PrincipalId $adgroup.Id + + # Loop through each role assignment to fetch the role definition name + foreach ($roleAssignment in $roleAssignments) { + + # Ensure the RoleDefinitionId exists + if ($roleAssignment.RoleDefinitionId) { + $roleDef = Get-AzRoleDefinition -Id $roleAssignment.RoleDefinitionId + + # Create a custom object + $roleAssignmentsInfo += [PSCustomObject]@{ + PrincipalName = $adgroup.DisplayName + PrincipalType = "Group" + RoleAssignmentName = $roleDef.Name + Scope = $roleAssignment.Scope + } + } + } + } + } + + # Print the results in a table format + $roleAssignmentsInfo | Export-Csv -NoTypeInformation -LiteralPath $folder"\RBAC\RBAC_Groups.CSV" + + Write-Verbose "`t$($roleAssignmentsInfo.Count) role were enumerated for groups" + } + # Get Storage Account name(s) if($StorageAccounts -eq "Y"){