Hasuniqueroleassignments Sharepoint 2016

Find SharePoint List items with unique permissions using powershell

We can easily find and retrieve SharePoint list items which has unique permissions using CSOM in Powershell. In this script, we are going to use GitHub open source library Load-CSOMProperties.ps1 to fetch extra properties (ex: HasUniqueRoleAssignments) in SharePoint CSOM API. You can refer this post : How to load additional CSOM properties in PowerShell for more details.

The following Powershell script get all files (or list items) which has unique (or explicit) permission entries from a given SharePoint Online document library. To use CSOM in Powershell, we need to load the required Microsoft SharePoint Online SDK assembly files.
#Add required references to SharePoint client assembly to use CSOM [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") C:\Scripts\Load-CSOMProperties.ps1    $siteUrl="https://spotenant.sharepoint.com/sites/mysite1" $UserName = "admin@spotenant.onmicrosoft.com" $SecPwd = $(ConvertTo-SecureString 'myAdminPwd' -asplaintext -force) $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl) $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,$SecPwd) $ctx.credentials = $credentials $ctx.Load($ctx.Web) $ctx.ExecuteQuery() $list=$ctx.Web.Lists.GetByTitle("Documents") $ctx.Load($list) $ctx.ExecuteQuery() $camlQuery = New-Object Microsoft.SharePoint.Client.CamlQuery $camlQuery.ViewXml ="<View Scope='RecursiveAll' />"; $allItems=$list.GetItems($camlQuery) $ctx.Load($allItems) $ctx.ExecuteQuery()   foreach($item in $allItems) { Load-CSOMProperties -object $item -propertyNames @("HasUniqueRoleAssignments"); $ctx.ExecuteQuery(); if($item.HasUniqueRoleAssignments -eq $true) { Write-Host $item["FileRef"] Write-Host "##############" } }

How to load additional CSOM properties in a PowerShell script

We can use CSOM (client-side object model) in different programming and scripting languages to manage SharePoint On-Premises and SharePoint Online objects, as you know loading additional properties in client side object is very challenging task. In .NET C#, we can easily load specific values using Lambda Expressions with SharePoint CSOM API, but we should have proper knowledge to write lambda expression in Windows PowerShell.

In this post, I am going to share how to use GitHub open source library Load-CSOMProperties.ps1 to fetch extra properties in SharePoint CSOM API. It includes the following steps.
  1. Copy the required Powershell script code from this GitHub location Load-CSOMProperties.ps1 or you also copy the same script code at the end of this post.
  2. Once you copied the script, open Notepad (or Text Document) and paste the copied script, then save the file with .ps1 extension (Ex: Load-CSOMProperties.ps1).
  3. Now you can load the saved Powershell script file in Powershell console by just entering the file path. Ex: C:\Scripts\Load-CSOMProperties.ps1
  4. Once you loaded the Load-CSOMProperties.ps1 file in Powershell console, you can call the function Load-CSOMProperties anywhere in your script to load extra properties for any client side object.

Example 1:

The below powershell script load the additional properties 'Url' and 'Title' of the object $web along with default properties.
C:\Scripts\Load-CSOMProperties.ps1 $web = $ctx.Web Load-CSOMProperties -object $web -propertyNames @("AllProperties", "Url", "Title") $ctx.ExecuteQuery()

Example 2:

The below powershell script load the property HasUniqueRoleAssignments in every list item and check if the item has any unique permission entry or not.
C:\Scripts\Load-CSOMProperties.ps1 foreach($listItem in $allItems) { Load-CSOMProperties -object $listItem -propertyNames @("HasUniqueRoleAssignments"); $ctx.ExecuteQuery(); if($listItem.HasUniqueRoleAssignments -eq $true) { Write-Host $listItem["FileRef"] } }

Source of Load-CSOMProperties.ps1:

