Error getting files. The collection has not been initialized - powershell

I am getting this error:
"Error getting files. The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested."
Code:
#Add references to SharePoint client assemblies
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("WindowsBase")
#Variables
$SiteURL = "****************"
$LibraryName = "Documents"
$FolderName = "Customer Files"
Function Get-FilesFromFolder()
{
Try
{
#Load credentials of the admin account that has access to the library
$Cred = Get-Credential
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName, $Cred.Password)
#Building Context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials
#Get the library
$Library = $Ctx.Web.Lists.GetByTitle($LibraryName)
$Folders = $Library.RootFolder.Folders
$Ctx.Load($Folders)
$Ctx.ExecuteQuery()
#Get the folder by name
$Folder = $Folders | Where {$_.Name -eq $FolderName}
$Ctx.Load($Folder)
$Ctx.ExecuteQuery()
#Iterate through each file
Foreach($File in $Folder.Files)
{
#Write out each file name
Write-Host "Now printing names for files in the folder."
Write-Host "There are "$Folder.ItemCount" files in the folder."
Write-Host -f Green $File.Name
}
}
Catch
{
Write-Host -f Red "Error getting files." $_.Exception.Message
}
}
All other guides I can find show examples of code missing "$Ctx.Load($Variable)", which I have, and I am stuck.
Hoping someone can see what I am missing - Thanks.

Related

How to delete files from Sharepoint with exclusions list using Powershell

I’m trying to delete certain files from a Sharepoint folder, however no matter what I try, I cannot get it to delete. I have an exclusions list, for the names of pictures that should not be deleted. I have attached one of many tries. Anyone know what to do?
The exclusionslist and the loop can write out the names to delete without any problems, and the below code gives no error-codes.
$siteurl = “https://sharepoint.com/sites/Some/Sharepoint/Folder”
$username = “AdminAccount”
$securePassword = ConvertTo-SecureString “MuchSecurePassWord” -AsPlainText -Force
$O365Credential = New-Object System.Management.Automation.PsCredential($username, $securePassword)
$count = 0
$exclusions = import-csv “Downloads\exclusions.txt”
$excounter = $exclusions.Count
write-host “Files to not delete $excounter”
Connect-PnPOnline -Url $siteurl -Credentials $O365Credential
$items = Get-PnPFolderItem -FolderSiteRelativeUrl "/Picture Folder/Test" -ItemType File
$ListItemCount = $items.Count
Write-Host $ListItemCount
$Found = 0
foreach ($item in $items)
{
foreach ($User in $exclusions)
{
#Write-Host $item.Name " " $User.User
if ($item.Name -eq $User.User)
{
# Write-Host $item.Name " " $User.User
$Found = 1
}
}
if($Found -eq 0)
{
$Name = $item.Name
Write-host "Delete: " $item.Name $Found
$item.DeleteObject()
}
$Found=0
}
I'm hoping to delete photos, that are not on the exclusions list.
Instead of:
$item.DeleteObject()
Use:
Remove-PnPFile -ServerRelativeUrl $item.ServerRelativeURL
Docs:
https://pnp.github.io/powershell/cmdlets/Remove-PnPFile.html

PowerShell script for checking links in SharePoint Pages

I'm trying to check whether every page on a given Sharepoint site contains certain URL with the following PowerShell script. It seems that the foreach loop does nothing at all. Whats should be the reason for this? Also I'm not getting any error messages. I successfully changed some of the list's properties but can't process the data.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Mysite URL
$site = 'https://contoso.sharepoint.com/sites/contoso'
$urlToFind = "https://google.com"
#Admin User Principal Name
$admin = 'SampleUsername'
#Get Password as secure String
$Password = "SamplePassword"
$SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
#Get the Client Context and Bind the Site Collection
$context = New-Object Microsoft.SharePoint.Client.ClientContext($site)
#Authenticate
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($admin , $SecurePassword)
$context.Credentials = $credentials
$list = $context.Web.Lists.GetByTitle('Pages')
$context.Load($list)
$query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()
$Items = $list.GetItems($query)
$context.Load($Items)
$context.ExecuteQuery()
$dataValues = #()
$items.GetEnumerator() | % {
$dataValues += $_.FieldValues
}
$dataValues.Count #determine the amount of items
foreach($item in $dataValues)
{
write-host "inside"
write-host ""
write-host "*** PAGE *** "$item.Url
write-host ""
$file = $item.File
#get binary data, and decode into text
$data = $file.OpenBinary()
$encode = New-Object System.Text.ASCIIEncoding
$text = $encode.GetString($data)
if($text -match $urlToFind)
{
write-warning "FOUND BAD URL IN THIS DOCUMENT!"
}
else {
write-host "nothing found"
}
#comment below to parse all pages
#break
}
We are unable to foreach $list.Items to $item.
We need query $Items by
$Items = $list.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
Then
foreach($item in $Items)

