CSOM

Powershell: Publishing all files in a SharePoint Online library programmatically

One of our clients build up a library of 500+ documents. After these were modified (added meta data and the content went through several rounds of corrections), we were asked to mass publish all files so the site could go live. Which leaves us with 2 options; 1. manually check-in, publish, approve all files. 2. add some CSOM & PowerShell together in a file and do it programmatically. Off course, I, Mark Overdijk, chose to persue the second option. I asked Massimo Prota to assist in getting a script ready. The first version of the script turned out rather usefull, so I added some extra features and more out-put to & interaction with the user. This latest version is generic enough so it can be re-used.

Features

- No limitation on # of files for a list/library - Added code to filter which files should be published - User will be promoted for password and confirmation - Feedback to user on screen - If a file is checked out, the script will check in before proceeding - If Content Approval is enabled for the list/library, the script will approve the file - Screen out-put will be saved to a txt file which includes the current date/time in the filename

Prerequisites Powershell

Step 1. Gather parameters

For the script to run properly, you'll need the following parameters;

.SiteUrl: This is the full URL to the (sub)site where the list is stored for which you want to publish/approve the files

.ListName: This is the Title of the list for which you want to publish/approve the files

.UserName: This is the UserName that has enough permissions to publish/approve the files

Step 2. Run PowerShell script

Start Windows Powershell as administrator.

Be sure to first set the ExecutionPolicy correctly so you are able to run scripts. Set-ExecutionPolicy Unrestricted [ENTER] Input "A" for all After the ExecutionPolicy is set, we can run the script file.

[code language="powershell"] #################################### # Script: PublishFilesSPO.ps1 # # Version: 2.0 # # Rapid Circle (c) 2016 # # by Mark Overdijk & Massimo Prota # ####################################

# Clear the screen Clear-Host

# Add Wave16 references to SharePoint client assemblies - required for CSOM 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"

# Parameters # Specify the subsite URL where the list/library resides $SiteUrl = "https://DOMAIN.sharepoint.com/SUBSITE" # Title of the List/Library $ListName = "TITLE" # Username with sufficient publish/approve permissions $UserName = "USER@DOMAIN.com" # User will be prompted for password

# Set Transcript file name $Now = Get-date -UFormat %Y%m%d_%H%M%S $File = "PublishFilesSPO_$Now.txt" #Start Transcript Start-Transcript -path $File | out-null

# Display the data to the user Write-Host "/// Values entered for use in script ///" -foregroundcolor cyan Write-Host "Site: " -foregroundcolor white -nonewline; Write-Host $SiteUrl -foregroundcolor green Write-Host "List name: " -foregroundcolor white -nonewline; Write-Host $ListName -foregroundcolor green Write-Host "Useraccount: " -foregroundcolor white -nonewline; Write-Host $UserName -foregroundcolor green # Prompt User for Password $SecurePassword = Read-Host -Prompt "Password" -AsSecureString Write-Host "All files in " -foregroundcolor white -nonewline; Write-Host $ListName -foregroundcolor green -nonewline; Write-Host " on site " -foregroundcolor white -nonewline; Write-Host $SiteUrl -foregroundcolor green -nonewline; Write-Host " will be published by UserName " -foregroundcolor white -nonewline; Write-Host $UserName -foregroundcolor green Write-Host " "

# Prompt to confirm Write-Host "Are these values correct? (Y/N) " -foregroundcolor yellow -nonewline; $confirmation = Read-Host

# Run script when user confirms if ($confirmation -eq 'y') {

# Bind to site collection $Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl) $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword) $Context.Credentials = $credentials

# Bind to list $list = $Context.Web.Lists.GetByTitle($ListName) # Query for All Items $query = New-Object Microsoft.SharePoint.Client.CamlQuery $query.ViewXml = " " $collListItem = $list.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()) $Context.Load($List) $Context.Load($collListItem) $Context.ExecuteQuery()

# Go through process for all items foreach ($ListItem in $collListItem){ # Adding spacer Write-Host " " Write-Host "/////////////////////////////////////////////////////////////" Write-Host " " # Write the Item ID, the FileName and the Modified date for each items which is will be published Write-Host "Working on file: " -foregroundcolor yellow -nonewline; Write-Host $ListItem.Id, $ListItem["FileLeafRef"], $ListItem["Modified"]

# Un-comment below "if" when you want to add a filter which files will be published # Fill out the details which files should be skipped. Example will skip all files which where modifed last < 31-jan-2015 # # if ( # $ListItem["Modified"] -lt "01/31/2015 00:00:00 AM"){ # Write-Host "This item was last modified before January 31st 2015" -foregroundcolor red # Write-Host "Skip file" -foregroundcolor red # continue # }

