How do I find the set of Site Pages to which I have assigned unique permissions? - sharepoint-online

I am the owner of a SharePoint Online site, and I have a handful of pages that I wanted to hide from Visitors, so I went to the Site Pages folder and clicked Manage Access for each file I wanted to hide, and I clicked the name of the SiteVisitors group and clicked Stop Sharing. The result is that Visitors cannot navigate or even see those pages in a Search. Now I want to restore the access for Visitors.
BUT, let's say I forgot the names of the pages that I hid. I can still see the pages because I am the Owner, but I forgot which pages the Visitors cannot see. So how do I generate a list of all pages that have non-standard permissions?

You can get all pages with unqiue permissions in your Site Pages library using below CSOM powershell.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server
Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server
Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Function to call a non-generic method Load
Function Invoke-LoadMethod() {
param([Microsoft.SharePoint.Client.ClientObject]$Object = $(throw "Please provide a Client Object"),[string]$PropertyName)
$ctx = $Object.Context
$load = [Microsoft.SharePoint.Client.ClientContext].GetMethod("Load")
$type = $Object.GetType()
$clientLoad = $load.MakeGenericMethod($type)
$Parameter = [System.Linq.Expressions.Expression]::Parameter(($type), $type.Name)
$Expression = [System.Linq.Expressions.Expression]::Lambda([System.Linq.Expressions.Expression]::Convert([System.Linq.Expressions.Expression]::PropertyOrField($Parameter,$PropertyName),[System.Object] ), $($Parameter))
$ExpressionArray = [System.Array]::CreateInstance($Expression.GetType(), 1)
$ExpressionArray.SetValue($Expression, 0)
$clientLoad.Invoke($ctx,#($Object,$ExpressionArray))
}
#Define Parameter values
$SiteURL="https://crescent.sharepoint.com/sites/PMO"
$ListName="Site Pages"
Try {
#Setup Credentials to connect
$Cred= Get-Credential
$Credentials = New-Object
Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials
#Get All Lists of the web
$List = $Ctx.Web.Lists.GetByTitle($ListName)
$Ctx.Load($List)
$Ctx.ExecuteQuery()
Write-host "Total List Items Found:"$List.ItemCount
#Query to Get 2000 items from the list
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = "<View Scope='RecursiveAll'><RowLimit>2000</RowLimit></View>"
#Batch process list items - to mitigate list threshold issue on larger lists
Do {
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
#Loop through each List item
ForEach($ListItem in $ListItems)
{
Invoke-LoadMethod -Object $ListItem -PropertyName "HasUniqueRoleAssignments"
$Ctx.ExecuteQuery()
if ($ListItem.HasUniqueRoleAssignments -eq $true)
{
Write-Host -f Green "List Item '$($ListItem["Title"])' with ID '$($ListItem.ID)' has Unique Permissions"
}
else
{
Write-Host -f Yellow "List Item '$($ListItem["Title"])' with ID '$($ListItem.ID)' is inhering Permissions from the Parent"
}
}
} While ($Query.ListItemCollectionPosition -ne $null)
}
Catch {
write-host -f Red "Error Checking Unique Permissions!" $_.Exception.Message
}
Or use PnP PowerShell.
#Set Variables
$SiteURL = "https://crescent.sharepoint.com/sites/PMO"
$ListName = "Site Pages"
#Connect to PnP Online
Connect-PnPOnline -Url $SiteURL -UseWebLogin
#Get all list items in batches
$ListItems = Get-PnPListItem -List $ListName -PageSize 2000
#Iterate through each list item
ForEach($ListItem in $ListItems)
{
#Check if the Item has unique permissions
$HasUniquePermissions = Get-PnPProperty -ClientObject $ListItem -Property
"HasUniqueRoleAssignments"
If($HasUniquePermissions)
{
Write-Host -f Green "List Item '$($ListItem["Title"])' with ID '$($ListItem.ID)' has Unique Permissions"
}
Else
{
Write-Host -f Yellow "List Item '$($ListItem["Title"])' with ID '$($ListItem.ID)' is inhering Permissions from its Parent"
}
}
Reference: SharePoint Online: Get All List Items with Unique Permissions using PowerShell
You can also delete all unique permissions in a library using PowerShell. Reference: SharePoint Online: Delete Unique Permissions for All Items in a List using PowerShell

Related

List View Threshold Exceeded Error while Get items of specific folder in Sharepoint online

var camlQuery = new CamlQuery
{
ViewXml = "<View Scope='RecursiveAll'><RowLimit>"+chunkSize+"</RowLimit></View>"
};
context.Load(list, x => x.ItemCount);
context.Load(list, x => x.Title);
var fetchedCount = 0L;
var uniqueRolesCount = 0L;
do
{
camlQuery.FolderServerRelativeUrl = FolderServerRelativeUrl;
var targetItems = list.GetItems(camlQuery);
context.Load(targetItems);
context.Load(targetItems, x => x.Include(y => y.HasUniqueRoleAssignments));
context.ExecuteQuery();
I have use folderServerRelativeUrl in CamlQuery to retrive all list items and getting Threshold Exceeded Error.
According to my research and testing, you can use the following code to get list items in SharePoint Online List without List view threshold exceeded Error:
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Config Parameters
$SiteURL="https://Crescent.SharePoint.com"
$ListName="Projects"
$BatchSize= 2000
Try {
$Cred= Get-Credential
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials
#Get the List
$List = $Ctx.Web.Lists.GetByTitle($ListName)
$Ctx.Load($List)
$Ctx.ExecuteQuery()
#Define Query to get List Items in batch
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = "<View Scope='RecursiveAll'><RowLimit>$BatchSize</RowLimit></View>"
#Get List Items in Batch
Do
{
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$ListItems.count
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
}
While($Query.ListItemCollectionPosition -ne $null)
}
Catch {
write-host -f Red "Error Getting List Items:" $_.Exception.Message
}
More information for reference: SharePoint Online: Get List Items from Large Lists ( >5000 Items) using PowerShell without List View Threshold Exceeded Error
Note: Microsoft is providing this information as a convenience to you. The sites are not controlled by Microsoft. Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. Please make sure that you completely understand the risk before retrieving any suggestions from the above link.

Export version history event log of SharePoint List

I'm looking for an event log or full version history which holds all changes ever made to the items of a SharePoint List.
Version history is enabled. When I right-mouse click on an item and select Version History, it actually shows me all the data I need:
Timestamp of modification
(Column, value) pair of the new modified column and it's new value
Modified by who
Now I "only" need to get this data structured in a table or a file (xlsx, xml, json, csv). And for all the List's items.
I can see that the data is there. But I haven't found a way to export it. So far I've tried customizing an .iqy file, using PowerShell and using Power Automate, without success.
I hope there is some way for me to get the full history. I need it to calculate average run times.
For SharePoint Online:
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Function Export-VersionHistory()
{
param
(
[Parameter(Mandatory=$true)] [string] $SiteURL,
[Parameter(Mandatory=$true)] [string] $ListName,
[Parameter(Mandatory=$true)] [string] $CSVFile
)
Try {
#Delete the Output report file if exists
if (Test-Path $CSVFile) { Remove-Item $CSVFile }
#Get Credentials to connect
$Cred= Get-Credential
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials
#Get the List
$List = $Ctx.Web.Lists.GetByTitle($ListName)
$Ctx.Load($List)
$Ctx.ExecuteQuery()
#Get all items
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
#Array to hold result
$VersionHistoryData = #()
#Iterate throgh each item
Foreach ($Item in $ListItems)
{
write-host "Processing Item:" $item.id -f Yellow
#Get all versions of the list item
$Versions = $Item.versions
$ctx.Load($Versions)
$Ctx.ExecuteQuery()
If($Versions.count -gt 0)
{
#Iterate each version
Foreach($Version in $Versions)
{
#Get the Creator object of the version
$CreatedBy = $Version.createdby
$Ctx.Load($CreatedBy)
$Ctx.ExecuteQuery()
#Send Data to object array
$VersionHistoryData += New-Object PSObject -Property #{
'Item ID' = $Item.ID
'Title' = $Version.FieldValues["Title"]
'Version Label' = $Version.VersionLabel
'Version ID' = ($Version.VersionId/512)
'Created On' = (Get-Date ($Version.Created) -Format "yyyy-MM-dd/HH:mm:ss")
'Created By' = $CreatedBy.Email
}
}
}
}
#Export the data to CSV
$VersionHistoryData | Export-Csv $CSVFile -Append -NoTypeInformation
write-host -f Green "Version History Exported Successfully to:" $CSVFile
}
Catch {
write-host -f Red "Error Exporting version History to CSV!" $_.Exception.Message
}
}
#Set parameter values
$SiteURL="https://tenant.sharepoint.com"
$ListName="list name"
$CSVFile="C:\VersionHistory.csv"
#Call the function to generate version History Report
Export-VersionHistory -SiteURL $SiteURL -ListName $ListName -CSVFile $CSVFile
For SharePoint Server:
# ******* Variables Section ******************
#Define these variables
$WebURL="site collection URL"
$ListName ="list name"
$ReportFile = "C:\VersionHistory.csv"
# *********************************************
#delete the file if exists
If (Test-Path $ReportFile)
{
Remove-Item $ReportFile
}
#Get the Web and List
$Web = Get-SPWeb $WebURL
$List = $web.Lists.TryGetList($ListName)
#Check if list exists
if($List -ne $null)
{
#Get all list items
$ItemsColl = $List.Items
#Write Report Header
Add-Content -Path $ReportFile -Value "Item ID, Version Lable, Created by, Created at, Title"
#Loop through each item
foreach ($item in $ItemsColl)
{
#Iterate each version
ForEach($version in $item.Versions)
{
#Get the version content
$VersionData = "$($item.id), $($version.VersionLabel), $($version.CreatedBy.User.DisplayName), $($version.Created), $($version['Title'])"
#Write to report
Add-Content -Path $ReportFile -Value $VersionData
}
}
}
Write-Host "Version history has been exported successfully!"

do we have CSOM code to retrieve all lists under a site collection?

I am trying hard to get details of all the lists from a SharePoint site collection and export to CSV.
I am trying to run remotely from my machine and it doesn't work. I am not an export CSOM guy so asking for help, please.
I heard from someone that CSOM can run from anywhere and able to get info from SHarePoint 2013 server.
import-module C:\powershell\SharePointPnPPowerShell2013\3.16.1912.0\sharepointpnppowershell2013.psd1 -DisableNameChecking
$username = "testing#domain.com"
$password="Password"
$secureStringPwd = $Password | ConvertTo-SecureString -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $secureStringPwd
$connection=Connect-PnPOnline -Url https://cys.test.domain.com -Credentials $Credentials
$siteurl = "https://cys.test.domain.com/sites/testsite"
function Get-DocInventory([string]$siteUrl) {
$site = New-Object Microsoft.SharePoint.SPSite "https://cys.test.domain.com"
$web = Get-SPWeb "https://cys.test.domain.com/sites/testsite"
foreach ($list in $web.Lists) {
foreach ($item in $list.Items) {
#foreach($version in $item.Versions){
$data = #{
"List Name" = $list.Title
"Created By" = $item["Author"]
"Created Date" = $item["Created"]
"Modified By" = $item["Editor"]
"Modified Date" = $item["Modified"]
"Item Name" = $item.File.Name
"URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)");
}
New-Object PSObject -Property $data | Select "List Name", "Item Name", "Created By", "Created Date", "Modified By", "Modified Date", "URL"
}
#}
$web.Dispose();
}
}
Get-DocInventory | Export-Csv -NoTypeInformation -Path "d:\test\test.csv"
If you are using SharePoint 2013 On-Premise, try to install SharePoint 2013 CSOM firstly:
SharePoint Server 2013 Client Components SDK
Then use this script to get list details in a site collection includes sub sites:
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Variables for Processing
$SiteUrl= "http://sp/sites/devtest"
$username="administrator"
$password="******"
$domain="Contoso"
#Setup Credentials to connect
$Credentials = New-Object System.Net.NetworkCredential($username, $password, $domain)
Try {
#Function to Get all lists from the web
Function Get-SPOList($Web)
{
#Get All Lists from the web
$Lists = $Web.Lists
$Context.Load($Lists)
$Context.ExecuteQuery()
#Get all lists from the web
ForEach($List in $Lists)
{
#Get the List Name
Write-host $List.Title
Write-host $List.Created
}
}
#Function to get all webs from given URL
Function Get-SPOWeb($WebURL)
{
#Set up the context
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebURL)
$Context.Credentials = $Credentials
$Web = $context.Web
$Context.Load($web)
#Get all immediate subsites of the site
$Context.Load($web.Webs)
$Context.executeQuery()
#Call the function to Get Lists of the web
Write-host "Processing Web :"$Web.URL
Get-SPOList $Web
#Iterate through each subsite in the current web
foreach ($Subweb in $web.Webs)
{
#Call the function recursively to process all subsites underneaththe current web
Get-SPOWeb($SubWeb.URL)
}
}
#Call the function to get all sites
Get-SPOWeb $SiteUrl
}
catch {
write-host "Error: $($_.Exception.Message)" -foregroundcolor Red
}

Change multiple files content type programatically using CSOM for SharePoint Online

I am attempting to change all the files in a library from one content type to another. This is in SharePoint Online so I'm using the CSOM. I am new to this so I'm stuck at where to go from what I have below.
I think my biggest issue is getting the values of the content types. That and I'm so used to SP On Premise I'm having trouble grasping this CSOM stuff. Much thanks to anyone that can help point me in the right direction!
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user"
$Pass = "password"
$WebUrl = "SiteURL"
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, (ConvertTo-SecureString $Pass -AsPlainText -Force))
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$List = $Context.Web.Lists.GetByTitle("TestLibrary")
Write-Host "Getting the Content Types." -ForegroundColor Green
$oldCT = $list.ContentTypes("OldCTName")
$newCT = $list.ContentTypes("NewCTName")
$newCTID = $newCT.ID
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(1000);
$Items = $List.GetItems($Query);
$Context.Load($Items);
$Context.ExecuteQuery();
#Check if the values specified for the content types actually exist on the list
if (($oldCT -ne $null) -and ($newCT -ne $null))
{
#Go through each item in the list
#Edit existing list items
foreach($item in $Items)
{
#Check if the item content type currently equals the old content type specified
if ($_.ContentType.Name -eq $oldCT.Name)
{
#Check the check out status of the file
if ($_.File.CheckOutType -eq "None")
{
#Change the content type association for the item
$_.File.CheckOut()
write-host "Resetting content type for file" $_.Name "from" $oldCT.Name "to" $newCT.Name
$_["ContentTypeId"] = $newCTID
$_.Update()
$_.File.CheckIn("Content type changed to " + $newCT.Name, 1)
}
else
{
write-host "File" $_.Name "is checked out to" $_.File.CheckedOutByUser.ToString() "and cannot be modified"
}
}
else
{
write-host "File" $_.Name "is associated with the content type" $_.ContentType.Name "and shall not be modified"
}
}
}
else
{
write-host "One of the content types specified has not been attached to the list"$list.Title
}
$Context.ExecuteQuery();
}

