Share and Enjoy !

Time to surf the SharePoint PowerShell pipeline.

No, this is not a pipeline Kelly Slater would be surfing, but it is about as sweet as a North Shore wave if you are an IT Pro. I recently had to update a template file across a large number of site collections. Luckily, the root web of the sites that I needed to update all had a common Document Library (name) and a standard folder structure.

SharePoint 2010’s PowerShell module makes performing IT Pro tasks like these extremely simple. Let’s just jump in and look at the cool part of the script.

#Actual start of script
Start-Transcript -Path "$pwd\UploadTemplateLog.rtf" -Force -Append;
$rootWebs = Get-SPWebApplication -Identity "https://extranet.acme.com" | `
Get-SPSite -Limit All | Get-SPWeb -Limit All | Where-Object {$_.IsRootWeb} |
%{
Add-SPFile $_ "Documents" @(dir "$pwd\StatusReportTemplate.docx")[0]
}
Stop-Transcript

Since I wanted to make sure I knew which sites got the file, and where any errors may have occurred, I used the Start-Transcript cmdlet to append information to the file. To simplify the script a bit (I’ll leave making this a one-liner to the Kelly Slater’s of the PowerShell world), I create the $rootWebs variable. To me, the next part is truly the magic of the pipeline. First, we make a call to Get-SPWebApplication cmdlet, filtered to the web application we want. Next, each result is passed along in the pipeline to Get-SPSite. By default, we will only get back a limited set (usually a good thing), but in this case we want all sites, so we use the -Limit All switch to get all of the sites. Once we have the sites, we want to filter down to only the RootWeb SPWeb instances. Finally, we use a for-each (the % alias) to loop over the RootWeb instances we filtered our objects to, and we call Add-SPFile for each web to update the document template.

You could change the script to take the Document Library name and file as parameters, but I will leave that up to you. I know nothing of surfing, and would face certain death on the North Shore pipeline, but don’t be afraid of the PowerShell pipeline when performing SharePoint 2010 admin or development tasks. After all, it’s a command line, not the North Shore! (Caution: Consider production environments “the North Shore” and prepare appropriately) Here is the whole script in it’s entirety. Feel free to comment on how to make this script better or just to let me know if this was useful. Have fun riding the waves…

Complete Script:

Add-PSSnapin "Microsoft.SharePoint.Powershell" -ErrorAction SilentlyContinue</code>
<code>#Add file function called by entry point below
function global:Add-SPFile
{
param ([Microsoft.SharePoint.SPWeb]$web= `
$(throw("You must provide the web to which document(s) will be added.")),
$docLibName=$(throw("You must specify the document library name.")),
$file=$(throw("You must specify the file to add."))
)</code>

if ($web -ne $null)
{
Write-Host "`tProcesing Web - " $web
if ($web.Lists[$docLibName] -ne $null)
{ $folderFound = $false
foreach ($folder in $web.Lists[$docLibName].Folders)
{
if ($folder.Title -eq "Status Reports")
{
Write-Host "`t`t- Found Status Reports Subfolder."
$folderFound = $true
$spFolder = $web.GetFolder("$docLibName/Status Reports" );</code>

<code>Write-Host "`t`t- Loading file byte[]..."
$stream=[IO.File]::OpenRead($file)
Write-Host "`t`t- Read " $stream.Length.ToString() " bytes from file."</code>

#set property bag values in order to apply some
#"hidden" meta-data to the files, specifically the "AddedBy" property
[email protected]{"vti_title"="";"ContentType"="Document"; '
"AddedBy"="PowerShell Add-SPFile CmdLet"}
#update the vti_title in the hash
#Enables setting the SPFile.Item.Title property without calling Item.Update()
$propertybag.vti_title = $file.Name

Write-Host "`t`t- Attempting to add " $file.Name
#add with stream - using a streams performs better than the above byte[] copy
[Microsoft.SharePoint.SPFile]$newFile = '
$spFolder.Files.Add($file.Name,$stream,$propertybag, $true)
Write-Host "`t`t- Successfully added file to " $web
Write-Host "`t`t- Closing file stream."
$stream.Close()
Write-Host "`t`t- Closed stream."
Write-Host "`t`t- Completed processing $web"
}
}
if (-not $folderFound)
{
Write-Host "`t`t- No Status Reports Subfolder found."
}
}
else
{
Write-Host "`t`t- Document library does not exist. Skipping $web"
}
}else
{
Write-Host "`t`t- Web was null"
}
}

<code>#Actual start of script
Start-Transcript -Path "$pwd\UploadTemplateLog.rtf" -Force -Append;
$rootWebs = Get-SPWebApplication -Identity "https://extranet.acme.com" | `
Get-SPSite -Limit All | Get-SPWeb -Limit All | Where-Object {$_.IsRootWeb} |
%{
Add-SPFile $_ "Documents" @(dir "$pwd\StatusReportTemplate.docx")[0]
}
Stop-Transcript

Share and Enjoy !

Related Content: