Exporting and Importing SharePoint 2010 Terms
Ever had the need to migrate Terms from the Managed Metadata Term Store from one environment to another? Do you find the flat, CSV, import approach provided out of the box to be insufficient (especially with its lack of support for alternate labels)? When I first started working with Terms over two years ago I was extremely frustrated by the lack of export and import capabilities so I decided to solve the problem myself by creating two cmdlets, Export-SPTerms and Import-SPTerms. I’ve actually had these cmdlets publicly available for about two years now but I suspect very few people actually know they exist so I thought I’d put together this short post just to highlight them (I also recently pushed out an update which adds support for Site Collection scoped Groups if you have SP1 deployed).
I don’t want to go into a lot of detail regarding how these cmdlets work as they’re really very simple and the bulk of the code is just about iterating through the Term Store structure and turning the various objects into an XML structure (you can download the code from my downloads page). So with brevity in mind, here’s the full help for the Export-SPTerms cmdlet:
NAME
Export-SPTerms
SYNOPSIS
Export the Managed Metadata Terms.
SYNTAX
Export-SPTerms [-TaxonomySession] <SPTaxonomySessionPipeBind> [[-OutputFile] <String>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Export-SPTerms [-TermStore] <SPTaxonomyTermStorePipeBind> [[-OutputFile] <String>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Export-SPTerms [-Group] <SPTaxonomyGroupPipeBind> [[-OutputFile] <String>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Export-SPTerms [-TermSet] <SPTaxonomyTermSetPipeBind> [[-OutputFile] <String>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Export-SPTerms [-Term] <SPTaxonomyTermPipeBind> [[-OutputFile] <String>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
DESCRIPTION
Export the Managed Metadata Terms.
Copyright 2011 Falchion Consulting, LLC
> For more information on this cmdlet and others:
>http://blog.falchionconsulting.com/
> Use of this cmdlet is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-TaxonomySession <SPTaxonomySessionPipeBind>
The TaxonomySession object containing the Term Stores to export.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
-TermStore <SPTaxonomyTermStorePipeBind>
The TermStore object containing the terms to export.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-Group <SPTaxonomyGroupPipeBind>
The Group object containing the terms to export.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-TermSet <SPTaxonomyTermSetPipeBind>
The TermSet object containing the terms to export.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-Term <SPTaxonomyTermPipeBind>
The Term object containing the terms to export.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-OutputFile [<String>]
The path to the file to save the terms to.
Required? false
Position? 2
Default value
Accept pipeline input? false
Accept wildcard characters? false
-AssignmentCollection [<SPAssignmentCollection>]
Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.
When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.
Required? false
Position? named
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
NOTES
For more information, type "Get-Help Export-SPTerms -detailed". For technical information, type "Get-Help Export-SPTerms -full".
------------------EXAMPLE 1-----------------------
PS C:\> Export-SPTerms -TaxonomySession "http://site/" -OutputFile "c:\terms.xml"
This example exports the terms for all term stores associated with the site and saves to c:\terms.xml.
------------------EXAMPLE 2-----------------------
PS C:\> Export-SPTerms -Group (Get-SPTaxonomySession -Site "http://site/").TermStores[0].Groups[0] -OutputFile "c:\terms.xml"
This example exports the first Group of the first Term Store and saves to c:\terms.xml.
RELATED LINKS
Import-SPTerms
Get-SPTaxonomySession
Now lets look at the Import-SPTerms cmdlet (it’s very similar):
NAME
Import-SPTerms
SYNOPSIS
Import the Managed Metadata Terms.
SYNTAX
Import-SPTerms [-TaxonomySession] <SPTaxonomySessionPipeBind> [-InputFile] <XmlDocumentPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Import-SPTerms [-ParentTermStore] <SPTaxonomyTermStorePipeBind> [-InputFile] <XmlDocumentPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Import-SPTerms [-ParentGroup] <SPTaxonomyGroupPipeBind> [-InputFile] <XmlDocumentPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Import-SPTerms [-ParentTermSet] <SPTaxonomyTermSetPipeBind> [-InputFile] <XmlDocumentPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Import-SPTerms [-ParentTerm] <SPTaxonomyTermPipeBind> [-InputFile] <XmlDocumentPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
DESCRIPTION
Import the Managed Metadata Terms.
Copyright 2011 Falchion Consulting, LLC
> For more information on this cmdlet and others:
> http://blog.falchionconsulting.com/
> Use of this cmdlet is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-TaxonomySession <SPTaxonomySessionPipeBind>
The TaxonomySession object to import Term Stores into.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
-ParentTermStore <SPTaxonomyTermStorePipeBind>
The TermStore object to import Groups into.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-ParentGroup <SPTaxonomyGroupPipeBind>
The Group object to import Term Sets into.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-ParentTermSet <SPTaxonomyTermSetPipeBind>
The TermSet object to import Terms into.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-ParentTerm <SPTaxonomyTermPipeBind>
The Term object to import Terms into.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-InputFile <XmlDocumentPipeBind>
The path to the file containing the terms to import or an XmlDocument object or XML string.
Required? true
Position? 2
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
-AssignmentCollection [<SPAssignmentCollection>]
Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.
When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.
Required? false
Position? named
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
NOTES
For more information, type "Get-Help Import-SPTerms -detailed". For technical information, type "Get-Help Import-SPTerms -full".
------------------EXAMPLE 1-----------------------
PS C:\> Import-SPTerms -ParentTermStore (Get-SPTaxonomySession -Site "http://site/").TermStores[0] -InputFile "c:\terms.xml"
This example imports the Group from c:\terms.xml to the first Term Store.
------------------EXAMPLE 2-----------------------
PS C:\> Import-SPTerms -TaxonomySession "http://site/" -InputFile "c:\terms.xml"
This example imports the terms from c:\terms.xml to the Term Store associated with http://site.
RELATED LINKS
Export-SPTerms
Get-SPTaxonomySession
Using these cmdlets I can easily export terms from one environment, such as production, to another environment, such as my test environment. This avoids the need to have backup and restore the database associated with the term store (which requires removing and re-provisioning the service application. And the way I’ve written the cmdlets all the Term Set, Group, and Term IDs remain consistent and, because the exported XML is easily modified, when it comes to Site Collection scoped Groups you can do a simple search and replace to change Site Collection URLs to match the new target (note that I first check for a Site Collection with the specified URL and if not found then I use the ID and if I still can’t locate the Site Collection then I create the Group as a standard shared Group).
-Gary
Resetting SharePoint 2010 Themes – Part 2, the Reset-SPTheme cmdlet
Yesterday I threw up a quick post showing how to reset a SharePoint 2010 theme using a reasonably simple Windows PowerShell script. In that post I promised that I’d convert the script to a cmdlet and make it part of my downloadable extensions. Well, as promised I’ve updated my extensions so that they now include a Reset-SPTheme cmdlet. I added on minor enhancement over the previously shown script in that I allow you to pass in either an SPSite or an SPWeb object and by default it will not force all child webs to inherit from the relevant SPWeb object. This way, if you have a child Site with it’s own theme it won’t wipe out that theme. If you have multiple Sites with a custom theme setting within a Site Collection then you’ll want to provide the -Site parameter and pass in an SPSite reference – this will result in all Sites with custom themes within the Site Collection to be reset. If you only wish to reset a single Site then use the -Web parameter and pass in a SPWeb reference.
Here’s the full help for the Reset-SPTheme cmdlet:
NAME
Reset-SPTheme
SYNOPSIS
Resets a theme by applying all user specified theme configuration settings to the original source files. This is particularly helpful when the original source files have changed to a Feature upgrade.
SYNTAX
Reset-SPTheme [-Web] <SPWebPipeBind> [-SetSubWebsToInherit <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Reset-SPTheme [-Site] <SPSitePipeBind> [-SetSubWebsToInherit <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
DESCRIPTION
Resets a theme by applying all user specified theme configuration settings to the original source files. This is particularly helpful when the original source files have changed to a Feature upgrade.
Copyright 2011 Falchion Consulting, LLC
> For more information on this cmdlet and others:
> http://blog.falchionconsulting.com/
> Use of this cmdlet is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-Web <SPWebPipeBind>
Specifies the URL or GUID of the Web containing the theme to reset.
The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid name of Microsoft SharePoint Foundation 2010 Web site (for example, MySPSite1); or an instance of a valid SPWeb object.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-Site <SPSitePipeBind>
The site containing the theme to reset.
The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid URL, in the form http://server_name; or an instance of a valid SPSite object.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-SetSubWebsToInherit [<SwitchParameter>]
If specified, all child webs will be reset to inherit the theme of the specified web or root web.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-AssignmentCollection [<SPAssignmentCollection>]
Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.
When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.
Required? false
Position? named
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
NOTES
For more information, type "Get-Help Reset-SPTheme -detailed". For technical information, type "Get-Help Reset-SPTheme -full".
------------------EXAMPLE 1-----------------------
PS C:\> Get-SPSite http://server_name | Reset-SPTheme -SetSubWebsToInherit
This example resets the theme for the site collection http://server_name and resets all child webs to inherit from the root web.
------------------EXAMPLE 2-----------------------
PS C:\> Get-SPWeb http://server_name/sub-web | Reset-SPTheme
This example resets the theme for the web http://server_name/sub-web.
RELATED LINKS
Get-SPWeb
Get-SPSite
In the following example I’m resetting the theme(s) for an entire Site Collection. If one any child Sites within the Site Collection have a custom theme then they’ll be updated, not just the root (inheritance will not be changed):
PS C:\> Reset-SPTheme -Site http://example.com
In this next example I’m resetting all child Sites to inherit whatever theme has been specified for the root Site and I’m updating the root Site’s theme with changes to the source files:
PS C:\> Reset-SPTheme -Site http://example.com -SetSubWebsToInherit
For this last example I’m resetting the theme of a specific sub-Site:
PS C:\> Reset-SPTheme -Web http://example.com
As you can see, this is pretty easy to use and, if you’re deploying your branding via Features and you have theme support then a cmdlet like this can be quite critical when you need to push out updates to that brand.
Retrieving and Configuring the SharePoint 2010 Developer Dashboard using PowerShell
It’s been almost a year to the day since I’ve released my SharePoint 2010 cmdlets and, despite many good intentions to get them documented on my blog, things have just fallen by the wayside; this was primarily due to me going out on my own and writing my first book – but now that the book is done and I’ve begun to establish myself as an independent consultant, I believe it’s about time I start blogging about all these hidden cmdlets that I’ve created. So, to start I’m going to take a couple of cmdlets that I originally developed for some conference presentations; specifically Get-SPDeveloperDashboard and Set-SPDeveloperDashboard.
Before I show these two new cmdlets, let’s look at what it currently takes to retrieve and manipulate the developer dashboard using Windows PowerShell:
As you can see from the preceding figure, you obtain an instance of the SPDeveloperDashboardSettings object via the DeveloperDashboardSettings property of an SPWebService instance (obtained using the static ContentService property of the SPWebService class). Note that there are several properties that we can manipulate beyond just the simple DisplayLevel property that is used to enable or disable the developer dashboard (or to put it into on demand mode). Some people still like to use STSADM to change the DisplayLevel property but doing so doesn’t allow you to manipulate the other properties available; often the reason people use STSADM is because it’s slightly less verbose if all you wish to do is change the DisplayLevel property. Here’s an example of how you would do it with PowerShell:
$dds = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.DeveloperDashboardSettings $dds.DisplayLevel = "On" $dds.Update()
So, not a whole lot of code but still more than the single STSADM line (that and people have a hard time remembering the full object path to get to the SPDeveloperDashboardSettings object – I personally can remember this easier than the STSADM key names).
Because of this slightly higher level of complexity I decided to create these cmdlets, but I also went ahead and added some PowerShell type extensions so that I could get to the developer dashboard from an SPFarm instance. I’ll examine that before we get into the cmdlets; if you download my source code you should notice a file named Lapointe.SharePoint2010.Automation.Cmdlets.Types.ps1xml in the {Project Root}\PowerShell\Types folder. Here’s the relevant contents of that file:
<?xml version="1.0" encoding="utf-8"?> <Types> <Type> <Name>Microsoft.SharePoint.Administration.SPFarm</Name> <Members> <ScriptProperty> <Name>DeveloperDashboard</Name> <GetScriptBlock>[Microsoft.SharePoint.Administration.SPWebService]::ContentService.DeveloperDashboardSettings</GetScriptBlock> </ScriptProperty> </Members> </Type> </Types>
What I’ve done here is essentially create a type extension using XML; the <Name /> element defines the full type name that you want to extend and the <Members /> element contains all the extensions. In this case I’ve added a new property named DeveloperDashboard and I provided the same script we saw previously so that the SPDeveloperDashboardSettings object will be returned. It’s important to understand that you are not limited to just get properties – you can create set properties as well as methods (type help about_types for more information about creating type extensions). With this type extension added we can now access the developer dashboard in a slightly simpler manner:
$dds = (Get-SPFarm).DeveloperDashboard
Using this approach there really isn’t a need for the Get-SPDeveloperDashboard cmdlet that I created, as the cmdlet only saves about seven characters; however, this approach isn’t obvious – what I want is users to be able to type Get-Command *dashboard* so that they can see all the cmdlets related to the developer dashboard. (Plus, I created the cmdlet originally just for demonstration purposes but it does make things a little more obvious). So now that we have the type extension out of the way, let’s take a look at the cmdlet. Here’s a dump of the full help for the Get-SPDeveloperDashboard cmdlet:
PS C:\> help Get-SPDeveloperDashboard -Full
NAME
Get-SPDeveloperDashboard
SYNOPSIS
Retrieves the Developer Dashboard Settings object.
SYNTAX
Get-SPDeveloperDashboard [-AssignmentCollection <spassignmentcollection>] [<commonparameters>]
DESCRIPTION
Retrieves the Developer Dashboard Settings object.
Copyright 2010 Falchion Consulting, LLC
> For more information on this cmdlet and others:
> http://blog.falchionconsulting.com/
> Use of this cmdlet is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-AssignmentCollection [<spassignmentcollection>]
Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite,
can use large amounts of memory and use of these objects in Windows PowerShell scripts requires
proper memory management. Using the SPAssignment object, you can assign objects to a variable
and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or
SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment
collection or the Global parameter is not used.
When the Global parameter is used, all objects are contained in the global store. If objects are
not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory
scenario can occur.
Required? false
Position? named
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
<commonparameters>
This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable,
WarningAction, WarningVariable, OutBuffer and OutVariable. For more information,
type, "get-help about_commonparameters".
INPUTS
OUTPUTS
NOTES
For more information, type "Get-Help Get-SPDeveloperDashboard -detailed".
For technical information, type "Get-Help Get-SPDeveloperDashboard -full".
------------------EXAMPLE------------------
PS C:\> $dash = Get-SPDeveloperDashboard
This example returns back the developer dashboard settings object.
RELATED LINKS
Set-SPDeveloperDashboard
So obviously the cmdlet is pretty simple as there aren’t any parameters beyond the standard parameters (remember, the -AssignmentCollection parameter is included as part of the cmdlet base class but as the SPDeveloperDashboardSettings object is not disposable there is no reason to use it.
The code for this cmdlet is actually shorter than the help for it:
using System.Collections.Generic; using System.Management.Automation; using Lapointe.PowerShell.MamlGenerator.Attributes; using Microsoft.SharePoint.PowerShell; using Microsoft.SharePoint.Administration; namespace Lapointe.SharePoint2010.Automation.Cmdlets.Farm { [Cmdlet(VerbsCommon.Get, "SPDeveloperDashboard", SupportsShouldProcess = false), SPCmdlet(RequireLocalFarmExist = true, RequireUserFarmAdmin = false)] [CmdletDescription("Retrieves the Developer Dashboard Settings object.")] [RelatedCmdlets(typeof(SPCmdletSetDeveloperDashboard))] [Example(Code = "PS C:\\> $dash = Get-SPDeveloperDashboard", Remarks = "This example returns back the developer dashboard settings object.")] public class SPCmdletGetDeveloperDashboard : SPGetCmdletBaseCustom<SPDeveloperDashboardSettings> { protected override IEnumerable<SPDeveloperDashboardSettings> RetrieveDataObjects() { WriteObject(SPWebService.ContentService.DeveloperDashboardSettings); return null; } } }
The following figure shows how you can call the cmdlet:
Note that I’ve also added a new view for the SPDeveloperDashboardSettings object type (as shown in the first example – to see all the properties use the Select-Object cmdlet as shown in the second example). The custom views are added just like the custom type extensions – for views, however, you create another XML file which you can see in my source code under the {Project Root}\PowerShell\Format folder. The following XML snippet illustrates the relevant portion of that file:
<?xml version="1.0" encoding="utf-8"?> <Configuration> <ViewDefinitions> <View> <Name>SPDeveloperDashboardSettings</Name> <ViewSelectedBy> <TypeName>Microsoft.SharePoint.Administration.SPDeveloperDashboardSettings</TypeName> </ViewSelectedBy> <TableControl> <TableHeaders> <TableColumnHeader> <Label>Display Level</Label> <Width>14</Width> <Alignment>left</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>Trace Enabled</Label> <Width>14</Width> <Alignment>left</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>Required Permissions</Label> <Alignment>left</Alignment> </TableColumnHeader> </TableHeaders> <TableRowEntries> <TableRowEntry> <TableColumnItems> <TableColumnItem> <PropertyName>DisplayLevel</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>TraceEnabled</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>RequiredPermissions</PropertyName> </TableColumnItem> </TableColumnItems> </TableRowEntry> </TableRowEntries> </TableControl> </View> </ViewDefinitions> </Configuration>
Okay, so we’ve made it easier to retrieve the developer dashboard, now I want to change the values in one step (because retrieving the object, changing the value, and calling Update() is just too much work). To do this I created the Set-SPDeveloperDashboard cmdlet. This cmdlet is a bit more complex in that I’ve exposed all the relevant properties of the SPDeveloperDashboardSettings object with an equivalent parameter. Here’s the full help for the cmdlet:
PS C:\> help Set-SPDeveloperDashboard -Full
NAME
Set-SPDeveloperDashboard
SYNOPSIS
Sets the Developer Dashboard Settings.
SYNTAX
Set-SPDeveloperDashboard [-AutoLaunchEnabled <Boolean>] [-DisplayLevel <Off | OnDemand | On>] [-MaximumCriticalEventsToTrack <Int32>]
[-MaximumSQLQueriesToTrack <Int32>] [-RequiredPermissions <EmptyMask | ViewListItems | AddListItems | EditListItems | DeleteListItems |
ApproveItems | OpenItems | ViewVersions | DeleteVersions | CancelCheckout | ManagePersonalViews | ManageLists | ViewFormPages | Open |
ViewPages | AddAndCustomizePages | ApplyThemeAndBorder | ApplyStyleSheets | ViewUsageData | CreateSSCSite | ManageSubwebs | CreateGroups
| ManagePermissions | BrowseDirectories | BrowseUserInfo | AddDelPrivateWebParts | UpdatePersonalWebParts | ManageWeb |
UseClientIntegration | UseRemoteAPIs | ManageAlerts | CreateAlerts | EditMyUserInfo | EnumeratePermissions | FullMask>]
[-TraceEnabled <Boolean>] [-AdditionalEventsToTrack <String[]>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
DESCRIPTION
Sets the Developer Dashboard Settings.
Copyright 2010 Falchion Consulting, LLC
> For more information on this cmdlet and others:
> http://blog.falchionconsulting.com/
> Use of this cmdlet is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-AutoLaunchEnabled [<Boolean>]
Indicates whether the developer dashboard can be auto launched.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-DisplayLevel [<SPDeveloperDashboardLevel>]
Indicates whether the developer dashboard is set to Off, On, or On Demand.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-MaximumCriticalEventsToTrack [<Int32>]
The maximum number of critical events and asserts that will be recorded in a single transaction (i.e. one request or timer job).
If a single transaction has more than this number of asserts the remainder will be ignored. This can be set to 0 to disable
assert tracking.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-MaximumSQLQueriesToTrack [<Int32>]
The maximum number of SQL queries that will be recorded in a single transaction (i.e. one request or timer job). If a single
transaction executes more than this number of requests the query will be counted but the query call stack and text will not be kept.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-RequiredPermissions [<SPBasePermissions>]
A permission mask defining the permissions required to see the developer dashboard. This defaults to SPBasePermissions.AddAndCustomizePages.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-TraceEnabled [<Boolean>]
Whether a link to display full verbose trace will be available at the bottom of the page when the developer dashboard is launched or not.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-AdditionalEventsToTrack [<String[]>]
A list of URL tags to track in addition to events with severity above High.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-AssignmentCollection [<SPAssignmentCollection>]
Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite,
can use large amounts of memory and use of these objects in Windows PowerShell scripts requires
proper memory management. Using the SPAssignment object, you can assign objects to a variable
and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or
SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment
collection or the Global parameter is not used.
When the Global parameter is used, all objects are contained in the global store. If objects are
not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory
scenario can occur.
Required? false
Position? named
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
NOTES
For more information, type "Get-Help Set-SPDeveloperDashboard -detailed". For technical information,
type "Get-Help Set-SPDeveloperDashboard -full".
------------------EXAMPLE 1-----------------------
PS C:\> Set-SPDeveloperDashboard -RequiredPermissions "ManageWeb,ManageSubwebs"
This example sets the required permissions to view the developer dashboard.
------------------EXAMPLE 2-----------------------
PS C:\> Set-SPDeveloperDashboard -DisplayLevel OnDemand -TraceEnabled $true
This example enables the developer dashboard.
RELATED LINKS
Get-SPDeveloperDashboard
The code for this cmdlet is obviously going to be slightly longer than the Get-SPDeveloperDashboard cmdlet, but again, it’s very simple as most of the code is just for defining the parameters:
using System.Collections.Generic; using System.Management.Automation; using Lapointe.PowerShell.MamlGenerator.Attributes; using Microsoft.SharePoint; using Microsoft.SharePoint.PowerShell; using Microsoft.SharePoint.Administration; namespace Lapointe.SharePoint2010.Automation.Cmdlets.Farm { [Cmdlet(VerbsCommon.Set, "SPDeveloperDashboard", SupportsShouldProcess = false), SPCmdlet(RequireLocalFarmExist = true, RequireUserFarmAdmin = false)] [CmdletDescription("Sets the Developer Dashboard Settings.")] [RelatedCmdlets(typeof(SPCmdletGetDeveloperDashboard))] [Example(Code = "PS C:\\> Set-SPDeveloperDashboard -DisplayLevel OnDemand -TraceEnabled $true", Remarks = "This example enables the developer dashboard.")] [Example(Code = "PS C:\\> Set-SPDeveloperDashboard -RequiredPermissions \"ManageWeb,ManageSubwebs\"", Remarks = "This example sets the required permissions to view the developer dashboard.")] public class SPCmdletSetDeveloperDashboard : SPSetCmdletBaseCustom<SPDeveloperDashboardSettings> { public SPCmdletSetDeveloperDashboard() { SPDeveloperDashboardSettings dash = SPWebService.ContentService.DeveloperDashboardSettings; AutoLaunchEnabled = dash.AutoLaunchEnabled; DisplayLevel = dash.DisplayLevel; MaximumCriticalEventsToTrack = dash.MaximumCriticalEventsToTrack; MaximumSQLQueriesToTrack = dash.MaximumSQLQueriesToTrack; RequiredPermissions = dash.RequiredPermissions; TraceEnabled = dash.TraceEnabled; AdditionalEventsToTrack = ((List<string>) dash.AdditionalEventsToTrack).ToArray(); } [Parameter(HelpMessage = "Indicates whether the developer dashboard can be auto launched.")] public bool AutoLaunchEnabled { get; set; } [Parameter(HelpMessage = "Indicates whether the developer dashboard is set to Off, On, or On Demand.")] public SPDeveloperDashboardLevel DisplayLevel { get; set; } [Parameter(HelpMessage = "The maximum number of critical events and asserts that will be recorded in a single transaction (i.e. one request or timer job). If a single transaction has more than this number of asserts the remainder will be ignored. This can be set to 0 to disable assert tracking.")] public int MaximumCriticalEventsToTrack { get; set; } [Parameter(HelpMessage = "The maximum number of SQL queries that will be recorded in a single transaction (i.e. one request or timer job). If a single transaction executes more than this number of requests the query will be counted but the query call stack and text will not be kept. ")] public int MaximumSQLQueriesToTrack { get; set; } [Parameter(HelpMessage = "A permission mask defining the permissions required to see the developer dashboard. This defaults to SPBasePermissions.AddAndCustomizePages.")] public SPBasePermissions RequiredPermissions { get; set; } [Parameter(HelpMessage = "Whether a link to display full verbose trace will be available at the bottom of the page when the developer dashboard is launched or not.")] public bool TraceEnabled { get; set; } [Parameter(HelpMessage = "A list of URL tags to track in addition to events with severity above High. ")] public string[] AdditionalEventsToTrack { get; set; } protected override void UpdateDataObject() { SPDeveloperDashboardSettings dash = SPWebService.ContentService.DeveloperDashboardSettings; dash.AutoLaunchEnabled = AutoLaunchEnabled; dash.DisplayLevel = DisplayLevel; dash.MaximumCriticalEventsToTrack = MaximumCriticalEventsToTrack; dash.MaximumSQLQueriesToTrack = MaximumSQLQueriesToTrack; dash.RequiredPermissions = RequiredPermissions; dash.TraceEnabled = TraceEnabled; dash.AdditionalEventsToTrack.Clear(); ((List<string>)dash.AdditionalEventsToTrack).AddRange(AdditionalEventsToTrack); dash.Update(); } } }
The following figure shows how you can call the cmdlet:
So that wraps up my first (very long overdue) post for my 2010 cmdlets – look for more posts coming soon as well as an update to my index page listing all the available cmdlets.
-Gary
Creating PowerShell Help Files Dynamically
It’s been a while since I’ve blogged anything useful due to all my writing efforts going to the book that I’ve been working on. However, I’ve recently wrapped up my last chapter for the book so I figured what better time to start focusing on my blog again.
The first thing I wanted to cover was something that I should have documented back in May of 2010 when I released my SharePoint 2010 cmdlets and it is something that I just finished referencing in my last book chapter: creating help files for custom cmdlets.
In the book I emphasize that creating these help files is not a trivial task and there are virtually no good tools available to help you with the effort. When I created my SharePoint 2007 cmdlets, I had first tried using the Cmdlet Help Editor v1.0 that the Windows PowerShell team released back in May of 2007; I quickly found that this wasn’t very practical for long term use for numerous reasons, particularly when looking at SharePoint cmdlets where I don’t have a snap-in that I can point the tool to. But the biggest issue I had with using this tool, or any other tool that required me to add descriptions manually, was that I just couldn’t keep up with the changes. I was making new cmdlets and extending existing ones so fast that it was taking me longer to update the help file than it was to create/update the cmdlet – that was just unacceptable to me.
As you may know, I’m all about automation; so I figured, how hard could it possibly be to automate the creation of the help file? All I needed to do was to decorate my cmdlets with some metadata that I could then use with a little reflection to spit out the required XML. I could then generate this XML on the Post Build event of my assembly so that the help file would be automatically updated just prior to the SharePoint Solution Package (WSP) being generated. So, back during the beta days of SharePoint 2010, while migrating my 2007 STSADM extensions to cmdlets, I decided to go ahead and implement my idea. I released it along with my SharePoint 2010 source code with little fanfare (not very many people are generating PowerShell cmdlets and even fewer are creating help files for them). However, with my book having a reference to this code I figured I would write a short post about it and, along the way, break the code out of the SharePoint project and into it’s own project, thereby making it useful for anyone who wishes to dynamically develop Windows PowerShell help files for their cmdlets.
| Downloads You can download the .NET Assembly (Lapointe.PowerShell.MamlGenerator.dll) alone or the source code to the assembly from my downloads page. I thought about providing a separate download for the source but I’m lazy and really didn’t want to have to manage two different download packages; so, if you wish to download the source, just download the SharePoint 2010 source code and you’ll find the Lapointe.PowerShell.MamlGenerator project. |
So how does it work? It’s actually quite simple; I’ve created a series of custom Attribute classes which you can use to decorate your cmdlet class. I then use reflection to interrogate the Assembly for any classes that are based on PSCmdlet; for each class I look for these attributes. The rest is just simple XML generation. The Attributes are defined in the following table:
| Name | Example |
|---|---|
| CmdletDescriptionAttribute This Attribute is assigned to the class and contains the main, verbose description, as well as the synopsis for the cmdlet (or shorter description). You can only have one CmdletDescriptionAttribute assigned to the class. | [CmdletDescription("Delete a list from a web site.")] |
| ExampleAttribute This Attribute is assigned to the class and contains any example code and corresponding descriptions. You may assign multiple instances of the ExampleAttribute to the class (one for each example). | [Example( Code = "PS C:\\> Get-SPList \"http://server_name/lists/mylist\" | Remove-SPList -BackupDirectory \"c:\\backups\\mylist\"", Remarks = "This example deletes the list mylist and creates a backup of the list in the c:\\backups\\mylist folder.")] |
| RelatedCmdletsAttribute This Attribute is assigned to the class and contains the listing of related cmdlets. The related cmdlets can be added using the cmdlet's type or any applicable string representation of the cmdlet (appropriate for related cmdlets that are external to the current project). You can only have one RelatedCmdletsAttribute assigned to the class. | [RelatedCmdlets( typeof(SPCmdletGetList), ExternalCmdlets = new[] {"Get-SPWeb"})] |
| SupportsWildcardsAttribute This Attribute is assigned to the class and indicates whether the cmdlet supports wildcards. This Attribute is a marker only and contains no properties. You can only have one SupportsWildcardsAttribute assigned to the class. | [SupportsWildcards] |
These are all the custom Attributes that I’m using; the rest are are native to PowerShell and can be found in the System.Management.Automation namespace. Primarily I’m using CmdletAttribute and ParameterAttribute.
The example is taken from my SharePoint 2010 cmdlets and demonstrates how most of these Attributes are used:
using System.Collections.Generic; using Microsoft.SharePoint; using Microsoft.SharePoint.PowerShell; using System.Management.Automation; using Lapointe.SharePoint2010.Automation.Cmdlets.PipeBindObjects; using Lapointe.PowerShell.MamlGenerator.Attributes; namespace Lapointe.SharePoint2010.Automation.Cmdlets.Lists { [Cmdlet(VerbsCommon.Get, "SPList", SupportsShouldProcess = false), SPCmdlet(RequireLocalFarmExist = true)] [CmdletDescription("Retrieve an SPList object by name or type. Use the AssignmentCollection parameter to ensure parent objects are properly disposed.")] [RelatedCmdlets(typeof(SPCmdletDeleteList), typeof(SPCmdletCopyList), typeof(SPCmdletCopyListSecurity), typeof(SPCmdletExportListSecurity), ExternalCmdlets = new[] {"Get-SPWeb", "Start-SPAssignment", "Stop-SPAssignment"})] [Example(Code = "PS C:\\> $list = Get-SPList \"http://server_name/lists/mylist\"", Remarks = "This example retrieves the list at http://server_name/lists/mylist.")] public class SPCmdletGetList : SPGetCmdletBaseCustom<SPList> { #region Parameters [Parameter(Mandatory = false, ValueFromPipeline = true, Position = 0, ParameterSetName = "AllListsInIdentity")] public SPListPipeBind Identity { get; set; } [Parameter(Mandatory = false, ValueFromPipeline = false, ParameterSetName = "AllListsByType")] public SPBaseType ListType { get; set; } [Parameter(Mandatory = false, ValueFromPipeline = true, HelpMessage = "Specifies the URL or GUID of the Web containing the list to be retrieved.\r\n\r\nThe type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid name of Microsoft SharePoint Foundation 2010 Web site (for example, MySPSite1); or an instance of a valid SPWeb object.")] public SPWebPipeBind Web { get; set; } #endregion protected override IEnumerable<SPList> RetrieveDataObjects() { List<SPList> lists = new List<SPList>(); SPWeb web = null; if (this.Web != null) web = this.Web.Read(); if (Identity == null && ParameterSetName != "AllListsByType") { foreach (SPList list in web.Lists) lists.Add(list); } else if (Identity == null && ParameterSetName == "AllListsByType") { foreach (SPList list in web.GetListsOfType(ListType)) lists.Add(list); } else { SPList list = this.Identity.Read(web); if (list != null) lists.Add(list); } AssignmentCollection.Add(web); foreach (SPList list1 in lists) { AssignmentCollection.Add(list1.ParentWeb); AssignmentCollection.Add(list1.ParentWeb.Site); } return lists; } } }
With the cmdlet properly decorated I can make quick changes to my code and update the help documentation as I update the cmdlet. I don’t have to remember to go to another class file and remember this extremely cryptic MAML based XML format. This makes me considerably more efficient and it keeps my help files more up to date and inline with the actual cmdlet (I wish Microsoft would do something like this as much of the help for the SharePoint 2010 cmdlets is inaccurate, incomplete, or missing entirely).
The following shows a snippet of the help file that gets generated based on the attributes defined (I also use the Assembly’s CopyrightAttribute and DescriptionAttribute to add the copyright details that you see in the XML below):
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/1" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10"> <command:details> <command:name>Get-SPList</command:name> <maml:description> <maml:para>Retrieve an SPList object by name or type. Use the AssignmentCollection parameter to ensure parent objects are properly disposed.</maml:para> </maml:description> <maml:copyright> <maml:para>Copyright 2010 Falchion Consulting, LLC</maml:para> <maml:para> > For more information on this cmdlet and others:</maml:para> <maml:para> > http://blog.falchionconsulting.com/</maml:para> <maml:para> > Use of this cmdlet is at your own risk.</maml:para> <maml:para> > Gary Lapointe assumes no liability.</maml:para> </maml:copyright> <command:verb>Get</command:verb> <command:noun>SPList</command:noun> <dev:version>1.0.0.0</dev:version> </command:details> <maml:description> <maml:para>Retrieve an SPList object by name or type. Use the AssignmentCollection parameter to ensure parent objects are properly disposed.</maml:para> <maml:para /> <maml:para>Copyright 2010 Falchion Consulting, LLC</maml:para> <maml:para> > For more information on this cmdlet and others:</maml:para> <maml:para> > http://blog.falchionconsulting.com/</maml:para> <maml:para> > Use of this cmdlet is at your own risk.</maml:para> <maml:para> > Gary Lapointe assumes no liability.</maml:para> </maml:description> <command:syntax> <command:syntaxItem> <maml:name>Get-SPList</maml:name> <command:parameter required="false" position="1"> <maml:name>Identity</maml:name> <command:parameterValue required="true">SPListPipeBind</command:parameterValue> </command:parameter> <command:parameter required="false" position="named"> <maml:name>Web</maml:name> <command:parameterValue required="true">SPWebPipeBind</command:parameterValue> </command:parameter> <command:parameter required="false" position="named"> <maml:name>AssignmentCollection</maml:name> <command:parameterValue required="true">SPAssignmentCollection</command:parameterValue> </command:parameter> </command:syntaxItem> <command:syntaxItem> <maml:name>Get-SPList</maml:name> <command:parameter required="false" position="named"> <maml:name>ListType</maml:name> <command:parameterValue required="true">GenericList | DocumentLibrary | Unused | DiscussionBoard | Survey | Issue | UnspecifiedBaseType</command:parameterValue> </command:parameter> <command:parameter required="false" position="named"> <maml:name>Web</maml:name> <command:parameterValue required="true">SPWebPipeBind</command:parameterValue> </command:parameter> <command:parameter required="false" position="named"> <maml:name>AssignmentCollection</maml:name> <command:parameterValue required="true">SPAssignmentCollection</command:parameterValue> </command:parameter> </command:syntaxItem> </command:syntax> <command:parameters> <command:parameter required="false" globbing="false" pipelineInput="true (ByValue)" position="1" variableLength="false"> <maml:name>Identity</maml:name> <maml:description> <maml:para /> </maml:description> <command:parameterValue required="false" variableLength="false">SPListPipeBind</command:parameterValue> <dev:type> <maml:name>SPListPipeBind</maml:name> <maml:uri /> <maml:description> <maml:para /> </maml:description> </dev:type> </command:parameter> <command:parameter required="false" globbing="false" pipelineInput="false" position="named" variableLength="false"> <maml:name>ListType</maml:name> <maml:description> <maml:para /> </maml:description> <command:parameterValue required="false" variableLength="false">SPBaseType</command:parameterValue> <dev:type> <maml:name>SPBaseType</maml:name> <maml:uri /> <maml:description> <maml:para /> </maml:description> </dev:type> </command:parameter> <command:parameter required="false" globbing="false" pipelineInput="true (ByValue)" position="named" variableLength="false"> <maml:name>Web</maml:name> <maml:description> <maml:para>Specifies the URL or GUID of the Web containing the list to be retrieved.</maml:para> <maml:para /> <maml:para>The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid name of Microsoft SharePoint Foundation 2010 Web site (for example, MySPSite1); or an instance of a valid SPWeb object.</maml:para> </maml:description> <command:parameterValue required="false" variableLength="false">SPWebPipeBind</command:parameterValue> <dev:type> <maml:name>SPWebPipeBind</maml:name> <maml:uri /> <maml:description> <maml:para /> </maml:description> </dev:type> </command:parameter> <command:parameter required="false" globbing="false" pipelineInput="true (ByValue)" position="named" variableLength="false"> <maml:name>AssignmentCollection</maml:name> <maml:description> <maml:para>Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.</maml:para> <maml:para /> <maml:para>When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.</maml:para> </maml:description> <command:parameterValue required="false" variableLength="false">SPAssignmentCollection</command:parameterValue> <dev:type> <maml:name>SPAssignmentCollection</maml:name> <maml:uri /> <maml:description> <maml:para /> </maml:description> </dev:type> </command:parameter> </command:parameters> <command:inputTypes> <command:inputType> <dev:type> <maml:name /> <maml:uri /> <maml:description> <maml:para /> </maml:description> </dev:type> </command:inputType> </command:inputTypes> <command:returnValues> <command:returnValue> <dev:type> <maml:name /> <maml:uri /> <maml:description> <maml:para /> </maml:description> </dev:type> </command:returnValue> </command:returnValues> <command:terminatingErrors /> <command:nonTerminatingErrors /> <maml:alertSet> <maml:title /> <maml:alert> <maml:para>For more information, type "Get-Help Get-SPList -detailed". For technical information, type "Get-Help Get-SPList -full".</maml:para> </maml:alert> </maml:alertSet> <command:examples> <command:example> <maml:title>------------------EXAMPLE------------------</maml:title> <dev:code>PS C:\> $list = Get-SPList "http://server_name/lists/mylist"</dev:code> <dev:remarks> <maml:para>This example retrieves the list at http://server_name/lists/mylist.</maml:para> </dev:remarks> </command:example> </command:examples> <maml:relatedLinks> <maml:navigationLink> <maml:linkText>Remove-SPList</maml:linkText> <maml:uri /> </maml:navigationLink> <maml:navigationLink> <maml:linkText>Copy-SPList</maml:linkText> <maml:uri /> </maml:navigationLink> <maml:navigationLink> <maml:linkText>Copy-SPListSecurity</maml:linkText> <maml:uri /> </maml:navigationLink> <maml:navigationLink> <maml:linkText>Export-SPListSecurity</maml:linkText> <maml:uri /> </maml:navigationLink> <maml:navigationLink> <maml:linkText>Get-SPWeb</maml:linkText> <maml:uri /> </maml:navigationLink> <maml:navigationLink> <maml:linkText>Start-SPAssignment</maml:linkText> <maml:uri /> </maml:navigationLink> <maml:navigationLink> <maml:linkText>Stop-SPAssignment</maml:linkText> <maml:uri /> </maml:navigationLink> </maml:relatedLinks> </command:command>
As you can see, there is a lot of XML that you would have to manually generate (with over 50 cmdlets at the time of writing this and close to a hundred additional planned, you can hopefully understand why I wouldn't want to generate this manually).
So how do you call out to the assembly to generate the help file? Pretty easily! In the Lapointe.PowerShell.MamlGenerator Assembly there is a static class called CmdletHelpGenerator. This class has three static methods that you can call based on how you want to pass in the cmdlet's Assembly information:
public static void GenerateHelp(string outputPath, bool oneFile); public static void GenerateHelp(string inputFile, string outputPath, bool oneFile); public static void GenerateHelp(Assembly asm, string outputPath, bool oneFile);
If you want to run this code from PowerShell you can do so using the following syntax:
$asm = "W:\Lapointe.SharePoint2010.Automation.dll" $cmdletAsm = "W:\Lapointe.PowerShell.MamlGenerator.dll" $targetPath = "W:\MyProject\POWERSHELL\Help" [System.Reflection.Assembly]::LoadFrom($asm) | Out-Null [Lapointe.PowerShell.MamlGenerator.CmdletHelpGenerator]::GenerateHelp($asm, $targetPath, $true)
And again, this works with any cmdlet development, not just SharePoint cmdlet development. Hopefully all you ambitious PowerShell developers out there who appreciate the need to provide your IT Administrators with proper help documentation will find this code as useful as I have.
Good luck and happy PowerShelling!
Announcing My SharePoint 2010 PowerShell Cmdlets & STSADM Commands Now Available for Download
I’ve been wanting to release the SharePoint 2010 version of my STSADM extensions for quite some time but honestly just haven’t had the time to migrate as many as I would have liked. With over 145 STSADM extensions for SharePoint 2007 it was a challenge determining which ones I should focus on initially for the migration.
But today I’m happy to announce my initial release which contains 46 PowerShell cmdlets and 56 STSADM commands specific to SharePoint 2010. Yup, you read right, I’ve decided to maintain support for my STSADM commands and have been migrating them over as I create the equivalent replacement PowerShell cmdlet (though I recommend you don’t use them and suck it up and get used to PowerShell). You should note that there are more STSADM commands than PowerShell cmdlets – that’s because some of the things I was doing with STSADM can now easily be done with out of the box PowerShell cmdlets (I also have new PowerShell cmdlets that do not have an STSADM equivalent – everything new I create will be a cmdlet and I’ll create no new STSADM commands).
It’s going to take me a while to create all the posts needed to explain each cmdlet (assuming I create one at all) so for now I’ve created this simple table which lists all the STSADM commands and PowerShell cmdlets that are available in this initial release (I’ll eventually update my command index page but for now let this serve as the main reference for what is available as of 5/14/2010):
| STSADM Commands | PowerShell Cmdlets | Notes |
|---|---|---|
| gl-activatefeature | Enable-SPFeature2 | There’s an OOTB Enable-SPFeature cmdlet, this one simple adds some capabilities which were present in my existing STSADM command. |
| gl-addaudiencerule | New-SPAudienceRule | |
| gl-addavailablesitetemplate | I’ll eventually create a cmdlet for this. | |
| gl-adduser2 | Use the OOTB New-SPUser cmdlet. | |
| gl-adduserpolicyforwebapp | Add-SPWebApplicationUserPolicy | |
| gl-applytheme | This can be done pretty easily using Get-SPWeb and the ApplyTheme() method of the SPWeb object. | |
| gl-backup | Use the OOTB Backup-SPFarm and Backup-SPSite cmdlets. | |
| gl-backupsites | Backup-SPSite2 | Extends Backup-SPSite by including IIS settings. |
| gl-convertsubsitetositecollection | ConvertTo-SPSite | |
| gl-copycontenttypes | Copy-SPContentType | |
| gl-copylist | Copy-SPList | |
| gl-copylistsecurity | Copy-SPListSecurity | |
| gl-createaudience | New-SPAudience | |
| gl-createcontentdb | Use the OOTB New-SPContentDatabase cmdlet. | |
| gl-createpublishingpage | New-SPPublishingPage | |
| gl-createquotatemplate | New-SPQuotaTemplate | |
| gl-createwebapp | Use the OOTB New-SPWebApplication cmdlet | |
| gl-deactivatefeature | Disable-SPFeature2 | Extends the OOTB Disable-SPFeature cmdlet. |
| gl-deleteallusers | I probably won’t replicate this as it is easily done using the OOTB Remove-SPUser cmdlet. | |
| gl-deleteaudience | Remove-SPAudience | |
| gl-deletelist | Remove-SPList | |
| gl-deletewebapp | Use the OOTB Remove-SPWebApplication cmdlet. | |
| gl-disableuserpermissionforwebapp | This is fairly easy to do OOTB so I may not create a cmdlet for it. | |
| gl-editquotatemplate | Set-SPQuotaTemplate | |
| gl-enableuserpermissionforwebapp | This is fairly easy to do OOTB so I may not create a cmdlet for it. | |
| gl-enumaudiencerules | Export-SPAudienceRules | |
| gl-enumavailablepagelayouts | Get-SPPublishingPageLayout | |
| gl-enumavailablesitetemplates | Get-SPAvailableWebTemplates | |
| gl-enumeffectivebaseperms | This is fairly easy to do OOTB so I may not create a cmdlet for it. | |
| gl-enumfeatures | Use the OOTB Get-SPFeature cmdlet. | |
| gl-enuminstalledsitetemplates | Use the OOTB Get-SPWebTemplate cmdlet. | |
|
gl-enumpagewebparts | Get-SPWebPartList | |
| gl-enumunghostedfiles | Get-SPCustomizedPages | |
| gl-execadmsvcjobs | Start-SPAdminJob2 | I honestly need to research this a bit more as I’m not sure it’s necessary anymore but I’ve replicated the functionality in case someone finds it useful. |
| gl-exportaudiences | Export-SPAudiences | |
| gl-exportcontenttypes | Export-SPContentType | |
| gl-exportlist | Export-SPWeb2 | I’ve just extended the Export-SPWeb2 cmdlet to add additional parameters. |
| gl-exportlistsecurity | Export-SPListSecurity | |
| gl-extendwebapp | Use the OOTB New-SPWebApplicationExtension cmdlet. | |
| gl-fixpublishingpagespagelayouturl | Repair-SPPageLayoutUrl | |
| gl-importaudiences | Import-SPAudiences | |
| gl-importlist | Import-SPWeb2 | I’ve just extended the Import-SPWeb2 cmdlet to add additional parameters. |
| gl-importlistsecurity | Import-SPListSecurity | |
| gl-listaudiencetargeting | Set-SPListAudienceTargeting | |
| gl-managecontentdbsettings | Use the OOTB Set-SPContentDatabase cmdlet. | |
| gl-propagatecontenttype | Propagate-SPContentType | |
| gl-publishitems | Publish-SPListItems | |
| gl-reghostfile | Reset-SPCustomizedPages | |
| gl-removeavailablesitetemplate | I’ll eventually create a cmdlet for this (maybe). | |
| gl-repairsitecollectionimportedfromsubsite | Repair-SPSite | |
| gl-replacewebpartcontent | Replace-SPWebPartContent | |
| gl-setbackconnectionhostnames | Set-SPBackConnectionHostNames | |
| gl-setselfservicesitecreation | Not sure if I’ll migrate this or not. | |
| gl-syncquotas | Set-SPQuota | |
| gl-tracelog | Use the OOTB Set-SPDiagnosticConfig cmdlet. | |
| gl-unextendwebapp | Use the OOTB Remove-SPWebApplication cmdlet. | |
| Get-SPAudience | ||
| Get-SPAudienceManager | ||
| Get-SPContentType | ||
| Get-SPFile | ||
| Get-SPLimitedWebPartManager | ||
| Get-SPList | ||
| Get-SPPublishingPage | ||
| Get-SPQuotaTemplate | ||
| Set-SPAudience |
For those that know a thing or two about cmdlet development you might be interested in knowing that I am dynamically generating the help XML file for the cmdlets. If you download the source you’ll find a class which uses reflection to interrogate the assembly and dynamically build the help file just prior to building the WSP package. This saved me literally days of hand editing XML.
You can download the source and WSP files here or from the Downloads page:
- SharePoint 2010 PowerShell Cmdlets Source Code
- SharePoint 2010 Server Cmdlets WSP
- SharePoint 2010 Foundation Cmdlets WSP
After you deploy the package you can type “help <cmdlet name>” to get detailed help about each cmdlet, including parameter descriptions and example usage. If you want to see the list of cmdlets installed type the following:
gcm | where {$_.DLL –like "*lapointe*"}
As always, your use of these cmdlets/stsadm commands is at your own risk – I do as much testing as I can but every environment is different and there’s simply not enough time in a day. If you have any suggestions or feedback please don’t hesitate to leave a comment – I appreciate all of them!
Creating Custom SharePoint 2010 Cmdlets using Visual Studio 2010
With SharePoint 2010 we now have the ability to create custom PowerShell cmdlets that can be deployed just like any other SharePoint artifact using SharePoint Solution Packages (WSP) created with Visual Studio 2010. With SharePoint 2007 it was necessary to build a custom setup (MSI) package which had to be run on every server in the farm. This setup package would register a custom snap-in that you'd have to create which would be responsible for registering all of your custom cmdlets with the PowerShell runtime.
With SharePoint 2010 we no longer have to create a custom snap-in or setup package. When the Microsoft.SharePoint.PowerShell snap-in is loaded it examines the {SharePointRoot}/Config/PowerShell/Registration folder for any XML files and dynamically registers the cmdlets specified in the XML. As long as the SharePoint binaries have been installed on the server then you can utilize this feature (if the farm has not yet been created then you'll have to manually GAC the assembly and deploy the registration XML file as solution deployments only work when the farm exists).
To facilitate a standard and consistent scripting experience SharePoint 2010 introduces five new base classes that all SharePoint 2010 PowerShell cmdlets should be derived from:
When creating your custom cmdlet you should carefully choose the correct base class for your cmdlet. When creating a cmdlet that is meant to work with persistent objects (objects that are to be used across calls) you should utilize one of the four task based base classes: SPRemoveCmdletBase, SPNewCmdletBase, SPSetCmdletBase, or SPGetCmdletBase. When creating cmdlets that return non-persistent objects/data or perform tasks that do not require a persistent object (e.g., Start-SP*) then you should use the SPCmdlet base class. A good example of a cmdlet that would use the SPCmdlet base class would be one what returns a report or some other information without returning back any specific objects.
Let's now take a look at an example of a custom cmdlet that we'll eventually package up in a SharePoint Solution Package:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.PowerShell;
using Microsoft.SharePoint.Administration;
using System.Management.Automation;
namespace Lapointe.SharePoint2010.PowerShell.Demo.Quotas
{
[Cmdlet(VerbsCommon.Get, "SPQuotaTemplate"),
SPCmdlet(RequireLocalFarmExist = true, RequireUserFarmAdmin = true)]
public class SPCmdletGetQuotaTemplate : SPGetCmdletBase<SPQuotaTemplate>
{
protected override void InternalValidate()
{
if (this.Identity != null)
{
base.DataObject = this.Identity.Read();
if (base.DataObject == null)
{
base.WriteError(new PSArgumentException("The quota template does not exist."), ErrorCategory.InvalidArgument, this.Identity);
base.SkipProcessCurrentRecord();
}
}
}
protected override IEnumerable<SPQuotaTemplate> RetrieveDataObjects()
{
List<SPQuotaTemplate> list = new List<SPQuotaTemplate>();
if (base.DataObject != null)
{
list.Add(base.DataObject);
return list;
}
SPWebService webService = SPWebService.ContentService;
if (webService != null)
{
foreach (SPQuotaTemplate quota in webService.QuotaTemplates)
{
list.Add(quota);
}
}
return list;
}
[Parameter(Mandatory = false, ValueFromPipeline = true, Position = 0), Alias(new string[] { "Name" })]
public SPQuotaTemplatePipeBind Identity
{
get;
set;
}
}
}
In the code example above I'm returning back SPQuotaTemplate objects based on the Identity (or Name) passed into the cmdlet. If the Identity parameter is not provided then all quota templates are returned to the pipeline. In the InternalValidate method I'm checking if the Identity parameter has been provided, and if it has, I set the base class's DataObject property by calling the Read method of the SPQuotaTemplatePipeBind object. In the override RetrieveDataObjects method I then check the DataObject property and return the value as an item in a generic list. If the DataObject property has not been set then I loop through all existing quota templates and return them as generic list. Note that if you are returning lots of items or large items it is better, and preferable, to directly call the WriteResult method and return back null - for this case I know there are typically not a lot of templates and they are not large so I just return back a single collection rather than calling WriteResult.
Pay particular attention to the SPQuotaTemplatePipeBind type - In SharePoint an object can be represented in numerous ways, for example, an SPSite object can be represented by either an URL or a GUID. In order to prevent the need to multiple parameters to support these various types Microsoft has introduced the PipeBind object which eliminates the need for these superfluous parameters and from having to create multiple parameter sets to support them. In the case of the SPQuotaTemplatePipeBind object I can pass in either an actual instance of an SPQuotaTemplate object or a name representing a quota template.
You're not limited to what is available out of the box. You can easily create your own PipeBind objects by simply inheriting from the SPCmdletPipeBind class. Take a look at the following example which demonstrates how to create a custom SPListPipeBind object:
using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Microsoft.SharePoint.PowerShell;
using System.Management.Automation;
using System.Globalization;
namespace Lapointe.SharePoint2010.PowerShell.Demo.Lists
{
public sealed class SPListPipeBind : SPCmdletPipeBind<SPList>
{
private bool m_IsAbsoluteUrl;
private bool m_IsCollection;
private Guid m_SiteGuid;
private Guid m_WebGuid;
private Guid m_ListGuid;
private string m_WebUrl;
private string m_ListUrl;
public SPListPipeBind(SPList instance)
: base(instance)
{
}
public SPListPipeBind(Guid guid)
{
this.m_ListGuid = guid;
}
public SPListPipeBind(string inputString)
{
if (inputString != null)
{
inputString = inputString.Trim();
try
{
this.m_ListGuid = new Guid(inputString);
}
catch (FormatException)
{
}
catch (OverflowException)
{
}
if (this.m_ListGuid.Equals(Guid.Empty))
{
this.m_ListUrl = inputString;
if (this.m_ListUrl.StartsWith("http", true, CultureInfo.CurrentCulture))
{
this.m_IsAbsoluteUrl = true;
}
if (WildcardPattern.ContainsWildcardCharacters(this.m_ListUrl))
{
this.m_IsCollection = true;
}
}
}
}
public SPListPipeBind(Uri listUri)
{
this.m_ListUrl = listUri.ToString();
}
protected override void Discover(SPList instance)
{
this.m_ListGuid = instance.ID;
this.m_WebGuid = instance.ParentWeb.ID;
this.m_SiteGuid = instance.ParentWeb.Site.ID;
}
public override SPList Read()
{
return this.Read(null);
}
public SPList Read(SPWeb web)
{
SPList list = null;
string parameterDetails = string.Format(CultureInfo.CurrentCulture, "Id or Url : {0}", new object[] { "Empty or Null" });
if (this.IsCollection)
{
return null;
}
try
{
if (Guid.Empty != this.ListGuid)
{
if (web == null && Guid.Empty != this.m_WebGuid && Guid.Empty != this.m_SiteGuid)
{
parameterDetails = string.Format(CultureInfo.CurrentCulture, "Id or Url: {0} and Web Id: {1}", new object[] { this.ListGuid.ToString(), this.m_WebGuid.ToString() });
using (SPSite site = new SPSite(this.m_SiteGuid))
{
web = site.OpenWeb(this.m_WebGuid);
list = web.Lists[ListGuid];
}
}
else
{
parameterDetails = string.Format(CultureInfo.CurrentCulture, "Id or Url: {0} and web Url {1}", new object[] { this.ListUrl, web.Url });
list = web.Lists[ListGuid];
}
}
else if (!string.IsNullOrEmpty(this.ListUrl))
{
string serverRelativeListUrl = null;
if (this.m_IsAbsoluteUrl)
{
serverRelativeListUrl = Utilities.GetServerRelUrlFromFullUrl(this.ListUrl).Trim('/');
}
else
{
serverRelativeListUrl = this.ListUrl.Trim('/');
}
if (web == null)
{
parameterDetails = string.Format(CultureInfo.CurrentCulture, "Id or Url : {0}", new object[] { this.ListUrl });
using (SPSite site = new SPSite(this.ListUrl))
{
web = site.OpenWeb();
}
}
else
{
parameterDetails = string.Format(CultureInfo.CurrentCulture, "Id or Url : {0} and web Url {1}", new object[] { this.ListUrl, web.Url });
}
if (!web.Exists)
{
list = null;
}
else
{
list = web.GetList(serverRelativeListUrl);
}
}
}
catch (Exception exception)
{
throw new SPCmdletPipeBindException(string.Format("The SPList Pipebind object could not be found ({0}).", parameterDetails), exception);
}
if (list == null)
{
throw new SPCmdletPipeBindException(string.Format("The SPList Pipebind object could not be found ({0}).", parameterDetails));
}
return list;
}
public bool IsCollection
{
get
{
return this.m_IsCollection;
}
}
public Guid ListGuid
{
get
{
return this.m_ListGuid;
}
}
public string ListUrl
{
get
{
return this.m_ListUrl;
}
}
}
}
There are two core components that are required for a custom PipeBind object. The first is to have a constructor that takes in the type that you wish to convert (in this example, a string, URI, or GUID) to the target object. The second is to override the Read method which is used to convert the argument value passed into the constructor into the target type. In some cases you'll need additional information which must be provided by the calling code - for example, if a GUID is passed in, representing the List ID, then you will also need to provide the SPWeb object which contains the List; this is done by creating an overload for the Read method which accepts an SPWeb object. It's up to the calling code to determine which overload to call.
Let's now look at how we can package our SPCmdletGetQuotaTemplate class into a SharePoint Solution Package using Visual Studio 2010.
From a new instance of Visual Studio 2010:
- Click File > New > Project to create a new Visual Studio Project
- In the New Project dialog select Visual C#/SharePoint/2010 in the Installed Templates panel and then select Empty Project:

- After you click OK you will be taken to the SharePoint Configuration Wizard:

You can specify any site to use for debugging as we won't be using it for PowerShell development (note that when you start the debugger you'll be given a warning if the specified site's web.config does not allow debugging). PowerShell cmdlets must be deployed to the GAC so select Deploy as full-trust solution and click the Finish button to create the project.
The first thing we need to do with our new empty project is to add a couple of project references:
- Right-click the References folder in the project and select Add Reference...
- In the Add Reference dialog's .NET tab select Microsoft.SharePoint.PowerShell and System.Management.Automation
- Click OK to add the references to the project
Now that we have our references added we can setup our project structure. PowerShell cmdlets are not deployed using Features so we can delete the starting Feature folder that is created:
- Expand the Features folder
- Right-click the Feature1 Feature and click Delete
The next step is to add a SharePoint Mapped Folder:
- Right-click the project and click Add > SharePoint Mapped Folder...
- Add the {SharePointRoot}/Config/PowerShell/Registration folder
- Note that you can add the Format and Help folders as well but I won't be using those in this example as creating help and format files are outside the scope of this article (I usually will add the {SharePointRoot}/Config/PowerShell folder and then manually add the three sub-folders so that I can keep things grouped together in one parent folder within my project).
- Click OK to add the mapped folder
- If a folder is created under the Registration folder then go ahead and delete it (this sub-folder is automatically added in Beta1 but may not be added come RTM)
In the new Registration mapped folder create a new XML file (you can name it anything you like but I usually give it the same name as my project) and paste the following XML into the file:
<?xml version="1.0" encoding="utf-8" ?>
<ps:Config xmlns:ps="urn:Microsoft.SharePoint.PowerShell"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:Microsoft.SharePoint.PowerShell SPCmdletSchema.xsd">
<ps:Assembly Name="$SharePoint.Project.AssemblyFullName$">
<ps:Cmdlet>
<ps:VerbName>Get-SPQuotaTemplate</ps:VerbName>
<ps:ClassName>Lapointe.SharePoint2010.PowerShell.Demo.Quotas.SPCmdletGetQuotaTemplate</ps:ClassName>
<ps:HelpFile>Lapointe.SharePoint2010.PowerShell.Demo.dll-help.xml</ps:HelpFile>
</ps:Cmdlet>
</ps:Assembly>
</ps:Config>
Note that the <ps:HelpFile /> element does require a value but the file specified does not have to exist.
Now we simply need to paste in the code for the SPCmdletGetQuotaTemplate class from above:
- Create a folder below the project root called Quotas
- Add a new class file named SPCmdletGetQuotaTemplate.cs
- Paste the code from above into this file (be sure to adjust your namespaces in the class file and the XML file if you used a different project name than the one shown)
You now have a complete SharePoint 2010 PowerShell Solution - all that's left is to build and deploy it:
- Right-click the project name and select Deploy
Notice what is happening in the output window - IIS application pools are being recycled along with the retraction and deployment of the solution. Because this is a PowerShell solution we don't need IIS to be recycled so let's create a new deployment configuration to remove the recycling of the application pools which should speed up our deployment time:
- Right-click the project and select Properties
- In the properties dialog select the Deploy tab
- In the Edit Configurations group select New to create a new deployment action
- Name the new deployment action PowerShell and configure the deployment steps as shown below:
- Click OK to save the new deployment configuration
Now that we have our custom deployment configuration we need to tell our project to use this configuration. Make sure the Properties Window is visible (type F4 if not) and select the project. Select the PowerShell configuration we just created in the Active Deployment Configuration drop-down.
Our final configuration setting change is to configure the project so that it will open PowerShell when we start the debugger:
- Right-click the project and select Properties to return to the project's properties dialog
- Click the Debug tab
- Select the radio button next to Start external program and specify the following value: C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe
- Paste the following into the Command line arguments text box: -NoExit " & ' C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\POWERSHELL\Registration\sharepoint.ps1 ' "
You can now start the debugger (F5) which will load a PowerShell console and register the SharePoint 2010 snap-in which results in the loading of your new custom cmdlet. To verify that the cmdlet is loaded type Get-Command Get-SPQuotaTemplate | Format-List. You should see the following output:
PS C:\> Get-Command Get-SPQuotaTemplate | Format-List
Name : Get-SPQuotaTemplate
CommandType : Cmdlet
Definition : Get-SPQuotaTemplate [[-Identity] <SPQuotaTemplatePipeBind>]
[-AssignmentCollection <SPAssignmentCollection>] [-Verbose]
[-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <
ActionPreference>] [-ErrorVariable <String>] [-WarningVariab
le <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Path :
AssemblyInfo :
DLL : C:\Windows\assembly\GAC_MSIL\Lapointe.SharePoint2010.PowerSh
ell.Demo\1.0.0.0__xxxxxxxxxxxxxxxx\Lapointe.SharePoint2010.P
owerShell.Demo.dll
HelpFile : C:\Program Files\Common Files\Microsoft Shared\Web Server Ex
tensions\14\CONFIG\PowerShell\Help\Lapointe.SharePoint2010.P
owerShell.Demo.dll-help.xml
ParameterSets : {[[-Identity] <SPQuotaTemplatePipeBind>] [-AssignmentCollect
ion <SPAssignmentCollection>] [-Verbose] [-Debug] [-ErrorAct
ion <ActionPreference>] [-WarningAction <ActionPreference>]
[-ErrorVariable <String>] [-WarningVariable <String>] [-OutV
ariable <String>] [-OutBuffer <Int32>]}
ImplementingType : Lapointe.SharePoint2010.PowerShell.Demo.Quotas.SPCmdletGetQu
otaTemplate
Verb : Get
Noun : SPQuotaTemplate
|
As you can see, creating and deploying custom PowerShell cmdlets for SharePoint 2010 using Visual Studio 2010 is now super easy. The only complexity lies in the logic of the cmdlet itself.
As you probably expected I have already been hard at work on creating some new cmdlets to replace some of my old PowerShell cmdlets as well as a few select STSADM commands. I'll be releasing these new cmdlets with full source shortly - keep checking back here for more example code and downloads!
SharePoint 2010: PSConfig and PowerShell
The information in this article is based on BETA 2 of SharePoint 2010 - there may be differences with the RTM release.
Update 12/18/2009: I've updated the post to reflect BETA 2 changes and have considerably simplified the script removing all the dependencies on helper functions so that the core pieces required to build a basic farm are focused on rather than the complex elements to support tracing and error handling as I previously had it.
If you've ever done a scripted install of SharePoint 2007 then you are familiar with how to script the initial farm creation using psconfig.exe. Unfortunately psconfig is still with us in SharePoint 2010 but we do have some PowerShell cmdlets which replace all the psconfig commands.
Before we look at how to use PowerShell lets refresh our memories by looking at an install script for SharePoint 2007. I usually have two scripts, one for the first server and a second script for additional servers - here's the first script (I've omitted the variable declarations):
1: ECHO %DATE% %TIME%: Building configuration database
2: psconfig -cmd configdb -create -server %SERVER_DB% -database %DB_CONFIG_NAME% -user %ACCT_SPFARM% -password %ACCT_SPFARM_PWD% -admincontentdatabase %DB_CENTRALADMINCONTENT_NAME%
3: if not errorlevel 0 goto errhnd
4:
5: ECHO %DATE% %TIME%: Installing help content
6: psconfig -cmd helpcollections -installall
7: if not errorlevel 0 goto errhnd
8:
9: ECHO %DATE% %TIME%: Securing resources
10: psconfig -cmd secureresources
11: if not errorlevel 0 goto errhnd
12:
13: ECHO %DATE% %TIME%: Installing services
14: psconfig -cmd services -install
15: if not errorlevel 0 goto errhnd
16:
17: ECHO %DATE% %TIME%: Installing features
18: psconfig -cmd installfeatures
19: if not errorlevel 0 goto errhnd
20:
21: ECHO %DATE% %TIME%: Creating central admin site
22: psconfig -cmd adminvs -provision -port %CENTRALADMIN_PORT% -windowsauthprovider enablekerberos
23: if not errorlevel 0 goto errhnd
24:
25: ECHO %DATE% %TIME%: Adding application content to central admin site
26: psconfig -cmd applicationcontent -install
27: if not errorlevel 0 goto errhnd
28:
29: goto end
30:
31: :errhnd
32:
33: echo An error occured - terminating script.
34:
35: :end
And here's the second script (variable declarations omitted):
1: ECHO %DATE% %TIME%: Connecting to farm
2: psconfig -cmd configdb -connect -server %SERVER_DB% -database %DB_CONFIG_NAME% -user %ACCT_SPFARM% -password %ACCT_SPFARM_PWD%
3: if not errorlevel 0 goto errhnd
4:
5: ECHO %DATE% %TIME%: Installing services
6: psconfig -cmd services install
7: if not errorlevel 0 goto errhnd
8:
9: ECHO %DATE% %TIME%: Installing features
10: psconfig -cmd installfeatures
11: if not errorlevel 0 goto errhnd
12:
13: ECHO %DATE% %TIME%: Setting security on registry and file system
14: psconfig -cmd secureresources
15: if not errorlevel 0 goto errhnd
16:
17: goto end
18:
19: :errhnd
20:
21: echo An error occured - terminating script.
22:
23: :end
Obviously the two scripts are very similar with the main difference being the parameters passed to the configdb command and with fewer commands being called. So how would we do this using SharePoint 2010's PowerShell cmdlets? First lets list each psconfig command and what the PowerShell equivalent is:
| PSConfig Command | PowerShell Cmdlet |
|---|---|
| configdb -create | New-SPConfigurationDatabase |
| configdb -connect | Connect-SPConfigurationDatabase |
| helpcollections -installall | Install-SPHelpCollection |
| secureresources | Initialize-SPResourceSecurity |
| services -install | Install-SPService |
| installfeatures | Install-SPFeature (provide the -AllExistingFeatures parameter) |
| adminvs -provision | New-SPCentralAdministration |
| applicationcontent -install | Install-SPApplicationContent |
Now that we know what PowerShell cmdlets to use lets rework our install script. Instead of using a batch file for variables I'm going to use an XML file which can be read in and parsed as needed. I'm also going to make it so that you can run the same script from any server and just specify a switch parameter indicating whether or not you are connecting to an existing farm or not.
Let's first take a look at the XML that we'll use to manage our settings - we'll store this in a file called FarmConfigurations.xml:
<Farm FarmAccount="sp2010\spfarm"
ConfigDB="SharePoint_ConfigDB"
AdminContentDB="SharePoint_Content_Admin"
DatabaseServer="spsql1"
Passphrase="Pa$$w0rd">
<CentralAdmin Port="1234" AuthProvider="NTLM">
<Servers>
<Server Name="spsvr1" />
</Servers>
</CentralAdmin>
</Farm>
In this XML I'm storing the core farm settings in the <Farm /> element which includes attributes for the farm account to use as well as the database server and names for the configuration and central admin content database. I then have a <CentralAdmin /> element which contains the servers that the Central Admin site should be installed on along with the port and authentication provider to use.
So now that we have our configuration settings all we need now is the core script to actually create our farm. I named this script BuildFarm.ps1 but you can name it whatever you want:
function Install-SharePointFarm([bool]$connectToExisting,
[string]$settingsFile = "FarmConfigurations.xml") {
[xml]$config = Get-Content $settingsFile
$farmAcct = Get-Credential $config.Farm.FarmAccount
$configDb = $config.Farm.ConfigDB
$adminContentDb = $config.Farm.adminContentDb
$server = $config.Farm.DatabaseServer
if ($config.Farm.Passphrase.Length -gt 0) {
$passphrase = (ConvertTo-SecureString $config.Farm.Passphrase `
-AsPlainText -force)
} else {
Write-Warning "Using the Farm Admin's password for a passphrase"
$passphrase = $farmAcct.Password
}
#Only build the farm if we don't currently have a farm created
if (([Microsoft.SharePoint.Administration.SPFarm]::Local) -eq $null) {
if ($connectToExisting) {
#Connecting to farm
Connect-SPConfigurationDatabase -DatabaseName $configDb `
-DatabaseServer $server -Passphrase $passphrase
} else {
#Creating new farm
New-SPConfigurationDatabase -DatabaseName $configDb `
-DatabaseServer $server `
-AdministrationContentDatabaseName $adminContentDb `
-Passphrase $passphrase -FarmCredentials $farmAcct
}
#Verifying farm creation
$spfarm = Get-SPFarm -ErrorAction SilentlyContinue -ErrorVariable err
if ($spfarm -eq $null -or $err) {
throw "Unable to verify farm creation."
}
#ACLing SharePoint Resources
Initialize-SPResourceSecurity
#Installing Services
Install-SPService
#Installing Features
Install-SPFeature -AllExistingFeatures
} else {
Write-Warning "Farm already exists. Skipping creation."
}
$installSCA = (($config.Farm.CentralAdmin.Servers.Server | `
where {$_.Name -eq $env:computername}) -ne $null)
$url = "http://$($env:computername):$($config.Farm.CentralAdmin.Port)"
$sca=[Microsoft.SharePoint.Administration.SPWebApplication]::Lookup($url)
if ($installSCA -and $sca -eq $null) {
#Provisioning Central Administration
New-SPCentralAdministration -Port $config.Farm.CentralAdmin.Port `
-WindowsAuthProvider $config.Farm.CentralAdmin.AuthProvider
#Installing Help
Install-SPHelpCollection -All
#Installing Application Content
Install-SPApplicationContent
}
}
Notice that the script takes a parameter which allows you to specify whether you are connecting to an existing farm. We can call the script using the following syntax (replace $false with $true if connecting to an existing farm):
PS C:\> . .\buildfarm.ps1
PS C:\> Install-SharePointFarm $false "FarmConfigurations.xml"
In a series of upcoming post I'll be building on what I created here by demonstrating how to create web applications and how to start each of the services that are included, including the extremely complex search service (gone are the days of a single line setup for search - we now have a dozen or so cmdlets that have to be run to get search started).
SharePoint 2010: STSADM and PowerShell
The information in this article is based on BETA 2 of SharePoint 2010 - there will likely be differences with the RTM release.
Finally, the NDA is lifted and we can openly talk about SharePoint 2010! There's so many cool things to talk about it's hard to decide where to begin, but as the focus of my blog has generally been on STSADM then I suppose that's a good place to start. The first thing we should do is load the new SharePoint 2010 Management Shell which can be found under the Microsoft SharePoint 2010 Products section of the start menu:
This new console window is actually just a PowerShell console which pre-loads the SharePoint PowerShell Snap-in. You can see that by looking at the target for the shortcut:
C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe -NoExit " & ' C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\POWERSHELL\Registration\\sharepoint.ps1 ' "
If you look at the SharePoint.ps1 file you'll see the following:
From this you can see that you can easily load up any PowerShell console app (either the native PowerShell console or a any other editor such as PowerGUI or the PowerShell ISE) and simply run the Add-PsSnapin cmdlet to load the new SharePoint 2010 cmdlets as shown above.
Note that the script is also changing the threading model of PowerShell so that commands are entered in the same thread rather than a different thread for each line of execution (I'll cover this in more detail in a later post but it's important to understand that this has a huge impact on how objects are disposed within PowerShell - see Zach's post about threading here: http://sharepoint.microsoft.com/blogs/zach/Lists/Posts/Post.aspx?ID=34)
I'll cover the PowerShell stuff in bit but first lets take a look at the STSADM changes. I did a simple stsadm -help command and saved that to a file in both my 2007 and 2010 environment and then compared those files. Here's what I found:
- The following STSADM commands no longer exist:
- associatewebapp
- createcmsmigrationprofile
- createssp
- deletecmsmigrationprofile
- deletessp
- deletessptimerjob
- editcmsmigrationprofile
- editssp
- enablecmsurlredirect
- enumssp
- enumssptimerjobs
- grantiis7permission
- listqueryprocessoroptions
- mysite
- preupgradecheck
- restoressp
- runcmsmigrationprofile
- setdefaultssp
- setqueryprocessoroptions
- setsharedwebserviceauthn
- setsspport
- trimauditlog
- The following STSADM commands have been added:
- add-adsdefaultapplication
- add-ecsblockedexcelfiletype
- monitordb
- patchpostaction
- remove-adsdefaultapplication
- remove-ecsblockedexcelfiletype
From the list above you can see that the bulk of the items removed have to do with the SSP and CMS migration features which were part of the 2007 product but have been removed from the 2010 product (2010 has a whole new services architecture which is really cool, but outside the scope of this article - stay tuned! - 2010 also does not support upgrading from Microsoft CMS, you must upgrade to SharePoint 2007 and then SharePoint 2010).
Also note that very few new commands have been added - in fact I was surprised to see that any were added - why? Because PowerShell is what we should all be using - STSADM is dead - just don't use it, forget that these new commands have been added as there are PowerShell equivalents (I wouldn't be surprised if they get pulled come RTM). That said, at beta there may be some stuff that still only exists with STSADM but expect that not to be the case going forward.
So now that we have that out of the way, lets talk about some PowerShell (as of this post I'm officially done creating STSADM extensions - at least for 2010, I may still have need for some new stuff with the 2007 product). In your new SharePoint 4.0 Management Console type the following command: gcm -pssnapin microsoft.sharepoint.powershell | select Name, Definition | fl > .\sp2010cmdlets.txt
Take a look at the file you just generated, you now have a listing of the 535 new PowerShell cmdlets that ship with SharePoint 2010. For brevity sake I won't show the syntax but here's a listing of all the new cmdlets that are available:
| Add-PluggableSecurityTrimmer | New-SPPerformancePointServiceApplication |
If you're going to be working with the SharePoint PowerShell cmdlets then there are two cmdlets that you should learn before any others: Start-SPAssignment and Stop-SPAssignment. If you've used the custom cmdlets that I created for the 2007 product and read my articles around them then you should be familiar with the core issue that I was trying to solve with some of them - the handling of disposable objects. When you use a cmdlet such as Get-SPSite you are returning back a disposable object, an object that implements the IDisposable interface in order to release handles to unmanaged resources which cause memory leaks if not released. I chose to solve the issue by simply not returning back disposable objects and instead using a proxy object. Microsoft chose a different route.
If you look closely at the definitions of the cmdlets from the text file you created above you should notice that every cmdlet has an -AssignmentCollection parameter which takes in an SPAssignmentCollection object type. The purpose of this collection is to store disposable objects so that they can be disposed when your operations complete. You create a new assignment collection by calling the Start-SPAssignment cmdlet. You can then optionally pass the created assignment collection object into your subsequent calls by either using the pipeline or directly setting the parameter (otherwise the global collection will be used). Lets look at the help for the cmdlet to understand this better:
PS C:\> help start-spassignment
NAME
Start-SPAssignment
SYNOPSIS
Initiates a new assignment store.
SYNTAX
Start-SPAssignment [-Global <SwitchParameter>] [<CommonParameters>]
DETAILED DESCRIPTION
Use this command to properly dispose of objects used with variable assignme
nts.
Using SPWeb, SPSite, or SPSiteAdminsitration objects can use large amounts
of memory and using these objects, or lists of these objects, in PowerShell
scripts requires proper memory management. By default, all Get commands di
spose of these objects immediately after the pipeline finishes, but using S
PAssignment, you can assign the list of objects to a variable and dispose o
f the objects after they are no longer needed. You can also ensure that the
objects will remain as long as you need them, even throughout multiple ite
rations of commands.
There are three levels of assignment:
* No assignment - The object is not assigned to a variable and is disposed
of after each iteration of the command.
* Simple assignment - All objects are assigned to the global assignment sto
re. This is done by using the Global parameter. When using this level, al
l objects are assigned to a global store and are disposed of when the Sto
p-SPAssignment command is called.
* Advanced assignment - Objects are assigned to named stores for disposal.
You can dispose of objects by using the -Identity parameter with the Stop
-SPAssignment command.
Regardless of the level used, all objects are disposed of when the PowerShe
ll runspace is closed.
RELATED LINKS
REMARKS
To see the examples, type: "get-help Start-SPAssignment -examples".
For more information, type: "get-help Start-SPAssignment -detailed".
For technical information, type: "get-help Start-SPAssignment -full".
|
As you can see from the help text there are three levels of assignment: No assignment (dispose immediately), simple assignment (use a global store), and advanced assignment (use a named store). Let's take a look at the syntax (note that in Beta 1 most of the help files do not match the actual syntax so I rarely rely on the help text to tell me what the cmdlet syntax is - instead I use the Get-Command (gcm) cmdlet):
PS C:\> gcm Start-SPAssignment -syntax Start-SPAssignment [-Global] [-AssignmentCollection <SPAssignmentCollection>] [ -Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPre ference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable < String>] [-OutBuffer <Int32>] |
If you specify the -Global switch then you do not need to store the returned object or pass it into your cmdlets - internally this cmdlet stores the object in a static variable which is used by all subsequent calls - this is the "simple assignment" method mentioned in the help text. If you do not specify the -Global switch then you must store the returned object in a variable and pass that variable into all subsequent cmdlet calls that return disposable objects and provide the variable to the Stop-SPAssignment cmdlet with the same variable via the -SemiGlobal parameter (this may change to Identity for the RTM) - this is the "advanced assignment" mentioned in the help text. So what about the "no assignment" option? The "no assignment" option is basically when you do not create an SPAssignmentCollection using the Start-SPAssignment cmdlet which causes cmdlets that return disposable objects to dispose of the object immediately after the call to WriteObject. So as long as the pipeline is active the object remains un-disposed but at the end of the pipeline the object is disposed.
So now we'll look at the syntax for the Stop-SPAssignment cmdlet:
PS C:\> gcm Stop-SPAssignment -syntax Stop-SPAssignment [[-SemiGlobal] <SPAssignmentCollection>] [-Global] [-Assignme ntCollection <SPAssignmentCollection>] [-Verbose] [-Debug] [-ErrorAction <Actio nPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-W arningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] |
As you can see this is pretty straightforward, if you used the -Global switch for the Start-SPAssignment cmdlet then you'll use it here, otherwise you would use the -SemiGlobal parameter and pass the variable you created earlier.
Here's a complete example demonstrating both approaches:
#Use of the Global assignment variable Start-SPAssignment -Global $site = Get-SPSite "http://portal" $site | fl Stop-SPAssignment -Global #Use of a semi-global, or named variable $gc = Start-SPAssignment $site = $gc | Get-SPSite "http://mysites" $site | fl $gc | Stop-SPAssignment
For the second example you can see that I'm passing in the variable using the pipeline rather than setting the parameter directly (for both the Get-SPSite cmdlet and the Stop-SPAssignment cmdlet). I could have easily set the parameter names directly but this just results in less code.
So one thing you should be asking is when do I need to do this - every cmdlet takes an SPAssignmentCollection so does that mean that I always have to deal with this stuff? My simple answer is, no, you don't have to do this all the time, only when you know you are working with disposable objects. The problem is that most people don't know when they are working with disposable objects, and in many cases what disposable objects are. So my first best practice recommendation for SharePoint 2010 will be to always use the simple assignment approach (use the global assignment variable) unless you specifically know to do otherwise. So wrap all your scripts with a call to Start-SPAssignment and Stop-SPAssignment. If you have functions that do not return values then wrap those using the advanced approach as shown below:
function Set-SomethingInteresting([string]$siteUrl) { trap { $gc | Stop-SPAssignment } $gc = Start-SPAssignment $site = $gc | Get-SPSite $siteUrl Write-Host "Doing something interesting..." $gc | Stop-SPAssignment } Set-SomethingInteresting "http://mysites"
So as you can see SharePoint 2010 introduces all kinds of really cool stuff - I've literally not even scratched the surface with what you can do with PowerShell and SharePoint 2010, let alone all the cool new features that 2010 introduces. Over the coming weeks and months I hope to provide details on how to do a full scripted install of SharePoint 2010 including detail on how to script out every single service - this will be critical information that every administrator and developer should have as PowerShell is going to be the recommended way to start and configure your services in the new architecture.
Getting an SPWebApplication object using PowerShell
A SharePoint deployment isn’t much of a deployment if there are no web applications. A web application in SharePoint contains one or more content databases, each of which can contain one or more site collections, etc., etc. The SPWebApplication class has tons of methods and properties for directly or indirectly manipulating all things related to web applications - you can do backups, add content databases and site collections, set alert settings, manipulate the web.config file, etc.
There are a couple of different ways in which we can work with the SPWebApplication using PowerShell. The first is to get a specific object using the static Lookup method and the second, which is useful for looping through all web applications, is to use the SPFarm object’s Service property. The first approach is shown below:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") $webapp = [Microsoft.SharePoint.Administration.SPWebApplication]::Lookup("http://portal")
If you need to loop through all web applications you would write something like the following:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") $farm = [Microsoft.SharePoint.Administration.SPFarm]::Local $websvcs = $farm.Services | where -FilterScript {$_.GetType() -eq [Microsoft.SharePoint.Administration.SPWebService]} $webapps = @() foreach ($websvc in $websvcs) { foreach ($webapp in $websvc.WebApplications) { $webapps = $webapps + $webapp } }
The code above isn’t the most intuitive but could be easily wrapped into a function to abstract out the complexity (note that there may be a better way to do the above - I’m still figuring this whole PowerShell thing out:) ). Personally I think the above sucks - it’s not intuitive and it’s difficult to maintain and forces me to do additional filtering if I want a subset of the items returned - thus the motivation behind my Get-SPWebApplication cmdlet. Here’s a couple examples that do the same thing as the above two examples but using my cmdlet instead:
$webapp = Get-SPWebApplication http://portal $webapps = Get-SPWebApplication *
On the first line I’m retrieving a specific web application and on the second line I’m using a wildcard character to retrieve all web applications in the farm. You could easily utilize the wildcard capabilities to reduce the set of web applications that are returned to those matching a specific pattern. You can also pass in multiple, comma separated URLs such as in the following example:
$webapps = Get-SPWebApplication http://portal,http://mysites
The code for the cmdlet is reasonably simple - most of the work is in dealing with the fact that wildcards are allowed thus making it necessary to loop through all the web applications and the corresponding alternate URL mappings in order to identify the web applications to return:
1: using System;
2: using System.Management.Automation;
3: using Lapointe.SharePoint.PowerShell.Commands.OperationHelpers;
4: using Lapointe.SharePoint.PowerShell.Commands.Validators;
5: using Microsoft.SharePoint;
6: using Microsoft.SharePoint.Administration;
7:
8: namespace Lapointe.SharePoint.PowerShell.Commands.WebApplications
9: {
10: [Cmdlet(VerbsCommon.Get, "SPWebApplication", SupportsShouldProcess=true, DefaultParameterSetName = "Url")]
11: public class GetSPWebApplicationCommand : PSCmdletBase
12: {
13: /// <summary>
14: /// Gets or sets the URL.
15: /// </summary>
16: /// <value>The URL.</value>
17: [Parameter(
18: ParameterSetName = "Url",
19: Mandatory = true,
20: Position = 0,
21: ValueFromPipeline = true,
22: ValueFromPipelineByPropertyName = true,
23: HelpMessage = "The URL of the web application to return. Supports wildcards.")]
24: [ValidateNotNullOrEmpty]
25: [ValidateUrl(true)]
26: public string[] Url { get; set; }
27:
28:
29: /// <summary>
30: /// Processes the record.
31: /// </summary>
32: protected override void ProcessRecordEx()
33: {
34: foreach (string url in Url)
35: {
36: if (!WildcardPattern.ContainsWildcardCharacters(url))
37: {
38: string webApp = url.TrimEnd('/');
39: WriteObject(SPWebApplication.Lookup(new Uri(webApp)));
40: }
41: else
42: {
43: WildcardPattern wildCard = new WildcardPattern(url.TrimEnd('/'), WildcardOptions.IgnoreCase);
44: if (SPFarm.Local == null)
45: throw new SPException(
46: "The SPFarm object is null. Make sure you are running as a Farm Administrator.");
47:
48: foreach (SPService svc in SPFarm.Local.Services)
49: {
50: if (!(svc is SPWebService))
51: continue;
52:
53: foreach (SPWebApplication webApp in ((SPWebService) svc).WebApplications)
54: {
55: foreach (SPAlternateUrl altUrl in webApp.AlternateUrls)
56: {
57: if (wildCard.IsMatch(altUrl.Uri.AbsolutePath.TrimEnd('/')))
58: {
59: WriteObject(webApp);
60: break;
61: }
62: }
63: }
64: }
65: }
66: }
67: }
68: }
69: }
Here’s the full help for the cmdlet:
NAME
Get-SPWebApplication
SYNOPSIS
Gets one or more SPWebApplication objects representing a SharePoint 2007 Web Application.
SYNTAX
Get-SPWebApplication [-Url] <String[]> [-WhatIf] [-Confirm] [<CommonParameters>]
DETAILED DESCRIPTION
Pass in a comma separated list of URLs or a string array of URLs to obtain a collection of SPWebAppl
ication objects.
Copyright 2008 Gary Lapointe
> For more information on these PowerShell cmdlets:
> http://blog.falchionconsulting.com/
> Use of these cmdlets is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-Url <String[]>
Specifies the URL of the web application(s) to retrieve. Wildcards are permitted. If you specify
multiple URLs, use commas to separate the URLs.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-WhatIf
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-Confirm
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: -Verbose, -Debug,
-ErrorAction, -ErrorVariable, and -OutVariable. For more information,
type, "get-help about_commonparameters".
INPUT TYPE
String
RETURN TYPE
Collection of SPWebApplication objects.
NOTES
For more information, type "Get-Help Get-SPWebApplication -detailed". For technical information,
type "Get-Help Get-SPWebApplication -full".
-------------- EXAMPLE 1 --------------
C:\PS>$webapp = get-spwebapplication -url http://portal
This example returns back a single SPWebApplication object.
RELATED LINKS
http://blog.falchionconsulting.com
|


![SNAGHTML16554e82[4] SNAGHTML16554e82[4]](http://blog.falchionconsulting.com/wp-content/Images/Programmatically-Setting-SharePoint-2010_12AEE/SNAGHTML16554e824.png)