App-V 5 and Killing Child Processes

I recently packaged an application that, upon launch, started a background service called EntDistributorService.exe.

EntDistributorService.exe spawned a child process called hvced.exe (I knew hvced.exe was a child process by running the wmic command found here.), which remained running when the launched application was closed.

When a process contained within the App-V package remains open, it presents issues when we need to unpublish it – the App-V package can’t be unpublished if it is still deemed as being in a ‘running’ state!

I tried a couple of ways to kill hvced.exe via some scripting (I tried taskkill.exe and Powershell’s Stop-Process) via both the ExitProcess and TerminateVirtualEnvironment execution times (in the UserConfig.xml).  Unfortunately the context that these scripts run in didn’t have enough permissions to kill the process, since EntDistributorService.exe was launched in a SYSTEM context and as a result hvced.exe was also running in a SYSTEM context.

After all this fiddling around, it turned out that the solution was quite simple really.  In the DeploymentConfig.xml file we can simply add the file who’s child processes we want to terminate like so:

<TerminateChildProcesses>      
    <Application Path="[{AppVPackageRoot}]\VFS\ProgramFilesCommonX86\HealthVISION\EntDistributorService.exe" />         
</TerminateChildProcesses>

And it worked like a charm.

Using Taskkill.exe to Kill Multiple Processes on One Line

I’ve had an issue with my current App-V 5 application.  When I launch an executable called CentralSurveillance.exe, it spawns another two processes called K2DataLogger.exe and K2MSService.exe.  And these remain open even when I close CentralSurveillance.exe.  My first thoughts were that these were child processes, so I added the following to the DeploymentConfig:

<TerminateChildProcesses>
<Application Path="[{ProgramFilesX86}]\K2 Medical Systems\Guardian\CentralSurveillance.exe" />
</TerminateChildProcesses>

Sure enough, when I closed the instance of CentralSurveillance.exe….the instances of K2DataLogger.exe and K2MSService.exe were still running!  So I dug a little deeper – were these actually child processes or not?

I opened up a command prompt and ran:

wmic process Get Name,Description,CommandLine,ProcessId,ParentProcessId /format:list > processes.txt

What this does is list the name, description, command line, process id and parent process id of each running process and outputs it to a text file called processes.txt.  The results (after I’d deleted the irrelevant stuff) were as follows:

CommandLine="C:\Program Files\Microsoft Application Virtualization\Client\AppVClient.exe"
Description=AppVClient.exe
Name=AppVClient.exe
ParentProcessId=496
ProcessId=2664

CommandLine=C:\windows\system32\svchost.exe -k DcomLaunch
Description=svchost.exe
Name=svchost.exe
ParentProcessId=496
ProcessId=612

CommandLine=C:\windows\Explorer.EXE
Description=explorer.exe
Name=explorer.exe
ParentProcessId=4032
ProcessId=4224

CommandLine="C:\Users\xxxxx\AppData\Local\Microsoft\AppV\Client\Integration\07390066-7746-41A4-B6FB-3D1977D289BA\Root\VFS\ProgramFilesX86\K2 Medical Systems\Guardian\CentralSurveillance.exe"
Description=CentralSurveillance.exe
Name=CentralSurveillance.exe
ParentProcessId=4224
ProcessId=6120

CommandLine="C:\ProgramData\App-V\07390066-7746-41A4-B6FB-3D1977D289BA\CF8C5523-5038-4C73-991E-EBB4812B110B\Root\VFS\ProgramFilesX86\K2 Medical Systems\Guardian\K2DataLogger.exe"
Description=K2DataLogger.exe
Name=K2DataLogger.exe
ParentProcessId=2664
ProcessId=6040

CommandLine="C:\ProgramData\App-V\07390066-7746-41A4-B6FB-3D1977D289BA\CF8C5523-5038-4C73-991E-EBB4812B110B\Root\VFS\ProgramFilesX86\K2 Medical Systems\Guardian\K2MSService.exe"
Description=K2MSService.exe
Name=K2MSService.exe
ParentProcessId=2664
ProcessId=3872

We can clearly see that the parent process of K2DataLogger.exe and K2MSService.exe is NOT CentralSurveillance.exe (process id 6120) but instead AppVClient.exe (process id 2664).  And this is probably why TerminateChildProcesses will not work in this instance.  The workaround I used is to run an ExitProcess script so that when we close CentralSurveillance.exe, it kills both K2DataLogger.exe and K2MSService.exe.

I did this like so:

<UserScripts>
<ExitProcess>
<Path>CMD.EXE</Path>
<Arguments>/C taskkill /im "K2DataLogger.exe" /f /t &amp; taskkill /im "K2MSService.exe" /f /t</Arguments>
<Wait RollbackOnError="false" />
<ApplicationId>[{ProgramFilesX86}]\K2 Medical Systems\Guardian\CentralSurveillance.exe</ApplicationId>
</ExitProcess>
</UserScripts>

You can see that I can specify multiple command lines to run via CMD.exe by separating each command by an ampersand (& – this needs to be URL encoded in an XML file which is why it would appear as &amp; instead).  In the workaround above I specify two processes.  However by using brackets and nesting commands, I can specify more!  Here’s an example of an argument that kills 4 processes:

taskkill /im "odbcad32.exe" /f /t & (taskkill /im "wordpad.exe" /f /t & (taskkill /im "notepad.exe" /f /t & taskkill /im "mspaint.exe" /f /t))