Skip to content

Instantly share code, notes, and snippets.

@JustinGrote
Created July 8, 2022 22:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JustinGrote/47ee8e0c6336235d628e0952dcea4f52 to your computer and use it in GitHub Desktop.
Save JustinGrote/47ee8e0c6336235d628e0952dcea4f52 to your computer and use it in GitHub Desktop.
Add a Role to a SAML-only Enterprise Application that you can then provide as a claim for user assignment (there is no GUI for this)
using namespace Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10
using namespace System.Management.Automation
using namespace System.Collections.Generic
function Add-JAzADServicePrincipalRole {
[CmdletBinding(DefaultParameterSetName='ByObject', SupportsShouldProcess)]
param(
#The display name of the role. This is the name that will be displayed in the app portal when assigning the role to a user or group.
[Parameter(Mandatory)]$Name,
#The value that will be added to the SAML roles claim for the user. Make this something that is appropriate to signal to your application what role the user should have, e.g. admin, owner, etc., your App may have specific documentation for this effect, for example Palo Alto defines specific values like superuser and superreader
[ValidateNotNullOrEmpty()]$Value = $Name,
#The description of the role. This should provide guidance as to what rights the role grants to the application
[string]$Description = $Name,
#Create the role as disabled. By default roles are created as enabled
[switch]$Disabled,
#Update any existing Roles with the same claim values. The roles will retain their ID
[Switch]$Update,
#The ID of the role. This is usually automatically generated and does not need to be specified
[ValidateNotNullOrEmpty()][Guid]$RoleId = $(New-Guid),
#What kind of resources can be assigned to the role. Options are User (which allows both users and groups) and Application (which allows Service Principals). Default is to allow all types.
[ValidateSet('User', 'Application')][string[]]$AllowedMemberType = @('Application','User'),
[Parameter(Mandatory,ParameterSetName='ById',ValueFromPipelineByPropertyName)][String]$Id,
[Parameter(Mandatory,ParameterSetName='ByObject',ValueFromPipeline)][MicrosoftGraphServicePrincipal]$InputObject
)
if (-not $InputObject) {
if (-not ($id -as [guid])) {throw 'The -Id Parameter must be a valid GUID'}
$InputObject = Get-AzADApplication -ObjectId $Id
}
$roles = [List[MicrosoftGraphAppRole]]$InputObject.AppRole
[MicrosoftGraphAppRole]$existingRole = $roles | Where-Object Value -eq $Value
if ($existingRole) {
if (-not $Update) {
$InputObject | Write-CmdletError "$($InputObject.DisplayName)`: A role with the claim value '$Value' already exists. Use -Update to update the existing role with new changes."
return
}
Write-Verbose "An existing role was found but -Force was specified, updating the existing role."
$roles.Remove($existingRole)
#We want to keep the ID otherwise we have to go thru a whole disablement process
$RoleId = $existingRole.Id
}
$newRole = [MicrosoftGraphAppRole]@{
IsEnabled = !$Disabled
Description = $Description
DisplayName = $Name
AllowedMemberType = $AllowedMemberType
Value = $Value
Id = [string]$RoleId
}
if (-not $PSCmdlet.ShouldProcess(
"$($InputObject.DisplayName) [$($InputObject.Id)]",
"Add New Role $($newRole.DisplayName) with role claim value: $($newRole.Value)"
)) {return}
$roles.Add($newRole)
$inputObject | Update-AzADServicePrincipal -AppRole $roles
}
function Get-ParamBlock ([String[]]$Name) {
[hashset[string]]$params = $PSCmdlet.MyInvocation.MyCommand.Parameters.Keys
$params.ExceptWith([string[]]([PSCmdlet]::CommonParameters + [PSCmdlet]::OptionalCommonParameters))
$result = @{}
if ($Name) {$params = $params -in $Name}
foreach ($name in $params) {
$result.$name = $PSCmdlet.GetVariableValue($name)
}
return $result
}
function Write-CmdletError {
param(
[Exception]$Message = 'An Error Occured in the cmdlet',
[String]$ErrorId,
[ErrorCategory]$Category = 'InvalidOperation',
$TargetObject = $PSItem,
$cmdlet = $PSCmdlet,
[Switch]$Terminating
)
process {
$errorRecord = [ErrorRecord]::new(
$Message,
$ErrorId,
$Category,
$TargetObject
)
if ($Terminating) {
$cmdlet.ThrowTerminatingError(
$ErrorRecord
)
} else {
$cmdlet.WriteError(
$ErrorRecord
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment