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.
Getting (and taking ownership of) Checked Out Files using Windows PowerShell
Often when I’m working on a project I need to generate a list of all checked out files and provide that to my client just prior to release to production. Sometimes the client will manually inspect each of them and act as they see fit and other times they’ll ask me to just batch publish all of them (for which I use my Publish-SPListItems cmdlet). So, how do I generate the report for the client? It’s actually pretty easy using PowerShell and a couple of quick loops. Here’s an example that loops through every Site Collection in the Farm and generates a nice report:
function Get-CheckedOutFiles() { foreach ($web in (Get-SPSite -Limit All | Get-SPWeb -Limit All)) { Write-Host "Processing Web: $($web.Url)..." foreach ($list in ($web.Lists | ? {$_ -is [Microsoft.SharePoint.SPDocumentLibrary]})) { Write-Host "`tProcessing List: $($list.RootFolder.ServerRelativeUrl)..." foreach ($item in $list.CheckedOutFiles) { if (!$item.Url.EndsWith(".aspx")) { continue } $hash = @{ "URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)"); "CheckedOutBy"=$item.CheckedOutBy; "CheckedOutByEmail"=$item.CheckedOutByEmail } New-Object PSObject -Property $hash } foreach ($item in $list.Items) { if ($item.File.CheckOutStatus -ne "None") { if (($list.CheckedOutFiles | where {$_.ListItemId -eq $item.ID}) -ne $null) { continue } $hash = @{ "URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)"); "CheckedOutBy"=$item.File.CheckedOutByUser; "CheckedOutByEmail"=$item.File.CheckedOutByUser.Email } New-Object PSObject -Property $hash } } } $web.Dispose() } } Get-CheckedOutFiles | Out-GridView
Running the above will generate a fairly nice report with URLs and usernames and whatnot; you could also use the Export-Csv cmdlet to dump the results to a CSV file that you can then hand off to your end-users. One cool thing to point out about this is that it will also show you files that you normally can’t see – that is files that have been created by other users but have never had a check in. This is actually pretty cool and I stumbled upon this when trying to fine tune my Publish-SPListItems cmdlet. You see, if the file has never been checked in then iterating through the SPListItemCollection object will not reveal the item (or file I should say); this meant that my cmdlet, as it was previously written, was missing a bunch of files. So to work around this all I had to do was add an additional loop to iterate over the collection returned by the SPDocumentLibrary’s CheckedOutFiles property. For each SPCheckedOutFile object in that collection I then call TakeOverCheckOut() to grab the checked out file so that I can then publish.
I use this enough that I decided to turn it into a cmdlet that is now part of my custom extensions. Like the above script, I return back a custom object that contains the full URLs and other useful information (such as the List, Site, and Site Collection identifiers). I also exposed a TakeOverCheckOut() and Delete() method which simply calls Microsoft’s implementation of those methods.
I called this cmdlet Get-SPCheckedOutFiles (note that I’d previously released this cmdlet under the name Get-SPFilesCheckedOut but have since reworked and renamed that original implementation).
Here’s the full help for the cmdlet:
PS C:\Users\spadmin> help Get-SPCheckedOutFiles -full
NAME
Get-SPCheckedOutFiles
SYNOPSIS
Retrieves check out details for a given List, Web, or Site.
SYNTAX
Get-SPCheckedOutFiles [-Site] <SPSitePipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Get-SPCheckedOutFiles [-Web] <SPWebPipeBind> [-ExcludeChildWebs <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
Get-SPCheckedOutFiles [[-Web] <SPWebPipeBind>] [-List] <SPListPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]
DESCRIPTION
Retrieves check out details for a given List, Web, or Site.
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
-Site <SPSitePipeBind>
Specifies the URL or GUID of the Site to inspect.
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
-Web <SPWebPipeBind>
Specifies the URL or GUID of the Web to inspect.
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 SPWeb object.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-List <SPListPipeBind>
The list whose checked out files are to be returned.
The value must be a valid URL in the form http://server_name/lists/listname or /lists/listname. If a server relative URL is provided then the Web parameter must be provided.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-ExcludeChildWebs [<SwitchParameter>]
Excludes all child sites and only considers the specified site.
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 Get-SPCheckedOutFiles -detailed". For technical information, type "Get-Help Get-SPCheckedOutFiles -full".
------------------EXAMPLE------------------
PS C:\> Get-SPCheckedOutFiles -Site "http://server_name/"
This example outputs a list of files that are checked out for the given Site Collection
RELATED LINKS
Get-SPFile
In the following example I’m retrieving pages from the root Pages library that are checked out:

