PowerShell script for checking links in SharePoint Pages - powershell

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)

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

Invalid Characters in Add-PnPFile stream output

I am trying to take a string and write it to a new file (or update an existing file) in SharePoint Online. Using the following code, the file is created, but it is full of invalid characters (? inside a diamond) and the string "test string" does not appear.
$RootPath = '/Shared Documents/General'
$FolderName = 'Customer'
$FileName = 'test.txt'
$fileContent = 'test string'
$Size = 8192;
[System.IO.MemoryMappedFiles.MemoryMappedFile]$MMF = [System.IO.MemoryMappedFiles.MemoryMappedFile]::CreateNew($FileName, $Size);
If ($Null -eq $MMF) {
Return;
}
$Stream = $MMF.CreateViewStream();
$StreamWriter = [System.IO.StreamWriter]::new($Stream);
$StreamWriter.Write($FileContent);
Add-PnPFile -FileName $FileName -Folder "$RootPath/$FolderName" -Stream $Stream
$StreamWriter.Dispose();
$Stream.Dispose();
$MMF.Dispose();
Am I encoding the string incorrectly or what?
Sample script for your reference.
#region Variables
$Username = "user#xxx.onmicrosoft.com"
$Password = "Password"
$siteURL = "https://xxx.sharepoint.com/sites/lee"
#endregion Variables
#region Credentials
[SecureString]$SecurePass = ConvertTo-SecureString $Password -AsPlainText -Force
[System.Management.Automation.PSCredential]$PSCredentials = New-Object System.Management.Automation.PSCredential($Username, $SecurePass)
#endregion Credentials
Connect-PnPOnline -Url $siteURL -Credentials $PSCredentials
$RootPath = '/Shared Documents/General'
$FolderName = 'Customer'
$FileName = 'test.txt'
$fileContent = 'test string'
$Stream = [IO.MemoryStream]::new([Text.Encoding]::UTF8.GetBytes($fileContent))
# $Size = 8192;
# [System.IO.MemoryMappedFiles.MemoryMappedFile]$MMF = [System.IO.MemoryMappedFiles.MemoryMappedFile]::CreateNew($FileName, $Size);
# If ($Null -eq $MMF) {
# Return;
# }
# $Stream = $MMF.CreateViewStream();
# $StreamWriter = [System.IO.StreamWriter]::new($Stream);
# $StreamWriter.Write($FileContent);
Add-PnPFile -FileName $FileName -Folder "$RootPath/$FolderName" -Stream $Stream
# $StreamWriter.Dispose();
# $Stream.Dispose();
# $MMF.Dispose();
Write-Host "----"

How to Update the Modified By and Created By fields using PnP