# Check if file is checked out by checking if the "CheckedOut By" column does not equal empty if ($ListItem["CheckoutUser"] -ne $null){ # Item is not checked out, Check in process is applied Write-Host "File: " $ListItem["FileLeafRef"] "is checked out." -ForegroundColor Cyan $listItem.File.CheckIn("Auto check-in by PowerShell script", [Microsoft.SharePoint.Client.CheckinType]::MajorCheckIn) Write-Host "- File Checked in" -ForegroundColor Green } # Publishing the file Write-Host "Publishing file:" $ListItem["FileLeafRef"] -ForegroundColor Cyan $listItem.File.Publish("Auto publish by PowerShell script") Write-Host "- File Published" -ForegroundColor Green

# Check if the file is approved by checking if the "Approval status" column does not equal "0" (= Approved) if ($List.EnableModeration -eq $true){ # if Content Approval is enabled, the file will be approved if ($ListItem["_ModerationStatus"] -ne '0'){ # File is not approved, approval process is applied Write-Host "File:" $ListItem["FileLeafRef"] "needs approval" -ForegroundColor Cyan $listItem.File.Approve("Auto approval by PowerShell script") Write-Host "- File Approved" -ForegroundColor Green } else { Write-Host "- File has already been Approved" -ForegroundColor Green } } $Context.Load($listItem) $Context.ExecuteQuery() } # Adding footer Write-Host " " Write-Host "/////////////////////////////////////////////////////////////" Write-Host " " Write-Host "Script is done" -ForegroundColor Green Write-Host "Files have been published/approved" -ForegroundColor Green Write-Host "Thank you for using PublishFilesSPO.ps1 by Rapid Circle" -foregroundcolor cyan Write-Host " " } # Stop script when user doesn't confirm else { Write-Host " " Write-Host "Script cancelled by user" -foregroundcolor red Write-Host " " } Stop-Transcript | out-null ############################## # Rapid Circle # # http://08b.4d7.myftpupload.com # ############################## [/code]

PowerShell: Terminate a workflow for all items in a list on SharePoint Online

This is a follow up on our previous post "PowerShell: Start a workflow for all items in a list on SharePoint Online". As it's great that now there's a script available to start a workflow for all items, it would also be great to have the ability to stop all workflows if necessary. So I, Mark Overdijk, got to work again with Massimo Prota to get this script in place. The script is very similar to the StartWorkflow Powershell script, but the difference is that we don't retrieve the workflow through WorkflowAssociations but we have to use WorkflowInstances.

Prerequisites Powershell

Step 1. Gather parameters

For the script to run properly, you'll need the following parameters;

.SiteUrl: This is the full URL to the (sub)site where the list is stored for which you want to run the workflow

.ListName: This is the Title of the list for which you want to run the workflow

.UserName: This is the UserName that has enough permissions to run the workflow

Step 2. run PowerShell script

Start Windows Powershell as administrator.

Be sure to first set the ExecutionPolicy correctly so you are able to run scripts. Set-ExecutionPolicy Unrestricted [ENTER] Input "A" for all After the ExecutionPolicy is set, we can run the script file.

Copy/Paste the code below in a txt file and save as an *.ps1 file (in this example "StopWorkflow.ps1"). Fill out the parameters with the gathered information and run the script.

PowerShell stop workflow
PowerShell stop workflow

[code language="powershell"] # Add Wave16 references to SharePoint client assemblies and authenticate to Office 365 site - required for CSOM 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" Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll"

# Specify tenant admin and site URL $SiteUrl = "https://[TENANT].sharepoint.com/" $ListName = "[TITLE OF THE LIST]" $UserName = "[USERNAME]" $SecurePassword = Read-Host -Prompt "Enter password" -AsSecureString

# Bind to site collection $ClientContext = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl) $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword) $ClientContext.Credentials = $credentials $ClientContext.ExecuteQuery()

# Get List $List = $ClientContext.Web.Lists.GetByTitle($ListName)

$ClientContext.Load($List) $ClientContext.ExecuteQuery()

$ListItems = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()) $ClientContext.Load($ListItems) $ClientContext.ExecuteQuery()

# Create WorkflowServicesManager instance $WorkflowServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($ClientContext, $ClientContext.Web)

# Connect to WorkflowSubscriptionService $WorkflowSubscriptionService = $WorkflowServicesManager.GetWorkflowSubscriptionService()

# Connect WorkflowInstanceService instance $WorkflowInstanceService = $WorkflowServicesManager.GetWorkflowInstanceService()

$ClientContext.Load($WorkflowServicesManager) $ClientContext.Load($WorkflowSubscriptionService) $ClientContext.Load($WorkflowInstanceService) $ClientContext.ExecuteQuery()

# Get WorkflowAssociations with List $WorkflowAssociations = $WorkflowSubscriptionService.EnumerateSubscriptionsByList($List.Id) $ClientContext.Load($WorkflowAssociations) $ClientContext.ExecuteQuery()

# Prepare Terminate Workflow Payload $EmptyObject = New-Object System.Object $Dict = New-Object 'System.Collections.Generic.Dictionary[System.String,System.Object]'

# Loop Terminate Workflow For ($j=0; $j -lt $ListItems.Count; $j++){

