Microsoft SharePoint quickly spreads through the enterprise because it’s very easy to use. Unfortunately, that often means that it’s easy to abuse, too.

To manage the ever-growing spread of SharePoint, we often write governance plans that mandate the auditing and policing of users, content, and policies. Which tools can you use to perform these audits or even just to find out what's happening in your SharePoint installation? Third-party tools can handle some of the necessary inventories and auditing, but you already have a great instrument in your toolkit: Windows PowerShell.

Both SharePoint 2010 and SharePoint 2013 ship with a custom shell, called the SharePoint 2010 (or SharePoint 2013) Management Shell, which automatically loads the SharePoint PowerShell cmdlets. SharePoint 2007 has not been left out; with an extra line or two of PowerShell to reference SharePoint DLLs, you can perform the same tasks as within the newer SharePoint versions.

SharePoint Permissions

PowerShell neither avoids nor works around SharePoint security, although it does add an additional requirement or two. By default, you cannot access any SharePoint content or feature to which you do not already have permissions. For more information on the necessary permissions and how to set them up, see the Microsoft article "Use Windows PowerShell to Administer SharePoint 2013."

PowerShell for SharePoint 2007

Although the examples in this article generally use SharePoint 2010 PowerShell cmdlets such as Get-SPSite and Get-SPWeb, SharePoint 2007 users are not left out of the PowerShell experience. But you will need to do just a little more work. You can either use custom cmdlets (available on my blog) or write a few extra lines of code. (Most of the examples in this article can be entered as a single line of code.)

For example, in SharePoint 2010, we can get the title of a SharePoint subsite by using the Get-SPWeb cmdlet:

                              $web = Get-SPWeb http://sharepoint/blog                              $web.Title                               

The site title is then displayed. If you are using SharePoint 2007 (or otherwise working with PowerShell without the SharePoint 2010 cmdlets), you can get the site title this way:

                              [System.Reflection.Assembly]::LoadWithPartialName                              ("Microsoft.SharePoint")                              $sitecollection = New-Object Microsoft.SharePoint.SPSite                              ("http://sharepoint/blog")                              $web = $sitecollection.AllWebs["blog"]                              $web.Title                               

 

Note that this code is entered as four distinct lines. The first line tells PowerShell to load the SharePoint libraries. The second line creates a site collection object. The remaining lines create the subsite object. You do a little more typing, but in the end you get the same results as when using the Get-SPWeb cmdlet.

 

Most of the SharePoint objects that the SharePoint 2010 cmdlets return can be created by using similar techniques. See my blog for more examples.

Disposing of Objects

To avoid memory issues when writing custom code, developers must carefully dispose of the objects that they create. You can also create objects in PowerShell. As a good coder, you probably want to dispose of some of these objects -- if you only knew which ones. Microsoft has a good (and long) document on object disposal in SharePoint, but it’s probably more than you want to know about the topic. Although SharePoint 2007 scripters should perform a web search on the topic, SharePoint 2010 scripters have two bonus cmdlets to help them automatically deal with object disposal. All you need to do is wrap your scripts between the Start-SPAssignment and Stop-SPAssignment cmdlets:

                              Start-SPAssignment -Global                              # Your script goes here.                              Stop-SPAssignment -Global                              

SharePoint PowerShell Example

To give you an example of how to use SharePoint for auditing, let's start by inventorying a few SharePoint items, such as site collections (referred to within SharePoint as sites) and websites (referred to as webs). The Get-SPSite cmdlet is used to find SharePoint site collections, and Get-SPWeb is used to find SharePoint websites. To learn more about Get-SPSite (or any PowerShell cmdlet), see "Getting PowerShell Help."

Get a list of all site collections. The SharePoint 2010 Get-SPSite cmdlet can return a list of site collections. If no parameters are added, then Get-SPSite returns a list of all site collections to which you have permissions in the farm.

Cmdlets such as Get-SPSite can return thousands of items. As Figure 1 shows, the output will be limited unless you add the -Limit ALL variable to the command.

Figure 1: Returning a List of All Site Collections
Figure 1: Returning a List of All Site Collections 

