MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Monday, October 19, 2009

SharePoint 2010: PSConfig and PowerShell

The information in this article is based on BETA 2 of SharePoint 2010 - there may be differences with the RTM release.

Update 12/18/2009: I've updated the post to reflect BETA 2 changes and have considerably simplified the script removing all the dependencies on helper functions so that the core pieces required to build a basic farm are focused on rather than the complex elements to support tracing and error handling as I previously had it.

If you've ever done a scripted install of SharePoint 2007 then you are familiar with how to script the initial farm creation using psconfig.exe. Unfortunately psconfig is still with us in SharePoint 2010 but we do have some PowerShell cmdlets which replace all the psconfig commands.

Before we look at how to use PowerShell lets refresh our memories by looking at an install script for SharePoint 2007. I usually have two scripts, one for the first server and a second script for additional servers - here's the first script (I've omitted the variable declarations):

   1: ECHO %DATE% %TIME%:  Building configuration database
   2: psconfig -cmd configdb -create -server %SERVER_DB% -database %DB_CONFIG_NAME% -user %ACCT_SPFARM% -password %ACCT_SPFARM_PWD% -admincontentdatabase %DB_CENTRALADMINCONTENT_NAME% 
   3: if not errorlevel 0 goto errhnd
   4:  
   5: ECHO %DATE% %TIME%: Installing help content
   6: psconfig -cmd helpcollections -installall 
   7: if not errorlevel 0 goto errhnd
   8:  
   9: ECHO %DATE% %TIME%: Securing resources
  10: psconfig -cmd secureresources 
  11: if not errorlevel 0 goto errhnd
  12:  
  13: ECHO %DATE% %TIME%: Installing services
  14: psconfig -cmd services -install 
  15: if not errorlevel 0 goto errhnd
  16:  
  17: ECHO %DATE% %TIME%: Installing features
  18: psconfig -cmd installfeatures 
  19: if not errorlevel 0 goto errhnd
  20:  
  21: ECHO %DATE% %TIME%: Creating central admin site
  22: psconfig -cmd adminvs -provision -port %CENTRALADMIN_PORT% -windowsauthprovider enablekerberos 
  23: if not errorlevel 0 goto errhnd
  24:  
  25: ECHO %DATE% %TIME%: Adding application content to central admin site
  26: psconfig -cmd applicationcontent -install
  27: if not errorlevel 0 goto errhnd
  28:  
  29: goto end
  30:  
  31: :errhnd
  32:  
  33: echo An error occured - terminating script.
  34:  
  35: :end

And here's the second script (variable declarations omitted):

   1: ECHO %DATE% %TIME%: Connecting to farm
   2: psconfig -cmd configdb -connect -server %SERVER_DB% -database %DB_CONFIG_NAME% -user %ACCT_SPFARM% -password %ACCT_SPFARM_PWD%
   3: if not errorlevel 0 goto errhnd
   4:  
   5: ECHO %DATE% %TIME%: Installing services
   6: psconfig -cmd services install
   7: if not errorlevel 0 goto errhnd
   8:  
   9: ECHO %DATE% %TIME%: Installing features
  10: psconfig -cmd installfeatures
  11: if not errorlevel 0 goto errhnd
  12:  
  13: ECHO %DATE% %TIME%: Setting security on registry and file system
  14: psconfig -cmd secureresources
  15: if not errorlevel 0 goto errhnd
  16:  
  17: goto end
  18:  
  19: :errhnd
  20:  
  21: echo An error occured - terminating script.
  22:  
  23: :end

Obviously the two scripts are very similar with the main difference being the parameters passed to the configdb command and with fewer commands being called. So how would we do this using SharePoint 2010's PowerShell cmdlets? First lets list each psconfig command and what the PowerShell equivalent is:

PSConfig Command PowerShell Cmdlet
configdb -create New-SPConfigurationDatabase
configdb -connect Connect-SPConfigurationDatabase
helpcollections -installall Install-SPHelpCollection
secureresources Initialize-SPResourceSecurity
services -install Install-SPService
installfeatures Install-SPFeature (provide the -AllExistingFeatures parameter)
adminvs -provision New-SPCentralAdministration
applicationcontent -install Install-SPApplicationContent

Now that we know what PowerShell cmdlets to use lets rework our install script. Instead of using a batch file for variables I'm going to use an XML file which can be read in and parsed as needed. I'm also going to make it so that you can run the same script from any server and just specify a switch parameter indicating whether or not you are connecting to an existing farm or not.

