MSDeploy Powershell Scripts Part I – Local Functions Only

Part II now posted - http://blogs.iis.net/jamescoo/archive/2009/10/24/msdeploy-powershell-scripts-part-ii-exceptions-and-remote-server-syncs.aspx

For MSDeploy API examples visit: http://blogs.iis.net/jamescoo/archive/2009/11/03/msdeploy-api-scenarios.aspx

In this blog I would like to show how to create MSDeploy Powershell scripts that you can customize and export to your Powershell console.

There is a new API coming out with MSDeploy that will allow a lot of new programmatic functionality around syncing and gathering information about the content and settings of web servers.  Now that it is finalized and the Powershell support in RTM V1 has been officially removed for this release I wanted to pursue some simple light weight script-lets that would allow folks who want some kind of Powershell option to get something to work for them.  This also gives some introduction to the API of MSDeploy in C#.

To give a high level view, whenever you want to sync content from one location to another you will generally have to create a DeploymentObject with source information and call the SyncTo method which will actually synchronize the content as if you were calling these from command-line MSDeploy.  These objects live inside the ‘Microsoft.Web.Deployment’ assembly which is installed with MSDeploy.  The source and destination will also have to define their DeploymentBaseOptions which are basically switches that can represent things like including ACLS of a source during a sync or using temp agent.  The DeploymentSyncOptions can help apply rules such as skip and replace during a sync. 

The examples below do not start with any support for remote cases as I wanted to start with very light weight examples.  I chose Powershell for another reason which is that it is very simple to experiment; not requiring rebuilds when you want to try out some customizations.

Step 1 – Get some representative C# API code that will sync two locations ( must add Microsoft.Web.Deployment as a reference in the MSDeploy install directory ):

//need using Microsoft.Web.Deployment;
 
DeploymentBaseOptions _sourceBaseOptions = new DeploymentBaseOptions(); 
DeploymentBaseOptions _destinationBaseOptions = new DeploymentBaseOptions(); 
DeploymentSyncOptions _syncOptions = new DeploymentSyncOptions();
// double quotes don’t copy and paste well so you might have to redo them
using (DeploymentObject deploymentObject = DeploymentManager.CreateObject(“contentPath”, @"c:\inetpub\wwwroot")) 
{
    deploymentObject.SyncTo( “contentPath”, "c:\temp1", _destinationBaseOptions,_syncOptions); 
}
 

 

Step 2 – Translate the C# code into an equivalent Powershell script:

 

In the above example, it looks simple enough to sync using contentPath provider so I will break it down into steps which follow line by line of the above example.

1. Make sure the assembly is loaded into the Powershell session

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

2. Create the simple objects needed as parameters.  I hope to elaborate on these objects in future blogs.

$sourceBaseOptions = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
$destBaseOptions   = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
$syncOptions       = new-object Microsoft.Web.Deployment.DeploymentSyncOptions

3. Call CreateObject to create the deployment object from the DeploymentManager.

Below there is an assumption that the CreateObject function will take two parameters: $sourceContent and $destinationContent.  However, there are several overloads for CreateObject. 

It turns out that DeploymentObject does not have an appropriate constructor to simply create a new object which makes sense because in the code above DeploymentManager is used to create an object of type DeploymentObject.  The DeploymentManager is actually a static class that you can use to call CreateObject as in the example below.  Just remove new-object and directly call CreateObject with the correct parameters: provider and $sourceDirectory ( both strings ).

$deploymentObject = [Microsoft.Web.Deployment.DeploymentManager]::CreateObject(“contentPath”,$sourceDirectory)

4. Define the destination information.

This is a lot similar to setting up the source data with the exception that you have to call SyncTo and pass a couple of extra parameters ( these extra parameters won’t have any configuration for this example ).

$deploymentObject.SyncTo("contentPath",$destinationDirectory,$destBaseOptions,$syncOptions);

With all of this complete there is only the task of putting it together in a nice little function and pasting into a Powershell window or adding it to a ps1 script upon Powershell session start.  The completed code is below.  And of course you must have MSDeploy installed so the assembly is available.

