Here is a script to automate ‘offline defragging’ your PVS vDisks. Why Defrag? It’s explained nicely here.
Effects of Fragmentation on Write Cache Size
The culprit above in excessive write cache size is fragmentation. This is caused because PVS redirection is block based and not file based. The redirection to the write cache is based on the logical block level structure of the vDisk. To illustrate this, consider the scenario below.
And the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
############################################################################################ # # Title: Citrix PVS vDisk Defrag # # Name: Trentent Tye # # Date: 2016-04-19 # # Description: This script was designed to automate defragging vDisks. The variables underneath # are hardcoded (Bad Trentent!) but they should become parameterized to make this # dynamic. On the To Do. This was just a quick and dirty script to get this # done... # # #Prerequistes # Citrix PVS Console (7.7 used while developing this script) # Appropriate permissions to login to PVS # Martin Zugec's MCLI to PowerShell https://www.citrix.com/blogs/2012/07/23/provisioning-services-and-powershell-easier-method/ # ^^ fixed up: http://trentent.blogspot.ca/2016/04/convertfrom-mcli-for-pvs-76-posh-module.html # # ############################################################################################ ###########################################VARIABLES########################################## #PVS Server $PVSServer = "PVS04" #PVS Port number $PVSPort = "54321" $TargetvDiskName = "XenApp65Tn05" $PVSStore = "XenApp" $PVSSite = "BDC" #Domain used $PVScred = Get-Credential -Message "Enter your credentials for Citrix PVS (DOMAIN\Username):" ###########################################VARIABLES########################################## #Add PowerShell MCLI for PVS #$installutil = $env:systemroot + '\Microsoft.NET\Framework64\v4.0.30319\installutil.exe' #&$installutil "C:\Program Files\Citrix\Provisioning Services Console\McliPSSnapIn.dll" add-PSSnapIn mclipssnapin #add ConvertFrom-MCLI $ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path . (Join-Path -Path $ScriptDir -ChildPath 'PVS-ConvertToPosh.ps1') ####SETUP CONNECTIONS#### #Setup PVS server connection, MCLI-Run appears to only plain text for the username and password... We will convert the secure string password #to plain text then blank it, and convert the username credential to a string to prevent an object being passed. Write-Host "Connecting to PVS..." -ForegroundColor Yellow $PVSUser = $PVScred.UserName.ToString() $PVSPassPlainText = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($PVSCred.Password)) try { MCLI-Run setupconnection -p server=$PVSServer,port=$PVSPort,user=$PVSUser,password=$PVSPassPlainText -ErrorAction Stop } catch { Write-Host "Connection to PVS Failed" -ForegroundColor Yellow Write-Host "Perhaps your credentials are incorrect?" -ForegroundColor Yellow write-host "$_" pause } $PVSPassPlainText = "" #First check, is the target vDisk set to prod? Write-Host "Checking if the target vDisk is set to Prod..." -ForegroundColor Yellow $diskver = mcli-get diskversion -p diskLocatorName=$TargetvDiskName,siteName=$PVSSite,storeName=$PVSStore #access reports back the following values: #0 (Production), 1 (Maintenance), 2 (MaintenanceHighestVersion), 3 (Override), 4 (Merge), 5(MergeMaintenance), 6 (MergeTest), and 7 (Test) Min=0, Max=7, Default=0 $diskobj = $diskver | convertfrom-MCLI foreach ($diskprop in $diskobj) { if ($diskprop.access -ne "0") { write-host "vDisks need to be in a good production state. A maintenance or test vDisk version was detected.`nPlease remove or promote this version before continuing." write-host "Disk detected in maintenance mode: " $diskprop.diskFileName pause #exit } } #all vDisks in chains are in production state. Creating new version... Write-Host "Creating Maintenance version..." -ForegroundColor Yellow $error.Clear() $createMaintenance = mcli-runwithreturn createmaintenanceversion -p diskLocatorName=$TargetvDiskName,siteName=$PVSSite,storeName=$PVSStore #check to see if creation of the Maintenance version was successful if ($error.Count -gt 0) { write-host "vDisk creation failed." write-host $createMaintenance pause } #set the description of the vDisk to identify who has run it: $diskver = mcli-get diskversion -p diskLocatorName=$TargetvDiskName,siteName=$PVSSite,storeName=$PVSStore $maintenanceVersion = ($diskver | convertfrom-MCLI).version[-1] Write-Host "Setting Maintenance version description..." -ForegroundColor Yellow Mcli-Set DiskVersion -p diskLocatorName=$TargetvDiskName,siteName=$PVSSite,storeName=$PVSStore,version=$maintenanceVersion -r description="$env:username defragged the vDisk" #get the vDisk filename from the return value: $vDiskFileName = $createMaintenance.split("= ")[-1] #get the serverStore path for the file: $storePath = mcli-get serverstore -p servername=$PVSServer,storename=$PVSStore | ConvertFrom-MCLI #mount the new version of the vDisk on this server Write-Host "Mounting vDisk..." -ForegroundColor Yellow $pathTovDiskVersion = $storePath.path + "\" + $vDiskFileName . "$env:ProgramFiles\Citrix\Provisioning Services\CVhdMount.exe" -p 1 $pathTovDiskVersion #get the driveLetter of the attached vDisk: sleep 5 $vDiskDriveLetter = (Mcli-RunWithReturn MappedDriveLetter).split("= ")[-1] + ":" if ($vDiskDriveLetter -eq ":") { write-host $vDiskDriveLetter write-host (Mcli-RunWithReturn MappedDriveLetter) write-host "CVHDMOUNT failed" pause } #https://blogs.technet.microsoft.com/askperf/2008/03/14/disk-fragmentation-and-system-performance/ #defrag switches: #-c: Defragments all volumes on the system. You can use this switch without needing to specify a drive letter or mount point #-a: Perform an analysis of the selected drive and provides a summary output (shown below): #-r: Performs a partial defragmentation by consolidating only file fragments that are less than 64MB in size. This is the default setting #-w: Performs a full defragmentation by consolidating all file fragments regardless of size #-f: Force defragmentation of the volume even if the amount of free space is lower than normally required. When running this, be aware that it can result in slow system performance while the defragmentation is occurring #-v: Displays verbose reports. When used in combination with the -a switch, only the analysis report is displayed. When used alone, both the analysis and defragmentation reports are shown. #-i: Runs the defragmentation in the background and only if the system is idle #-b: Optimizes boot files and applications, but leaves the rest of the drive untouched. Only works on boot drive defrag $vDiskDriveLetter -w -f -v . "$env:ProgramFiles\Citrix\Provisioning Services\CVhdMount.exe" -u 0 #promote version to production Write-Host "Promoting vDisk to production..." -ForegroundColor Yellow mcli-run PromoteDiskVersion -p diskLocatorName=$TargetvDiskName,siteName=$PVSSite,storeName=$PVSStore |
Nice script! I am sure I will try it out. Many thanxs! I think it took you many hours to build this script.