In this 3rd and final post about deployment with PowerShell I am going to provision newly created sites with lists, views and web part pages. At the end of this post I share my thoughts about when to use this kind of PowerShell deployment.
Lists
In the part-2 post I ended with creating sites after deploying the solution. Next stop is creating lists. In this example I also use a function, so I can reuse the code when creating several lists. Let’s assume there is one single site ($currentWeb) in the intranet that needs to have some custom lists.
function Create-CustomList { param ([string]$listName, [string]$contentTypeName) $listCollection = $currentWeb.Lists $newListId = $listCollection.Add($listName, $listName, SPListTemplateType.GenericList) $customList = $listCollection.TryGetList( $listName ) if( $customList ) { $customList.ContentTypesEnabled = $true $customList.Update() #Add content type to the list $ctToAdd = $site.RootWeb.ContentTypes[$contentTypeName] $customList.ContentTypes.Add($ctToAdd) #Delete the Item content type from the list $ctToRemove = $customList.ContentTypes["Item"] $customList.ContentTypes.Delete($ctToRemove.Id) $customList.Update() } } Create-CustomList "List1" "ContentType1" Create-CustomList "List2" "ContentType1" Create-CustomList "List3" "ContentType2"
To create a new list, you’ll need the Add method of the list collection of the current web. The Add method takes 3 arguments: title, description and a list template (type). For the last one, I used the SPListTemplateType.GenericList constant for creating a custom list. Then I get a reference to the list instance, because I want to add the content type (2nd argument of the function) to that list. I also remove the default Item contenttype because I want to have my content type to be the only one for the list. (Remember, you cannot remove a content type if it is the only one for that list!)
Maybe you think: Why would I create a list using PowerShell like this, if I already have a Visual Studio solution? Hold that thought. I’ll try to explain in my final word.
Views
Let’s add some custom views to a list. Again, I use a function.
function Create-CustomView { param ( [string]$listName, [string]$viewName, $viewFields, [string]$viewQuery, [bool]$isHidden=$false ) [Microsoft.SharePoint.SPList]$currentList = $currentWeb.Lists.TryGetList( $listName ) if( $currentList ) { $newView = $currentList.Views.Add( $viewName, $viewFields, $viewQuery, 100, $true, $false ) $newView.Hidden = $isHidden $newView.Update() } } [System.Collections.Specialized.StringCollection]$fields = New-Object System.Collections.Specialized.StringCollection $fields.Add("FirstName") $fields.Add("LastName") $fields.Add("MobileNumber") $query = "" Create-CustomView "RegisteredUsers" "Calling List" $fields $query $true $fields.Clear() $fields.Add("FirstName") $fields.Add("LastName") $fields.Add("Email") $fields.Add("Twitter") $fields.Add("Facebook") $query = " " Create-CustomView "RegisteredUsers" "Social Accounts" $fields $query
For starters, the function Create-CustomView uses an argument with a default value: $isHidden=$false. In my second call to create a view I omit this argument so it will use the default value. Then I create a StringCollection $fields that will contain all the internal field names to be used by the view and a $query variable for the CAML query. Throw in a list name and a name for the view to be created and we can call the Create-CustomView function.
If you have that thought again… you know the drill.
Provisioning Pages
Last piece of PowerShell action. We just have created some lists and views, but maybe you would also like to have a page with one of more webparts that shows that list. In my next example I have a publishing web. I create new pages in the Pages library based on a page layout that contains webpartzones.
[Microsoft.SharePoint.Publishing.PublishingWeb]$spPubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($currentWeb) function Create-PublishingPage { param ( [string]$pageName, [string]$pageTitle, [string]$pageDescription="", $pageLayout, [string]$listID, [string]$viewID) [Microsoft.SharePoint.Publishing.PublishingPage] $newPage = $spPubWeb.GetPublishingPages().Add($pageName, $pageLayout) $newPage.Title = $pageTitle $newPage.Description = $pageDescription $newPage.Update() $pageFile = $newPage.ListItem.File $wpmanager = $pageFile.GetLimitedWebPartManager([System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared) $listViewWebPart = New-Object "Microsoft.SharePoint.WebPartPages.ListViewWebPart" $listViewWebPart.Title = $pageTitle $listViewWebPart.WebId = $currentWeb.ID $listViewWebPart.ListName = $listID $listViewWebPart.ViewGuid = $viewID $listViewWebPart.ZoneID = "Header" $wpmanager.AddWebPart($listViewWebPart, "Middle", 0) $pageFile.CheckIn("Checked In - Initial Version"); $pageFile.Publish("Published - Initial Version"); } [Microsoft.SharePoint.Publishing.PageLayout] $layout = $spPubWeb.GetAvailablePageLayouts() | where { $_.Name -eq "MyCustomPageLayout.aspx" } [Microsoft.SharePoint.SPList]$pagesLib = $spPubWeb.PagesList Create-PublishingPage "RegisteredUsersSocialAccounts.aspx" "Social Accounts" "Some Description" $layout $pagesLib.ID $pagesLib.Views["Social Accounts"].ID.ToString("B")
Adding a page is like adding a list and a view: again calling the Add method of the collection does the trick. For adding a webpart I need the WebPartManager (line 12). I used the ListViewWebPart to show my list (line 16) and it’s view (line 17). Since it is a publishing web, we need to check in and publish the page.
How about connected webparts? It looks like the previous example, but in order to get connected I now use the XsltListViewWebPart. Then a Row-To-Parameter transformer object is needed to apply the provider and consumer fields and finally the connection points of both webparts. The SPConnectWebParts method of the WebPartManager can be used to create the connection.
function Create-ConnectedWebPartsPage { param ( [string]$pageName, [string]$pageTitle, [string]$pageDescription="", $pageLayout, [string]$providerField, [string]$consumerField) [Microsoft.SharePoint.Publishing.PublishingPage] $newPage = $spPubWeb.GetPublishingPages().Add($pageName, $pageLayout) $newPage.Title = $pageTitle $newPage.Description = $pageDescription $newPage.Update() $pageFile = $newPage.ListItem.File $wpmanager = $pageFile.GetLimitedWebPartManager([System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared) $masterWebPart = New-Object "Microsoft.SharePoint.WebPartPages.XsltListViewWebPart" $masterWebPart.Title = "Master" $masterWebPart.WebId = $currentWeb.ID $masterWebPart.ListName = $pagesLib.ID $masterWebPart.ViewGuid = $pagesLib.Views["My Master View"].ID.ToString("B") $masterWebPart.ZoneID = "Header" $wpmanager.AddWebPart($masterWebPart, "Middle", 0) $detailWebPart = New-Object "Microsoft.SharePoint.WebPartPages.XsltListViewWebPart" $detailWebPart .Title = "Detail" $detailWebPart .WebId = $currentWeb.ID $detailWebPart .ListName = $customList.ID $detailWebPart .ViewGuid = $customList.Views["My Detail View"].ID.ToString("B") $detailWebPart .ZoneID = "Header" $wpmanager.AddWebPart($detailWebPart , "Middle", 1) #Connect both webparts Master and Detail [Microsoft.SharePoint.WebPartPages.SPRowToParametersTransformer] $transformer = New-Object "Microsoft.SharePoint.WebPartPages.SPRowToParametersTransformer" $transformer.ProviderFieldNames = $providerField $transformer.ConsumerFieldNames = $consumerField [System.Web.UI.WebControls.WebParts.ProviderConnectionPoint] $addProviderConnPoint = $wpmanager.GetProviderConnectionPoints($masterWebPart) | where { $_.ID -eq "DFWP Row Provider ID" } [System.Web.UI.WebControls.WebParts.ConsumerConnectionPoint] $addConsumerConnPoint = $wpmanager.GetConsumerConnectionPoints($detailWebPart) | where { $_.ID -eq "DFWP Filter Consumer ID" } $wpmanager.SPConnectWebParts($masterWebPart, $addProviderConnPoint, $detailWebPart, $addConsumerConnPoint, $transformer) $pageFile.CheckIn("Checked In - Initial Version") $pageFile.Publish("Published - Initial Version") } Create-ConnectedWebPartsPage "MasterDetail.aspx" "Master and Detail" "" $layout "Category" "Category"
Awesome, right? Connecting XsltListViewWebPart is new in SharePoint 2010. I came across this blog post by Koen van der Linden, when I needed this in PowerShell for a project recently. Although he mentioned the ListViewWebPart it is actually the XsltListViewWebPart.
So, here ends my PowerShell examples for your solution deployment. I hope you have some new ideas for your deployment now. I will end these series with a final word. Do you remember your thoughts you had earlier?
Final word
What are the options to provision your SharePoint sites? By coding using eventreceivers, by using PowerShell and even just manually using the SharePoint UI. So, when to use what option?
If it’s one time only and you have just one SharePoint environment, manually provisioning the sites using the SharePoint UI would by okay. No need to write code.
If you have multiple SharePoint environments, like development, testing, Q&A and production you should choose a coding option, because you will have to deploy your solution multiple times. With PowerShell you don’t have to compile code, no GAC deployment, etc… I would choose PowerShell to provision the environment with initial setup, like the site structure or content like images, list items etc… In one of my current projects there was one subsite in the intranet. This subsite didn’t have a custom webtemplate (why should it, it’s just one subsite, one of it’s kind), so for scenario I also chose PowerShell to create and provision this subsite.
I also would use PowerShell to create and provision the service applications.
I would use eventreceivers when content definition cannot be done declaratively, like lookup columns. I would use a feature eventreceiver for this. Also when using webtemplates, feature receivers are the best choice. Vesa Juvonen has an excellent blog post on this! (and you can use PowerShell to create sites and apply the webtemplate… )
Just explore for yourself and I would say: happy coding. Whether it’s PowerShell or not.