I'm trying to upload a fileshare from my local machine to SharePoint using Add-PnPFile, i also have csv that has all the properties("Modified By", "Created By") for each file.
I have written this code below to grab the all the properties of the files from a csv document and tested to see if the user existed in the tenant before the using the Add-PnPFile command to upload the file.
Function Upload-Nom{
Param (
[parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[Alias('FullName')]
[string[]]$Path = $PWD
)
Begin {}
Process {
ForEach ($item in $Path) {
#iterate all the file urls in the csv
Import-Csv $item | ForEach-Object {
#capture all the properties you need to update the file properties on sharepoint
$name = $_.Name
$fullName = $_.FullName
$itemtype = $_.'Item Type'
$relativepath = $_.Path -replace '(sites\/honours\/)'
$modifiedbyuser = $_.'Modified By'
$createdbyuser = $_.'Created By'
$modified = $_.Modified
$path = $_.Path -replace '\/','\'
$path = $path -replace '(sites\\honours\\)'
$fullurl ="C:\Users\modonny\Downloads\" +$path+"\"+ $name
#convert dates to SP format
[DateTime]$dateformats = New-Object System.DateTime;
if([DateTime]::TryParse($_.Modified, [ref]$dateformats)){
$cdob = $dateformats;
}
$modifieduser = Get-PnPUser | ? Title -eq $modifiedbyuser
$createduser = Get-PnPUser | ? Title -eq $createdbyuser
#check if user exists in tenancy
if($modifieduser){
$muserid = $modifiedbyuser.Email
}else{
$muserid = "john.doe#test.gov.uk"
}
if($createduser){
$cuserid = $createduser.Email
}else{
$createduser = Get-PnPUser | ? Email -EQ "john.doe#test.gov.uk"
$cuserid = "john.doe#test.gov.uk"
}
$object = #{}
$object.Add("Modified",$cdob)
$object.Add("Editor" ,$muserid)
$object.Add("Author" ,$cuserid)
if($fullurl | Test-Path){
if($itemtype -eq 'Folder'){
write-host "this item is a folder"
}else{
#upload files to sharepoint with the data in the $object variable
Add-PnPFile -Path $fullurl -Folder $relativepath -Values $object
}
}
}
}
}
Upload-Nom -Path "C:\Users\modonny\Documents\testing.csv"
When the code completes running all files are uploaded but the Modified By/Created By property isn't.
Sample script for your reference.
#region Variables
$Username = "user#tenant.onmicrosoft.com"
$Password = "password"
$siteURL = "https://tenant.sharepoint.com/sites/Community"
#endregion Variables
#region Credentials
[SecureString]$SecurePass = ConvertTo-SecureString $Password -AsPlainText -Force
[System.Management.Automation.PSCredential]$PSCredentials = New-Object System.Management.Automation.PSCredential($Username, $SecurePass)
#endregion Credentials
Connect-PnPOnline -Url $siteURL -Credentials $PSCredentials
$user=Get-PnPUser | ? Email -eq "user1#tenant.onmicrosoft.com"
Add-PnPFile -Path "C:\Lee\test.docx" -Folder "MyDoc" -Values #{Editor=""+$user.Id+"";Modified="7/24/2019"}

automate sitecollection administrator assignment in sharepoint online with powershell for backup purposes

I was asked to create a powershell script to automate the assignment for new sitecollection administrator in SharePoint-Online for BackUp purposes NetApp CloudControl.
This is my firsttime ever in PowerShell and now I got stucked and don't know where to look anymore or least don't understand what I'm looking at.
The script is supposed to do the following:
Get Microsoft-tenant and password
Create a new ps-script where the credentials are already filled in
Connect to sharepoint-online and lookup personal space for every user(onedrive for business sites)
cut the log and create a second one if more than 200 lines were written
read the log and make the service-account a sitecollectionadmin
create task to run the created script once per week
At the moment I got it to do this:
Get Microsoft-tenant and password
Save Credentials
Connect to sharepoint-online and lookup personal space for every user(onedrive for business sites)
read the log and make the service-account a sitecollectionadministrator
Can anyone of you please help me out on how to proceed with the next steps?
P.S. Please excuse that I'm posting the script as a whole, I just didn't know what I should cut out.
$TenantName = $null0
$TenantPassword = $null1
if($TenantName -eq $null0){
$TenantName = Read-Host "Enter Office 365 - Tenant Name."
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$TenantName = \$null0$',"`$TenantName = '$TenantName'"}
$NewScript | Out-File $PSCommandPath -Force
}
if($TenantPassword -eq $null1){
$TenantPassword = Read-Host "Enter Password for netapp-service#$($TenantName).onmicrosoft.com."
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$TenantPassword = \$null1$',"`$TenantPassword = '$TenantPassword'"}
$NewScript | Out-File $PSCommandPath -Force
}
$username = "netapp-service#$($TenantName).onmicrosoft.com"
$cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $(convertto-securestring $TenantPassword -asplaintext -force)
Connect-SPOService -Url https://$($TenantName)-admin.sharepoint.com/ -Credential $cred
$AdminURI = "https://$($TenantName)-admin.sharepoint.com"
$AdminAccount = "netapp-service#$($TenantName).onmicrosoft.com"
$AdminPass = $TenantPassword
$eDiscoveryUser = "netapp-service#$($TenantName).onmicrosoft.com"
$MySitePrefix = "https://$($TenantName)-my.sharepoint.com"
$LogFile = '.\$TenantName\$TenantName-MySites.txt'
$MySiteListFile = '.\$TenantName\$TenantName-MySites.txt'
Connect-SPOService -Url $AdminURI -Credential $cred
$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")
$sstr = ConvertTo-SecureString -string $AdminPass -AsPlainText –Force
$AdminPass = ""
$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount, $sstr)
$proxyaddr = "$AdminURI/_vti_bin/UserProfileService.asmx?wsdl"
$UserProfileService= New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
$UserProfileService.Credentials = $creds
$strAuthCookie = $creds.GetAuthenticationCookie($AdminURI)
$uri = New-Object System.Uri($AdminURI)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container
$UserProfileResult = $UserProfileService.GetUserProfileByIndex(-1)
Write-Host "Starting- This could take a while."
Out-File $LogFile -Force
$NumProfiles = $UserProfileService.GetUserProfileCount()
$i = 1
While ($UserProfileResult.NextValue -ne -1)
{
Write-Host "Examining profile $i of $NumProfiles"
$Prop = $UserProfileResult.UserProfile | Where-Object { $_.Name -eq "PersonalSpace" }
$Url= $Prop.Values[0].Value
if ($Url) {
$Url | Out-File $LogFile -Append -Force
}
$UserProfileResult = $UserProfileService.GetUserProfileByIndex($UserProfileResult.NextValue)
$i++
}
Write-Host "Done!"
$reader = [System.IO.File]::OpenText($MySiteListFile)
try {
for(;;) {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$fullsitepath = "$MySitePrefix$line"
Write-Host "Operating on $fullsitepath "
$fullsitepath = $fullsitepath.trimend("/")
Write-Host "Making $eDiscoveryUser a Site Collection Admin"
Set-SPOUser -Site $fullsitepath -LoginName $eDiscoveryUser -IsSiteCollectionAdmin $true
}
}
finally {
$reader.Close()
}
Disconnect-SPOService
Write-Host "Done!"

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.