APPV Performance Troubleshooting Guide
APPV Performance Troubleshooting Guide
PERFORMANCE GUIDE
NOTE TO READER:
ALL THE SCRIPTS IN THIS DOCUMENT CONTAIN OUR STANDARD DISCLAIMER HOWEVER PLEASE MAKE SURE YOU
ALWAYS TRY OUT THESE SCRIPTS IN YOUR TEST ENVIRONMENT BEFORE YOU ARE CONFIDENT TO USE THEM IN
PRODUCTION.
1. SYSINTERNALS SUITE
https://docs.microsoft.com/en-gb/sysinternals/downloads/sysinternals-suite
TIP: Run this in an elevated PowerShell prompt to add your new path to the current path.
Please note the semi colon before the path must be present. Highlighted in RED below example.
This will enable all the suite apps to run directly from the CMD prompt.
This will write a reg key (HKCU\Software\Sysinternals\Process Monitor - EulaAccepted {DWORD: 1}) to the client user
hive so that the end user license agreement will not appear again.
Now you will be able to run ProcMon lower than other services (like McAfee or other security vendors)
https://developer.microsoft.com/en-us/windows/downloads/windows-8-1-sdk
click Next
Click No and Next
Click Accept
Select Windows Performance Toolkit and click Install
Click Close
http://www.tmurgent.com/Tools/xPerf_AppVProfile/AppVProfileforClients.zip
Extract the AppVProfileforClients.wprp file to C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit
Running a trace
For more info click here to watch the Channel 9 MSDN videos:
Open an elevated PowerShell ISE console and copy/paste the following contents into the top script area (if all the scripts
are missing: save the list of mentioned scripts using the extension as .ps1 [example: test.ps1] to C:\Tools\APPV Scripts.
The names of the files are up to you and have no impact on the script)
foreach($entry in $Packages){
$PacName = $entry.Name
$Ver = $entry.version
$PName = $PacName
$PI = [string]$entry.GroupID
$VI = [string]$entry.VersionID
$PD = $PI + "_" + $VI
Very efficient way of viewing all the APPV Logs (Admin, Operational & Virtual Applications) in one viewing without
waiting for the Event Viewer (below) to open and start consuming data to show.
The following script will open a browser (or you can use Out-GridView) and display all logs in chronological order, thus
making troubleshooting on your client easier.
<#
.DISCLAIMER The sample scripts are not supported under any Microsoft standard support program or service. The
sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties
including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall
Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any
damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
documentation, even if Microsoft has been advised of the possibility of such damages. #>
# Adding threading culture change so that get-winevent picks up the messages, if PS culture is set to none en-US then
the script will fail
$FilterXML_Admin = @"
<QueryList>
<Query Id="0" Path="Microsoft-AppV-Client/Admin">
<Select Path="Microsoft-AppV-Client/Admin">*[System[TimeCreated[timediff(@SystemTime) <=
86400000]]]</Select>
</Query>
</QueryList>
"@
$FilterXML_VirtApps = @"
<QueryList>
<Query Id="0" Path="Microsoft-AppV-Client/Virtual Applications">
<Select Path="Microsoft-AppV-Client/Virtual Applications">*[System[TimeCreated[timediff(@SystemTime) <=
86400000]]]</Select>
</Query>
</QueryList>
"@
#################
# Out-GridView (uncomment below line to view in PowerShell table mode)
#################
#################
# Convertto-Html
#################
Invoke-Item $HTML_Output
How to troubleshoot APPV packages using the Logman command and sending it to a log file
<#
.DISCLAIMER The sample scripts are not supported under any Microsoft standard support program or service. The
sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties
including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall
Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any
damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
documentation, even if Microsoft has been advised of the possibility of such damages. #>
$trace = "APPV5Debug"
$Date = get-date -f "ddMMhhmm"
$userpath = "$env:USERPROFILE\Desktop\APPVDebug"
$ETL_trace_output = "$userpath\appv5Debug.etl"
$EVTX_trace_output = "$userpath\appv5Debug$Date.evtx"
$TXT_trace_output = "$userpath\appv5Debug$Date.txt"
$Random = Get-Random
$ProviderFile = "$userpath\AppVClientProviders$Random.txt"
foreach($entry in $AppVProviders){
write-host
$Start_Trace = read-host -prompt "Do you want start the trace now? (Y/N)"
if ($Start_Trace -eq "Y" -or $Start_Trace -eq "y")
{ write-host "Starting Logman Trace $Trace" -f
yellow logman.exe start $trace write-host
}
elseif ($Start_Trace -eq "N" -or $Start_Trace -eq "n"){
write-host "You will need to start the trace manually from perfmon.exe..." -f yellow
}
$Stop_Trace = read-host -prompt "Do you want stop the trace now? (Y/N)"
#End of script
<#
.DISCLAIMER The sample scripts are not supported under any Microsoft standard support program or service. The
sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties
including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall
Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any
damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
documentation, even if Microsoft has been advised of the possibility of such damages. #>
Function Get-AppVPublishingTime($ClientName) {
[hashtable]$Return = @{}
# If the last publish time is higher than the done time no result will be returned
$Return.LastPublishTime = $LastPublishTime.TimeCreated
$Return.ComputerName = $ClientName
$Return.PublishTime = $PublishTime.TotalSeconds
# Return data
Return $Return
}
#End of script
$package = "alter"
Get-ChildItem -Path
HKLM:\SOFTWARE\Microsoft\AppV\Client\Packages\$($pkgid.PackageId)\Versions\$($pkgid.VersionId)\REGISTRY\
Recurse | Out-GridView -ErrorAction SilentlyContinue
#End of script
<# .DISCLAIMER The sample scripts are not supported under any Microsoft standard support program or service. The
sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties
including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall
Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any
damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
documentation, even if Microsoft has been advised of the possibility of such damages. #>
If ("$env:temp\AppxManifest.xml") {remove-item "$env:temp\AppxManifest.xml" -Force}
[STRING]$Zipfile = "C:\v-AlteryxDesigner_1.02\v-AlteryxDesigner_1.02.appv"
[STRING]$Filename = "AppxManifest.xml"
[STRING]$Destination = "$env:temp"
[STRING]$FILELOCATION = "$Destination\$Filename"
#End of script
There are two main XML files that contain the information about both COM and Object setting and they are included in
the Package Catalog:
%PROGRAMDATA%\Microsoft\AppV\Client\Catalog\Packages
If the Package is published globally you will see two extra files “UserManifest.xml” and
“UserDeploymentConfiguration.xml” which are created when a package is published globally.
https://technet.microsoft.com/en-us/itpro/mdop/appv-v5/application-publishing-and-clientinteraction?
f=255&MSPPError=-2147217396#bkmk-files-data-storage
If you open either XML file, the COM or Objects settings may not be set as there is an OOS (Out of Sequencer)
experience where you haven’t checked any of the advanced options on the sequencer i.e.
If you set the values on the advanced tab of the sequencer, then obviously the default OOS settings are changed.
The changed values are then updated in the Manifest.xml or UserManifest.xml (dependent upon whether the package is
published globally or not). Within the “.appv” package itself the file that gets updated is the AppxManifest.xml.
But the sequencer also updates the _DeploymentConfig.xml file to have the same values:
<# .DISCLAIMER The sample scripts are not supported under any Microsoft standard support program or service. The
sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties
including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall
Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any
damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
documentation, even if Microsoft has been advised of the possibility of such damages. #>
########################################
# Function Check-AppVClientPackages
########################################
Function Check-AppVClientPackages(){
$Results_PC = @()
foreach($PKG in $PKGs){
$Package_Name = $PKG.Name
$Package_PID = $PKG.PackageId
$Package_VID = $PKG.VersionId
$Package_IPG = $PKG.IsPublishedGlobally
$Package_V = $PKG.Version
$Package_DCP = $PKG.GetDynamicDeploymentConfigurationPath()
# DeploymentConfiguration.xml
[xml]$ManConDP = gc $Package_DCP
$DP_Objects = $ManConDP.DeploymentConfiguration.UserConfiguration.Subsystems.Objects.Enabled
$DP_COM_Mode = $ManConDP.DeploymentConfiguration.UserConfiguration.Subsystems.COM.Mode
$DP_COM_OutP =
$ManConDP.DeploymentConfiguration.UserConfiguration.Subsystems.COM.IntegratedCOMAttributes.OutOfProcessEna
bled
$DP_COM_InP =
$ManConDP.DeploymentConfiguration.UserConfiguration.Subsystems.COM.IntegratedCOMAttributes.InProcessEnable
d
# AppxManifest.xml
$Package_Dir = [io.path]::GetDirectoryName($Package_DCP)
$Package_Man = "$Package_Dir\UserManifest.xml"
}
[xml]$ManConAppx = gc $Package_Man
Clear-Variable Package_Man
Clear-Variable ManConDP
Clear-Variable ManConAppx
# Object Configuration
$Package_Objects = "true"
$Package_Objects_Set = "Default"
$Package_Objects = $DP_Objects
$Package_Objects_Set = "DeploymentConfiguration"
$Package_Objects = $Appx_Objects
$Package_Objects_Set = "AppXManifest"
# COM Mode
$Package_COM_Mode = "Isolated"
$Package_COM_Set = "Default"
$Package_COM_OutP = "true"
$Package_COM_OutP = $DP_COM_OutP
$Package_COM_OutP = $Appx_COM_OutP
$Package_COM_InP = "false"
$Package_COM_InP = $DP_COM_InP
$Package_COM_InP = $Appx_COM_InP
$Results_PC += $Result_PC
}
return $Results_PC
Check-AppVClientPackages
# End of script
First open the application in the APPV VE CMD Prompt (see above scripts) and type: powershell
Now PowerShell is running the APPV VE and you can run these useful commands:
Returns the total amount of files in the folder and subfolders (so you can do file compare from native to virtual)
Below are a few scripting examples for App-V 5 configuration files (DeploymentConfig, UserConfig and
AppxManifest files).
Installing a shim
<MachineScripts>
<AddPackage>
<Path>sdbinst.exe</Path>
<Arguments>/q "[{AppVPackageRoot}]\..\Scripts\ExampleFile.sdb"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
<MachineScripts>
<AddPackage>
<Path>powershell.exe</Path>
<Arguments>-ExecutionPolicy ByPass -WindowStyle Hidden -File "[{AppVPackageRoot}]\..\Scripts\
PowerShellFile.ps1"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
<MachineScripts>
<AddPackage>
<Path>powershell.exe</Path>
<Arguments>-ExecutionPolicy ByPass -WindowStyle Hidden -Command "& { Get-EventLog -LogName
security }"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
Running an EXE (For example, Powershell) without waiting for execution to complete
<MachineScripts>
<AddPackage>
<Path>cmd.exe</Path>
<Arguments>/c START "" "powershell.exe" -ExecutionPolicy ByPass -WindowStyle Hidden -File
"[{AppVPackageRoot}]\..\Scripts\runProcess.ps1"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
<MachineScripts>
<AddPackage>
<Path>cscript.exe</Path>
<Arguments>"[{AppVPackageRoot}]\..\Scripts\Cscript_File.vbs"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
<MachineScripts>
<AddPackage>
<Path>wscript.exe</Path>
<Arguments>"[{AppVPackageRoot}]\..\Scripts\VB_File.vbs"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
Installing an MSI
<MachineScripts>
<AddPackage>
<Path>msiexec.exe</Path>
<Arguments>/i "[{AppVPackageRoot}]\..\Scripts\MSI_File.msi" /qb</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
Installing a Driver
<MachineScripts>
<AddPackage>
<Path>pnputil.exe</Path>
<Arguments>/i /a "[{AppVPackageRoot}]\..\Scripts\Driver_File.inf"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
<MachineScripts>
<AddPackage>
<Path>icacls.exe</Path>
<Arguments>"C:\AshurstTest" /grant Users:(OI)(CI)(M) /C /Q</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
Creating a Symbolic Link (Running a windows command shell internal command – see here)
<MachineScripts>
<AddPackage>
<Path>cmd.exe</Path>
<Arguments>/C MKlink /D C:\Ashurst "C:\Program Files\AAshurst"</Arguments>
<Wait RollbackOnError="true" Timeout="30"/>
</AddPackage>
</MachineScripts>
<# .DISCLAIMER The sample scripts are not supported under any Microsoft standard support program or service. The
sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties
including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall
Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any
damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
documentation, even if Microsoft has been advised of the possibility of such damages. #>
# Using 8 threads of execution, each generating 8 outstanding random 8KB unbuffered read IOs #
PLEASE AMEND THE <architecture> in the path below before running script!!!
#End of script