PowerShell Change Download Folder Pathway in Network Share

I have this script that downloads files from a report server and puts those files in a local network share. The script does what it needs to, but the download folder looks like this hitsqlp -> Extracts -> output -> web16p...this is the pathway of where the folder needs to live, but it is replicating that pathway into subfolders so now I have to click on every subfolder to get to the files.
I want the folder 'SSRSFolder' to be a subfolder of \epicsqlt\Extracts\Output\HIT\web16p
Code below, I'm not sure where I went wrong:
set-location -path \\epicsqlt\Extracts\Output\HIT\web16p
$downloadFolder = "\\epicsqlt\Extracts\Output\HIT\web16p"
$ssrsServer = "blahblahblah"
$secpasswd = ConvertTo-SecureString "password" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("username", $secpasswd)
$ssrsProxy = New-WebServiceProxy -Uri "$($ssrsServer)" -Credential $mycreds
$ssrsProxy = New-WebServiceProxy -Uri "$($ssrsServer)" -UseDefaultCredential
$ssrsItems = $ssrsProxy.ListChildren("/", $true) | Where-Object {$_.TypeName -eq "DataSource" -or $_.TypeName -eq "Report"}
Foreach($ssrsItem in $ssrsItems)
{
# Determine extension for Reports and DataSources
if ($ssrsItem.TypeName -eq "Report")
{
$extension = ".rdl"
}
else
{
$extension = ".rds"
}
Write-Host "Downloading $($ssrsItem.Path)$($extension)";
$downloadFolderSub = $downloadFolder.Trim('\') + $ssrsItem.Path.Replace($ssrsItem.Name,"").Replace("/","\").Trim()
New-Item -ItemType Directory -Path $downloadFolderSub -Force > $null
$ssrsFile = New-Object System.Xml.XmlDocument
[byte[]] $ssrsDefinition = $null
$ssrsDefinition = $ssrsProxy.GetItemDefinition($ssrsItem.Path)
[System.IO.MemoryStream] $memoryStream = New-Object System.IO.MemoryStream(#(,$ssrsDefinition))
$ssrsFile.Load($memoryStream)
$fullDataSourceFileName = $downloadFolderSub + "\" + $ssrsItem.Name + $extension;
$ssrsFile.Save($fullDataSourceFileName);
}
if i'm reading this right.
you are starting the script with
set-location -path \epicsqlt\Extracts\Output\HIT\web16p
then you are setting the $downloadfolder variable to that path and including $downloadfolder in your $downloadfoldersub creation.
so the result would be
epicsqlt\Extracts\Output\HIT\web16p\somepath\somefolder\
and then you are creating a new-item with that whole path, when you are already working in the \web16p\ folder.

Get List with 5000 items on the Site Collections

Im trying to Get all the of the list in the Site Collections.
The script below just get the List in the specific site collection and this is working properly.
#environment variables
$username = "user.name#xxx.com"
$password = Read-Host -Prompt "Enter your password: " -AsSecureString
$url = "https://xxx.sharepoint.com/sites/xxxxxx"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
#add SharePoint Online DLL - update the location if required
$programFiles = [environment]::getfolderpath("programfiles")
add-type -Path $programFiles'\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll'
# connect/authenticate to SharePoint Online and get ClientContext object..
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($url)
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)
$ctx.Credentials = $credentials
#get all the sub webs
$Web = $ctx.Web
$ctx.Load($web)
$ctx.Load($web.Webs)
$ctx.executeQuery()
Write-Host -ForegroundColor Yellow "There are:" $web.Webs.Count "sub webs in this site collection"
#get all the lists
foreach ($subweb in $web.Webs)
{
$lists = $subweb.Lists
$ctx.Load($lists)
$ctx.ExecuteQuery()
#output the list details
Foreach ($list in $lists)
{
if ($list.ItemCount -gt 5000)
{
Write-Host -ForegroundColor Yellow "The site URL is" $subweb.Url
Write-Host "List title is: " $list.Title". This list has: " $list.ItemCount " items"
}
}
}
When i try to modify it to get lists in all of the site collection. It errored out. Here is the script that i modify.
#environment variables
$username = "user.name#xxxx.com"
$password = Read-Host -Prompt "Enter your password: " -AsSecureString
$url = get-content "C:\Users\user.name\Documents\PowershellScripts\sites.txt"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
#add SharePoint Online DLL - update the location if required
$programFiles = [environment]::getfolderpath("programfiles")
add-type -Path $programFiles'\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll'
# connect/authenticate to SharePoint Online and get ClientContext object..
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($url)
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)
$ctx.Credentials = $credentials
#get all the sub webs
$Web = $ctx.Web
$ctx.Load($web)
$ctx.Load($web.Webs)
$ctx.executeQuery()
foreach($urls in $url)
{
Write-Host -ForegroundColor Yellow "There are:" $web.Webs.Count "sub webs in this site collection"
#get all the lists
foreach ($subweb in $web.Webs)
{
$lists = $subweb.Lists
$ctx.Load($lists)
$ctx.ExecuteQuery()
#output the list details
Foreach ($list in $lists)
{
if ($list.ItemCount -gt 5000)
{
Write-Host -ForegroundColor Yellow "The site URL is" $subweb.Url
Write-Host "List title is: " $list.Title". This list has: " $list.ItemCount " items"
}
}
}
}
This is the error.
You cannot call a method on a null-valued expression. At
C:\Users\joshua.maniquiz\Documents\PowershellScripts\GetAllSubWebsandListswithItemCounts.ps1:22
char:1 + $ctx.executeQuery() + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo :
InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId :
InvokeMethodOnNull There are: 0 sub webs in this site collection There
are: 0 sub webs in this site collection There are: 0 sub webs in this
site collection There are: 0 sub webs in this site collection There
are: 0 sub webs in this site collection
Thank you in advance for your help!
Your mixing of singular/plural with $url and $urls is at best unlucky.
If your credentials match for all sites and the $ctx object hasn't to be unloaded/released this could probaply work.
#environment variables
$username = "user.name#xxx.com"
$password = Read-Host -Prompt "Enter your password: " -AsSecureString
$sites = get-content "C:\Users\user.name\Documents\PowershellScripts\sites.txt"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
#add SharePoint Online DLL - update the location if required
$programFiles = [environment]::getfolderpath("programfiles")
add-type -Path $programFiles'\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll'
ForEach($site in $sites) {
# connect/authenticate to SharePoint Online and get ClientContext object..
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($site)
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)
$ctx.Credentials = $credentials
#get all the sub webs
$Web = $ctx.Web
$ctx.Load($web)
$ctx.Load($web.Webs)
$ctx.executeQuery()
Write-Host -ForegroundColor Yellow "There are:" $web.Webs.Count "sub webs in this site collection"
#get all the lists
ForEach ($subweb in $web.Webs) {
$lists = $subweb.Lists
$ctx.Load($lists)
$ctx.ExecuteQuery()
#output the list details
ForEach ($list in $lists) {
if ($list.ItemCount -gt 5000) {
Write-Host -ForegroundColor Yellow "The site URL is" $subweb.Url
Write-Host "List title is: " $list.Title". This list has: " $list.ItemCount " items"
}
}
}
}
I rewrote your script a bit using the SharePoint PnP PowerShell cmdlets to do the same thing. I think I got implemented what you are trying to do :)
$urls = Get-Content "C:\Users\user.name\Documents\PowershellScripts\sites.txt"
$username = "user.name#xxxx.com"
$encpassword = Read-Host -Prompt "Enter your password: " -AsSecureString
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $encpassword
foreach($url in $urls) {
Connect-PnPOnline -Url $url -Credentials $cred
$rootweb = Get-PnPWeb -Includes Webs
foreach($web in $rootweb.Webs) {
$currentWeb = Get-PnPWeb $web.Id -Includes Lists
foreach($list in $currentWeb.Lists) {
if ($list.ItemCount -gt 5000) {
Write-Host -ForegroundColor Yellow "The site URL is" $currentWeb.Url
Write-Host "List title is: " $list.Title". This list has: " $list.ItemCount " items"
}
}
}
}
Before you can run the above script you need to install the SharePoint PnP cmdlets as well, that you can do by running
Install-Module SharePointPnPPowerShellOnline
if you are running Windows 10. In other cases, see this page for more information.
With the code above I want to illustrate how you can write the same thing shorter using more high level cmdlets.
SharePoint PnP PowerShell cmdlets are cmdlets created by the SharePoint PnP community and are distributed for free to use.

