Extending Citrix Cache Drives in vSphere

I have a large client running a Citrix XenDesktop farm on top of vSphere. The environment is using PVS to PXE boot desktops. The VM shells were created with a 2GB cache drive. However, the environment has grown and we needed to extend the drive to 3GB.

PowerShell and PowerCLI to the rescue! First, we need to extend the size of the VMDK from 2 to 3GB. The client wanted me to do this in a controlled manner, so I pointed my script to the AD OU containing computer accounts for a specific pool of desktops. I do realize I could have passed a few more of the variables as parameters.

[powershell]
Param(
[switch] $WhatIf=$true
)

$LOG_FILE_NAME = “output.txt”

function LogThis($buf)
{
write-host $buf
Add-Content -Path $LOG_FILE_NAME $buf
}

if ( Test-Path $LOG_FILE_NAME )
{
Remove-Item $LOG_FILE_NAME
}

Add-PSSnapin VMware.VimAutomation.Core
Import-Module ActiveDirectory
Connect-VIServer YOURVCENTER.foo.com
$computers = get-adcomputer -Filter * -SearchBase “OU=Some OU2,OU=Some OU,DC=foo,DC=com”
foreach ( $computer in $computers )
{
LogThis( $computer.Name )
$vm = Get-VM $computer.Name -ErrorAction SilentlyContinue
if ( $vm -eq $null)
{
LogThis( “Could not locate VM in vCenter” )
}
else
{
foreach ( $hd in (Get-HardDisk $vm) )
{
#$hd.CapacityKB -lt “2097153” #2097152 is 2048K
if ( $hd.CapacityKB -lt “2097513” )
{
if ( $WhatIf -eq $true )
{
LogThis(“Running in whatif mode – would have extended disk.”)
}

else
{
Set-HardDisk -HardDisk $hd -CapacityKB 3145728 -Confirm:$False
}
}
else
{
LogThis(“No disk extension required.”)
}
}
}
LogThis(“`r`n”)

}
[/powershell]

Next, I needed a way to expand the partition for Windows. I thought about some kind of script to disconnect the VMDK, mount it to another VM and extend it that way, but it seemed too destructive. So I looked at diskpart instead. I first thought I was going to use a GPO to trigger a startup script, but apparently you can’t use those with Citrix PVS. The VM thinks it’s the identity of the master on boot – your WMI filters don’t work.

Instead, I went with remote Powershell invocation of diskpart.exe

[powershell]
Param(
[switch] $WhatIf
)

Add-PSSnapin VMware.VimAutomation.Core
Import-Module ActiveDirectory
Connect-VIServer MYVCENTER.foo.com
$computers = get-adcomputer -Filter * -SearchBase “OU=OU2,OU=OU,DC=foo,DC=com”

$LOG_FILE_NAME = “diskpart_output.txt”

function LogThis($buf)
{
write-host $buf
Add-Content -Path $LOG_FILE_NAME $buf
}

if ( Test-Path $LOG_FILE_NAME )
{
Remove-Item $LOG_FILE_NAME
}

foreach ( $computer in $computers )
{
LogThis( $computer.Name )
if ( $WhatIf -eq $true )
{
LogThis(“Would have performed remote script”)
}
else
{
invoke-command -computername $computer.Name -ScriptBlock { $script = $Null;$script = @(“select disk 0″,”select partition 1″,”extend”,”exit”);$script | Out-File -Encoding ASCII -FilePath “c:\windows\temp\Diskpart-extend.txt”;diskpart.exe /S C:\windows\temp\Diskpart-extend.txt}
}

}
[/powershell]

The Invoke-Command line deserves some explanation

The diskpart commands I want to run are:
select disk 0
select partition 1
extend
exit

I create an empty variable and write the diskpart commands out to it. Then I use Out-File to save the diskpart commands to a text file in C:\windows\temp. Then I call diskpart.exe with an /S command switch, which executes the commands in the script. Because I used the -ComputerName parameter, all of my code is remotely executed on the desktop.

Hope this post saves you some time.

Leave a Reply

Your email address will not be published. Required fields are marked *