Simple Powershell Central Config

2

One of the aspects that I really like about the embracing of DevOps mentality is that we have more acceptance between the disciplines of Development and Operations. On the Ops side that means taking some of the core development pillars and incorporating those standards and ideas into areas like script development.  Two concepts that I think are important for Powershell scripting is the removal of hard coded values and code reuse. That means making scripts more robust, creating an ecosystem that supports your scripts, and creating scripts that are more modular.

I’m often coming up with Powershell scripts that need to target a specific environment. That environment could contain multiple servers that need to be updated,  a specific database connection, or specific URL. Instead of hard coding connection strings in every script, I wanted to store them in a Powershell central config. I also wanted to easily reuse the functionality with limited redundant code. What I’ve created is a simple Powershell Central Config. I specifically lets me get environment configuration details by referencing an environment name.

A Simple Powershell Central Config

Powershell-ConfigWhile there are several ways to implement this concept, I wanted to keep this as simple as possible to setup and use. Here is an overview of the 3 main components:

  • Environments.xml – This is an XML file containing Environment specific properties. For maximum reuse, put this on a file share that is accessible from all of your servers. If we need to update Environment details later we do it in one place here.
  • Include-Configuration.ps1– This is a Powershell script file that gets included by your primary scripts. It has a reference to the full path of Environments.xml and also the functions we’ll use later. We can update or add to our logic in one place.
  • Test-Env.1 – This is an example Powershell script file that would reference and include the Include-Configuration.ps1 script. This demonstrates how we would get environment specfic data using a script parameter value.

Now lets look at the details of each of these.

Environments.xml

Create an XML file that matches this syntax. It needs to reside on a server file share where everyone who needs to reference it can read it. You can update the values to match your needs. In my example I’m saving it as \\atlfilep01\Config\Environments.xml

<?xml version="1.0" encoding="utf-8"?>
<environments>
  <environment>
    <Name>Dev</Name>
	<Home>E:\Dev\</Home>
	<Servers>
		<Server>ATLWEBD01</Server>
	</Servers>
	<SVNStore>/svn/byron/trunk/Dev/Config/</SVNStore>
	<DBConnection>server=atlsqld01;Integrated Security=SSPI;database=ByronDB;</DBConnection>
  </environment>
  <environment>
    <Name>Test</Name>
	<Home>E:\Test\</Home>
	<Servers>
		<Server>ATLWEBT01</Server>
		<Server>ATLWEBT02</Server>
	</Servers>
	<SVNStore>/svn/byron/trunk/Test/Config/</SVNStore>
	<DBConnection>server=atlsqlt01;Integrated Security=SSPI;database=ByronDB;</DBConnection>
  </environment>
  <environment>
    <Name>Prod</Name>
	<Home>E:\Production\</Home>
	<Servers>
		<Server>ATLWEBP01</Server>
		<Server>ATLWEBP02</Server>
		<Server>ATLWEBP03</Server>
	</Servers>
	<SVNStore>/svn/byron/trunk/Prod/Config/</SVNStore>
	<DBConnection>server=atlsqlp01;Integrated Security=SSPI;database=ByronDB;</DBConnection>
  </environment>
</environments>
Include-Configuration.ps1

This script contains your configuration script functions. It should also be stored on server file share. In this example I’m saving it in \\atlfilep01\Scripts\Include-Configuration.ps1. The core functionality of this script is taking an environment name and then performing an XML query with that name. In the case of our environment servers (Get-EnvServers), we’re returning an array of server names that we can iterate over in our primary scripts.

$configfile = "\\atlfilep01\Config\Environments.xml"

function Get-SVNStore($name){
	$result = "NA"

	$xml = New-Object -TypeName XML
	$xml.Load($configfile)

	$result = $Xml.environments.environment | Where-Object { $_.Name -eq $name } | Select-Object -Property SVNStore

	return $result.SVNStore
}

function Get-DBConnection($name){
	$result = "NA"

	$xml = New-Object -TypeName XML
	$xml.Load($configfile)

	$result = $Xml.environments.environment | Where-Object { $_.Name -eq $name } | Select-Object -Property DBConnection

	return $result.DBConnection
}

function Get-HomePath($name){
	$result = "NA"

	$xml = New-Object -TypeName XML
	$xml.Load($configfile)

	$result = $Xml.environments.environment | Where-Object { $_.Name -eq $name } | Select-Object -Property Home

	return $result.Home
}

function Get-EnvServers($name){

	$xml = New-Object -TypeName XML
	$xml.Load($configfile)

	$result = $Xml.environments.environment | Where-Object { $_.Name -eq $name }

	$s2 = $result.Servers | Select-Object -Property Server
  return $s2.Server
}

Test-Env.ps1

This is an example of how to use Include-Configuration.ps1 to load our environment data. It could be stored on your server file share, but would also work from a local path as well. A few things to make note of:

  • The script has a mandatory Parameter called $Env, this is the Environment name we’ll use to search on.
  • We’re dot sourcing Include-Configuration.ps1, but before we do that we’re doing a Test-Path to make sure the script is accessible.
  • We’re calling the functions we defined earlier in the case of Get-EnvServers we’re getting an array of server names back and using that in a foreach loop.
param (
    [Parameter(Mandatory=$true)]
    [String]$Env
    )

# Load Include Scripts
if (!(Test-Path "\\atlfilep01\Scripts\Include-Configuration.ps1")){Write-Error "Include Script Not Found: \\atlfilep01\Scripts\Include-Configuration.ps1"; exit}
. "\\atlfilep01\Scripts\Include-Configuration.ps1"

Write-Host "Loading Environment Details for $Env"

# Get Database Connection String
$connstr = Get-DBConnection $Env

Write-Host "SQL Connection String: $connstr"

# Get Server List and Iterate
$servers = Get-EnvServers $Env

foreach ($svr in $servers)
{
	#Do something with server
	Write-Host "Updating $svr"
}

Write-Host ""

Hopefully you find this a simple way to make your scripts more powerful and easier to manage. In future posts I’ll expand on this and show some examples of how to use this.

My New Stories

March 2016 Web Hosting Deals
Powershell AD Group Management
Troubleshooting 403