In this example I am running the cmdlet as the aptillon\spadmin user and I’m now able to see the checkout by the user aptillon\glapointe. I ran the cmdlet twice so you could see the default tabular view as well as the more detailed view. Again, you could easily use the Export-Csv cmdlet to dump this information to a file that you can provide your end-users.
I hope you find this cmdlet useful – it personally has proven invaluable to me, particularly when working on anonymous access internet sites as end-users are notorious about creating pages and not getting them checked in.
P.S. With this release the Publish-SPListItems cmdlet has been updated to now consider files that don’t have any existing check-ins.
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!
Service Accounts and Managed Service Accounts in SharePoint 2010
With SharePoint 2010 we now have the ability to allow SharePoint to manage various service accounts thus foregoing the need to have IT administrators manually manage password changes. This new feature is a great benefit to SharePoint administrators and security conscious admins in general as it allows us to easily enforce our corporate security policies by changing these passwords on a schedule, and the administrators don’t even know what the password is so the likelihood of a compromise due to a disgruntled admin, though not eliminated, is somewhat reduced.
But the introduction of this new feature isn’t all good. The complication comes from the fact that SharePoint 2010 doesn’t implement this capability consistently. So an account that is configured as a Managed Service Account and set to have its password changed automatically could also be used in certain places that don’t understand the managed account concept. When the managed account password is changed the feature that uses that account and only knows the username and password (so it does not use the managed account details) will effectively be broken. As an example, if you configure the Enterprise Search Service to use a managed account whose password is scheduled to be changed every 30 days and you use that same account for the content crawl account then when that password is changed the content crawl will cease to function as it will be unable to authenticate the account. It’s important to note, however, that this issue only comes to light when you configure the managed account to have it’s password changed automatically.
So what things can be managed accounts and what cannot? The following lists what I’ve come across so far (if I’ve missed anything please leave a comment so I can update these lists):
Managed Service Accounts:
- All Service Application Pool Accounts
- Access Service Application
- BCS Service Application
- Excel Services Service Application
- Metadata Service Application
- PerformancePoint Service Application
- Enterprise Search Service Application
- Secure Store Service Application
- Subscription Settings Service Application
- User Profile Service Application
- Visio Services Service Application
- Web Analytics Service Application
- Word Automation Service Application
- Word Viewing Service Application
- PowerPoint Viewing Service Application
- Security Token Service Application
- All Content Web Application Pools
- Service Instances
- Claims to Windows Token Service
- Document Conversion Launcher Service
- Document Conversion Load Balancer Service
- Microsoft SharePoint Foundation Sandboxed Code Service
- SharePoint Foundation Help Search
- SharePoint Server Search (Enterprise Search)
- Web Analytics Data Processing Service
Service Accounts (should not be managed):
- Search Crawl Accounts
- For Foundation Search and Server (Enterprise) Search
- Unattended User Accounts
- Excel Services Service Application
- Visio Services Service Application
- PerformancePoint Service Application
- (in general, any Secure Store application credentials)
- Object Cache Portal Accounts
- Super User Account
- Super Reader Account
- User Profile
- Synchronization Service Account (listed incorrectly on the FarmCredentialManagement.aspx page)
- Synchronization Connection Account
- Server Search Custom Crawl Rule Accounts
- Any crawl rule that specifies an account other than the default crawl account
Again, these are just the accounts that I’ve personally bumped up against so it may not be a complete listing.
Viewing and Creating Managed Accounts
To see the current list of Managed Service Accounts using Central Admin go to Security –> Configure managed accounts:
You can edit the settings for any managed account by simply clicking the edit icon associated with the account you wish to modify. Once on the Manage Account screen you can configure the automatic password change settings:
To perform the same tasks using Windows PowerShell we can use the Get-SPManagedAccount cmdlet to retrieve the list of managed accounts:

Or we can retrieve a specific account using the -Identity parameter or by passing in a Web Application or Service:

