PowerShell RegEx Fun

I am writing a script that is going to automate a number of manual steps involved in creating a new image with Citrix PVS.

First step is to copy the most recent base image which is kept in a folder structure. The folder name is always YYYY-MM-DD (description):


I needed to determine the most recent folder and didn’t want to rely on creation date. Instead I walk the directory tree and filter the date out of the filename with a regular expression:

# Base Images Folder
$goldenImageFolder = "\\server\xenapp$\Base Images\"

# Determine folder with most recent date
$date =[datetime]0
gci $goldenImageFolder | foreach {
	$_ -match '(?^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01]))' | Out-Null
	if ($Matches.date -gt $date)
		$date = $Matches.date
		$goldenImage = $_

"Most recent Base Image is: {0}" -f $goldenImage


Most recent Base Image is: 2011-11-30 (updated production base images)

Next step is to copy the base image to the PVS Folder and name it according to the following convention: XenApp5_v{0}_Off2k3_Core where {0} is a 3 digit version number.

So we walk the PVS directory use a regular expression to filter out the version digits. We collect the version digits in an array and use the Measure-Object to obtain the highest number which we then increment by 1:

$baseName = "XenApp5_v{0}_Off2k3_Core"
$pVSFolder = "\\s-pvs03\d$"

# Walk the pvs server to find current images
[int[]]$versions = @()
gci $pVSFolder | foreach {
	$_ -match '^XenApp5_v(?\d{1,3})' | Out-Null
	$versions += [int]$Matches.Version

# Get current image version
$curver = ($versions | Measure-Object -Maximum).Maximum

"Current Image version is: {0}" -f $curver
# Increment version
$newver = $curver + 1

$newImage = $baseName -f $newver
"New Image Basename is: {0}" -f $newImage


Current Image version is: 25
New Image Basename is: XenApp5_v26_Off2k3_Core

Last step for this post is to copy the image over to the PVS folder but since the files are large I wanted to have progress indication (which the Copy-Item cmdlet doesn’t have). I found a function that does exactly this on stackoverflow, I only changed [int] to [uint64] to accommodate for files > 2 GB:

function Copy-File {
    param( [string]$from, [string]$to)
    $ffile = [io.file]::OpenRead($from)
    $tofile = [io.file]::OpenWrite($to)
    Write-Progress -Activity "Copying file" -status "$from -> $to" -PercentComplete 0
    try {
        [byte[]]$buff = new-object byte[] 65536
        [uint64]$total = [uint64]$count = 0
        do {
            $count = $ffile.Read($buff, 0, $buff.Length)
            $tofile.Write($buff, 0, $count)
            $total += $count
            if ($total % 1mb -eq 0) {
                Write-Progress -Activity "Copying file" -status "$from -> $to" `
                   -PercentComplete ([uint64]($total/$ffile.Length* 100))
        } while ($count -gt 0)
    finally {