src/Security/Get-XrmPrivileges.ps1
|
<# .SYNOPSIS Retrieve privileges with their table, access right and supported depths. .DESCRIPTION Read privilege definitions (privilege table) and describe each one: Id, Name, AccessRight (Read, Write, Create, Delete, Append, AppendTo, Assign, Share, or None for the miscellaneous privileges such as prvBypassCustomPlugins), AccessRightValue, EntityLogicalName, EntityLogicalNames, CanBeBasic, CanBeLocal, CanBeDeep, CanBeGlobal, SupportedDepths. A privilege can cover several tables (prvReadActivity covers every activity table, prvReadAccount also covers customeraddress): EntityLogicalNames lists them all. EntityLogicalName is the table named after the privilege (prvReadAccount => account), the filtered table with -EntityLogicalName, the only table, or $null when none of these applies. .PARAMETER XrmClient Xrm connector initialized to target instance. Use latest one by default. (Dataverse ServiceClient) .PARAMETER Name Privilege names (e.g. "prvReadAccount"). (Default: all) .PARAMETER Id Privilege unique identifiers. (Default: all) .PARAMETER EntityLogicalName Keep the privileges that apply to this table. (Default: all) .PARAMETER AccessRight Keep the privileges of this access right: Read, Write, Create, Delete, Append, AppendTo, Assign, Share. (Default: all) .PARAMETER RoleId Keep the privileges granted to this security role. (Default: all) .OUTPUTS PSCustomObject[]. One object per privilege. .EXAMPLE $privilege = Get-XrmPrivileges -XrmClient $xrmClient -EntityLogicalName "account" -AccessRight Write; # prvWriteAccount .EXAMPLE Get-XrmPrivileges -XrmClient $xrmClient -Name "prvBypassCustomPlugins" | Select-Object Name, SupportedDepths; .LINK https://github.com/AymericM78/PowerDataOps/blob/main/documentation/commands/Get-XrmPrivileges.md #> function Get-XrmPrivileges { [CmdletBinding()] [OutputType([PSCustomObject[]])] param ( [Parameter(Mandatory = $false, ValueFromPipeline)] [Microsoft.PowerPlatform.Dataverse.Client.ServiceClient] $XrmClient = $Global:XrmClient, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [Guid[]] $Id, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [String] $EntityLogicalName, [Parameter(Mandatory = $false)] [ValidateSet("Read", "Write", "Create", "Delete", "Append", "AppendTo", "Assign", "Share")] [String] $AccessRight, [Parameter(Mandatory = $false)] [Guid] $RoleId ) begin { $StopWatch = [System.Diagnostics.Stopwatch]::StartNew(); Trace-XrmFunction -Name $MyInvocation.MyCommand.Name -Stage Start -Parameters ($MyInvocation.MyCommand.Parameters); } process { $accessRights = [ordered]@{ Read = 1; Write = 2; Append = 4; AppendTo = 16; Create = 32; Delete = 65536; Share = 262144; Assign = 524288 }; $query = New-XrmQueryExpression -LogicalName "privilege" -Columns "name", "accessright", "canbebasic", "canbelocal", "canbedeep", "canbeglobal"; if ($PSBoundParameters.ContainsKey('Name')) { $query = $query | Add-XrmQueryCondition -Field "name" -Condition In -Values $Name; } if ($PSBoundParameters.ContainsKey('Id')) { $query = $query | Add-XrmQueryCondition -Field "privilegeid" -Condition In -Values $Id; } if ($PSBoundParameters.ContainsKey('AccessRight')) { $query = $query | Add-XrmQueryCondition -Field "accessright" -Condition Equal -Values $accessRights[$AccessRight]; } if ($PSBoundParameters.ContainsKey('EntityLogicalName')) { $entityLink = $query | Add-XrmQueryLink -ToEntityName "privilegeobjecttypecodes" -FromAttributeName "privilegeid" -ToAttributeName "privilegeid"; $entityLink | Add-XrmQueryLinkCondition -Field "objecttypecode" -Condition Equal -Values $EntityLogicalName | Out-Null; } if ($PSBoundParameters.ContainsKey('RoleId')) { $roleLink = $query | Add-XrmQueryLink -ToEntityName "roleprivileges" -FromAttributeName "privilegeid" -ToAttributeName "privilegeid"; $roleLink | Add-XrmQueryLinkCondition -Field "roleid" -Condition Equal -Values $RoleId | Out-Null; } $query = $query | Add-XrmQueryOrder -Field "name" -OrderType Ascending; $privileges = $XrmClient | Get-XrmMultipleRecords -Query $query -AsEntity -AsArray; if ($privileges.Count -eq 0) { return; } # Tables of each privilege: one query, filtered on the privileges when they are few $entityQuery = New-XrmQueryExpression -LogicalName "privilegeobjecttypecodes" -Columns "privilegeid", "objecttypecode"; if ($privileges.Count -le 500) { $entityQuery = $entityQuery | Add-XrmQueryCondition -Field "privilegeid" -Condition In -Values @($privileges | ForEach-Object { $_.Id }); } $entitiesByPrivilege = @{}; foreach ($row in ($XrmClient | Get-XrmMultipleRecords -Query $entityQuery -AsEntity -AsArray)) { $objectTypeCode = [string]$row["objecttypecode"]; if ([string]::IsNullOrEmpty($objectTypeCode) -or $objectTypeCode -eq "none") { continue; } $privilegeId = $row["privilegeid"].Id; if (-not $entitiesByPrivilege.ContainsKey($privilegeId)) { $entitiesByPrivilege[$privilegeId] = [System.Collections.Generic.List[string]]::new(); } $entitiesByPrivilege[$privilegeId].Add($objectTypeCode); } foreach ($privilege in $privileges) { $privilegeName = [string]$privilege["name"]; $accessRightValue = [int]$privilege["accessright"]; $accessRightName = "None"; foreach ($right in $accessRights.Keys) { if ($accessRights[$right] -eq $accessRightValue) { $accessRightName = $right; } } $entityNames = @(); if ($entitiesByPrivilege.ContainsKey($privilege.Id)) { $entityNames = @($entitiesByPrivilege[$privilege.Id] | Sort-Object -Unique); } $entityName = $null; if ($PSBoundParameters.ContainsKey('EntityLogicalName')) { $entityName = $EntityLogicalName; } elseif ($entityNames.Count -eq 1) { $entityName = $entityNames[0]; } elseif ($entityNames.Count -gt 1 -and $privilegeName.StartsWith("prv$accessRightName", [StringComparison]::OrdinalIgnoreCase)) { $nameSuffix = $privilegeName.Substring("prv$accessRightName".Length); $entityName = $entityNames | Where-Object { $_ -eq $nameSuffix } | Select-Object -First 1; } $supportedDepths = [System.Collections.Generic.List[Microsoft.Crm.Sdk.Messages.PrivilegeDepth]]::new(); if ($privilege["canbebasic"]) { $supportedDepths.Add([Microsoft.Crm.Sdk.Messages.PrivilegeDepth]::Basic); } if ($privilege["canbelocal"]) { $supportedDepths.Add([Microsoft.Crm.Sdk.Messages.PrivilegeDepth]::Local); } if ($privilege["canbedeep"]) { $supportedDepths.Add([Microsoft.Crm.Sdk.Messages.PrivilegeDepth]::Deep); } if ($privilege["canbeglobal"]) { $supportedDepths.Add([Microsoft.Crm.Sdk.Messages.PrivilegeDepth]::Global); } [PSCustomObject]@{ Id = $privilege.Id; Name = $privilegeName; AccessRight = $accessRightName; AccessRightValue = $accessRightValue; EntityLogicalName = $entityName; EntityLogicalNames = $entityNames; CanBeBasic = [bool]$privilege["canbebasic"]; CanBeLocal = [bool]$privilege["canbelocal"]; CanBeDeep = [bool]$privilege["canbedeep"]; CanBeGlobal = [bool]$privilege["canbeglobal"]; SupportedDepths = $supportedDepths.ToArray(); }; } } end { $StopWatch.Stop(); Trace-XrmFunction -Name $MyInvocation.MyCommand.Name -Stage Stop -StopWatch $StopWatch; } } Export-ModuleMember -Function Get-XrmPrivileges -Alias *; Register-ArgumentCompleter -CommandName Get-XrmPrivileges -ParameterName "EntityLogicalName" -ScriptBlock { param($CommandName, $ParameterName, $WordToComplete, $CommandAst, $FakeBoundParameters) $validLogicalNames = Get-XrmEntitiesLogicalName; return $validLogicalNames | Where-Object { $_ -like "$wordToComplete*" }; } |