By default, the Get-SPSite cmdlet displays only the URL to the site. If you want to learn more about the data that is returned from SharePoint, see "Learning About Data Returned from SharePoint." To learn more about how to display properties, see "Selectively Displaying SharePoint Properties."

If you want to see the URL, the owner, and the quota of all the site collections, use this cmdlet:

                              Get-SPSite http://yourserver/sites/yoursite |                              Select Url, Owner, {$_.Quota.StorageMaximumLevel}                               

 

Figure 2 shows an example of the returned output. To learn more about displaying data, see "Displaying Data."

 

Figure 2: Seeing the Owner of All Site Collections
Figure 2: Seeing the Owner of All Site Collections 

Get a list of all webs (subsites). Getting a list of all websites is much like getting a list of all site collections. All we need is another cmdlet: Get-SPWeb. Unlike Get-SPSite, Get-SPWeb cannot return all the sites by itself. You need to supply a starting site’s URL, either by typing it or by piping the output of another source, such as Get-SPSite. For each website that is piped to Get-SPWeb, the cmdlet displays that website’s properties.

To display information about a single website, use Get-SPWeb, then use Select to choose the properties to display:

                              Get-SPWeb http://intranet.contoso.com |                              Select Title, WebTemplate, Configuration                               

Figure 3 shows the output. Note that STS#1 is the template ID for a blank site; STS#0 is the ID for a team site. In this example, WebTemplate = STS and Configuration = 0, so the site was created as a team site.

Figure 3: Displaying Information for a Single Web
Figure 3: Displaying Information for a Single Web 

To see all the subsites in all the site collections, pipe the output of Get-SPSite into Get-SPWeb, as Figure 4 shows. If you want to get a list of sites in one site collection, then specify the URL of that site collection (see Figure 5).

Figure 4: Seeing All Subsites in All Site Collections
Figure 4: Seeing All Subsites in All Site Collections

Figure 5: Seeing a List of Sites in a Single Site Collection

Figure 5: Seeing a List of Sites in a Single Site Collection


Taking Inventory

The previous examples returned all site collections and all websites. We usually want to find only certain sites, users, or lists. Some cmdlets have parameters to limit what they return, but for most cmdlets, you need to filter the results by piping the output into the Where-Object cmdlet. Instead of typing Where-Object, you can use one of its aliases, such as "where" or "?".

For example, to search the entire farm to see whether anyone has created a blog site, you can use this cmdlet:

                              Get-SPSite -Limit All | Get-SPWeb -Limit All |                              Where { $_.WebTemplate -eq "BLOG" } | Select Url, Title                               

The Where-Object (Where) condition is wrapped inside curly brackets ( { } ). The property that is being tested is prefixed with "$_.", where $_ represents the current object being passed through the pipe. Notice that in PowerShell, the comparison operator is not a symbol such as the equals sign (=) or greater than sign (>), but rather -eq or -gt.

Now let’s expand on this idea and get inventories of all kinds of SharePoint objects. For all the following examples, you can pipe the output of a cmdlet to Get-Member to discover a list of properties and then use Select to display the properties or use Where to filter based on a property.

To get the SharePoint version number, use the following cmdlet:

                              Get-SPFarm | Select BuildVersion                               

 

From the output that Figure 6 shows, this farm appears to be running SharePoint 2010 Service Pack 1 (SP1). Todd Klindt's SharePoint Admin Blog post "SharePoint 2010 Build Numbers" shows a list of SharePoint versions.

 

Figure 6: Output of Getting the Version Number
Figure 6: Output of Getting the Version Number 

To get a list of all servers in the farm, enter the following:

                              Get-SPServer | Select DisplayName, Role | ft -AutoSize                               

 

To get a list of all SharePoint service applications that exist in the farm, use this cmdlet:

 

                              Get-SPServiceApplication | Select DisplayName,                              {$_.ApplicationPool.Name}                               

To get a list of all SharePoint Web Apps, enter the following:

                              Get-SPWebApplication | Select DisplayName,                              Url, {$_.AlternateUrls.Count}                               

 

Figure 7: Output of Getting a List of All SharePoint Web Applications
Figure 7: Output of Getting a List of All SharePoint Web Applications 