clTo change the settings for a Managed Account we can use the Set-SPManagedAccount cmdlet:
To create a new Managed Account we use the New-SPManagedAccount cmdlet. In the example below I’m manually creating a PSCredential object so that I can specify my password (pa$$w0rd) in script (very useful for building out dev or test environments – otherwise you should use Get-Credential to prompt for the password so that it is not hard coded anywhere):

Applying Managed Accounts
Once you have your Managed Accounts created you can begin to use them for things such as Service Instances and Service and Content Application Pools. To associate a managed account with a specific Service Instance using Central Admin you can go to Security –> Configure service accounts. On the Service Accounts page you can set the account used for the Farm Account, Service Instances, Web Content Application Pools, and Service Application Pools. The Service Instances are highlighted in the following image:
Service Instances
To set the account associated with a particular Service Instance using Windows PowerShell we simply get the ProcessIdentity property of the Service Instance and set its Username property. Once set we call Update() to update the Configuration Database and then Deploy() to push the change out to all Service Instances. To make this easier I put this code in a function that I can call by passing in the Service Instance and credentials to use:
function Set-ServiceIdentity($svc, $username)
{
$pi = $svc.Service.ProcessIdentity
if ($pi.Username-ne $username) {
$pi.Username= $username
$pi.Update()
$pi.Deploy()
}
}
Here’s an example of how you can call this function:

Service Application Pools
To create a new Service Application pool we use the New-SPServiceApplicationPool cmdlet and pass in the name of the Application Pool to create and the Managed Account to assign as the Application Pool identity:

It’s extremely important to note that the application pool that you create using the New-ServiceApplicationPool cmdlet cannot be used for your content Web Applications. Unfortunately there is no out-of-the-box equivalent for creating Application Pools for Web Applications.
Web Application Pools
As previously noted there is no cmdlet for creating Application Pools for Web Applications. Instead what you need to do is first check if the Application Pool you need already exists by using the SPWebService’s ContentService static property. If it exists then pass in just the name of the Application Pool to the New-SPWebApplication cmdlet, otherwise pass in the name and the Managed Account to use as the Application Pool’s identity:

