Skip to content

Commit bf1271d

Browse files
feat: Added scripts to manage Azure Active Directory App Role Assignments (#336)
Co-authored-by: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> Co-authored-by: Pim Simons <pim.simons@codit.eu> Closes #330
1 parent 7bb8bd4 commit bf1271d

16 files changed

Lines changed: 1304 additions & 12 deletions

build/templates/run-pester-tests.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ steps:
3232
where { $_.ModuleName -ne $null -and $_.ModuleName -notlike 'Arcus.Scripting.*' -and $_.ModuleVersion -ne "#{Package.Version}#" } |
3333
% { Write-Host "Install $($_.ModuleName) module $($_.ModuleVersion)"
3434
Install-Module $_.ModuleName -MaximumVersion $_.ModuleVersion -AllowClobber -Force -SkipPublisherCheck } }
35-
Install-Module -Name Az -Force -AllowClobber -SkipPublisherCheck -MaximumVersion 5.6.0
35+
Install-Module -Name Az -Force -AllowClobber -SkipPublisherCheck -MaximumVersion 9.1.1
3636
Install-Module -Name AzTable -Force -SkipPublisherCheck -MaximumVersion 2.1.0
37+
Install-Module -Name Microsoft.Graph.Applications -Force -SkipPublisherCheck -MaximumVersion 1.15.0
3738
Write-Host "Done installing, start importing modules"
3839
displayName: 'Install Pester test framework and Az required modules'
3940
- powershell: |
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
title: "Azure Active Directory"
3+
layout: default
4+
---
5+
6+
# Azure Active Directory
7+
8+
## Installation
9+
10+
To have access to the following features, you have to import the module:
11+
12+
```powershell
13+
PS> Install-Module -Name Arcus.Scripting.ActiveDirectory
14+
```
15+
16+
## Access Rights to Azure Active Directory
17+
18+
To interact with Azure Active Directory these scripts use the [Microsoft.Graph.Applications](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.applications/) module, import this module:
19+
20+
```powershell
21+
PS> Install-Module -Name Microsoft.Graph.Applications
22+
```
23+
24+
After importing this module, make sure you are connected to Microsoft Graph with the following scopes:
25+
26+
```powershell
27+
PS> Connect-MgGraph -Scopes "Application.ReadWrite.All,AppRoleAssignment.ReadWrite.All"
28+
```
29+
30+
## Listing the Roles and Role Assignments for an Azure Active Directory Application
31+
32+
Lists the roles and role assignments for an Azure Active Directory Application.
33+
34+
| Parameter | Mandatory | Description |
35+
| ------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
36+
| `ClientId` | yes | The client ID of the Azure Active Directory Application Registration for which the roles and assignments are retrieved. |
37+
| `RolesAssignedToClientId` | no | The client ID of the Azure Active Directory Application Registration to which roles have been assigned, used when you only want to retrieve the assignments for this specific application. |
38+
39+
**Example**
40+
41+
Retrieving all information for a Client Id.
42+
43+
```powershell
44+
PS> List-AzADAppRoleAssignments `
45+
-ClientId "b885c208-6067-44bd-aba9-4010c62b7d85"
46+
#Found role 'FirstRole' on Active Directory Application 'main-application'
47+
#Role 'FirstRole' is assigned to the Active Directory Application 'client-application-one' with ID '6ea09bbd-c21c-460c-b58a-f4a720f51826'
48+
#Role 'FirstRole' is assigned to the Active Directory Application 'client-application-two' with ID 'ebafc99d-cbf4-4bd2-9295-f2b785cfc1a1'
49+
#Found role 'SecondRole' on Active Directory Application 'arcus-scripting-test-main'
50+
#Role 'SecondRole' is assigned to the Active Directory Application 'client-application-one' with ID '6ea09bbd-c21c-460c-b58a-f4a720f51826'
51+
```
52+
53+
Retrieving all information for a Client Id and a specific role.
54+
55+
```powershell
56+
PS> List-AzADAppRoleAssignments `
57+
-ClientId 'b885c208-6067-44bd-aba9-4010c62b7d85' `
58+
-RolesAssignedToClientId '6ea09bbd-c21c-460c-b58a-f4a720f51826'
59+
#Found role 'FirstRole' on Active Directory Application 'main-application'
60+
#Role 'FirstRole' is assigned to the Active Directory Application 'client-application-one' with id '6ea09bbd-c21c-460c-b58a-f4a720f51826'
61+
#Found role 'SecondRole' on Active Directory Application 'main-application'
62+
#Role 'SecondRole' is assigned to the Active Directory Application 'client-application-one' with id '6ea09bbd-c21c-460c-b58a-f4a720f51826'
63+
```
64+
65+
## Add a Role and Assignment for an Azure Active Directory Application
66+
67+
Adds a role assignment for an Azure Active Directory Application. The role will be added to the Azure Active Directory Application Registration defined by the `ClientId` parameter, and a role assignment for this role will be added to the Azure Active Directory Application Registration defined by the `AssignRoleToClientId` parameter.
68+
69+
| Parameter | Mandatory | Description |
70+
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
71+
| `ClientId` | yes | The client ID of the Azure Active Directory Application Registration to which the role will be added if not present. |
72+
| `Role` | yes | The name of the role. |
73+
| `AssignRoleToClientId` | yes | The client ID of the Azure Active Directory Application Registration for which the role assignment will be created. The role assignment will be created based on the role added to the Azure Active Directory Application Registration defined by the `ClientId`. |
74+
75+
**Example**
76+
77+
```powershell
78+
PS> Add-AzADAppRoleAssignment `
79+
-ClientId "b885c208-6067-44bd-aba9-4010c62b7d85" `
80+
-Role "DummyRole" `
81+
-AssignRoleToClientId "6ea09bbd-c21c-460c-b58a-f4a720f51826"
82+
#Active Directory Application 'main-application' does not contain the role 'DummyRole', adding the role
83+
#Added Role 'DummyRole' to Active Directory Application 'main-application'
84+
#Role Assignment for the role 'DummyRole' added to the Active Directory Application 'client-application-one'
85+
```
86+
87+
## Remove a Role and Assignment from an Azure Active Directory Application
88+
89+
Removes a role assignment for an Azure Active Directory Application.
90+
91+
| Parameter | Mandatory | Description |
92+
| ---------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
93+
| `ClientId` | yes | The client ID of the Azure Active Directory Application Registration containing the role for which the assignment must be removed. |
94+
| `Role` | yes | The name of the role. |
95+
| `RemoveRoleFromClientId` | yes | The client ID of the Azure Active Directory Application Registration for which the role assignment will be removed. |
96+
| `RemoveRoleIfNoAssignmentsAreLeft` | no | Indicate whether to remove the role from the Azure Active Directory Application Registration defined by the `ClientId` parameter when no more role assignments remain for the role. |
97+
98+
**Example**
99+
100+
Removes a role assignment.
101+
102+
```powershell
103+
PS> Remove-AzADAppRoleAssignment `
104+
-ClientId "b885c208-6067-44bd-aba9-4010c62b7d85" `
105+
-Role "DummyRole" `
106+
-RemoveRoleFromClientId "6ea09bbd-c21c-460c-b58a-f4a720f51826" `
107+
#Role assignment for 'DummyRole' has been removed from Active Directory Application 'client-application-one'
108+
```
109+
110+
Removes a role assignment and removes the fole if no assignments are left on the role.
111+
112+
```powershell
113+
PS> Remove-AzADAppRoleAssignment `
114+
-ClientId "b885c208-6067-44bd-aba9-4010c62b7d85" `
115+
-Role "DummyRole" `
116+
-RemoveRoleFromClientId "6ea09bbd-c21c-460c-b58a-f4a720f51826" `
117+
-RemoveRoleIfNoAssignmentsAreLeft
118+
#Role assignment for 'DummyRole' has been removed from Active Directory Application 'client-application-one'
119+
#Role 'DummyRole' on Active Directory Application 'main-application' has been disabled as no more role assignments were left and the option 'RemoveRoleIfNoAssignmentsAreLeft' is set
120+
#Role 'DummyRole' removed from Active Directory Application 'main-application' as no more role assignments were left and the option 'RemoveRoleIfNoAssignmentsAreLeft' is set
121+
```
122+
Binary file not shown.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<#
2+
.Synopsis
3+
Return the app roles and their assignments that are present on an Azure Active Directory Application Registration.
4+
5+
.Description
6+
Return the app roles that are present in an Azure Active Directory Application Registration and list the applications they are assigned to.
7+
8+
.Parameter ClientId
9+
The client ID of the Azure Active Directory Application Registration from which the role assignments are to be retrieved.
10+
11+
.Parameter RolesAssignedToClientId
12+
The client ID of the Azure Active Directory Application Registration to which roles are assigned.
13+
#>
14+
function List-AzADAppRoleAssignments {
15+
param(
16+
[Parameter(Mandatory = $true)][string] $ClientId = $(throw "ClientId is required"),
17+
[Parameter(Mandatory = $false)][string] $RolesAssignedToClientId
18+
)
19+
. $PSScriptRoot\Scripts\List-AzADAppRoleAssignments.ps1 -ClientId $ClientId -RolesAssignedToClientId $RolesAssignedToClientId
20+
}
21+
22+
Export-ModuleMember -Function List-AzADAppRoleAssignments
23+
24+
<#
25+
.Synopsis
26+
Add and assign a role to an Azure Active Directory Application Registration.
27+
28+
.Description
29+
Add a role to an Azure Active Directory Application Registration and assign the role to a different Active Directory Application Registration.
30+
31+
.Parameter ClientId
32+
The client ID of the Azure Active Directory Application Registration to which the role will be added.
33+
34+
.Parameter Role
35+
The name of the role to add and assign.
36+
37+
.Parameter AssignRoleToClientId
38+
The client ID of the Azure Active Directory Application Registration to which the role will be assigned.
39+
#>
40+
function Add-AzADAppRoleAssignment {
41+
param(
42+
[Parameter(Mandatory = $true)][string] $ClientId = $(throw "ClientId is required"),
43+
[Parameter(Mandatory = $true)][string] $Role = $(throw "Role is required"),
44+
[Parameter(Mandatory = $true)][string] $AssignRoleToClientId = $(throw "ClientId to assign the role to is required")
45+
)
46+
. $PSScriptRoot\Scripts\Add-AzADAppRoleAssignment.ps1 -ClientId $ClientId -Role $Role -AssignRoleToClientId $AssignRoleToClientId
47+
}
48+
49+
Export-ModuleMember -Function Add-AzADAppRoleAssignment
50+
51+
<#
52+
.Synopsis
53+
Remove a role assignment from an Azure Active Directory Application Registration.
54+
55+
.Description
56+
Remove a role assignment from an Azure Active Directory Application Registration and optionally remove the role if no role assignments are left.
57+
58+
.Parameter ClientId
59+
The client ID of the Azure Active Directory Application Registration on which the role is present.
60+
61+
.Parameter Role
62+
The name of the role to remove the assignment for.
63+
64+
.Parameter RemoveRoleFromClientId
65+
The client ID of the Azure Active Directory Application Registration for which the role assignment will be removed.
66+
67+
.Parameter PassThru
68+
Indicates that the role will be removed from the Azure Active Directory Application Registration if no role assigments are left.
69+
#>
70+
function Remove-AzADAppRoleAssignment {
71+
param(
72+
[Parameter(Mandatory = $true)][string] $ClientId = $(throw "ClientId is required"),
73+
[Parameter(Mandatory = $true)][string] $Role = $(throw "Role is required"),
74+
[Parameter(Mandatory = $true)][string] $RemoveRoleFromClientId = $(throw "ClientId to remove the role from is required"),
75+
[Parameter(Mandatory = $false)][switch] $RemoveRoleIfNoAssignmentsAreLeft = $false
76+
)
77+
78+
if ($RemoveRoleIfNoAssignmentsAreLeft) {
79+
. $PSScriptRoot\Scripts\Remove-AzADAppRoleAssignment.ps1 -ClientId $ClientId -Role $Role -RemoveRoleFromClientId $RemoveRoleFromClientId -RemoveRoleIfNoAssignmentsAreLeft
80+
} else {
81+
. $PSScriptRoot\Scripts\Remove-AzADAppRoleAssignment.ps1 -ClientId $ClientId -Role $Role -RemoveRoleFromClientId $RemoveRoleFromClientId
82+
}
83+
}
84+
85+
Export-ModuleMember -Function Remove-AzADAppRoleAssignment
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<PropertyGroup>
3+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4+
<SchemaVersion>2.0</SchemaVersion>
5+
<ProjectGuid>{8c0379ad-d886-491f-9e1c-fce0a7d144e8}</ProjectGuid>
6+
<OutputType>Exe</OutputType>
7+
<RootNamespace>Arcus.Sripting.ActiveDirectory</RootNamespace>
8+
<AssemblyName>Arcus.Sripting.ActiveDirectory</AssemblyName>
9+
<Name>Arcus.Scripting.ActiveDirectory</Name>
10+
</PropertyGroup>
11+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
12+
<DebugSymbols>true</DebugSymbols>
13+
<DebugType>full</DebugType>
14+
<Optimize>false</Optimize>
15+
<OutputPath>bin\Debug\</OutputPath>
16+
<DefineConstants>DEBUG;TRACE</DefineConstants>
17+
<ErrorReport>prompt</ErrorReport>
18+
<WarningLevel>4</WarningLevel>
19+
</PropertyGroup>
20+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
21+
<DebugType>pdbonly</DebugType>
22+
<Optimize>true</Optimize>
23+
<OutputPath>bin\Release\</OutputPath>
24+
<DefineConstants>TRACE</DefineConstants>
25+
<ErrorReport>prompt</ErrorReport>
26+
<WarningLevel>4</WarningLevel>
27+
</PropertyGroup>
28+
<ItemGroup>
29+
<Folder Include="Scripts\" />
30+
</ItemGroup>
31+
<ItemGroup>
32+
<Compile Include="Arcus.Scripting.ActiveDirectory.psd1" />
33+
<Compile Include="Arcus.Scripting.ActiveDirectory.psm1" />
34+
<Compile Include="Scripts\Add-AzADAppRoleAssignment.ps1" />
35+
<Compile Include="Scripts\List-AzADAppRoleAssignments.ps1" />
36+
<Compile Include="Scripts\Remove-AzADAppRoleAssignment.ps1" />
37+
</ItemGroup>
38+
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
39+
<Target Name="Build" />
40+
<Import Project="$(MSBuildExtensionsPath)\PowerShell Tools for Visual Studio\PowerShellTools.targets" Condition="Exists('$(MSBuildExtensionsPath)\PowerShell Tools for Visual Studio\PowerShellTools.targets')" />
41+
</Project>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
param(
2+
[Parameter(Mandatory = $true)][string] $ClientId = $(throw "ClientId is required"),
3+
[Parameter(Mandatory = $true)][string] $Role = $(throw "Role is required"),
4+
[Parameter(Mandatory = $true)][string] $AssignRoleToClientId = $(throw "ClientId to assign the role to is required")
5+
)
6+
7+
$adApplication = Get-AzADApplication -Filter "AppId eq '$ClientId'"
8+
if (!$adApplication) {
9+
throw "Active Directory Application for the ClientId '$ClientId' could not be found"
10+
}
11+
$adServicePrincipal = Get-AzADServicePrincipal -Filter "AppId eq '$ClientId'"
12+
if (!$adServicePrincipal) {
13+
throw "Active Directory Service Principal for the ClientId '$ClientId' could not be found"
14+
}
15+
16+
$adApplicationRoleAssignTo = Get-AzADApplication -Filter "AppId eq '$AssignRoleToClientId'"
17+
if (!$adApplicationRoleAssignTo) {
18+
throw "Active Directory Application for the ClientId '$AssignRoleToClientId' could not be found"
19+
}
20+
$adServicePrincipalRoleAssignTo = Get-AzADServicePrincipal -Filter "AppId eq '$AssignRoleToClientId'"
21+
if (!$adServicePrincipalRoleAssignTo) {
22+
throw "Active Directory Service Principal for the ClientId '$AssignRoleToClientId' could not be found"
23+
}
24+
25+
try {
26+
if ($adApplication.AppRole.Value -notcontains $Role) {
27+
Write-Host "Active Directory Application '$($adApplication.DisplayName)' does not contain the role '$Role', adding the role"
28+
29+
$newRole = @{
30+
"DisplayName" = $Role
31+
"Description" = $Role
32+
"Value" = $Role
33+
"Id" = [Guid]::NewGuid().ToString()
34+
"IsEnabled" = $true
35+
"allowedMemberTypes" = @("User", "Application")
36+
}
37+
38+
$adApplication.AppRole += $newRole
39+
40+
Update-AzADApplication -ObjectId $adApplication.Id -AppRole $adApplication.AppRole
41+
Write-Host "Added role '$Role' to Active Directory Application '$($adApplication.DisplayName)'"
42+
43+
$currentAppRole = $newRole
44+
} else {
45+
Write-Host "Active Directory Application '$($adApplication.DisplayName)' already contains the role '$Role'"
46+
$currentAppRole = $adApplication.AppRole | Where-Object Value -eq $Role
47+
}
48+
49+
$currentRoleAssignments = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $adServicePrincipal.Id | Where-Object AppRoleId -eq $currentAppRole.Id
50+
if ($currentRoleAssignments.AppRoleId -notcontains $currentAppRole.Id) {
51+
$updatedAdServicePrincipal = Get-MgServicePrincipal -ServicePrincipalId $adServicePrincipal.Id
52+
53+
while ($updatedAdServicePrincipal.AppRoles.Value -notcontains $Role -and $counter -lt 10) {
54+
Write-Host "Role '$Role' has been added to Active Directory Application '$($adApplication.DisplayName)' but not yet available for use, waiting 10 seconds to retry..."
55+
Start-Sleep -Seconds 10
56+
$counter++
57+
$updatedAdServicePrincipal = Get-MgServicePrincipal -ServicePrincipalId $adServicePrincipal.Id
58+
}
59+
60+
if ($counter -eq 10) {
61+
throw "Exhausted the retries, the role '$Role' has been added to Active Directory Application '$($adApplication.DisplayName)' but not yet available for use"
62+
}
63+
64+
$newRoleAssignment = New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $adServicePrincipalRoleAssignTo.Id -PrincipalId $adServicePrincipalRoleAssignTo.Id -ResourceId $adServicePrincipal.Id -AppRoleId $currentAppRole.Id
65+
Write-Host "Role Assignment for the role '$Role' added to the Active Directory Application '$($adApplicationRoleAssignTo.DisplayName)'"
66+
} else {
67+
Write-Host "Active Directory Application '$($adApplicationRoleAssignTo.DisplayName)' already contains a role assignment for the role '$Role'"
68+
}
69+
} catch {
70+
throw "Adding the role '$Role' for the Active Directory Application with ClientId '$ClientId' failed. Details: $($_.Exception.Message)"
71+
}

0 commit comments

Comments
 (0)