App-V 5 and Terminate Child Process

I recently packaged an application that, upon launch, started a process which spawned a child process.  The child process remained running after the parent process was closed, and this caused an issue when unpublishing the App-V 5 package.  This blog will discuss App-V 5 and terminate child process.

EntDistributorService.exe was the parent process and hvced.exe was the child process.  I knew hvced.exe was a child process by running the wmic command found here.  But 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!  So a reboot is usually required.

I tried to kill hvced.exe using a script (I tried taskkill.exe and Powershell’s Stop-Process) which ran in the ExitProcess scripting phase of EntDistributorService.exe in the UserConfig.xml.  Unfortunately the context that UserConfig 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 parent file who’s child processes we want to terminate like so:

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

This tells App-V that whenever the EntDistributorService.exe process is stopped, to kill any child processes that remain open.  Hopefully this example will clarify App-V 5 and terminate child process feature.

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:

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

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"

CommandLine=C:\windows\system32\svchost.exe -k DcomLaunch


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

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

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

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:

<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>

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))