Create Multiple SPGroups in all the subsites if the SPGroups doesn't exist using power Shell script

I need to create 2 SPGroups in the SubSites with Multiple AD Group members added to the group.
For Example,
I have sub sites x,y,z under my Site
I have groups Group A, Group B
Members of Group A are Member1, Member2, Member3
Members of Group B are Member1, Member2, Member3, Member4, Member5
I need to create the groups in the sub sites if they doesn't exist.
Please let me know for any better approach.
I am trying to do that using Power shell.
$SPWeb = $Web.Read()
if ($SPWeb.SiteGroups[$GroupName] -ne $null){
throw "Group $GroupName already exists!"
}
if ($SPWeb.Site.WebApplication.UseClaimsAuthentication){
$op = New-SPClaimsPrincipal $OwnerName -IdentityType WindowsSamAccountName
$mp = New-SPClaimsPrincipal $MemberName -IdentityType WindowsSamAccountName
$owner = $SPWeb | Get-SPUser $op
$member = $SPWeb | Get-SPUser $mp
}
else {
$owner = $SPWeb | Get-SPUser $OwnerName
$member = $SPWeb | Get-SPUser $MemberName
}
$SPWeb.SiteGroups.Add($GroupName, $owner, $member, $Description)
$SPGroup = $SPWeb.SiteGroups[$GroupName]
$SPWeb.RoleAssignments.Add($SPGroup)
$SPWeb.Dispose()
#Create an XML with all the details for the new Groups and menbers for the groups
<?xml version="1.0"?>
<Groups>
<Group name="GroupA" description="Test GroupA" PermissionLevel="Contribute">
<Users>
<User>Domain\Member1</User>
<User>Domain\Member2</User>
<User>Domain\Member3</User>
</Users>
</Group>
<Group name="GroupB" description="Test GroupB" PermissionLevel="Read">
<Users>
<User>Domain\Member1</User>
<User>Domain\Member2</User>
<User>Domain\Member3</User>
<User>Domain\Member4</User>
<User>Domain\Member5</User>
</Users>
</Group>
#Now create a script file with the below script
#Get Site and Web objects
$site = get-spsite https://portal/site/Test/
#Get all the sub sites under the web
foreach($web in $site.allwebs)
{
#Get XML file containing groups and associated users
$groupsXML = [xml] (Get-Content ("C:\Temp\Groups.XML"))
#Walk through each group node defined in the XML file
$groupsXML.Groups.Group | ForEach-Object {
[string]$permissionLevel = $_.PermissionLevel
#Check to see if SharePoint group already exists in the site collection
if ($web.SiteGroups[$_.name] -eq $null)
{
#If the SharePoint group doesn't exist already - create it from the name and description values at the node
$web.SiteGroups.Add($_.name, $web.CurrentUser, $null, $_.description)
$newGroup = $web.SiteGroups[$_.name]
}
#Get SharePoint group from the site collection
$group = $web.SiteGroups[$_.name]
#Add the users defined in the XML to the SharePoint group
$_.Users.User | ForEach-Object {
$group.AddUser($_, "", "", "")
}
$roleAssignment = new-object Microsoft.SharePoint.SPRoleAssignment($group)
$roleDefinition = $web.Site.RootWeb.RoleDefinitions[$permissionLevel]
$roleAssignment.RoleDefinitionBindings.Add($roleDefinition)
$web.RoleAssignments.Add($roleAssignment)
Write-Host "Group Name: "$group" Created at site: " $web.url
}
#Dispose of Web and Site objects
$web.Dispose()
$site.Dispose()
}

Resources