Public/New-RBACAssignmentScript.ps1

function New-RBACAssignmentScript {
    <#
    .SYNOPSIS
        Generates ready-to-run PowerShell snippets to grant or revoke a role.
 
    .DESCRIPTION
        Produces idempotent 'add' and 'remove' PowerShell snippets that assign or
        remove a single Azure RBAC role for a caller at a given scope. The add
        snippet checks for an existing assignment before creating one, and the
        remove snippet checks for presence before deleting, so both are safe to
        run repeatedly.
 
    .PARAMETER CallerId
        The target identity (UPN / sign-in name) to grant or revoke.
 
    .PARAMETER Role
        The Azure RBAC role definition name to assign.
 
    .PARAMETER Scope
        The scope at which the assignment applies.
 
    .EXAMPLE
        New-RBACAssignmentScript -CallerId 'patrick.gallucci@microsoft.com' `
            -Role 'Reader' -Scope '/subscriptions/00000000-0000-0000-0000-000000000000'
 
    .OUTPUTS
        PSCustomObject with CallerId, Role, Scope, AddScript, RemoveScript.
    #>

    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'Generates script text only; makes no state change.')]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$CallerId,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Role,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Scope
    )

    $scope = $Scope.TrimEnd('/')

    $addScript = @"
# PSAutoRBAC: grant '$Role' to '$CallerId' at scope '$scope'.
# The account running this must hold roleAssignments/write (RBAC Administrator,
# User Access Administrator, or Owner). Idempotent: skips if already assigned.
Import-Module Az.Accounts -ErrorAction Stop
Import-Module Az.Resources -ErrorAction Stop
 
`$upn = '$CallerId'
`$role = '$Role'
`$scope = '$scope'
 
`$existing = Get-AzRoleAssignment -SignInName `$upn -RoleDefinitionName `$role -Scope `$scope -ErrorAction SilentlyContinue
if (`$existing) {
    Write-Host "Already assigned '`$role' to '`$upn' at '`$scope'. No action."
}
else {
    New-AzRoleAssignment -SignInName `$upn -RoleDefinitionName `$role -Scope `$scope
    Write-Host "Granted '`$role' to '`$upn' at '`$scope'."
}
"@


    $removeScript = @"
# PSAutoRBAC: revoke '$Role' from '$CallerId' at scope '$scope'.
# The account running this must hold roleAssignments/delete. Idempotent: skips
# if the assignment is not present.
Import-Module Az.Accounts -ErrorAction Stop
Import-Module Az.Resources -ErrorAction Stop
 
`$upn = '$CallerId'
`$role = '$Role'
`$scope = '$scope'
 
`$existing = Get-AzRoleAssignment -SignInName `$upn -RoleDefinitionName `$role -Scope `$scope -ErrorAction SilentlyContinue
if (`$existing) {
    Remove-AzRoleAssignment -SignInName `$upn -RoleDefinitionName `$role -Scope `$scope
    Write-Host "Revoked '`$role' from '`$upn' at '`$scope'."
}
else {
    Write-Host "No '`$role' assignment for '`$upn' at '`$scope'. No action."
}
"@


    [pscustomobject]@{
        PSTypeName   = 'PSAutoRBAC.AssignmentScript'
        CallerId     = $CallerId
        Role         = $Role
        Scope        = $scope
        AddScript    = $addScript
        RemoveScript = $removeScript
    }
}