SharePoint 2010 is the first version of SharePoint technologies in which Microsoft supports administration through PowerShell scripts. In SharePoint 2007, farm administrators use a command-line utility named STSADM.EXE to run interactive commands from the console window and to write DOS-style batch file scripts to automate common administrative tasks such as creating, backing up or restoring a new site collection.
SharePoint Foundation still installs STSADM.EXE but it is primarily included to support backwards compatibility with scripts migrating from earlier versions. Microsoft now recommends using the new PowerShell support for writing, testing and executing scripts that automate the same types of administrative tasks that you can accomplish using STSADM.EXE.
The new PowerShell support for SharePoint Foundation adds a new required skill for every farm administrator and every developer moving from SharePoint 2007 to SharePoint 2010. You are now required to be able to read, write and execute PowerShell scripts to automate tasks such as creating a new Web application or a new site collection.
Today there are scores of SharePoint farm administrators and SharePoint developers with no prior experience in PowerShell. After all, a SharePoint 2007 environment is a place where the squeaky wheel gets the grease. Who's got time to learn about something they cannot use in their day to day activities. It is likely that many of these SharePoint professionals will not learn about PowerShell until they are forced to in their move to SharePoint 2010.
What about you? Are you moving to SharePoint 2010 but lacking PowerShell skills? Then this post is for you. It will teach you how to read, write, execute and debug PowerShell scripts. You'll also learn how to call into the PowerShell library used administrative tasks in SharePoint Foundation. Fasten your seatbelt.
Learn PowerShell in 21 Minutes
Working with PowerShell is much easier than writing DOS-style batch files. It's easier because PowerShell scripting language treats everything like an object. You can create and program against .NET objects as well as COM objects. Furthermore, PowerShell has first rate support for executing commands on command-line utilities.
There are two common ways in which you can use PowerShell. First, you can execute commands interactively using the PowerShell console window. Second, you can write scripts to automate administration tasks. Then you can execute these scripts either on demand or through some type of scheduling mechanism.
Let's start by getting familiar with the PowerShell console window. You can launch the PowerShell console window from the following path in the Windows Start menu.
Start > All Programs > Accessories > Windows PowerShell > Windows PowerShell
When the Windows PowerShell console appears, you should type and execute the following three commands interactively.
- Type cd\ and then press ENTER. This will set the current location to the root of the C:\ drive.
- Type cls and then press ENTER. This will clear the console window.
- Type 2 + 2 and then press ENTER. This will perform a mathematic calculation and display the result.
If you followed these steps correctly and executed each of the three commands, your console windows should look like the one in the screenshot in figure 1.
Figure 1: The PowerShell console window.
Congratulations! You have just completed your first lesson. Now you know how to execute a command interactively from the PowerShell console window. You simply type the command at the cursor in the PowerShell console window and then press the ENTER key.
PowerShell is based on reusable libraries containing functions known as cmdlets (pronounced command lets). Cmdlets have names which follow the convention of a common verb followed by a noun. For example, the built-in PowerShell libraries provide a cmdlet named Get-Process which returns a collection of objects representing the Windows processes running on the current machine.
PS C:\> Get-Process
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
599 0 108 300 3 4 System
2683 6161 85248 84996 124 0.39 1648 dns
568 63 16240 30584 169 1.28 3888 explorer
588 48 29492 41536 191 1.17 848 iexplore
146 21 22168 28552 97 0.25 1680 inetinfo
1805 231 30220 32364 243 2.00 580 lsass
765 74 98828 79176 740 2.64 2892 OWSTIMER
270 22 64564 60460 569 0.83 3432 powershell
791 82 167088 98088 -1604 4.11 2368 ReportingServicesService
733 597 278316 153224 -1592 3.97 2024 sqlservr
977 135 173372 180504 1511 4.94 2176 w3wp
773 123 161220 164464 1485 3.36 5112 w3wp
270 31 25052 17860 496 0.14 2568 WSSADMIN
Pipelining in an important concept to understand when executing cmdlets. The basic idea is that every cmdlets returns an object or a collection of objects. Pipelining allows you to take the results of one cmdlets and pass it to a second cmdlet. The second cmdlets can run and then pass its results to a third cmdlets and so on. You create a pipeline by typing a sequence of cmdlets separated by the | (pipe) character.
cmdlet1 | cmdlet2 | cmdlet3
Let's examine a common scenario where you need to create a pipeline of two cmdlets in order to filter a collection of objects. First, you call Get-Process to return a collection of objects and then you use pipelining to pass this collection of objects to the Where-Object cmdlet.
PS C:\> Get-Process | Where-Object {$_.ProcessName -like "w*"}
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
977 135 173372 180504 1511 4.94 2176 w3wp
773 123 161220 164464 1485 3.36 5112 w3wp
270 31 25052 17860 496 0.14 2568 WSSADMIN
The Where-Object cmdlet takes a predicate expression enclosed in curly braces as a parameter. Inside these curly braces, you can use $_ to refer to an object as it's being filtered. The predicate expression in this examples is {$_.ProcessName -like "w*"}. The filter returns all processes whose process name starts with a "w".
Windows PowerShell cmdlets such as Where-Object use standard PowerShell comparison operators. It is helpful to memorize them because you will be using them on a regular basis as you work with PowerShell. The following table is provided for you as a reference.
Operator | Purpose |
-lt | less than |
-le | less than or equal to |
-gt | greater than |
-ge | greater than or equal to |
-eq | equal to |
-ne | not equal |
-like | like using wildcard marches |
-notlike | not like using wildcard matches |
You should understand that PowerShell comparison operators that work with strings are case insensitive by default. However, these operators can be made case sensitive by adding a c immediately after the hyphen. For example, -ceq represents the case-sensitive equals operator.
Writing PowerShell Scripts
Now that you have seen how to execute cmdlets from the PowerShell console window, it's time to move on to PowerShell scripting. PowerShell scripts are text files that have an extension of .ps1. You can create and edit a PowerShell script using any text editor including NOTEPAD.EXE.
Before you can begin writing and testing PowerShell scripts, you must adjust the PowerShell script execution policy on your developer workstation. The reason for this is that PowerShell is configured out of the box to prohibit or to prompt the user during script execution. On a developer workstation, it's common to disable the default execution constraints so you can write and test scripts without security errors. You do this by calling the Set-ExecutionPolicy cmdlet from the PowerShell console in order to set the current machine's execution policy to "bypass".
Set-ExecutionPolicy "bypass"
Once you have correctly adjusted the PowerShell execution policy, it's time to write your first script. Open up NOTEPAD.EXE and type in the following one line script.
Write-Host "Hello World"
Now you need to save the file for the script with a .ps1 extension. First, create a new directory named Scripts on your local C:\ drive. Next save your new PowerShell script file as c:\Scripts\Script1.ps1. Now that you have saved the PowerShell script file with a .ps1 extension, you can execute the script to test your work.
Let's first execute the script through the PowerShell console window. In the PowerShell console window, move to the new directory by executing Set-Location c:\Scripts. Now, you can execute the script by typing .\Script1.ps1 and pressing ENTER. When you do this, you should be able to see the message Hello World in the PowerShell console window.
Now, let's create a Windows batch file so you can execute the script without having to use the PowerShell console Window. You can do this by creating a new text file named RunIt.bat in the same directory as Script1.ps1 and call powershell.exe and pass the -Command parameter with the following syntax to execute the script.
powershell.exe -Command "& {.\Script1.ps1}"
pause
Note that this example batch file also add a pause operation at the end. This can be handy because it keeps the DOS console open so you can see the output of your PowerShell script.
Finally, you should learn how to directly execute a PowerShell script without an assistance from a DOS batch file. If you right-click on a PowerShell script such as Script1.ps1 in the Windows explorer, you will see a menu command with the caption of Run with PowerShell. If you execute this command, the Windows operating system will take care of executing the PowerShell script for you.
Executing PowerShell scripts by using the Run with PowerShell command is quick and easy but it does not leave the PowerShell console window open when it is done. If you like using this technique but you still want to see the PowerShell console window afterwards, you can simply add the Read-Host cmdlet at the bottom of your script.
Write-Host "Hello World"
Read-Host
The PowerShell Integrated Scripting Environment (ISE)
While you can use any text editor you'd like to write PowerShell scripts, you should prefer to use a powerful new utility named the PowerShell Integrated Scripting Environment (ISE) which is included with the Windows operating system. A screenshot of the PowerShell ISE is shown in Figure 2.
Figure 2: You should write PowerShell scripts using the PowerShell Integrated Scripting Environment (ISE).
Note that SharePoint Foundation installs the PowerShell runtime but does not automatically install the PowerShell ISE. You need to explicitly install the PowerShell ISE on your development workstation. This is done in Windows Server 2008 and Windows Server 2008 R2 by enabling a the PowerShell ISE feature through the Server Manager. With Windows 7, you install the PowerShell ISE through the Windows control panel.
The PowerShell ISE will be immediately familiar to anyone with experience in Visual Studio. You can type in a script in the top window and then press the {F5} key to execute the script in debug mode. The PowerShell ISE allows you to debug by setting breakpoints and to single stepping through your code. Once you have launched the PowerShell ISE, type the following PowerShell script into the top window and then press the {F5} key.
$sum1 = 2 + 2
$sum2 = 3 + 4
$sum3 = $sum1 + $sum2
Write-Host $sum3
This example shows how to create a new variable in a PowerShell script. You simply create a new variable name which begins the $ character. You don't need to define variables before you use them as you do in C#. Instead you just create a variable when you begin using it.
Now, let's write a PowerShell control of flow construct. In this case we will create a new string array using the proper PowerShell syntax and then write a foreach loop to enumerate each string.
$band = "Paul", "John", "George", "Ringo"
foreach($member in $band) {
Write-Host $member
}
One aspect of PowerShell that will instantly appeal to .NET developers is that you can create and program against .NET object. For example, imagine you want to create an object from the DateTime class of the .NET framework. You do this by executing the New-Object cmdlet and passing the class name and initialization values as parameters.
$date = New-Object -TypeName System.DateTime -ArgumentList @(1882,7,4,0,0,0)
$message = "Wingtip Toys, Inc. was founded on " + $date.ToLongDateString()
Write-Host $message
The script you have just seen will produce the following output.
Wingtip Toys, Inc. was founded on Tuesday, July 04, 1882
In addition to creating new .NET objects, PowerShell also allows you to call the static methods and static properties of classes in the .NET Framework. You do this by typing the namespace-qualified class name in square brackets like this: [System.DateTime]. After you type the class name you add the :: operator (two colons) and then the call to a static member.
$today = [System.DateTime]::Today
Write-Host $today.ToLongDateString()
Write-Host $today.ToString("MM/dd/yy")
Write-Host $today.AddDays(100).ToString("MMMM d")
If you are feeling nostalgic, you can even use PowerShell to create and program against COM objects. For example, let's say you want to write a PowerShell script that launches the Internet Explorer and navigates to a specific URL. The Windows operating system provides a built-in COM interface that allows you to launch and control the Internet Explorer.
$ie = New-Object -ComObject "InternetExplorer.Application"
$ie.Navigate("http://intranet.wingtip.com")
$ie.Visible = $true
The SharePoint PowerShell Snap-in
PowerShell installs a set of core libraries containing cmdlets such as Write-Host, Get-Process and Where-Object. Environments like SharePoint Foundation add their own custom cmdlet library by installing a PowerShell Snap-in. When you install SharePoint Foundation, it installs its core PowerShell snap-in named Microsoft.SharePoint.PowerShell. However, you have to ensure that Microsoft.SharePoint.PowerShell is loaded before you begin to call its cmdlets.
Microsoft Foundation provides a specialized version of the PowerShell console known as the SharePoint 2010 Management Shell. You can launch the SharePoint 2010 Management Shell from a shortcut that SharePoint Foundation adds to the Windows Start menu.
All Programs > Microsoft SharePoint 2010 Products > SharePoint 2010 Management Shell
The main difference between the standard PowerShell console window and the SharePoint 2010 Management Shell console has to do with what PowerShell providers get loaded automatically. More specifically, the SharePoint 2010 Management Shell automatically loads the SharePoint provider named Microsoft.SharePoint.PowerShell while the standard PowerShell console does not. In general, you cannot always rely on Microsoft.SharePoint.PowerShell being loaded automatically so you need to learn how to explicitly load it within a PowerShell script.
Let's say you have just launched the standard PowerShell console window and you attempt to execute one of the cmdlets built into SharePoint Foundation such as the cmdlets named Get-SPWebApplication. The call to this cmdlets will fail unless you have already loaded the SharePoint PowerShell snap-in named Microsoft.SharePoint.PowerShell. Before calling the Get-SPWebApplication cmdlets, you need to load the SharePoint Foundation PowerShell snap-in using the Add-PSSnapin cmdlet .
Add-PSSnapin Microsoft.SharePoint.PowerShell
Get-SPWebApplication
Executing these two cmdlets in sequence will display the current collection of Web applications for the current farm excluding the Web application for SharePoint 2010 Central Administration.
DisplayName Url
----------- ---
Wingtip Intranet http://intranet.wingtip.com/
Wingtip Extranet http://extranet.wingtip.com/
Wingtip Public Web site http://www.wingtip.com/
One thing to keep in mind is that a call to Add-PSSnapin will fail if the SharePoint snap-in is already loaded. Therefore, You might play safe and check to see if it's already loaded before attempting to load it.
$snap = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snap -eq $null) {
Add-PSSnapin Microsoft.SharePoint.Powershell
}
Of course, if you just want to get rid of the error message you can get the same effect with less typing by calling the Add-PSSnapin using the ErrorAction parameter with a value of SilentlyContinue.
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction "SilentlyContinue"
Now, let's write a PowerShell script to create a new Web application. You can do this by calling the New-SPWebApplication cmdlet. The call requires quite a few parameters.
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction "SilentlyContinue"
$name = "Wingtip Testing Web App"
$port = 1001
$hostHeader = "intranet.wingtip.com"
$url = "http://intranet.wingtip.com"
$appPoolName = "SharePoint Default Appl Pool"
$appPoolAccount = Get-SPManagedAccount "WINGTIP\SP_WorkerProcess"
New-SPWebApplication -Name $name -Port $port -HostHeader $hostHeader -URL $url
-ApplicationPool $appPoolName
-ApplicationPoolAccount $appPoolAccount
As you can imagine, writing and executing scripts like this can save quite a bit of time in a production farm because it eliminates the need to perform the same tasks manually through SharePoint 2010 Central Administration. Scripts like this also create a great way to create consistency in how you create Web applications across farms.
We will finish with one more example. Let's write a script to create a new site collection which has a Team site as its top-level site. You can accomplish this by calling the New-SPSite cmdlet.
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction "SilentlyContinue"
$title= "Wingtip Dev Site"
$url = "http://intranet.wingtip.com:1001"
$owner = "WINGTIP\Administrator"
$template = "STS#1"
New-SPSite -URL $url -Name $title -OwnerAlias $owner -Template $template
When you create a new site collection using the New-SPSite cmdlet, you must specify the URL and title and provide a user account to be configured as the site collection owner. You can also specify a template using the Template parameter which will be applied on the top-level site. In this example, a template of STS#1 has been applied to create the top-level site as a standard Team site.
Now, we have written a script to create a new site collection. The first time you run it, it works great. But what happens when you run it a second time? The second attempt to call the New-SPSite cmdlet fails because a site collection already exists at the target URL.
During development, there's a common scenario where you must continually delete and recreate a site to effectively test and debug your code. Before deleting a site collection, your script should check to see if a target site collection already exists at the target URL using the Get-SPSite cmdlet. If the site collection already exists, you can delete it with the Remove-SPSite cmdlet.
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction "SilentlyContinue"
$title= "Wingtip Dev Site"
$url = "http://intranet.wingtip.com:1001"
$owner = "WINGTIP\Administrator"
$template = "STS#1"
# delete target site collection if it exists
$targetSite = Get-SPSite | Where-Object {$_.Url -eq $url}
if ($targetSite -ne $null) {
Remove-SPSite -Identity targetSite -Confirm:$false
}
# create new site collection
New-SPSite -URL $url -Name $title -OwnerAlias $owner -Template $template
Remember that cmdlets such as New-SPSite return objects that you can program against. For example, imagine you want to update the title of the top-level site after the site collection has been created. A site collection object exposes a RootWeb property which allows you to access the top-level site. The site object provides a Title property you can modify with a new title. Note that you must call the site object's Update method to write your changes back to the content database.
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction "SilentlyContinue"
$title= "Wingtip Dev Site"
$url = "http://intranet.wingtip.com:1001"
$owner = "WINGTIP\Administrator"
$template = "STS#1"
$sc = New-SPSite -URL $url -Name $title -OwnerAlias $owner -Template $template
$site = $sc.RootWeb
$site.Title = "My New Site Title"
$site.Update
You have just seen an example of writing code against the server-side object model of the SharePoint Foundation. Unfortunately, the PowerShell ISE is not able to provide IntelliSense in the same manner as Visual Studio. However, the PowerShell ISE still has valuable editing and debugging features that are easy to learn and use. You should become familiar with this tool because it provides a quick way to script out changes to the local farm in your development workstation or in a production environment.
Congratulations. You made it through the PowerShell Boot Camp. Now get out there in the real world and start scripting.