Summary: Learn how to use Windows PowerShell to script changes to the web.config file on SharePoint 2010.
Hey, Scripting Guy! I need help using Windows PowerShell to automate making changes to the web.config file on my SharePoint 2010 farm. Do you know of a way to automate making these changes?
— JG
Hello JG,
Microsoft Scripting Guy Ed Wilson here. We are continuing with Guest Blogger Week, and today’s guest blogger is Josh Gavant who will talk about SharePoint.
Josh is a Premier Field Engineer (PFE) with Microsoft who specializes in both SharePoint and Windows PowerShell. Before joining Microsoft in fall 2009 he helped build and maintain an enterprise SharePoint farm for a United States government agency. Find SharePoint and Windows PowerShell-related discussions from Josh and contact him via his blog at http://blogs.msdn.com/b/besidethepoint.
Take it away, Josh.
What SharePoint Is and Is Not
When discussing SharePoint with customers, I often find myself emphasizing that a SharePoint farm is, in essence, a logical collection of services—not a collection of physical servers. When administrators and developers make modifications to their farm, they are manipulating and configuring these logical services; changes to files and other “physical” artifacts are a side effect of the logical changes. Another way of expressing this is to emphasize that changes to SharePoint should actually be perceived only as changes to the Object Model and ultimately the shared databases, not to any server-level constructs (for example, the file system or registry).
To this end, SharePoint engineers constantly emphasize to developers the importance of using Solution (capital S) packages to deploy customizations to SharePoint. Solution packages upload all the files and other pieces necessary for new SharePoint artifacts to the SharePoint database, from where SharePoint itself handles deploying them to component servers as necessary.
The Solution package is well and good for developers, but what about administrators who need to make farm-wide changes? For example, administrators sometimes need to modify the web.config files that govern the behavior of SharePoint Web Applications, or need to modify IIS settings, registry keys, or files on multiple SharePoint servers. Ideally, administrators would create single “solutions” to deal with configuring a single SharePoint logical service, instead of having to repeat processes on lots of physical servers. The SharePoint administrator tools are fine for single server installations, as shown in the following image. But such a procedure is difficult to maintain, hinders scale-out of a SharePoint farm, and is antithetical to the management paradigm espoused above, viewing SharePoint as a collection of logical services.
So what is an administrator to do? Windows PowerShell scripts, the SharePoint Management Shell, and the SharePoint administrative object model provide a Solution solution (sic) for SharePoint farm administrators. In this post, we explore using these tools to write a single reusable script that modifies the web.config file for a Web Application across an entire farm. Though we’ll focus on a single example, the concepts can be utilized for any web.config modifications.
Introducing Today’s Audience Participant, the SharePoint BlobCache
A commonly implemented configuration change for SharePoint Publishing sites is that of enabling the BlobCache for the parent Web Application. The BlobCache is a special file-system cache created on SharePoint front-end web servers to store binary large objects (BLOBs) such as images, text files, and media files retrieved from SharePoint content databases. By storing these files in the BlobCache, the front-end server saves a trip back to the content database when serving these files for subsequent requests, improving response times. In addition, when administrators configure and enable the BlobCache, they can cause SharePoint to add a HTTP cache header to the file as it is delivered to the browser, which instructs the browser to rely on its cached version of the file for some defined period. This helps speed up repeat requests for pages on the client side.
With these benefits, it’s easy to see why administrators and managers would want to turn on the SharePoint BlobCache. Unfortunately, the documented way to do so involves manually changing the web.config file for every effected Web Application on every front-end Web server, a process that can be difficult to maintain and control without errors. What we need is a way to modify the web.config for a Web Application across the farm in a single stroke.
SPWebConfigModification
Enter SPWebConfigModification. This object contains properties for making changes to web.config files for an associated Web Application. The job of the administrator or developer is to construct one of these objects and assign appropriate values to its properties, and then add the new object to the collection of modifications associated with a given Web Application. After this is done, SharePoint takes care of applying the modification to all instances of that Web Application across the farm, including any additional servers added in the future. Another benefit is that by removing the modification from the list, the change is automatically reverted, which returns every server to its default original state.
Voila! With SPWebConfigModification, web.config changes no longer need to involve directly touching files or settings on any server.
So how can you create and apply these changes via Windows PowerShell? There are three steps to follow:
- Construct and configure the SPWebConfigModification object.
- Get a SPWebApplication object to which to add your modifications.
- Wrap your work in a function for reusability.
You’ll also implement a complementary function to potentially undo the changes that you make. Let’s get started.
Construct and Configure the SPWebConfigModification Object
When Windows PowerShell and its loaded snap-ins do not contain a cmdlet for returning an object that you want to use, you often can use the New-Object cmdlet to create an instance of that object. New-Object takes the fully qualified name of a type and an array of objects as its two main parameters; the array of objects contains the arguments to be passed to the object’s constructor method.
In this case, you are going to call the default constructor for Microsoft.SharePoint.Administration.SPWebConfigModification, which takes no arguments, and then store your newly constructed object in a variable for further manipulation. Here is the line:
$configMod1 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
Next, set the properties needed to change the enabled attribute for the BlobCache node in the web.config file:
$configMod1.Path = “configuration/SharePoint/BlobCache”
$configMod1.Name = “enabled”
$configMod1.Value = “true”
$configMod1.Sequence = 0
$configMod1.Owner = “BlobCacheMod”
## SPWebConfigModificationType.EnsureChildNode -> 0
## SPWebConfigModificationType.EnsureAttribute -> 1
## SPWebConfigModificationType.EnsureSection -> 2
$configMod1.Type = 1
The various properties can be tricky, and the required values change based on the SPWebConfigModificationType chosen for the Type property. In this case, you want to make sure that an attribute on an existing node takes on a specific value, so we choose EnsureAttribute as the value for the Type property. There are a few ways of choosing values from an Enum in Windows PowerShell; for this script, I am simply using the integer value that the specific Enum choice corresponds to, as noted in the comments for setting the Type property.
The Path property expects an XPath expression pointing to the element that we will be considering; Name refers to the attribute on that element to check. Sequence determines precedence if multiple SPWebConfigModification objects attempt to modify the same attribute; the lower the number, the higher the priority. By choosing 0, I’ve overridden any other change. Value determines the actual value that the attribute will be set to. The result of this modification will be setting enabled=”true” on the BlobCache node in web.config.
One last property is the Owner property. The value of this property is arbitrary, but it is useful in locating specific modifications for manipulation after they have already been added to a collection. As you will see, for our reversion function you can find the modifications by checking the value assigned to this property.
With these steps completed, you have the first of our two SPWebConfigModifications. The second one sets the Max-Age attribute on the same BlobCache node. This sets the Max-Age HTTP header on the outgoing file so that browsers know to cache the object for the specified period. This modification is seen in the following Windows PowerShell code:
$configMod2 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification $configMod2.Path = “configuration/SharePoint/BlobCache” $configMod2.Name = “max-age” $configMod2.Value = “86400” $configMod2.Sequence = 0 $configMod2.Owner = “BlobCacheMod” ## SPWebConfigModificationType.EnsureChildNode -> 0 ## SPWebConfigModificationType.EnsureAttribute -> 1 ## SPWebConfigModificationType.EnsureSection -> 2 $configMod2.Type = 1
The setup and properties for this modification follow the same pattern as the previous one. Choose a value of 86400 seconds, or 24 hours, as a reasonable time for the browser to rely on its cached version of a file. Once again, set the Owner property to BlobCacheMod to help find this modification when you need to remove it.
Get a SPWebApplication Object with Which to Work
You have created your SPWebConfigModification objects; now add them to the WebConfigModifications property of the Web Application they will be applied to. To do this, start by creating an instance of a SPWebApplication object. In the SharePoint 2007 days, I might have asked the user of the function to supply us with a URL, and then I would use the static SPWebApplication.Lookup() method to return an instance. While this tactic would still be valid in SharePoint 2010, there are now more robust options available.
Introducing SPCmdletPipeBind<TCmdletObject>
As with many other Microsoft-provided foundations in SharePoint, the SharePoint team has taken the Windows PowerShell framework and extended it specifically for SharePoint: the classes and utilities provided by the Microsoft.SharePoint.PowerShell namespace. This namespace contains not only the 500-plus SharePoint-specific cmdlets, but also a set of utility classes for creating more SharePoint cmdlets and scripts, in addition to allowing us to work more easily with the SharePoint object model.
In SharePoint 2010, instead of asking the user for a string or even an SPWebApplication object, you can specify a SPWebApplicationPipeBind object, itself derived from the generic SPCmdletPipeBind<TCmdletObject> class. The idea behind the PipeBind classes is that they allow the same object to be referred to in different ways. In the case of SPWebApplication, you can pass a string representing the URL of the Web Application, a GUID identifying the specific SharePoint configuration object that is the Web Application, or even an actual SPWebApplication object (that is, output from the pipeline or stored in a variable). The SPWebApplicationPipeBind class takes care of ultimately returning a SPWebApplication object for further manipulation in the shell. An immediate benefit of using the PipeBind classes is you can accept SPWebApplication objects output by previous cmdlets in the pipeline without making it difficult to call the cmdlet in standalone fashion, passing it a URL as a string.
The function will expect a SPWebApplicationPipeBind object and will convert this object into a true SPWebApplication object for further manipulation. Here are the relevant lines in the script:
param([Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
[Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]
$WebApplication ) process {
$WebApp = $WebApplication.Read()
The Parameter attribute is typical for an advanced Windows PowerShell function, specifying that the parameter is mandatory, can be accepted directly from the pipeline, and does not have to be named. The second pair of square brackets ([ ]) specify the type of the parameter: a SPWebApplicationPipeBind object. Finally, the first action within the Process block of the cmdlet is to call the Read method on the PipeBind object that was received, which is the defined method for extracting the relevant TCmdletObject from the SPCmdletPipeBind-derived class.
What this all means at the end of the day is that the $WebApp variable now contains a SPWebApplication object to which you can add your web.config modifications.
Add the Modifications to the SPWebApplication Object
While the previous section might have been your first direct encounter of the PipeBind kind, this next part should be a bit simpler. The SPWebApplication instance you are now the proud parent of contains a property WebConfigModifications that references a Collection <SPWebConfigModification> object; that is, a collection of SPWebConfigModifications. The Collection class offers a lot of useful functionality, but let’s focus only on its Add and Remove methods. To add the new SPWebConfigModification objects to the collection associated with a Web Application, use the following two lines:
$WebApp.WebConfigModifications.Add( $configMod1 ) $WebApp.WebConfigModifications.Add( $configMod2 )
To ensure that the changes are persisted back to the SharePoint configuration object for the Web Application in the configuration database and thus propagated out to all instances of the Web Application in the farm, call Update():
$WebApp.Update()
Finally, to apply these new modifications across the farm, you can call the appropriate method on the SPWebService object, the host service for all SPWebApplications, which is also the parent of the Web Application in question:
$WebApp.Parent.ApplyWebConfigModifications()
And with that, the web.config files for this Web Application across our entire farm will be modified. If you want to verify these changes, call Get-SPWebApplication and check the value of the WebConfigModifications property for the Web Application that you modified.
Complete Function
Here is the complete script for the previous work, all wrapped in a nice function.
function Enable-SPBlobCache { param([Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
[Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]
$WebApplication ) process {
$WebApp = $WebApplication.Read()
# SPWebConfigModification to enable BlobCache
$configMod1 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
$configMod1.Path = “configuration/SharePoint/BlobCache”
$configMod1.Name = “enabled”
$configMod1.Sequence = 0
$configMod1.Owner = “BlobCacheMod”
## SPWebConfigModificationType.EnsureChildNode -> 0
## SPWebConfigModificationType.EnsureAttribute -> 1
## SPWebConfigModificationType.EnsureSection -> 2
$configMod1.Type = 1
$configMod1.Value = “true”
# SPWebConfigModification to enable client-side Blob caching (max-age)
$configMod2 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
$configMod2.Path = “configuration/SharePoint/BlobCache”
$configMod2.Name = “max-age”
$configMod2.Sequence = 0
$configMod2.Owner = “BlobCacheMod”
## SPWebConfigModificationType.EnsureChildNode -> 0
## SPWebConfigModificationType.EnsureAttribute -> 1
## SPWebConfigModificationType.EnsureSection -> 2
$configMod2.Type = 1
$configMod2.Value = “86400”
# Add mods, update, and apply
$WebApp.WebConfigModifications.Add( $configMod1 )
$WebApp.WebConfigModifications.Add( $configMod2 )
$WebApp.Update()
$WebApp.Parent.ApplyWebConfigModifications() } }
Reverting the Changes
Though creating a function to automate web.config changes across the farm is great, what happens if you need to revert your changes? Here is another situation where the utility of SPWebConfigModification shines. Remember that in our previous example, we set the Owner property of our modifications to BlobCacheMod. Removing the changes now becomes a matter of once again getting a reference to the SPWebApplication and its WebConfigModifications property, sifting through the collection and finding objects with the Owner property set to BlobCacheMod, and then calling the Remove method on the collection for each of these. You then wrap up by calling the Update method on the Web Application object and ApplyWebConfigModifications() on the SPWebService parent object to apply the changes. Here is the complete function:
function Disable-SPBlobCache { param([Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
[Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]
$WebApplication ) process {
$WebApp = $WebApplication.Read()
$mods = @()
foreach ( $mod in $WebApp.WebConfigModifications ) {
if ( $mod.Owner -eq “BlobCacheMod” ) {
$mods += $mod
} }
foreach ( $mod in $mods ) {
[void] $WebApp.WebConfigModifications.Remove( $mod )
}
$WebApp.Update()
$WebApp.Parent.ApplyWebConfigModifications() } }
So there it is. Two functions, Enable-SPBlobCache and Disable-SPBlobCache, which take a Web Application object from the pipeline or via command-line input and make the necessary web.config changes to enable or disable the BlobCache across the farm. Other changes to web.config files can be automated in the same way.
I typically wrap these and other custom cmdlets into a module and import the module into my SharePoint Management Shell when I need the functions. You could also create a script and dot-source it, or create a script that defines the functions and then calls them. The choice is yours.
There are many other opportunities in Windows PowerShell to simplify and unify cross-farm and cross-component administration in a SharePoint farm. Stay tuned for future posts.
JG, that is all there is to using Windows PowerShell to automate changes to the SharePoint 2010 web.config file. Guest Blogger Week will continue tomorrow when Glyn Clough will talk more about SharePoint.
We invite you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments