We are having performance issues with some virtualising some packages in App-v 5. There’s a package that needs it’s entire registry before it performs. When a user runs the starts the packages 3 to 4 times it starts to perform better. We have seen that the registry increased by 200 MB of plain text size. This is quit a lot. Since all our Xenapp servers are virtualised and provisioned will every reboot remove the changes in the registry. So the package remains very slow. We created a script that runs on all servers and starts a CMD.exe in a virtualised process. This will trigger staging and thus loading the entire registry. When this script is ran before any users connect, users will always have a good performance.
#import AppVClient module ipmo *appv* #get all appv packages $apps = Get-AppvClientPackage $obj = @() #Get connection group applications $connApps = (Get-AppvClientConnectionGroup).GetPackages() #remove connecion-group applications from the list [System.Collections.ArrayList]$appList = $apps foreach ($connApp in $connApps) {$appList = $appList | ? { $_.name -ne $connApp.Name }} #for each (non-connection group) appv package... foreach ($app in $appList) { $prop = New-Object System.Object #get each appv package ID and version ID $package = ($app.packageID).ToString() $version = ($app.versionID).ToString() #start a blank cmd.exe in the environment (this kicks off the AppV5 registry staging) Start-AppvVirtualProcess -AppvClientObject (Get-AppvClientPackage $app.name) cmd.exe do { write-host "Testing: " $app.name sleep 1 } until (Test-Path "HKLM:\SOFTWARE\Microsoft\AppV\Client\Packages\$package\Versions\$version\RegistryStagingFinished") write-host $app.name $appvProcess = get-appvVirtualProcess stop-process $appvProcess -force } #for each connection group package... $conGroups = Get-AppvClientConnectionGroup foreach ($group in $conGroups) { $prop = New-Object System.Object #get each connection group package ID and version ID $package = ($group.groupID).ToString() $version = ($group.versionID).ToString() #start a blank cmd.exe in the environment (this kicks off the AppV5 registry staging) Start-AppvVirtualProcess -AppvClientObject ($group) cmd.exe do { write-host "Testing: " $group.name sleep 1 } until (Test-Path "HKLM:\SOFTWARE\Microsoft\AppV\Client\PackageGroups\$package\Versions\$version\RegistryStagingFinished") write-host $group.name $appvProcess = get-appvVirtualProcess stop-process $appvProcess -force }
In order to start the above script I used DPAPI to encrypt the password of the service account. I configured a scheduled task to run every day at 6:30 AM. I wrote a article or two about his some time ago. It is important to encrypt the password when logged in to that account. The profile of that service account should not be removed!
The script used to start the script above is shown below
<#Custom Module#> Import-Module "LocationWhenTheFunctionIsLocated\Function.psm1" -force <#Script Start#> Add-PSSnapin Citrix* #Note that the username is without the domain name $UserName = "ServiceAccount" $SecureString = Get-Content -Path "LocationOfTheStoredPassword.txt" | ConvertTo-SecureString -Entropy ([Math]::PI) $SecureString = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)) #If the server that launch the script is not a Citrix server you have to add -ComputerName COMPUTERNAME $OnlineServers = Get-XAServer -ZoneName FarmName -OnlineOnly | ?{$_.ServerName -match "PrefixFromProductionServers" -and $_.ServerName -notmatch "tst" -and $_.ServerName -notmatch "DEV"} #Line below is for testing purposes Add-content -Value $OnlineServers -Path "G:\Scheduler_Scripts\GMN\App-V Prelaunch\Test.csv" Foreach ($Server in $Onlineservers){ $ServerName = $Server.ServerName $Date = (Get-Date).AddMinutes(30) schtasks /create /S $ServerName /RU DOMAIN\$Username /RP $SecureString /SC Once /SD $date.ToString('dd"/"MM"/"yyy') /ST $date.ToString('HH":"mm') /TN "App-V 5 Prelaunch Script" /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe \\SharedLocationOfScriptAbove.ps1" /F }
A few things are important to make this work. First you need to share the first script on a shared location, let’s say the netlogon or whatever directory works for you. Next you’ll need to have the Xenapp SDK installed on the server that runs the script. This is needed. Only the Powershell CMDlets are required. You need to have a Xenapp server that can be reached over the network. You’ll also need to know the farm name. And of course you’ll need the have the function loaded. I added the function below this post. Check you Execution policy settings before scheduling.