Let's first take a look at the XML that we'll use to manage our settings - we'll store this in a file called FarmConfigurations.xml:

<Farm FarmAccount="sp2010\spfarm" 
ConfigDB="SharePoint_ConfigDB"
AdminContentDB="SharePoint_Content_Admin"
DatabaseServer="spsql1"
Passphrase="Pa$$w0rd">
<CentralAdmin Port="1234" AuthProvider="NTLM">
<Servers>
<Server Name="spsvr1" />
</Servers>
</CentralAdmin>
</Farm>

In this XML I'm storing the core farm settings in the <Farm /> element which includes attributes for the farm account to use as well as the database server and names for the configuration and central admin content database. I then have a <CentralAdmin /> element which contains the servers that the Central Admin site should be installed on along with the port and authentication provider to use.

So now that we have our configuration settings all we need now is the core script to actually create our farm. I named this script BuildFarm.ps1 but you can name it whatever you want:

function Install-SharePointFarm([bool]$connectToExisting, 
[string]$settingsFile = "FarmConfigurations.xml") {

[xml]$config = Get-Content $settingsFile

$farmAcct = Get-Credential $config.Farm.FarmAccount

$configDb = $config.Farm.ConfigDB
$adminContentDb = $config.Farm.adminContentDb
$server = $config.Farm.DatabaseServer
if ($config.Farm.Passphrase.Length -gt 0) {
$passphrase = (ConvertTo-SecureString $config.Farm.Passphrase `
-AsPlainText -force)
} else {
Write-Warning "Using the Farm Admin's password for a passphrase"
$passphrase = $farmAcct.Password
}

#Only build the farm if we don't currently have a farm created
if (([Microsoft.SharePoint.Administration.SPFarm]::Local) -eq $null) {
if ($connectToExisting) {
#Connecting to farm
Connect-SPConfigurationDatabase -DatabaseName $configDb `
-DatabaseServer $server -Passphrase $passphrase
} else {
#Creating new farm
New-SPConfigurationDatabase -DatabaseName $configDb `
-DatabaseServer $server `
-AdministrationContentDatabaseName $adminContentDb `
-Passphrase $passphrase -FarmCredentials $farmAcct
}
#Verifying farm creation
$spfarm = Get-SPFarm -ErrorAction SilentlyContinue -ErrorVariable err
if ($spfarm -eq $null -or $err) {
throw "Unable to verify farm creation."
}

#ACLing SharePoint Resources
Initialize-SPResourceSecurity

#Installing Services
Install-SPService

#Installing Features
Install-SPFeature -AllExistingFeatures
} else {
Write-Warning "Farm already exists. Skipping creation."
}

$installSCA = (($config.Farm.CentralAdmin.Servers.Server | `
where {$_.Name -eq $env:computername}) -ne $null)
$url = "http://$($env:computername):$($config.Farm.CentralAdmin.Port)"
$sca=[Microsoft.SharePoint.Administration.SPWebApplication]::Lookup($url)
if ($installSCA -and $sca -eq $null) {
#Provisioning Central Administration
New-SPCentralAdministration -Port $config.Farm.CentralAdmin.Port `
-WindowsAuthProvider $config.Farm.CentralAdmin.AuthProvider

#Installing Help
Install-SPHelpCollection -All

#Installing Application Content
Install-SPApplicationContent
}
}

Notice that the script takes a parameter which allows you to specify whether you are connecting to an existing farm. We can call the script using the following syntax (replace $false with $true if connecting to an existing farm):

PS C:\> . .\buildfarm.ps1
PS C:\> Install-SharePointFarm $false "FarmConfigurations.xml"

In a series of upcoming post I'll be building on what I created here by demonstrating how to create web applications and how to start each of the services that are included, including the extremely complex search service (gone are the days of a single line setup for search - we now have a dozen or so cmdlets that have to be run to get search started).

22 comments:

Markus said...

Hi Gary,

I think this is very useful. Currently I am working on a whitepaper document on how to create a clonable sp2010 development machine with 100% scripted sharepoint installation. Can I use your information? I´ll give you full credit in the document of course. Please give me a quick feedback.

markus.alt@gmail.com
http://blog.markus-alt.de

Gary Lapointe said...

Sure - I'll be updating this fairly soon to account for beta2 but the structure will remain.

Kyle said...

This is great work and has solved some of the problems I have been running into with automating farm installs, except for the Service Application install.

Where I work we have a very structured naming policy for database names. The only thing that will hold us back from 2010 is being able to apply our naming policy to the 14 Service Application databases.

Any chance you are going to be discussing that soon? :D

Gary Lapointe said...

Soon :) The scripts are complex so I'm still figuring out how best to share them.

Anonymous said...

Hi Gary,

Sorry to ask a stupid question, but I'm unable to run the scripts.

..\buildFarm.ps1 --> doesn't work
.\buildFarm.ps1 --> no errors
PS D:\Users\PKMACCT\Desktop> .\buildfarm.ps1
PS D:\Users\PKMACCT\Desktop> Install-SharePointFarm $false "FarmConfigurations.xml"
The term 'Install-SharePointFarm' is not recognized as the name of a cmdlet, function, script file, or operable program
. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:23
+ Install-SharePointFarm <<<< $false "FarmConfigurations.xml"
+ CategoryInfo : ObjectNotFound: (Install-SharePointFarm:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException


I was hoping if you can please tell me what is going wrong.

Gary Lapointe said...

You need to dot source the script which loads it into memory and then call the function:

. .\buildfarm.ps1
Install-SharePointFarm $false "FarmConfigurations.xml"

Gary Lapointe said...

You need to dot source the script which loads it into memory and then call the function:

. .\buildfarm.ps1
Install-SharePointFarm $false "FarmConfigurations.xml"

Anonymous said...

Hi Gary,

Thank you that worked. I was wondering is there way in the config file to give password as I'm going to run the script from code and don't want the messagebox to popup.

Gary Lapointe said...

Yes - you can put the password in the XML but you'll need to construct the PSCredential object by hand:

if ($accountNode.Password.Length -gt 0) {
$accountCred = New-Object System.Management.Automation.PSCredential $accountNode.Name, (ConvertTo-SecureString $accountNode.Password -AsPlainText -force)
} else {
Write-Info "Please specify the credentials for" $accountNode.Name
$accountCred = Get-Credential $accountNode.Name
}

alx said...

Any chance that these cmdlets could work on a SP 2007 Server? Or are brand new classes being called in those cmdlets?

Gary Lapointe said...

All the cmdlets are specific to 2010 - it could be possible to reverse engineer them and build for 2007 but that would be a pretty significant undertaking.

Wender said...

Hi,
I give this error,
Please, Help me.

PS C:\sharepointScript> Install-SharePointFarm $false "FarmConfigurations.xml"
New-SPConfigurationDatabase : Exception of type 'Microsoft.SharePoint.SPException' was thrown.
At C:\sharepointScript\install.ps1:25 char:31
+ New-SPConfigurationDatabase <<<< -DatabaseName $configDb `
+ CategoryInfo : InvalidData: (Microsoft.Share...urationDatabase:SPCmdletNewSPConfigurationDatabase) [New
-SPConfigurationDatabase], SPCmdletException
+ FullyQualifiedErrorId : Microsoft.SharePoint.PowerShell.SPCmdletNewSPConfigurationDatabase

Thanks.

Gary Lapointe said...

Make sure you can connect to your database from the server and that your account has db_creator and security_admin on the db server and is a local administrator on the local box. Also make sure that your farm account exists (you'll also need to make sure it is a sys_admin on the db server and a local admin as well).

Anonymous said...

Thanks a million Gary. I have modified my script with your xml config file.
When I run your script however, I get
WARNING: Feature "AdminReportCorePushdown\Feature.xml has failed to install for the following reason: Object reference not set to an instance of an object..."

I am running on SP2010 RC

Gary Lapointe said...

I recommend you log it as a bug on the connect site - issue would be with the install-spfeature cmdlet.

Anders said...

When I ran your script, PowerShell couldn't find any of the SharePoint classes since the assembly wasn't loaded. I fixed it by adding

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

at the beginning of the script. Did only I encounter this?

Gary Lapointe said...

You shouldn't need to load the assemblies if you are loading the snap-in.

javier said...

I was suffering the InvalidData: Exception too.
I fixed it opening port 1433 on my SQL Server box, SharePoint being in another box.

Anonymous said...

nice:
suppose i want to specify the password for Farm Account inside the XML parameters file:
would this work?
$farmAcctPwd = (ConvertTo-SecureString $config.Farm.FarmPassword -AsPlainText -force)

and then can I place this variable on the create config line next to the farm account name?

please explain, I need this script to run unattended. no prompts

Gary Lapointe said...

Yes, you can store the password in the xml and use it instead of prompting.

Anonymous said...

Why does the farm account need sys_admin permissions on the database server?

Gary Lapointe said...

You don't need sys_admin rights for the spfarm account - there were bugs with b2 that necessitated it but they should be resolved with rtm.