$msg = [string]::Format("Killing workflows {0} on ListItemID {1}", $WorkflowAssociations[0].Name, $ListItems[$j].Id) Write-Host $msg

$itemWfInstances = $WorkflowInstanceService.EnumerateInstancesForListItem($List.Id, $ListItems[$j].Id) $ClientContext.Load($itemWfInstances) $ClientContext.ExecuteQuery() for ($k=0;$k -lt $itemWfInstances.Count;$k++) { try { $WorkflowInstanceService.TerminateWorkflow($itemWfInstances[$k]) $msg = "Worfklow terminated on " + $ListItems[$j].Id $ClientContext.ExecuteQuery() } catch { $msg = "Error terminating workflow on " + $ListItems[$j].Id + " Details: $_" }

Write-Host $msg } } [/code]

PowerShell: Start a workflow for all items in a list on SharePoint Online

For one of our Office 365 clients (mix of E1 and E3 licences) we created a workflow which will check the status of an item and, depending on this status, sends out e-mails and updates other columns. As the list was already in use, it was necessary to start the workflow for all present items. But to start the workflow manually for all 477  items, was not preferable. So I, Mark Overdijk, asked Massimo Prota to help me on the quest to see if it would be possible to to do it via PowerShell. As there are no PowerShell commands available for SharePoint Online to access the workflow instance, we searched for CSOM solutions. We came across this script on github. Thanks to Azam-A we had a base script to work from. What we changed/added were the following;

  • Referenced the new wave16 components as Office 365 is already on wave16.
  • Added feedback in the script when it runs. It'll show for each item the item ID for which the script is starting the workflow.
  • For obvious security reasons we're not storing the user's Admin password as plain text, but prompt for the password.

Prerequisites Powershell

Step 1. Gather required parameters

For the script to run properly, you'll need the following parameters;

.SiteUrl: This is the full URL to the (sub)site where the list is stored for which you want to run the workflow

.ListName: This is the Title of the list for which you want to run the workflow

.UserName: This is the UserName that has enough permissions to run the workflow

Step 2. Run PowerShell script

Start Windows Powershell as administrator.

Be sure to first set the ExecutionPolicy correctly so you are able to run scripts. Set-ExecutionPolicy Unrestricted [ENTER] Input "A" for all After the ExecutionPolicy is set, we can run the script file.

Copy/Paste the code below in a txt file and save as an *.ps1 file (in this example "StartWorkflow.ps1"). Fill out the parameters with the gathered information and run the script.

StartWorkflow1 screenshot in  Powershell
StartWorkflow1 screenshot in Powershell

[code language="powershell"] # Add Wave16 references to SharePoint client assemblies and authenticate to Office 365 site - required for CSOM Add-Type -Path (Resolve-Path "$env:CommonProgramFiles\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll") Add-Type -Path (Resolve-Path "$env:CommonProgramFiles\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll") Add-Type -Path (Resolve-Path "$env:CommonProgramFiles\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll")

# Specify tenant admin and site URL $SiteUrl = "https://[TENANT].sharepoint.com/" $ListName = "[TITLE OF THE LIST]" $UserName = "[USERNAME]" $SecurePassword = Read-Host -Prompt "Enter password" -AsSecureString

# Connect to site $ClientContext = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl) $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword) $ClientContext.Credentials = $credentials $ClientContext.ExecuteQuery()

# Get List and List Items $List = $ClientContext.Web.Lists.GetByTitle($ListName) $ListItems = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()) $ClientContext.Load($List) $ClientContext.Load($ListItems) $ClientContext.ExecuteQuery()

# Retrieve WorkflowService related objects $WorkflowServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($ClientContext, $ClientContext.Web) $WorkflowSubscriptionService = $WorkflowServicesManager.GetWorkflowSubscriptionService() $WorkflowInstanceService = $WorkflowServicesManager.GetWorkflowInstanceService() $ClientContext.Load($WorkflowServicesManager) $ClientContext.Load($WorkflowSubscriptionService) $ClientContext.Load($WorkflowInstanceService) $ClientContext.ExecuteQuery() # Get WorkflowAssociations with List $WorkflowAssociations = $WorkflowSubscriptionService.EnumerateSubscriptionsByList($List.Id) $ClientContext.Load($WorkflowAssociations) $ClientContext.ExecuteQuery()

# Prepare Start Workflow Payload $Dict = New-Object 'System.Collections.Generic.Dictionary[System.String,System.Object]'

# Loop List Items to Start Workflow For ($j=0; $j -lt $ListItems.Count; $j++){ $msg = [string]::Format("Starting workflow {0}, on ListItemId {1}", $WorkflowAssociations[0].Name, $ListItems[$j].Id) Write-Host $msg #Start Workflow on List Item $Action = $WorkflowInstanceService.StartWorkflowOnListItem($WorkflowAssociations[0], $ListItems[$j].Id, $Dict) $ClientContext.ExecuteQuery() }[/code]

If, for some reason, you want to stop/terminate all workflows, check this blogpost: PowerShell: Terminate a workflow for all items in a list on SharePoint Online