<# .Synopsis Facilitates the loading of specific properties of a Microsoft.SharePoint.Client.ClientObject object or Microsoft.SharePoint.Client.ClientObjectCollection object. .DESCRIPTION Replicates what you would do with a lambda expression in C#. For example, "ctx.Load(list, l => list.Title, l => list.Id)" becomes "Load-CSOMProperties -object $list -propertyNames @('Title', 'Id')". .EXAMPLE Load-CSOMProperties -parentObject $web -collectionObject $web.Fields -propertyNames @("InternalName", "Id") -parentPropertyName "Fields" -executeQuery $web.Fields | select InternalName, Id .EXAMPLE Load-CSOMProperties -object $web -propertyNames @("Title", "Url", "AllProperties") -executeQuery $web | select Title, Url, AllProperties #> function global:Load-CSOMProperties { [CmdletBinding(DefaultParameterSetName='ClientObject')] param ( # The Microsoft.SharePoint.Client.ClientObject to populate. [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = "ClientObject")] [Microsoft.SharePoint.Client.ClientObject] $object, # The Microsoft.SharePoint.Client.ClientObject that contains the collection object. [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = "ClientObjectCollection")] [Microsoft.SharePoint.Client.ClientObject] $parentObject, # The Microsoft.SharePoint.Client.ClientObjectCollection to populate. [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1, ParameterSetName = "ClientObjectCollection")] [Microsoft.SharePoint.Client.ClientObjectCollection] $collectionObject, # The object properties to populate [Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ClientObject")] [Parameter(Mandatory = $true, Position = 2, ParameterSetName = "ClientObjectCollection")] [string[]] $propertyNames, # The parent object's property name corresponding to the collection object to retrieve (this is required to build the correct lamda expression). [Parameter(Mandatory = $true, Position = 3, ParameterSetName = "ClientObjectCollection")] [string] $parentPropertyName, # If specified, execute the ClientContext.ExecuteQuery() method. [Parameter(Mandatory = $false, Position = 4)] [switch] $executeQuery ) begin { } process { if ($PsCmdlet.ParameterSetName -eq "ClientObject") { $type = $object.GetType() } else { $type = $collectionObject.GetType() if ($collectionObject -is [Microsoft.SharePoint.Client.ClientObjectCollection]) { $type = $collectionObject.GetType().BaseType.GenericTypeArguments[0] } } $exprType = [System.Linq.Expressions.Expression] $parameterExprType = [System.Linq.Expressions.ParameterExpression].MakeArrayType() $lambdaMethod = $exprType.GetMethods() | ? { $_.Name -eq "Lambda" -and $_.IsGenericMethod -and $_.GetParameters().Length -eq 2 -and $_.GetParameters()[1].ParameterType -eq $parameterExprType } $lambdaMethodGeneric = Invoke-Expression "`$lambdaMethod.MakeGenericMethod([System.Func``2[$($type.FullName),System.Object]])" $expressions = @() foreach ($propertyName in $propertyNames) { $param1 = [System.Linq.Expressions.Expression]::Parameter($type, "p") try { $name1 = [System.Linq.Expressions.Expression]::Property($param1, $propertyName) } catch { Write-Error "Instance property '$propertyName' is not defined for type $type" return } $body1 = [System.Linq.Expressions.Expression]::Convert($name1, [System.Object]) $expression1 = $lambdaMethodGeneric.Invoke($null, [System.Object[]] @($body1, [System.Linq.Expressions.ParameterExpression[]] @($param1))) if ($collectionObject -ne $null) { $expression1 = [System.Linq.Expressions.Expression]::Quote($expression1) } $expressions += @($expression1) } if ($PsCmdlet.ParameterSetName -eq "ClientObject") { $object.Context.Load($object, $expressions) if ($executeQuery) { $object.Context.ExecuteQuery() } } else { $newArrayInitParam1 = Invoke-Expression "[System.Linq.Expressions.Expression``1[System.Func````2[$($type.FullName),System.Object]]]" $newArrayInit = [System.Linq.Expressions.Expression]::NewArrayInit($newArrayInitParam1, $expressions) $collectionParam = [System.Linq.Expressions.Expression]::Parameter($parentObject.GetType(), "cp") $collectionProperty = [System.Linq.Expressions.Expression]::Property($collectionParam, $parentPropertyName) $expressionArray = @($collectionProperty, $newArrayInit) $includeMethod = [Microsoft.SharePoint.Client.ClientObjectQueryableExtension].GetMethod("Include") $includeMethodGeneric = Invoke-Expression "`$includeMethod.MakeGenericMethod([$($type.FullName)])" $lambdaMethodGeneric2 = Invoke-Expression "`$lambdaMethod.MakeGenericMethod([System.Func``2[$($parentObject.GetType().FullName),System.Object]])" $callMethod = [System.Linq.Expressions.Expression]::Call($null, $includeMethodGeneric, $expressionArray) $expression2 = $lambdaMethodGeneric2.Invoke($null, @($callMethod, [System.Linq.Expressions.ParameterExpression[]] @($collectionParam))) $parentObject.Context.Load($parentObject, $expression2) if ($executeQuery) { $parentObject.Context.ExecuteQuery() } } } end { } }


Leave a Reply

Your email address will not be published. Required fields are marked *