I have been diving into doing larger scale operations in SharePoint Online using the Client Side Object Model (CSOM) utilizing PowerShell and ran into a scenario that I couldn’t easily find documented anywhere. What I wanted to do was technically “share” a file with a specific user and have that user receive an email just like if it was done through the GUI. What I didn’t want to see is just the breaking of permissions. What I found was the Web.ShareObject method and this great blog post from Vesa Juvonen in 2015.
Once I found this I started working on putting this into a useful PowerShell format. To get started with CSOM & PowerShell with SharePoint Online here is a good blog post from Chris O’Brien. You can get the latest version of SharePoint Online CSOM here. If you download the nuget file you can change the file extension to .zip and extract the .dlls.
Here is link to the GitHub rep and I will break it down below along with the script. Here are some key things to note:
- The Web.ShareObject method has been updated since the Vesa blog post with a parameter called useSimplifiedRoles that can be used for utilizing modern sharing
- SharePoint PnP has extended the sharing APIs and built a sample that can be used
- This script is built to share a file based on filename within a site to a single user
- This works on SharePoint Online and OneDrive for Business
- It will share as the user who runs the script
- This script could be updated to share a site or to multiple people
- You can share with Edit or View permission based on the roleValue
- It doesn’t replicate the modern sharing UI in capabilities exactly (more of what occurs details below)
To utilize the script make sure you fill out the appropriate variables and more information about what this will do is below the script.
# Use this script to share a file via CSOM and PowerShell # ShareObject https://msdn.microsoft.com/en-us/library/office/mt684216.aspx # External sharing blog https://blogs.msdn.microsoft.com/vesku/2015/10/02/external-sharing-api-for-sharepoint-and-onedrive-for-business/ ### ENTER YOU VARIABLES HERE ### #path to the SP CSOM files $csomPath = "C:\...." #Email of person running the script $adminEmail = "user@domain.com" #Site collection to be connected to $siteUrl = "https://site.sharepoint.com/sites/site" #Library title where the file exists $libraryTitle = "Documents" #Filename including file type $fileName = "Test Document 1.docx" #Email of who the document is being shared to $emailSharedTo = "user2@domain.com" #UNVALIDATED_EMAIL_ADDRESS if they are in AD or GUEST_USER if they are not $principalType = "UNVALIDATED_EMAIL_ADDRESS" #role:1073741826 = View, role:1073741827 = Edit $roleValue = "role:1073741827" #A flag to determine if permissions should be pushed to items with unique permissions. $propageAcl = $true #Flag to determine if an e-mail notification should to sent, if e-mail is configured. $sendEmail = $true #If an e-mail is being sent, this determines if an anonymous link should be added to the message. $includedAnonymousLinkInEmail = $false #The ID of the group to be added to. Use zero if not adding to a permissions group. Not actually used by the code even when user is added to existing group. $groupId = 0 #Doesn't matter as it isn't sent in current email format $emailSubject = "" #Text for the body of the e-mail. $emailBody = "Check out my email body" #Use modern sharing links instead of directly granting access $useSimplifiedRoles = $true ################ # Get CSOM files Add-type -Path "$csomPath\Microsoft.SharePoint.Client.dll" Add-type -Path "$csomPath\Microsoft.SharePoint.Client.Runtime.dll" # Connnect to site $ss = Read-Host -Prompt "Enter admin password" -AsSecureString $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl) $creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($adminEmail, $ss) $ctx.Credentials = $creds if(!$ctx.ServerObjectIsNull.Value) { Write-Host "Connected to site:" $siteUrl -ForegroundColor Green } # Get web $web = $ctx.Web # Connect to library $list = $web.Lists.GetByTitle($libraryTitle) $ctx.Load($web) $ctx.Load($list) $ctx.Load($list.RootFolder) $ctx.ExecuteQuery() # Get doc $query = New-Object Microsoft.SharePoint.Client.CamlQuery $caml ="<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='File'>" + $fileName + "</Value></Eq></Where></Query></View>" $query.ViewXml = $caml $item = $list.GetItems($query) $ctx.Load($item) $ctx.ExecuteQuery() if (!$item) { Write-Host "Could not find the file:" $fileName -ForegroundColor Yellow } else { Write-Host "Sharing the the file:" $item.FieldValues.FileLeafRef -ForegroundColor Green } # Get doc url $itemUrl = $item.FieldValues.FileRef $split = $web.Url -split '/' $itemUrl = "https://" + $split[2] + $itemUrl # Build user object to be shared to $jsonPerson = "[{`"Key`":`"$emailSharedTo`", `"Description`":`"$emailSharedTo`", `"DisplayText`":`"$emailSharedTo`", `"EntityType`":`"`", `"ProviderDisplayName`":`"`", `"ProviderName`":`"`", `"IsResolved`":true, `"EntityData`":{`"Email`":`"$emailSharedTo`", `"AccountName`":`"$emailSharedTo`", `"Title`":`"$emailSharedTo`", `"PrincipalType`":`"$principalType`"}, `"MultipleMatches`":[]}]" # Initiate share $result = [Microsoft.SharePoint.Client.Web]::ShareObject($web.Context,$itemUrl,$jsonPerson,$roleValue,$groupid,$propageAcl,$sendEmail,$includedAnonymousLinkInEmail,$emailSubject,$emailBody,$useSimplifiedRoles) $web.Context.Load($result) $web.Context.ExecuteQuery() Write-Host "Status of the share:" $result.StatusCode -ForegroundColor Green
Starting from a non shared file this is what you will see based on different configurations:
Sharing with useSimplifiedRoles set to $true and sendEmail set to $true
- The file does not have inheritance broken
- After initiating the ShareObject, inheritance is broken but you don’t see any changes
- The person being shared to receives an email that the person who ran the script wants to share a file with you and you will see the email subject is preset but the email body is included
- Once the person being shared to clicks on the link you can see a new ‘Managed Links’ section in the item permissions
- If you follow that link you will see the item is now shared with that individual
Sharing with useSimplifiedRoles set to $true and sendEmail set to $false
- The file does not have inheritance broken
- After initiating the ShareObject, inheritance is broken but you don’t see any changes if the user tries to access the file through the document library
- There is a new link viewable in the modern manage access section showing a new sharing link and that someone can access via that link
- If the user accesses the file via that link you can see a new ‘Managed Links’ section in the item permissions and you can see that user in the Shared with section
Sharing with useSimplifiedRoles set to $false and sendEmail set to $false
- The file does not have inheritance broken
- After initiating the ShareObject, inheritance is broken but you don’t see any changes even after a user accesses the file, that means this does nothing but break inheritance
Sharing with useSimplifiedRoles set to $false and sendEmail set to $true
- The file does not have inheritance broken
- After initiating the ShareObject, inheritance is broken but you don’t see any changes
- Once a user accesses the file via the link in the email they are granted permissions directly to the file (contribute instead of edit)
Ending…
After putting this together I realized I don’t really have a great use case to actually use this. Either way it was a good learning experience for me as I am just getting started into this kind of CSOM & PowerShell work and maybe it will come in handy for someone else in the future.