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
Output:
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
Output:
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 {
$ffile.Close()
$tofile.Close()
}
}
Was once an enthusiastic PepperByte employee but is now working elsewhere. His blogs are still valuable to us and we hope to you too.