Reading Time: 2 minutes

It’s always good to keep an eye on your Azure subscriptions and what Role Based Access Control assignments you have. Doing this via the portal is a pain as you can have assignments at the subscription level, resource group level and resource level. Microsoft does have a tool to audit users called Azure AD Privileged Identity Management. To use Azure AD Privileged Identity Management you will need to have Azure AD Premium p2.

I have used a script from Stephane Lapointe as a base. https://www.codeisahighway.com/how-to-audit-an-azure-subscription-role-based-access-control-rbac-assignments/ Below you will find my updated PowerShell script that will generate you a nice CSV or Email of all the users, their parent group, their role and where the assignment is (Scope).

The Code

#requires -Version 3.0 -Modules Az.Resources
param(
[switch]
$email
)
$ErrorActionPreference = 'Stop'
## Email Style
$Style = @"
<style>
BODY{font-family:Segoe UI;font-size:12pt;}
TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse; padding-right:5px}
TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;color:black }
TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;background-color:#ffea00}
TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;background-color:white}
P{font-family:Segoe UI;font-size:14pt;}
</style>
"@
## Functions
function Login {
$needLogin = $true
Try {
$content = Get-AzContext
if ($content) {
$needLogin = ([string]::IsNullOrEmpty($content.Account))
}
}
Catch {
if ($_ -like "*Login-AzAccount to login*") {
$needLogin = $true
}
else {
throw
}
}
if ($needLogin) {
Login-AzAccount
}
}
Function Select-Subs {
CLS
$ErrorActionPreference = 'SilentlyContinue'
$Menu = 0
$Subs = @(Get-AzSubscription | select Name, ID, TenantId)
Write-Host "Please select the subscription you want to use:" -ForegroundColor Green;
% {Write-Host ""}
$Subs | % {Write-Host "[$($Menu)]" -ForegroundColor Cyan -NoNewline ; Write-host ". $($_.Name)"; $Menu++; }
% {Write-Host ""}
% {Write-Host "[S]" -ForegroundColor Yellow -NoNewline ; Write-host ". To switch Azure Account."}
% {Write-Host ""}
% {Write-Host "[Q]" -ForegroundColor Red -NoNewline ; Write-host ". To quit."}
% {Write-Host ""}
$selection = Read-Host "Please select the Subscription Number - Valid numbers are 0 - $($Subs.count -1), S to switch Azure Account or Q to quit"
If ($selection -eq 'S') {
Get-AzContext | ForEach-Object {Clear-AzContext -Scope CurrentUser -Force}
Login
Select-Subs
}
If ($selection -eq 'Q') {
Clear-Host
Exit
}
If ($Subs.item($selection) -ne $null)
{ Return @{name = $subs[$selection].Name; ID = $subs[$selection].ID}
}
}
function Resolve-AzureAdGroupMembers {
param(
[guid]
$GroupObjectId,
$GroupList = (Get-AzADGroup)
)
$VerbosePreference = 'continue'
Write-Verbose -Message ('Resolving {0}' -f $GroupObjectId)
$group = $GroupList | Where-Object -Property Id -EQ -Value $GroupObjectId
$groupMembers = Get-AzADGroupMember -GroupObjectId $GroupObjectId
Write-Verbose -Message ('Found members {0}' -f ($groupMembers.DisplayName -join ', '))
$parentGroup = $group.DisplayName
$groupMembers |
Where-Object -Property Type -NE -Value Group |
Select-Object -Property Id, DisplayName, @{
Name = 'ParentGroup'
Expression = { $parentGroup }
}
$groupMembers |
Where-Object -Property type -EQ -Value Group |
ForEach-Object -Process {
Resolve-AzureAdGroupMembers -GroupObjectId $_.Id -GroupList $GroupList
}
}
## Main Part of Script
Login
$SubscriptionSelection = Select-Subs
Select-AzSubscription -SubscriptionName $SubscriptionSelection.Name -ErrorAction Stop
## Get current Azure Subscription
$Azuresub = $SubscriptionSelection.Name -replace , '/'
$roleAssignments = Get-AzRoleAssignment -IncludeClassicAdministrators
$members = $roleAssignments | ForEach-Object -Process {
Write-Verbose -Message ('Processing Assignment {0}' -f $_.RoleDefinitionName)
$roleAssignment = $_
if ($roleAssignment.ObjectType -eq 'Group') {
Resolve-AzureAdGroupMembers -GroupObjectId $roleAssignment.ObjectId ` | Sort-Object -Property { $roleAssignment.RoleDefinitionName }, DisplayName `
| Select-Object -Property Id,
DisplayName,
@{
Name = 'RoleDefinitionName'
Expression = { $roleAssignment.RoleDefinitionName }
}, @{
Name = 'Scope'
Expression = { $roleAssignment.Scope }
},
ParentGroup
}
else {
$roleAssignment | Sort-Object -Property { $roleAssignment.RoleDefinitionName }, DisplayName | Select-Object -Property DisplayName, ParentGroup,
@{
Name = 'RoleDefinitionName'
Expression = { $roleAssignment.RoleDefinitionName }
},
Scope
}
}
## Email Switch
if ($email) {
$output = $members | ConvertTo-HTML -head $style
## Email body
$body = "
<h1>Azure RBAC Audit For Subscription $Azuresub </h1>
<p>Below is a table of all users, their Role and the Parent Group they are a member of. Please review and if you see an Issue please report to it.helpdesk@pixelrobots.co.uk</p>
<p>This message was generated automatically.</P>
" + " $output "
## Email settings
$mailprops = @{
From = 'richard.hoooper@pixelrobots.co.uk'
To = 'richard.hoooper@pixelrobots.co.uk'
Subject = "$Azuresub" + ' Azure AD RBAC Audit'
Body = $body
BodyAsHtml = $true
SmtpServer = 'smtp address'
}
Send-MailMessage @mailprops
}
## CSV Save
else {
$output = $members | Export-CSV -path $($PSScriptRoot + "\" + "$Azuresub" + " Azure RBAC Audit.csv") -NoTypeInformation
}

How to use

Save the script to a location on your computer. I am using C:\Scripts.

Open PowerShell and navigate to the location of the script.

If you would just like to create a CSV of the data you just need to run the script. The CSV will be saved in the same directory as the script. To run the script just type the name of it. As I have called mine AzureSubscriptionRBACAudit.ps1. I would type

Output after script run
Output after script run for CSV

You will then be asked to log into Azure if you are not already and then you will be asked to pick a subscription. After you have picked the subscription the script will finish and your CSV will be waiting for you.

If you would like to send an email with the results then first you will need to update the script to add your email address and smtp server. This can be found at the bottom under the Email settings section.

Once you have edited that section and saved it run the script again but this time use the -email switch.

You will then be asked to log into Azure if you are not already and then you will be asked to pick a subscription. After you have picked the subscription the script will finish and you will now have an email with the audit report in your inbox.

Output from email switch
Output from email switch

You can find an always up to date version of this script and many more at this GitHub Repo.

I hope you found this article helpful. If you have any questions or improvements to the script let me know.


Pixel Robots.

I’m Richard Hooper aka Pixel Robots. I started this blog in 2016 for a couple reasons. The first reason was basically just a place for me to store my step by step guides, troubleshooting guides and just plain ideas about being a sysadmin. The second reason was to share what I have learned and found out with other people like me. Hopefully, you can find something useful on the site.

1 Comment

Tim · May 7, 2020 at 3:07 pm

Thanks for this script! Is there a way to add an option to loop through all subscriptions and generate a different file for each?

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *