Introduction
In this post we will see a generic function to add a Web Part from local drive to a page in a particular Web Part zone using PowerShell script
The script include
- Reading Web Part details from config file
- Check out the page
- Adds Web Part to the page
- Check in the page
- Approve the page (if EnableModeration is true)
Add Web Part Config file
Create a config xml file and name it as “WebPartToPageConfig.xml”. Add the following content into it
<?xml version="1.0"?> <Config> <SiteSettings url="http://www.adicodes.com/MySite"></SiteSettings> <WebParts> <WebPart> <Title>NewsTagsWebpart</Title> <LocalSrc>D:\Adi\powershell\AddWebpartToPage\NewsTagsWebpart.webpart</LocalSrc> <Replace>true</Replace> <ZoneName>Main Zone</ZoneName> <ZoneIndex>1</ZoneIndex> <DestinationPagePath>http://www.adicodes.com/MySite/Pages/default.aspx</DestinationPagePath> </WebPart> </WebParts> </Config>
url : Url of the site
Title : Title of the Web Part
LocalSrc : Local path of the Web Part
Replace : true/false
true-deletes the existing Web Part in the page and adds the new one
false-adds the Web Part without deleting.
(if false is used we will get multiple Web Part if we run the script more than once)
ZoneName : The Zone name where the Web Part should be added
ZoneIndex : 0/1/2.. The order of the Web Part in the Zone
DestinationPagePath : The path of the page where the Web Part should be added
We are now ready to use the script
Add Web Part script
Create a powershell script file and name it as “WebPartToPage.ps”. Add the following script into it
Remove-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue Add-PSSnapin Microsoft.SharePoint.Powershell function AddWebPartToPage([string]$siteUrl,[string]$pageRelativeUrl,[string]$localWebpartPath,[string]$ZoneName,[int]$ZoneIndex) { try { #this reference is required here $clientContext= [Microsoft.SharePoint.Client.ClientContext,Microsoft.SharePoint.Client, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c] $context=New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl) write-host "Reading file " $pageRelativeUrl $oFile = $context.Web.GetFileByServerRelativeUrl($pageRelativeUrl); $limitedWebPartManager = $oFile.GetLimitedWebPartManager([Microsoft.Sharepoint.Client.WebParts.PersonalizationScope]::Shared); write-host "getting xml reader from file" $xtr = New-Object System.Xml.XmlTextReader($localWebpartPath) [void] [Reflection.Assembly]::LoadWithPartialName("System.Text") $sb = new-object System.Text.StringBuilder while ($xtr.Read()) { $tmpObj = $sb.AppendLine($xtr.ReadOuterXml()); } $newXml = $sb.ToString() if ($xtr -ne $null) { $xtr.Close() } #Add Web Part to catalogs folder write-host "Adding Webpart....." $oWebPartDefinition = $limitedWebPartManager.ImportWebPart($newXml); $limitedWebPartManager.AddWebPart($oWebPartDefinition.WebPart, $ZoneName, $ZoneIndex); $context.ExecuteQuery(); write-host "Adding Web Part Done" } catch { write-host "Error while 'AddWebPartToPage'" $_.exception } } #Checks out the page function CheckOutPage ($SPFile) { $x=$SPFile.ServerRelativeUrl if($SPFile.Level -eq [Microsoft.SharePoint.SPFileLevel]::Checkout) { write-host " File already checked-out...doing undo checkout" $SPFile.UndoCheckOut() } if ($SPFile.Level -ne [Microsoft.SharePoint.SPFileLevel]::Checkout) { write-host " Checking-out page" $x $SPFile.CheckOut() } else { write-host " No Check-out needed page" $x } } #check in the page function CheckInPage ($SPFile) { $x=$SPFile.ServerRelativeUrl write-host "file level" $SPFile.Level -ForegroundColor Green if ($SPFile.Level -eq [Microsoft.SharePoint.SPFileLevel]::Checkout) { write-host " Checking-in page" $x $SPFile.CheckIn("Checkin", [Microsoft.SharePoint.SPCheckInType]::MajorCheckin) } else { write-host " No Check-in needed page" $x } } #Approve the page function ApprovePage ($PageListItem) { if($PageListItem.ListItems.List.EnableModeration) { #Check to ensure page requires approval, and if so, approve it try{ write-host " Approving page" $PageListItem.File.ServerRelativeUrl $PageListItem.File.Publish("") $PageListItem.File.Approve("Page approved automatically by PowerShell script") } catch { write-host $_ } } else { write-host " No approval on list" } } #Add Web Part to the page function AddWebPart($wpTitle, $wpDestinationPageFullUrl, $wpLocalPath, $wpZoneName, $wpZoneIndex, $IsReplace) { [Microsoft.SharePoint.SPFile] $spFile = $Web.GetFile($wpDestinationPageFullUrl) if($spFile.Exists) { try { if ($SPFile.CheckOutStatus -ne "None") { write-host "doing undocheckout" $SPFile.UndoCheckOut() } else { write-host "checkout the page" -ForeGround Green CheckOutPage -SPFile $spFile } #### [Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager]$wpManager = $Web.GetLimitedWebPartManager($FullUrl,[System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared) if ($null -eq [System.Web.HttpContext]::Current) { $sw = New-Object System.IO.StringWriter $resp = New-Object System.Web.HttpResponse $sw $req = New-Object System.Web.HttpRequest "", $Web.Url, "" $htc = New-Object System.Web.HttpContext $req, $resp #explicitly cast $web to spweb object else sharepoint will #see it as a PSObject, and AddWebpart wil fail $htc.Items["HttpHandlerSPWeb"] = $web -as [Microsoft.SharePoint.SPweb] [System.Web.HttpContext]::Current = $htc if ($sw -ne $null) { $sw.Dispose() } } $Web.AllowUnsafeUpdates = $true if ($IsReplace -eq $true) { $wpToDelete = $wpManager.WebParts | % { $_ } foreach($WebPart in $wpToDelete) { if($WebPart -ne $null) { if($WebPart.Title -eq $WebPartTitle) { write-host "deleting existing Web Part" $WebPart.Title -ForegroundColor Green $wpManager.DeleteWebPart($WebPart) } } } } #### $pageRelativeUrl = $SPFile.ServerRelativeUrl AddWebPartToPage $siteUrl $pageRelativeUrl $wpLocalPath $wpZoneName $wpZoneIndex } catch { write-host $_.exception } finally { #check in CheckInPage -SPFile $spFile # Approve & Publish ApprovePage -PageListItem $spFile.Item if($wpManager -ne $null) { $wpManager.Dispose() } if($Web -ne $null) { $Web.AllowUnsafeUpdates = $false $Web.Dispose() } } } } ## Main Programm ## try { $runningDir = resolve-Path .\ $configXmlPath = join-path -path $runningDir -childpath "WebPartToPageConfig.xml" [xml]$SiteConfig = get-content $configXmlPath $siteUrl = $SiteConfig.Config.SiteSettings.Url $Web = Get-SPWeb -identity $siteUrl foreach($WebPart in $SiteConfig.Config.WebParts.WebPart) { #if attributes are present to the node, use innerText as $WebPart.Title will not return value #$wpTitle = $WebPart.Title.InnerText $wpTitle = $WebPart.Title $FullUrl = $WebPart.DestinationPagePath $LocalWebPartPath = $WebPart.LocalSrc $ZoneName = $WebPart.ZoneName $ZoneIndex = $WebPart.ZoneIndex $Replace = $WebPart.Replace AddWebPart $wpTitle $FullUrl $LocalWebPartPath $ZoneName $ZoneIndex $Replace } } catch { write-host $error[0] } finally { if($Web -ne $null) { $Web.Dispose() } } Pop-Location
The script will read the settings from the config file ‘WebPartToPageConfig.xml’ and uploads the Web Part to the page.
You can check how to use config file in PowerShell
If we have more than 1 Web Part, just add another ‘WebPart’ node in ‘WebParts’ with values.
Note: If the Web Part does not has title, the script will add duplicate Web Part to the zone though you set ‘Replace’ to ‘true’.
Its always good way to maintain the Title. The visibility can be managed from chrome type of the Web Part
Also I strongly prefer using write-log to log any error or status instead of just using write-host.
Check how to use log file in PowerShell
Conclusion
Hope this generic function will be helpful to add or replace Web Parts in any page. Now, we can just concentrate on maintaining the config file
and our work is so simple. If you are stuck up at any point let me know. Happy Coding Image may be NSFW.
Clik here to view.