ManageRoles.psm1
<# ManageRoles.psm1
This powershell module allows you to manage a role's actions and scope buy outputting them to editable text files. Roles are AD objects that span multiple subscriptions, however they have a history of being affliated with a subscription that you created them from. To manage them you must be connected to a subscription that is in the list of subscriptions for that role (known as assignablescope). The Commandlets names are structured as follows <verb>-Role<object> <verb> = Get - retrieves role infomation and writes to a file Set - Overwrites a roles information from a file New - Creates a new role Remove - Removes a role, Note: will remove it from all subscriptions <object> = blank (Applies to Actions and Scope or whole object) Actions - list of actions (aka Provider Operations) Scope - list of subscription ids Actual functions Set-RoleFilename - Internal function to remove '<prefix>]' from role to create a filename substring Get-Role - Outputs a role's actions to an action file and scope to a scope file. Get-RoleActions - Outputs a role's actions to an action file 'actions-*.txt' and scope to a scope file. Get-RoleScope - Outputs a role's scope to an scope file 'scope-*.txt' and scope to a scope file. Set-Role - Overwrites a role based on an actions file and a scope file. Set-RoleActions - Overwrites a role's actions to an action file 'actions-*.txt' and scope to a scope file. Set-RoleScope - Overwrites a role's scope to an scope file 'scope-*.txt' and scope to a scope file. New-Role - Creates a new role based on an actions file and a scope file Remove-Role - Removes a role from active directory from all subscriptions (scope) Edit-RoleActions - Gets a role's actions, opens up notepad on the actions file, then overwrites the actions from that file Notes: In PowerShell, use the Get-AzProviderOperation command to get the list of operations for the Microsoft.Support resource provider you are interested in. It's helpful to know the operations that are available to you when creating custom roles. Example: Get-AzProviderOperation "Microsoft.Support/*" | Format-Table Operation, Description -AutoSize Custom roles are stored in Active Directory but they are accessed via the subscriptions in the assignable scope. Your current logged in context must be in the assignablescope for these operations to work. To see your current context use the following command Write-output "Connected to $($(Get-azcontext).name)" To set your context use the command Connect-AzAccount -Subscription -Tenant ################################################################################################################ #> function Set-RoleFilename { <# .Synopsis Remove the "<prefix>]" string from filename .Description The braces '[]' are not valid filename characters so we need to remove them. This will find the closing brace (right angle bracket) and trim off the string up to it. .Parameter role Filename - full path or not doesn't matter #> Param ( [string] $role ) $loc=$role.LastIndexOf("]") + 1 $len=$role.Length - $loc $filename=$role.Substring($loc,$len).Trim() Return $filename } function Get-Role { <# .Synopsis Output a role's actions and scopes to two text files. .Description This function calls Get-RoleActions and Get-RoleScope; It creates two files scope-<role>.txt and actions-<role>.txt One subscription or action per line. .Parameter Role Required - name of the role you want to get the scope from If not specified it will look for a global variable $global:scope #> Param ( [string] $role ) If ($role -eq "") {$role = $global:role} If ($role -eq "") {write-output "Please supply -role parameter"; Return} $global:role = $role; $roledef = Get-RoleActions; $roledef = Get-RoleScope; } function Get-RoleActions { <# .Synopsis Output a role's actions to a text file. .Description This function will output the permissions (actions) to a text file which you may then edit and use the New-Role or Set-Role function to create a new role or set an existing role. It creates the file actions-<role>.txt one action per line. .Parameter Role Name of the role you want to get the actions from. If not specified this will look for a global variable $global:role to use. Your current subscription context must have the role in its scope for this to work. Enter $(Get-azcontext).name at the powershell prompt to see your current subscription context. #> Param ( [string] $role ) If ($role -eq "") {$role = $global:role} If ($role -eq "") {write-output "Please supply -role parameter"; Return;} $global:role = $role; $actionsfile = "Actions-" + $(Set-rolefilename -filename $role) + ".txt"; # Get the current role definition Try { $roledef = Get-AzRoleDefinition -Name $role -ErrorAction Stop; } Catch { Write-output "Unable to get $role, error $($_.Exception.Message)"; Return} Try { If ($roledef.Name = "") { Write-output "Unable to get $role from subscription $(Get-AzContext).name"; Return;} } Catch { Write-output "Unable to get $role from subscription $($(Get-AzContext).name)"; Write-Output "Error $($_.Exception.Message)"; Write-Output "Try setting your context to another subscription. Connect-AzAccount -Subscription $subid"; Return; } # write the actions to the file Set-Content -Path $actionsfile -Value $roledef.Actions Write-Host "$role actions have been written to $actionsfile" } function Get-RoleScope { <# .Synopsis Output a role's scopes to a text file. .Description This function will output the scopes (subscriptions or resource groups) to a text file in the format scope-<role>.txt The text file will have one subscription per line in the format /subscriptions/<subscription-id> example: /subscriptions/a1234567-890a-bcde-f012-34567890abcd .Parameter Role Name of the role you want to get the actions from. If not specified this will look for a global variable $global:role to use. Your current subscription context must have the role in its scope for this to work. Enter $(Get-azcontext).name at the powershell prompt to see your current subscription context. #> Param ( [string] $role ) If ($role -eq "") {$role = $global:role} If ($role -eq "") {write-output "Please supply -role parameter"; Return;} $global:role = $role; $scopefile = "Scope-" + $(Set-rolefilename -role $role) + ".txt"; # Get the current role definitoin $roledef = Get-AzRoleDefinition -Name $role # write the scopes to the file Set-Content -Path $scopefile -Value $roledef.AssignableScopes Write-Host "$role scopes have been written to $scopefile" } function Set-Role { <# .Synopsis Overwrites a role's actions and scope .Description Sets the role's actions to the list from an actions file. Sets the role's scope to the list from the scope file. For more in-depth documentation on custom roles check out https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal .Parameter Role Name of the role you want to get the actions from. If not specified this will look for a global variable $global:role to use. Your current subscription context must have the role in its scope for this to work. Enter $(Get-azcontext).name at the powershell prompt to see your current subscription context. .Parameter actionsfile Text file with list of permissions "actions". Defaults to actions-<role>.txt if not supplied. Use Get-RoleActions to dump out an existing roles actions to a text file for editting. One action per line in the format {Company}.{ProviderName}/{resourceType}/{action} example: Microsoft.Compute/hostgroups/* To see a full list of ARM resource provider operations use the PowerShell command Get-AzProviderOperation To see a full list of "Azure Resource Manager resource provider operations" go to https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations .Parameter scopefile File with list of subscriptions in the format /subscription/<guid> Defaults to scope-<role>.txt if not supplied. The text file will have one subscription per line in the format /subscriptions/<subscription-id> example: /subscriptions/a1234567-890a-bcde-f012-34567890abcd #> Param ( [string] $role, [string] $actionsfile, [string] $scopefile ) # validate parameters If ($role -eq "") {$role = $global:role} If ($role -eq "") {write-output "Please supply -role parameter"; Return;} $global:role = $role; If ($actionsfile -eq "") {$actionsfile = "Actions-" + $(Set-rolefilename -role $role) + ".txt";} If ($scopefile -eq "") {$scopefile = "Scope-" + $(Set-rolefilename -role $role) + ".txt";} # Get the current role definition and overwrite the actions and scope $roledef = Get-AzRoleDefinition -Name $rolename; $roledef.Actions = Get-Content -Path $actionsfile; $roledef.AssignableScopes = Get-Content -Path $scopefile; $roledef = Set-AzRoleDefinition -Role $roledef; Write-output "$rolename [Id= $($roledef.Id) ] updated" Return $roledef } function Set-RoleActions { <# .Synopsis Overwrites a role's actions .Description Sets the role actions to the list from an actions text file. Use Get-RoleActions to dump out an existing role's actions to a text file for editting. .Parameter Role Name of the role you want to get the actions from. If not specified this will look for a global variable $global:role to use. Your current subscription context must have the role in its scope for this to work. Enter $(Get-azcontext).name at the powershell prompt to see your current subscription context. .Parameter actionsfile Text file with list of permissions "actions". Defaults to actions-<role>.txt if not supplied. Use Get-RoleActions to dump out an existing roles actions to a text file for editting. One action per line in the format {Company}.{ProviderName}/{resourceType}/{action} example: Microsoft.Compute/hostgroups/* To see a full list of ARM resource provider operations use the PowerShell command Get-AzProviderOperation To see a full list of "Azure Resource Manager resource provider operations" go to https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations #> Param ( [string] $role, [string] $actionsfile ) # Validate parameters If ($role -eq "") {$role = $global:role} If ($role -eq "") {write-output "Please supply -role parameter"; Return;} $global:role = $role; If ($actionsfile -eq "") {$actionsfile = "Actions-" + $(Set-rolefilename -role $role) + ".txt";} # Get the current role definition try {$roledef = Get-AzRoleDefinition -Name $role -ErrorAction Stop } catch {write-output "Error retrieving role $role"; Return;} $roledef.Actions = Get-Content -Path $actionsfile; $roledef = Set-AzRoleDefinition -Role $roledef Write-output "$role [Id= $($roledef.Id) ] actions updated with $($roledef.Actions.Count) actions" } function Set-RoleScope { <# .Synopsis Sets a role's scope list .Description Overwrite an existing role's AssignableScope entered in a text file. Use Get-RoleScope to dump out an existing role's scope to a text file for editting. .Parameter Role Name of the role you want to get the actions from. If not specified this will look for a global variable $global:role to use. Your current subscription context must have the role in its scope for this to work. Enter $(Get-azcontext).name at the powershell prompt to see your current subscription context. .Parameter scopefile File with list of subscriptions in the format /subscription/<guid> Defaults to Scope-<role>.txt if not supplied. The text file will have one subscription per line in the format /subscriptions/<subscription-id> example: /subscriptions/a1234567-890a-bcde-f012-34567890abcd #> Param ( [Parameter(Mandatory=$true)] [string] $role, [Parameter(Mandatory=$false)] [string] $scopefile ) # Validate $role parameter If ($role -eq "") {$role = $global:role}; $global:role = $role; If ($role -eq "") {Write-Output "Please pass -role parameter"; exit 1}; If ($scopefile -eq "") {$scopefile = "Scope-" + $(Set-rolefilename -role $role) + ".txt";} try {$roledef = Get-AzRoleDefinition -Name $role -ErrorAction Stop} catch {write-output "Error retrieving role $role"; Return;} $roledef.AssignableScopes = Get-Content -Path $scopefile $roledef = Set-AzRoleDefinition -Role $roledef Write-output "$role [Id= $($roledef.Id) ] = AssignableScope updated" Write-output "$role [Id= $($roledef.Id) ] AssignableScopes updated with $($roledef.AssignableScopes.Count) scopes" } function New-Role { <# .Synopsis Create a new custom role .Description Create a new role based on Azure actions entered in a text file. Use Get-RoleActions to dump out an existing role's actions to a text file for editting. Use Get-RoleScope to dump out an existing role's scope to a text file for editting. For more in-depth documentation on custom role's check out https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal .Parameter Role Name of the role you want to create .Parameter actionsfile Text file with list of permissions "actions". If not specified this will create a default action of */read Use Get-RoleActions to dump out an existing roles actions to a text file for editting. One action per line in the format {Company}.{ProviderName}/{resourceType}/{action} example: Microsoft.Compute/hostgroups/* To see a full list of "Azure Resource Manager resource provider operations" go to https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations To see a full list of ARM resource provider operations use the PowerShell command Get-AzProviderOperation Example: Get-AzProviderOperation "Microsoft.Compute/*" | Format-Table Operation, Description -AutoSize .Parameter scopefile Text file with list of subscriptions. If not specified this will attempt to set the scope to the contents of a file named Scope-test.txt Use Get-RoleScope to dump out an existing role's scope to a text file for editting. File with list of subscriptions in the format /subscription/<guid> Defaults to scope-<role>.txt if not supplied. The text file will have one subscription per line in the format /subscriptions/<subscription-id> example: /subscriptions/a1234567-890a-bcde-f012-34567890abcd #> Param ( [string] $role, [string] $actionsfile, [string] $scopefile ) # Validate $role parameter If ($role -eq "") {Write-Output "Please pass -role parameter with the name of the role"; exit 1} $global:role = $role; # Validate $actionsfile If ($actionsfile -eq "") { $actionsfile = "Actions-" + $(Set-rolefilename -role $role) + ".txt"; Set-Content -Path $actionsfile "*/read"; Write-Output "No actions specified. Setting actions to */read" } # Validate $scopefile (default = Scope-test.txt) else Error If ($scopefile -eq "") {$scopefile = "Scope-" + $(Set-rolefilename -role $role) + ".txt";} Try { get-item -path $scopefile -ErrorAction Stop } Catch { Try { Copy-Item -Path '.\Scope-test.txt' -Destination $scopefile -ErrorAction Stop; Write-Output "No scope specified. Setting scope to Scope-test.txt" } Catch { Write-Output "Error - default scope file Scope-test.txt not found."; Write-Output "Use Get-RoleScope -role 'your role name' to create an example scopefile"; Return; } } # Create a new role definition object $global:role = $role; $roledef = New-Object -type Microsoft.Azure.Commands.Resources.Models.Authorization.PSRoleDefinition; $roledef.Id = $null $roledef.IsCustom = $true $roledef.Name = $role $roledef.Description = $role $roledef.Actions = Get-Content -Path $actionsfile; $roledef.AssignableScopes = Get-Content -Path $scopefile; Try { $roledef = New-AzRoleDefinition -Role $roledef -ErrorAction Stop; Write-output "$role [Id= $($roledef.Id) ] created"; Write-Output "Please allow 15min for Active Directory to propgate this change."; Write-Output "If you are logged into the Azure Portal you may need to relogin."; } Catch { Write-output "Error creating $role"; Write-Output "Message: $($_.Exception.Message)"; } } function Remove-Role { <# .Synopsis Remove a role from Active Directory. .Description Removes a role which will remove it from all subscriptions. This is not recoverable. Recommend using Get-Role so you have a copy of the actions and scope as a backup. Note: Custom roles are stored in Active Directory and may take time to propgate changes .Parameter Role Name for the Role to remove. Note: Defaults to global variable $global:role .Example Remove-Role .Example Remove-Role -role "I dislike this custom role" #> Param ( [string] $role ) # Validate $role parameter If ($role -eq "") {$role = $global:role} $global:role = $role; If ($role -eq "") {Write-Output "Please pass -role parameter"; Return;} # Get the current role definition Try { Remove-AzRoleDefinition -Name $role -ErrorAction Stop; Write-output "Deleted role $role" Write-Output "Please allow 15min for Active Directory to propgate this change" } Catch { write-output "Failed to delete role $role"; write-output $_.Exception.Message; Return; } } function Get-RoleHelp { Write-Output "" Write-Output "*************** Welcome to ManageRoles Powershell Module ***************" Write-Output "You are connected to $($(Get-azcontext).name)" Write-Output "" Write-Output "ManageRoles installs the following PowerShell functions for you:" Write-Output "**************************************************************************************************************************" Write-Output "Get-Role - Writes a role's actions and scope to seperate files." Write-Output "Get-RoleActions - Writes a role's actions to an action file named actions-<role>.txt " Write-Output "Get-RoleScope - Writes a role's scope to a scope file named scope-<role>.txt" Write-Output "Set-Role - Overwrites a role based on an actions file and a scope file." Write-Output "Set-RoleActions - Overwrites a roles actions to an action file actions-*.txt and scope to a scope file." Write-Output "Set-RoleScope - Overwrites a roles scope to an scope file scope-*.txt and scope to a scope file." Write-Output "New-Role - Creates a new role based on an actions file and a scope file" Write-Output "Remove-Role - Removes a role from active directory from all subscriptions (scope)" #Write-Output "Edit-RoleActions - Gets a roles actions, opens up notepad on the actions file, then overwrites the actions from that file" Write-Output "" Write-Output "Manage-Roles examples: " Write-Output " Get-Help *-role*" Write-Output " New-Role -role 'My new role'" Write-Output " Get-Role -role 'Cosmos DB'" Write-Output " Set-RoleActions -role 'Cosmos DB'" Write-Output " Set-RoleScope -role 'Cosmos DB' -scopefile Scope-allsubs.txt" Write-Output " New-Role -role 'Cosmos DB v2' -actionsfile Actions-CosmosDB.txt -scopefile Scope-testsubs.txt" Write-Output "" Write-Output "For more in-depth documentation on custom roles check out https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal" Write-Output "" Write-Output "To see a full list of Azure Resource Manager resource provider operations" Write-Output "go to https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations" Write-Output "To see a full list of ARM resource provider operations use the PowerShell command Get-AzProviderOperation" Write-Output "" } ############################################################################## # Main Program ############################################################################## # set aliases Try {Get-Alias -name gr -ErrorAction Stop; Set-Alias -Name gr -Value Get-Role -Scope Global} Catch {New-Alias -Name gr -Value Get-Role -Scope Global} Try {Get-Alias -name gra -ErrorAction Stop; Set-Alias -Name gra -Value Get-RoleActions -Scope Global} Catch {New-Alias -Name gra -Value Get-RoleActions -Scope Global} Try {Get-Alias -name grs -ErrorAction Stop; Set-Alias -Name grs -Value Get-RoleScope -Scope Global} Catch {New-Alias -Name grs -Value Get-RoleScope -Scope Global} Try {Get-Alias -name sra -ErrorAction Stop; Set-Alias -Name sra -Value Set-RoleActions -Scope Global} Catch {New-Alias -Name sra -Value Set-RoleActions -Scope Global} Try {Get-Alias -name srs -ErrorAction Stop; Set-Alias -Name srs -Value Set-RoleScope -Scope Global} Catch {New-Alias -Name srs -Value Set-RoleScope -Scope Global} Try {Get-Alias -name rr -ErrorAction Stop; Set-Alias -Name rr -Value Remove-Role -Scope Global} Catch {New-Alias -Name rr -Value Remove-Role -Scope Global} Try {Get-Alias -name grh -ErrorAction Stop; Set-Alias -Name grh -Value Get-RoleHelp -Scope Global} Catch {New-Alias -Name grh -Value Get-RoleHelp -Scope Global} |