SPO Powershell Set Permissions Error in RoleDefinitionBindingCollection Call

On Sharepoint Online, using Powershell, I am trying to set list item permissions, and am finding dozens of tutorials that use a RoleDefinitionBindingCollection($ctx) call...
When I do this, though, I get the following error:
New-Object : Cannot find an overload for "RoleDefinitionBindingCollection" and
the argument count: "1".At
C:\Users\thebear\Desktop\SEDA\SEDASetIPPermissions.ps1:172 char:31
+ ... entReader = New-Object Microsoft.SharePoint.Client.RoleDefinitionBind ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
I am iterating through Doclib folders, then through the Folder.Files, checking for a value in a custom field, and setting the permissions on the matching items. EDIT: Here is the full code:
# cd 'C:\Users\thebear\Desktop\SEDA'
# .\SEDASetIPPermissions test KLY KLY1
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
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"
If($($args.Count) -ne 3)
{
Write-Host “Usage: .\SEDASetIPPermissions <'prod' or 'test'> <ProgCode i.e. 'LCL' or 'All'> <IPGroup i.e. 'KLY1' or 'All'>"
break
}
$Site = if($args[0] -eq 'prod') {'sedasearch'} elseif ($args[0] -eq 'test') {'sedasearchtest'}
$Lib = $args[1]
$IPGroup = $args[2]
# Get Connected
$Cred = Get-Credential
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $Cred.UserName, $Cred.Password
$Url = "https://MySite.sharepoint.com/sites/$Site"
Connect-SPOnline -Url $Url -Credentials $Credentials
# Get Client Context
$ctx = Get-SPOContext
$ctx.RequestTimeout = 1000000
$ctx.ExecuteQuery()
# Get Web & Lists
$web = $ctx.Web
$ctx.Load($web)
$ctx.Load($web.Lists)
$ctx.Load($web.RoleDefinitions)
$ctx.ExecuteQuery()
$lists = $web.Lists
# Get Site Groups
$groups = $web.SiteGroups
$ctx.Load($groups)
$ctx.ExecuteQuery()
# Get Target Group
$groupFound = $false
$ScriptStart = Get-Date
foreach ($group in $groups)
{
if ($group.Title -eq "SEDA Admins")
{
$AdminGroupID = $group.Id
}
elseif($group.Title -eq $IPGroup + " Security Group")
{
$groupFound = $true
$IPGroupID = $group.Id
Write-Host "`n'$IPGroup Security Group' Found...`n" -ForegroundColor Green
}
}
if (!$groupFound) { Write-Host "`n'$IPGroup Security Group' NOT Found...`n" -ForegroundColor Red; break }
# Get Target List
$list = $lists.GetByTitle($Lib + " Library")
$ctx.Load($list)
$ctx.Load($list.RootFolder)
$ctx.Load($list.Fields)
$ctx.ExecuteQuery()
if($list -ne $null)
{ "`n'{0}' Found...`n" -f $list.Title | Write-Host -ForegroundColor Green }
else
{ "`n'{0}' NOT Found...`n" -f $list.Title | Write-Host -ForegroundColor Red; break }
# Get List Folders
$folders = $list.RootFolder.Folders
$ctx.Load($folders)
$ctx.ExecuteQuery()
$folders = $folders | sort Name
# Set Up Group and Admin Permissions (if not already there)
$RoleDefinitions = $web.RoleDefinitions
$ctx.Load($RoleDefinitions)
$ctx.ExecuteQuery()
$foundIPGroupRole = $false
$foundIPAdminRole = $false
foreach ($role in $RoleDefinitions)
{
if ($role.Name -eq "Read")
{
$IPGroupRole = $role
$foundIPGroupRole = $true
}
elseif ($role.Name -eq "Full Control")
{
$IPAdminRole = $role
$foundIPAdminRole = $true
}
}
# Set the permissions for 'IP Group'
$roleAssignmentReader = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
$roleAssignmentReader.Add($IPGroupRole)
# Set the permissions for 'IP Admin'
$roleAssignmentAdmin = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
$roleAssignmentAdmin.Add($IPAdminRole)
# Set Counters
$FileCount = 0
$FailCount = 0
foreach ($folder in $folders)
{
$FolderFileCount = 0
$ctx.Load($folder)
$ctx.Load($folder.ListItemAllFields)
$ctx.ExecuteQuery()
if ($folder.ItemCount -lt 5000)
{
$files = $folder.Files
$ctx.Load($files)
$ctx.ExecuteQuery()
"`nProcessing Folder {0}..." -f $folder.Name | Write-Host -ForegroundColor Green
}
else
{ "`nFolder {0} Exceeds 5000 Items...`n" -f $folder.Url | Write-Host -ForegroundColor Red; continue }
foreach ($file in $files)
{
$ctx.Load($file)
$ctx.Load($file.ListItemAllFields)
$ctx.ExecuteQuery()
$item = $file.ListItemAllFields
$ctx.Load($item)
$ctx.ExecuteQuery()
$name = $file.Name
$group = $item.get_item('IPGroup')
if($group -eq $IPGroup)
{
"`nProcessing File {0}...`n" -f $name | Write-Host -ForegroundColor Green;
# Break inheritance on the list item and remove existing permissons.
# NOTE: Use $item.ResetRoleInheritance() to Restore Roll Inheritance
$item.BreakRoleInheritance($false, $true)
# Apply the two permission roles to the list item.
$ctx.Load($item.RoleAssignments.Add($IPGroupID, $roleAssignmentReader))
$ctx.Load($item.RoleAssignments.Add($AdminGroupID, $roleAssignmentAdmin))
# Update the list item and execute
$item.Update()
$ctx.ExecuteQuery()
"`nProcessed File {0}...`n" -f $name | Write-Host -ForegroundColor Green;
}
$FolderFileCount += 1
if($FolderFileCount % 1000 -eq 0) { "{0}K" -f ($FolderFileCount/1000).ToString() | Write-Host }
elseif($FolderFileCount % 100 -eq 0) {Write-Host '*'}
else {Write-Host -NoNewline '.'}
}
}
“`n{0} Files Processed, {1} Error(s), Elapsed Time: {2}" -f $FileCount, $FailCount, $((Get-Date) - $ScriptStart) | Write-Host
$ctx appears to be legit... what else could be causing this error (for a day now)?
This error occurs since RoleDefinitionBindingCollection constructor expects ClientRuntimeContext object but the following line:
$ctx = Get-SPOContext
returns object of OfficeDevPnP.Core.PnPClientContext type. Even though it inherits from ClientRuntimeContext object (PnPClientContext -> ClientContext -> ClientRuntimeContext) it could not be used for instantiating of Microsoft.SharePoint.Client.RoleDefinitionBindingCollection object.
Solution
One option would be to replace the lines:
Connect-SPOnline -Url $Url -Credentials $Credentials
#Get Client Context
$ctx = Get-SPOContext
with
$ctx = Get-Context -WebUrl $Url -UserName $Credentials.UserName -Password $Credentials.Password
where
Function Get-Context([String]$WebUrl,[String]$UserName,[System.Security.SecureString]$Password) {
$context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $Password)
return $context
}
which returns Microsoft.SharePoint.Client.ClientContext object.
According to this link below. The Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx) is looking for a url as an argument, not a filename.
https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.roledefinitionbindingcollection.aspx