function Sync-Content($sourceContent,$destinationContent)
{
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Deployment")
    $destBaseOptions   = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
    $syncOptions       = new-object Microsoft.Web.Deployment.DeploymentSyncOptions
    $deploymentObject = [Microsoft.Web.Deployment.DeploymentManager]::CreateObject(“contentPath”,$sourceContent)
    $deploymentObject.SyncTo("contentPath",$destinationContent,$destBaseOptions,$syncOptions);
}

 

There is the first script-let and a powerful one!  ContentPath is a very useful provider that can sync by the name of a site or a directory location and can sync to remote UNCs that you have access.  It can also sync from a directory to a site or from a site to a directory, but it does not create new sites while it will create new directories.

 

This first script-let is a good template for a few more, by plugging in “apphostconfig” or “metakey” in place of “contentPath” and changing the script name ( maybe parameters for clarity ) you get easy to reuse code.  I will remove the LoadWithPartialName line since it will be assumed this is loaded before hand ( a one time call per session ).

 

function Sync-Site7to7($sourceSite,$destSite)
{
    $destBaseOptions   = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
    $syncOptions       = new-object Microsoft.Web.Deployment.DeploymentSyncOptions
    $deploymentObject = [Microsoft.Web.Deployment.DeploymentManager]::CreateObject(“apphostConfig”,$sourceSite)
    $deploymentObject.SyncTo("apphostConfig",$destSite,$destBaseOptions,$syncOptions);
}

function Sync-Site6to6($sourceMetakey,$destMetakey)
{
    $destBaseOptions   = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
    $syncOptions       = new-object Microsoft.Web.Deployment.DeploymentSyncOptions
    $deploymentObject = [Microsoft.Web.Deployment.DeploymentManager]::CreateObject(“metaKey”,$sourceMetakey)
    $deploymentObject.SyncTo("metaKey",$destMetakey,$destBaseOptions,$syncOptions);
}

function Sync-Site6to7($sourceMetakey,$destMetakey)

{
    $destBaseOptions   = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
    $syncOptions       = new-object Microsoft.Web.Deployment.DeploymentSyncOptions
    $deploymentObject = [Microsoft.Web.Deployment.DeploymentManager]::CreateObject(“metaKey”,$sourceMetakey)
    $deploymentObject.SyncTo("metaKey”,$destMetakey,$destBaseOptions,$syncOptions);
}

 

Again very useful providers for server administrators and for these examples you have to fill in values for the path, but in the future when remote syncs are added no path will sync the whole server!  If you notice the pattern already, we can probably consolidate these above functions into one function that brings it all together if you want something a little more versatile.  Of course you pay the price of having to remember the order of three parameters but no problem now that we are getting use to it.

function Sync-Provider($provider, $sourceLocation, $destLocation)
{
    $destBaseOptions   = new-object Microsoft.Web.Deployment.DeploymentBaseOptions
    $syncOptions       = new-object Microsoft.Web.Deployment.DeploymentSyncOptions
    $deploymentObject = [Microsoft.Web.Deployment.DeploymentManager]::CreateObject($provider, $sourceLocation)
    $deploymentObject.SyncTo($provider,$destLocation,$destBaseOptions,$syncOptions);
}

That is it for Part I.  In part II, it would be nice to explore adding remote functionality and coming up with some creative approaches to saving credentials for remote server syncs.  Also, I hope to cover some other MSDeploy operations like GetSystemInfo or GetDependencies.  Please let me know if there are request for certain functions as well.

1 Comment

  • I would appreciate seeing an example of using MSDeploy via a custom action in a MSI (perhaps with an example using WIX).

    To be VERY SPECIFIC, NIST SCAP has guidance on how IIS (and the OS) should be secured. A MSDeploy script that implements checking for conformity (producing warnings or aborts) as well as one that change the settings appropriately would be ideal. See http://scap.nist.gov/

    Items should include:
    * http://web.nvd.nist.gov/view/ncp/repository/checklistDetail?id=157
    * http://web.nvd.nist.gov/view/ncp/repository/checklistDetail?id=98

    (both are for older versions, but are at least a base line)


    Producing such an example would likely result in massive reuse of it (best practises, etc).

    Ken

Comments have been disabled for this content.