Error message

  • Deprecated function: implode(): Passing glue string after array is deprecated. Swap the parameters in drupal_get_feeds() (line 394 of /users/fisherde/public_html/fishpitt.com/includes/common.inc).
  • Deprecated function: The each() function is deprecated. This message will be suppressed on further calls in menu_set_active_trail() (line 2394 of /users/fisherde/public_html/fishpitt.com/includes/menu.inc).

Powershell - Migrating Blackboard B2s

  • Posted on: 23 January 2015
  • By: Ashley

Intro

To start this blog post I would like to highlight that I haven't had too much experience with Powershell until late, however with an ever growing fleet of applications, environments and therefore servers to look after, I've tried to start scripting some of the tasks involved with Windows server administration.

About

This script is the second in an library of Powershell scripts for the management of applicatons on Windows servers, this particular script is for the Blackboard LMS, and is concerned with one frustrating task that often needs to be carried out; migrating building blocks between environments. I have found this task to be particularly frustrating for a variety of reasons, the most prolific is trying to keep versions the same while migrating, Blackboard does a good job of advertising through the UI that a new B2 upgrade is available, however by the time we get through to migrating everything into production, there are many released of a building block which are newer than those we tested.

Standardisation

I'm trying to create a standardised approach to all of my scripts, drawing attention back to the fact I'm hoping to develop a library of scripts for a large variety of tasks, one of the things I've done so far is to have 'action' arguments, these so far consist of 'describe' 'retrieve and 'run'. Describe is similar to the Unix man pages, and can be used to give usage examples and the like, 'retrieve' is meant to return the script object, the intention here is to have a parent script able to retrieve the information about the script it's calling, to use internally as an object, run doesn't need too much expansion.

The Moving Parts

Inputs/Arguments

Declaring inputs in Powershell is incredibly easy, using them is just as easy. The below example is what I've got so far in the scripts I've created, $action is what you want to do, and $force is so far unused, but is intended to be used in cases where you're wanting to definitely override a setting, or replace a file, no questions asked.

param (
	[string]$action,
	[string]$force
)
PSObject - My Information Source

The script object, this is what I'm using to populate information about the script, the $script object is returned by using '-action retrieve' as an argument when starting the .ps1 file, and the information is output to the screen when using '-action describe'.

$script = New-Object PSObject -Property @{
	Title = 'Building Block Installer'
	Affects = 'Blackboard' 
	Author = 'Ashley Fisher'
	Version = '1.0'
	PublishDate = '22/01/2015'
	Description = 'Reads input from a ...'
}
Run dog, run

This particular script is incredibly tiny, for good reason, I'm employing one of the batch files Blackboard provides for the actual installation of the building block, all I'm really giving it is a list of the B2s I want migrated/installed, the arguments required (forcing override of security limitations), and the order that I want the B2s installed in.

$B2Location = "D:\B2s"
$installOrder = Get-Content $B2Location'\InstallOrder.txt'

$B2Manager = "D:\blackboard\tools\admin\B2Manager.bat"

$B2s = Get-ChildItem $B2Location -Filter *.war

Write-Host "Defined Install Order for B2s" -foregroundcolor "red"
foreach($line in $installOrder){
	Write-Host "Installing "$line.split(',')[0]", with options "$line.split(',')[1]
}
$ack = Read-Host "Do you want to continue with installing the building blocks in this order?"
if($ack -eq 'yes'){
	foreach($line in $installOrder){
		$installB2 = $B2Location + "\" + $line.split(',')[0]
		$bat = & $B2Manager "-i" $installB2 $line.split(',')[1]
		Write-Host ''
		Write-Host $bat
		Write-Host ''
	}
}
Huh?

In the above example, you can see a few different objects I'm initialising, a couple aren't yet used, however are going to be build around reducing input, verifying prior to trying to run the install, and just logging everything that has happened for review later.

While running through the initial testing, all of my Building Blocks were stored in D:\B2s\, this location for a proper migration tool would be a centralised location, such as '\\dfs.domain.internal\B2Repo\', the $B2s object is not currently used, but will be used in conjunction with the 'InstallOrder.txt' file, to assess whether the building blocks listed in the text file actually exist at that location.

I am sticking with the plan to have manual input to kick off the task, I do not want to allow this script to run accidentally and potentially break a B2, or even worse, the environment.

The script then works through the InstallOrder.txt file, working through the listed building blocks with their required arguments, the B2Manager does all the work for us. The processing of the building blocks is purposely sequential, allowing us to install the mandatory building blocks prior to others which depend on them.

Summary

Overall, the writing and the testing of the above script was 20 or so minutes very well spent, a lot has been learned, and I can see alot of potential here for reducing the time it takes for us to upgrade our environments.