Applying Service Accounts
When it comes to applying non-managed accounts to the various features things get a little more complicated. Let’s start with the Crawl Accounts.
SharePoint Foundation Search Service
For SharePoint Foundation Search we can set the crawl account (or content access account) using Central Admin by navigating to the Services on Server page and clicking the SharePoint Foundation [Help] Search link which takes you to the settings page where we can set the crawl account:
To set the same information using Windows PowerShell we actually have to go old-school and use STSADM as there’s no PowerShell equivalent cmdlet. Here’s a snippet of PowerShell code that I use to accomplish this:
function ConvertTo-UnsecureString([System.Security.SecureString]$string) { $unmanagedString = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($string) $unsecureString = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($unmanagedString) [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($unmanagedString) return $unsecureString } $searchSvcAccount = Get-Credential "localdev\spsearchsvc" $crawlAccount = Get-Credential "localdev\spcrawl" $stsadmArgs = "-o spsearch -action start " + ` "-farmserviceaccount `"$($searchSvcAccount.Username)`" " + ` "-farmservicepassword `"$(ConvertTo-UnsecureString $searchSvcAccount.Password)`" " + ` "-farmcontentaccessaccount `"$($crawlAccount.Username)`" " + ` "-farmcontentaccesspassword `"$(ConvertTo-UnsecureString $crawlAccount.Password)`" " + ` "-databaseserver `"spsql1`" " + ` "-databasename `"SharePoint_FoundationSearch`"" Write-Host "Running: stsadm $stsadmArgs" $stsadmoutput = cmd /c "stsadm $stsadmArgs" 2>&1 if ($lastexitcode -ne 0) { throw "Unable to start Foundation Search Service.`n$stsadmoutput" }
Note that I’m using a helper function to convert the secure password to a static string which I can then pass to the STSADM spsearch command.
SharePoint Server Search Service
To manage the crawl account for the SharePoint Server Search Service (also known as the Enterprise Search Service) using Central Admin we simply need to navigate to the Search Administration page of the Service Application that we wish to modify and click the link for the Default content access account. This will bring up the following screen:
Note that by default this account will be set to be the same account you used for the Search Service Instance which is a Managed Account. If you do not change this account and you have configured SharePoint to manage the account password then your crawls will fail when the password changes. To make this change using Windows PowerShell we use the Set-SPEnterpriseSearchServiceApplication cmdlet:
$crawlAccount = Get-Credential "localdev\spcrawl"
$searchApp | Set-SPEnterpriseSearchServiceApplication -DefaultContentAccessAccountPassword $crawlAccount.Password -DefaultContentAccessAccountName $crawlAccount.Username
Remember not to do this step until after you have provisioned the Administration Component.
Object Cache Accounts
Many administrators when they first configure SharePoint 2010 and hit a Web Application for the first time are likely to see a recurring event in the event log stating that the object cache has not been configured correctly. The specific error is as follows:
Object Cache: The super user account utilized by the cache is not configured. This can increase the number of cache misses, which causes the page requests to consume unneccesary system resources.
This is essentially telling you that you have missed a manual configuration step in which you need to run some PowerShell to set two accounts for SharePoint to use to access the object cache:
function Set-WebAppUserPolicy($webApp, $userName, $userDisplayName, $perm) { [Microsoft.SharePoint.Administration.SPPolicyCollection]$policies = $webApp.Policies [Microsoft.SharePoint.Administration.SPPolicy]$policy = $policies.Add($userName, $userDisplayName) [Microsoft.SharePoint.Administration.SPPolicyRole]$policyRole = $webApp.PolicyRoles | where {$_.Name -eq $perm} if ($policyRole -ne $null) { $policy.PolicyRoleBindings.Add($policyRole) } $webApp.Update() } $webApp = Get-SPWebApplication "http://content" $portalSuperUserAccount = Get-Credential "localdev\SPSuperUser" $webApp.Properties["portalsuperuseraccount"] = $portalSuperUserAccount.UserName Set-WebAppUserPolicy $webApp $portalSuperUserAccount.UserName $portalSuperUserAccount.UserName "Full Control" $portalSuperReaderAccount = Get-Credential "localdev\SPSuperReader" $webApp.Properties["portalsuperreaderaccount"] = $portalSuperReaderAccount.UserName Set-WebAppUserPolicy $webApp $portalSuperReaderAccount.UserName $portalSuperReaderAccount.UserName "Full Read"
Make sure that you do not use the same account for both the super user and super reader. (And of course make sure you change the URL and account names to match your environment). For more information about these settings see the following TechNet article: http://technet.microsoft.com/en-us/library/ff758656.aspx
Unattended Accounts
There are some services, specifically the Visio Services Service Application, the Excel Services Service Application, and the PerformancePoint Service Application, that allow us to set an account that we can use for access data sources behind the scenes. These are called unattended access accounts. To set these accounts we must create a new target application in the Secure Store Service Application and associate the target application’s ID with the appropriate Service Application. The following PowerShell code demonstrates how to do this for the Visio Services Service Application (the Excel Services Service Application is virtually identical and just uses cmdlets specific to Excel rather than Visio; PerformancePoint is a lot simpler):
#Get the Visio Service App $svcApp = Get-SPServiceApplication | where {$_.TypeName -like "*Visio*"} #Get the existing unattended account app ID $unattendedServiceAccountApplicationID = ($svcApp | Get-SPVisioExternalData).UnattendedServiceAccountApplicationID #If the account isn't already set then set it if ([string]::IsNullOrEmpty($unattendedServiceAccountApplicationID)) { #Get our credentials $unattendedAccount = Get-Credential "localdev\SPUnattended" #Set the Target App Name and create the Target App $name = "$($svcApp.ID)-VisioUnattendedAccount" Write-Host "Creating Secure Store Target Application $name..." $secureStoreTargetApp = New-SPSecureStoreTargetApplication -Name $name ` -FriendlyName "Visio Services Unattended Account Target App" ` -ApplicationType Group ` -TimeoutInMinutes 3 #Set the group claim and admin principals $groupClaim = New-SPClaimsPrincipal -Identity "nt authority\authenticated users" -IdentityType WindowsSamAccountName $adminPrincipal = New-SPClaimsPrincipal -Identity "$($env:userdomain)\$($env:username)" -IdentityType WindowsSamAccountName #Set the account fields $usernameField = New-SPSecureStoreApplicationField -Name "User Name" -Type WindowsUserName -Masked:$false $passwordField = New-SPSecureStoreApplicationField -Name "Password" -Type WindowsPassword -Masked:$false $fields = $usernameField, $passwordField #Set the field values $secureUserName = ConvertTo-SecureString $unattendedAccount.UserName -AsPlainText -Force $securePassword = $unattendedAccount.Password $credentialValues = $secureUserName, $securePassword #Get the service context $subId = [Microsoft.SharePoint.SPSiteSubscriptionIdentifier]::Default $context = [Microsoft.SharePoint.SPServiceContext]::GetContext($svcApp.ServiceApplicationProxyGroup, $subId) #Check to see if the Secure Store App already exists $secureStoreApp = Get-SPSecureStoreApplication -ServiceContext $context -Name $name -ErrorAction SilentlyContinue if ($secureStoreApp -eq $null) { #Doesn't exist so create. Write-Host "Creating Secure Store Application..." $secureStoreApp = New-SPSecureStoreApplication -ServiceContext $context ` -TargetApplication $secureStoreTargetApp ` -Administrator $adminPrincipal ` -CredentialsOwnerGroup $groupClaim ` -Fields $fields } #Update the field values Write-Host "Updating Secure Store Group Credential Mapping..." Update-SPSecureStoreGroupCredentialMapping -Identity $secureStoreApp -Values $credentialValues #Set the unattended service account application ID $svcApp | Set-SPVisioExternalData -UnattendedServiceAccountApplicationID $name }
When it comes to PerformancePoint we have a lot less work we need to do as the product team was nice enough to make it so that the Set-SPPerformancePointSecureDataValues does all the work of setting up the target application for us (note though that they did screw up how the Service Application is passed into the cmdlet requiring you to pass in the ID of the Service Application rather than the actual Service Application object):
$unattendedAccount = Get-Credential "localdev\SPUnattended" $secureValues = Get-SPPerformancePointSecureDataValues -ServiceApplication $svcApp.Id if ($secureValues.DataSourceUnattendedServiceAccount -ne $unattendedServiceAccount.UserName) { Write-Host "Setting unattended service account $($unattendedServiceAccount.UserName)..." $svcApp.Id | Set-SPPerformancePointSecureDataValues -DataSourceUnattendedServiceAccount $unattendedServiceAccount }
User Profile Synchronization Service Identity
One thing to watch out for is when setting the account for the User Profile Synchronization Service. This service wants you to use the Farm Account as the identity. This means that your Farm Admin account cannot have it’s password managed by SharePoint if you intend to use this service (or at least, it shouldn’t be unless you don’t mind manually fixing this service every time your password changes – good luck with that BTW). Your Farm Admin account will always be a Managed Account (you can’t change that) so be extra careful when changing this accounts password (either manually or automatically). To set this account using Central Admin you can click Start next to the User Profile Synchronization Service entry on the Services on Server page.
To accomplish the same thing using PowerShell we need to get an instance of the Synchronization Service and set a few properties and call the SetSynchronizationMachine method passing in the username and password of the Farm Admin account (note that it requires the password be passed in as a standard string and not a secure string so I use my previously defined ConvertTo-UnsecureString function):
$syncMachine = Get-SPServer "sp2010dev" $profApp = Get-SPServiceApplication | where {$_.Name -eq "User Profile Service Application 1"} $account = Get-Credential "localdev\spfarm" if ($syncMachine.Address -eq $env:ComputerName) { $syncSvc = Get-SPServiceInstance -Server $env:ComputerName | where {$_.TypeName -eq "User Profile Synchronization Service"} $syncSvc.Status = [Microsoft.SharePoint.Administration.SPObjectStatus]::Provisioning $syncSvc.IsProvisioned = $false $syncSvc.UserProfileApplicationGuid = $profApp.Id $syncSvc.Update() $profApp.SetSynchronizationMachine($syncMachine.Address, $syncSvc.Id, $account.UserName, (ConvertTo-UnsecureString $account.Password)) } if ($syncSvc.Status -ne "Online") { Write-Host "Starting User Profile Synchronization Service..." Start-SPServiceInstance $syncSvc } do {Start-Sleep 2} while ((Get-SPServiceInstance -Server $env:ComputerName | where {$_.TypeName -eq "User Profile Synchronization Service"}).Status -ne "Online")
Summary
As you can see setting the accounts that are used throughout SharePoint 2010 is anything but consistent and in some cases a real pain in the a$$. I know I didn’t cover how to set every account (custom crawl rule accounts, user profile sync connection accounts, others?) but hopefully someone out there has already documented these, or if not perhaps they’d be nice enough to post a comment here for others benefit from (maybe one day I’ll add them myself but for now I think this post is quite long enough). As always, please let me know if I’ve missed something or otherwise got something wrong as I certainly don’t claim to have all the answers.
Happy PowerShelling ![]()
Getting an Inventory of All SharePoint Documents Using Windows PowerShell
I got an email today asking if I had anything that would generate a report detailing all the documents throughout an entire SharePoint Farm. As this wasn’t the first time I’ve been asked this same question I decided that I’d just go ahead and post the script for generating such a report.
The script is really quite straightforward – it simply iterates through all Web Applications, Site Collections, Webs, Lists, and finally, List Items. I skip any List that is not a Document Library (as well as the Central Admin site) and then build a hash table containing all the data I want to capture. I then convert that hash table to an object which is written to the pipeline.
All of this is placed in a function which I can call and then pipe the output to something like the Out-GridView cmdlet or the Export-Csv cmdlet. I also wrote the script so that it works with either SharePoint 2007 or SharePoint 2010 so that I don’t have to maintain two versions (I could have used cmdlets such as Get-SPWebApplication, Get-SPSite, and Get-SPWeb but there was little benefit to doing so and the script would be limited to SharePoint 2010).
One word of caution – in a large Farm this script should be run off hours or at least on a back facing server (not your WFE) – it’s going to generate a lot of traffic to your database.
function Get-DocInventory() { [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") $farm = [Microsoft.SharePoint.Administration.SPFarm]::Local foreach ($spService in $farm.Services) { if (!($spService -is [Microsoft.SharePoint.Administration.SPWebService])) { continue; } foreach ($webApp in $spService.WebApplications) { if ($webApp -is [Microsoft.SharePoint.Administration.SPAdministrationWebApplication]) { continue } foreach ($site in $webApp.Sites) { foreach ($web in $site.AllWebs) { foreach ($list in $web.Lists) { if ($list.BaseType -ne "DocumentLibrary") { continue } foreach ($item in $list.Items) { $data = @{ "Web Application" = $webApp.ToString() "Site" = $site.Url "Web" = $web.Url "list" = $list.Title "Item ID" = $item.ID "Item URL" = $item.Url "Item Title" = $item.Title "Item Created" = $item["Created"] "Item Modified" = $item["Modified"] "File Size" = $item.File.Length/1KB } New-Object PSObject -Property $data } } $web.Dispose(); } $site.Dispose() } } } } Get-DocInventory | Out-GridView #Get-DocInventory | Export-Csv -NoTypeInformation -Path c:\inventory.csv
Deploying SharePoint 2010 Solution Packages Using PowerShell
Update 4/19/2011: I've reworked this script completely. You can find the update here: http://blog.falchionconsulting.com/index.php/2011/04/deploying-sharepoint-2010-solution-package-using-powershell-revisited/
With SharePoint 2010 we can now deploy our Solution Packages using PowerShell. What’s cool about this is that it’s a bit easier than it was with 2007 to check if a package is already deployed and conditionally retract, delete, and then re-add and re-deploy. By now most people already know how to do this as it’s fairly straightforward but I thought I’d go ahead and share the script that I use as it’s great for deploying lots of Solution Packages to my various client environments in bulk.
Like most of my scripts this one is driven by an XML file but I have a core function which can be called directly – I just wrap that in another function which can iterate through the XML file thus facilitating bulk installs of packages. First lets look at the XML file:
<Solutions>
<Solution Path="W:\my.sharepoint.package.wsp" CASPolicies="false" GACDeployment="true">
<WebApplications>
<WebApplication>http://portal</WebApplication>
</WebApplications>
</Solution>
</Solutions>
As you can see the structure is fairly simplistic – just provide the path to the WSP file and whether it contains CAS policies and whether it should be deployed to the GAC or not. If it’s a Farm level solution (no web application resources) then simply omit the <WebApplications /> element. If you have more than one solution just add another <Solution /> element. If you’re deploying to multiple web applications then add as many <WebApplication /> elements as is needed.
Now we’ll take a look at the wrapper function which loops through the XML:
function Install-Solutions([string]$configFile) { if ([string]::IsNullOrEmpty($configFile)) { return } [xml]$solutionsConfig = Get-Content $configFile if ($solutionsConfig -eq $null) { return } $solutionsConfig.Solutions.Solution | ForEach-Object { [string]$path = $_.Path [bool]$gac = [bool]::Parse($_.GACDeployment) [bool]$cas = [bool]::Parse($_.CASPolicies) $webApps = $_.WebApplications.WebApplication Install-Solution $path $gac $cas $webApps } }
As you can see the code just loads the passed in file as an XmlDocument object and grabs each Solution element ($solutionsConfig.Solutions.Solution) and then iterates through each object using the ForEach-Object cmdlet. For pure convenience I grab each attribute and assign it to a local variable. And finally I call the Install-Solution function which is shown below:
function Install-Solution([string]$path, [bool]$gac, [bool]$cas, [string[]]$webApps = @()) { $spAdminServiceName = "SPAdminV4" [string]$name = Split-Path -Path $path -Leaf $solution = Get-SPSolution $name -ErrorAction SilentlyContinue if ($solution -ne $null) { #Retract the solution if ($solution.Deployed) { Write-Host "Retracting solution $name..." if ($solution.ContainsWebApplicationResource) { $solution | Uninstall-SPSolution -AllWebApplications -Confirm:$false } else { $solution | Uninstall-SPSolution -Confirm:$false } Stop-Service -Name $spAdminServiceName Start-SPAdminJob -Verbose Start-Service -Name $spAdminServiceName #Block until we're sure the solution is no longer deployed. do { Start-Sleep 2 } while ((Get-SPSolution $name).Deployed) } #Delete the solution Write-Host "Removing solution $name..." Get-SPSolution $name | Remove-SPSolution -Confirm:$false } #Add the solution Write-Host "Adding solution $name..." $solution = Add-SPSolution $path #Deploy the solution if (!$solution.ContainsWebApplicationResource) { Write-Host "Deploying solution $name to the Farm..." $solution | Install-SPSolution -GACDeployment:$gac -CASPolicies:$cas -Confirm:$false } else { if ($webApps -eq $null -or $webApps.Length -eq 0) { Write-Warning "The solution $name contains web application resources but no web applications were specified to deploy to." return } $webApps | ForEach-Object { Write-Host "Deploying solution $name to $_..." $solution | Install-SPSolution -GACDeployment:$gac -CASPolicies:$cas -WebApplication $_ -Confirm:$false } } Stop-Service -Name $spAdminServiceName Start-SPAdminJob -Verbose Start-Service -Name $spAdminServiceName #Block until we're sure the solution is deployed. do { Start-Sleep 2 } while (!((Get-SPSolution $name).Deployed)) }
The code looks more complicated than it really is. I first start out by getting the solution name which I always assume to be the filename of the WSP file. I then use that to get the SPSolution object using Get-SPSolution. If a value comes back then I check if it has been deployed and if it has then I retract it by calling Uninstall-SPSolution. The trick is knowing whether it has web application scoped resources and if it does then we need to retract using the -AllWebApplications parameter. Once retracted I stop the SharePoint Administration Service (SPAdminV4) so that I can call Start-SPAdminJob and force the retraction timer job to execute. Once the Start-SPAdminJob cmdlet returns I then restart the SharePoint Administration Service. With the solution retracted I can now delete the solution from the solution store using Remove-SPSolution (I re-get the solution to make sure that I get no errors due to the current variables state being invalid).
Once deleted I can then add the new solution to the store using the path provided (Add-SPSolution). Now that it’s in the store I can check if it has web application resources or not – if it does not then the deployment is simply a matter of calling Install-SPSolution and specifying whether it should be deployed to the GAC and if it contains CAS policies. If it does contain web application resources then I have to loop through all the web application items in the provided string array ($webApps) and then pass each one into a separate call to Install-SPSolution.
You now have two options for adding your solution: you can call the first function and pass in an XML file or you can call the second function directly. I’ll first show how to call the second function directly:
PS C:\>Install-Solution "w:\my.sharepoint.package.wsp" $true $false @("http://portal","http://mysites")
Now lets look at how to call the first function given an XML file named “solutions.xml” containing a structure similar to that shown above:
PS C:\>Install-Solutions "w:\solutions.xml"
Hopefully you’ll find this script useful for deploying your custom SharePoint 2010 Solution Packages.












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