Figure 7 shows the output. Note that this does not include Central Administration by default. To include it, use this cmdlet:

                              Get-SPWebApplication -IncludeCentralAdministration 

To get all site collections (for which you have permissions), enter

                              Get-SPSite -Limit All | Select Url, Owner,                              {$_.Quota.StorageMaximumLevel}                               

 

To get all site collections in a single SharePoint Web App, enter

 

                              Get-SPWebapplication http://intranet | Get-SPSite |                              Select Url                               

 

We already talked about the cmdlet to get all websites:

 

                              Get-SPSite -Limit All | Get-SPWeb -Limit All |                              Select Title, WebTemplate, Configuration                               

 

Figure 8 shows the output.

 

Figure 8: Output of Getting all Webs
Figure 8: Output of Getting all Webs 

To get all websites in a site collection, enter

                              Get-SPSite http://intranet.contoso.com |                              Get-SPWeb | Select Title, WebTemplate, Configuration                               

 

To get a list of installed Web Templates, use this cmdlet:

 

                              Get-SPWebTemplate                               

 

Getting all websites in a site collection and their Web Templates is a bit more complicated and shows how quickly PowerShell scripting can jump from the quick and obvious to ... well, something more complex. In Listing 1, we create a function to return details of a Web Template for a specified template name and ID. The code then displays the data about the web, the URL, WebTemplate, and configuration, as well as looking up the template name by calling our function. Figure 9 shows the output of Listing 1. You can use the code in Listing 2 to clean up the column titles. Figure 10 shows the results.

 

Figure 9: Getting All Webs in a Site Collection and Their Web Templates
Figure 9: Getting All Webs in a Site Collection and Their Web Templates 

Figure 10: Cleaned Output of Getting All Webs in a Site Collection and Their Web Templates
Figure 10: Cleaned Output of Getting All Webs in a Site Collection and Their Web Templates 

Discovering all the websites that are based on a single template uses similar code but uses a Where cmdlet with an added Web Template lookup.

                              Get-SPSite -Limit All | Get-SPWeb -Limit All |                              Where { $_.WebTemplateId -eq (Get-SPWebTemplate "BLOG#0").Id} |                              Select Url                               

 

This example finds all blog sites in the farm. The blog template name is BLOG#0. Figure 11 shows the output.

 

Figure 11: Output of Getting All Webs of a Single Template
Figure 11: Output of Getting All Webs of a Single Template 


From Inventory to Content

In this article, we got a start inventorying core SharePoint objects such as site collections and websites. In future articles, we'll focus on content, such as finding all documents of a certain type (e.g., .docx) or over a certain size; listing all libraries, their file counts, and total file size or finding all libraries that use a specific content type; or finding all customized (unghosted) pages or all pages that use a selected Web Part. We'll also focus on users and security, such as listing all groups and their members, all site owners in all sites, all site collection administrators, all users who have access to a file, everything to which a user has access, or all sites, libraries, folders, and documents that have unique permissions (i.e., broken inheritance).

Until then, take a look at these helpful PowerShell resources:

Then take a look at my subsequent article, "Windows PowerShell Scripts for SharePoint."


Listing 1: Creating a Function to Return Web Template Details

                              Function Get-SPWebTemplateByIdentity ($name,$id)                                {Get-SPWebTemplate -Identity $name"#"$id}                              Get-SPSite -Limit All | Get-SPWeb -Limit All |                                Select Url, WebTemplate, Configuration,                                { (Get-SPWeb TemplateByIdentity $_.WebTemplate $_.Configuration).Title } |                                Format-Table                                                             

 

Listing 2: Cleaning up Column Titles

 

                              Function Get-SPWebTemplateByIdentity ($name,$id)                                {Get-SPWebTemplate -Identity $name"#"$id}                               Get-SPSite -Limit All | Get-SPWeb -Limit All | Select Url,                                @{ label="Template"; expression={$_.WebTemplate+"#"+$_.Configuration}},                                @{ label="Template Name"; expression={ (Get-SPWebTemplateByIdentity                                $_.WebTemplate $_.Configuration).Title }} | Format-Table