Packaging DSC configurations for Visual Studio / TFS Release Management vNext

If you are using Visual Studio Release Management vNext to release your applications you’ll probably have DSC (Desired State Configuration) configurations that are shared between applications or provided by your operations team. In both cases they have a different lifecycle than your application and should be provisioned individually. But how do you publish PowerShell scripts or other files with the TFS build engine without creating empty solutions and adding the files?

What you can do is to add a simple project file like TFSBuild.proj that calls a PowerShell script. This project file can be used in a team build. The project file is really simple and all the logic is in the script file.

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <Target Name="EndToEndIteration">
        <Exec Command="powershell.exe -file .\Package.ps1 -verbose" />
    </Target>
</Project>

The script uses TFS build variables $Env:TF_BUILD_SOURCESDIRECTORY and $Env:TF_BUILD_BINARIESDIRECTORY to copy files to the output directory. The build engine then takes care of copying the output to the drop folder.

# Specify file types to exclude
$FileTypes = $("*.log";"*.proj";"*.vsprops")

$SourceDir = "$($Env:TF_BUILD_SOURCESDIRECTORY.TrimEnd('\'))\DSCResources"

# Find the files
$files = gci $SourceDir -Recurse -Exclude $FileTypes

if($files)
{
    Write-Verbose "Found $files.count files:"

    foreach ($file in $files) {
        Write-Verbose $file.FullName
    }
}
else
{
    Write-Warning "Found no files."
}

# If binary output directory exists, make sure it is empty
# If it does not exist, create one
# (this happens when 'Clean workspace' build process parameter is set to True)
if ([IO.Directory]::Exists($Env:TF_BUILD_BINARIESDIRECTORY))
{
    $DeletePath = $Env:TF_BUILD_BINARIESDIRECTORY + "\*"
    Write-Verbose "$Env:TF_BUILD_BINARIESDIRECTORY exists."
    if(-not $Disable)
    {
        Write-Verbose "Ready to delete $DeletePath"
        Remove-Item $DeletePath -recurse
        Write-Verbose "Files deleted."
    }
}
else
{
    Write-Verbose "$Env:TF_BUILD_BINARIESDIRECTORY does not exist."

    if(-not $Disable)
    {
        Write-Verbose "Ready to create it."
        [IO.Directory]::CreateDirectory($Env:TF_BUILD_BINARIESDIRECTORY) | Out-Null
        Write-Verbose "Directory created."
    }
} 

# Copy the binaries
Write-Verbose "Ready to copy files."
if(-not $Disable)
{
    Copy $SourceDir $Env:TF_BUILD_BINARIESDIRECTORY -Recurse -Exclude $FileTypes
    Write-Verbose "Files copied."
}

With the project file you can create a team build and use its output for a component is Release Management that can be reused in every project.

You can use the same technique to ensure that your custom DSC resources and the resources from the resource kit are present on all servers. Put all the resources in a repository an create a build to publish them. Use a configuration like DSCResourcesConfiguration.ps1 in your release templates as the first action.

Configuration DSCResourceConfiguration
{
    Node  $env:COMPUTERNAME
    {
        File DSCModules
        {
            SourcePath      = "$applicationPath\DSCResources"
            DestinationPath = "$env:ProgramFiles\WindowsPowerShell\Modules"
            Type            = "Directory"
            Recurse         = $true
            Ensure          = "Present"
        }
    }
}

DSCResourceConfiguration

I use this technique a lot to separate things from my application that I might use in other projects. I can also give the operations team its own git repostitory where they can easily store their DSC configurations. If you find it usefull you can get the file from my script repository on GitHub.

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s