seanmcne / Microsoft.Xrm.Data.PowerShell

This module uses the CRM connection from Microsoft.Xrm.Tooling.CrmConnector.Powershell and provides common functions to create, delete, query, and update data as well as functions for common tasks such as publishing, and manipulating System & CRM User Settings, etc. The module should function for both Dynamics CRM Online and On-Premise environment.
201 stars 64 forks source link

List record access for a user? #496

Closed spplante closed 2 years ago

spplante commented 2 years ago

Hi there,

I am able to successfully use the Grant-CrmRecordAccess to give a user write access to a target workflow. However, I am trying to find a way to check if the user already has write access before granting it, and I can't find any documentation on how to do so.

I would expect something like Get-CrmRecordAccess but there is no such thing. Also, when trying the remove the record access I just granted, it looks like Revoke-CrmRecordAccess can only use the -Revokee parameter which seems to remove all access from the specified user on the given record.

Isn't there a way to list existing record access for a user and delete a specific record access for a user?

Thanks!

spplante commented 2 years ago

For anyone interested, I didn't find any command in this module but I made my own by reverse engineering the Grant-CrmRecordAccess method and modifying it with the Microsoft.Crm.Sdk.Messages.RetrievePrincipalAccessRequest and Microsoft.Crm.Sdk.Messages.RetrievePrincipalAccessResponse classes :

function Get-CrmRecordAccess {0
    [OutputType([Microsoft.Crm.Sdk.Messages.AccessRights])]
    [CmdletBinding()]
    PARAM(
        [parameter(Mandatory=$false, Position=0)]
        [Microsoft.Xrm.Tooling.Connector.CrmServiceClient]$conn,

    [parameter(Mandatory=$true, Position=1, ParameterSetName="CrmRecord", ValueFromPipeline=$true)]
        [PSObject[]]$CrmRecord,

        [parameter(Mandatory=$true, Position=1, ParameterSetName="NameWithId")]
        [string]$EntityLogicalName,

        [parameter(Mandatory=$true, Position=2, ParameterSetName="NameWithId")]
        [guid]$Id,

    [parameter(Mandatory=$true, Position=3)]
        [Microsoft.Xrm.Sdk.EntityReference]$Principal
    )
    begin
    {
        $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn'))

        if ($EntityLogicalName) {
            $CrmRecord += [PSCustomObject] @{
                logicalname = $EntityLogicalName
                "$($EntityLogicalName)id" = $Id
            }
        }
    }
    process
    {
        foreach ($record in $CrmRecord) {
            try {
                $request = [Microsoft.Crm.Sdk.Messages.RetrievePrincipalAccessRequest]::new()
                $request.Target = New-CrmEntityReference -EntityLogicalName $record.logicalname -Id $record.($record.logicalname + "id")
                $request.Principal = $Principal

                $response = [Microsoft.Crm.Sdk.Messages.RetrievePrincipalAccessResponse]$conn.Execute($request)
                return $response.AccessRights
            }
            catch {
                Write-Error $_
            }   
        }
    }
}

With this method you will successfully get the existing permission of the specified user on the target record!

seanmcne commented 2 years ago

This is great, thanks for sharing! I can take a look at consider adding this in as a core function, it seems like some folks might find this useful. If nothing else, adding this in the samples repo would also help others - thanks!

https://github.com/seanmcne/Microsoft.Xrm.Data.PowerShell.Samples

PS: for adding into the module, it might be good to figure out how best to process the record and what object to return - in this current form I think it's a fantastic sample and almost at the point where we can include it in the module.