Note that absolutely none of this is authoritative or directly based on relevant documentation. It’s mostly what I found and figured out and guessed and (in some cases) made up. Some of it may be wrong or dangerous or lead to disaster or confusion. I am not taking responsibility here for anything, not even spelling. Read and digest at your own peril!

As explained in the previous post on Processes, it is not trivial to modify process ACLs to allow a user who does not own the process and is not a members of the Administrators group to manipulate (mostly terminate) it.

A perhaps better solution to the problem is using JEA.

Let’s look again at the situation. User legrand in session 3 started a program Winver and session 1 user benoit, for his own reasons, wants to terminate it.

PS C:\Users\benoit> query session
 SESSIONNAME               USERNAME                 ID  STATE   TYPE        DEVICE
 services                                            0  Disc
>console                   benoit                    1  Active
                           legrand                   3  Disc
 rdp-tcp                                         65536  Listen
PS C:\Users\benoit> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    184      13     2308      15436              8604   3 winver


PS C:\Users\benoit> Get-Process winver|stop-process
stop-process : Cannot stop process "winver (8604)" because of the following error: Access is denied
At line:1 char:20
+ Get-Process winver|stop-process
+                    ~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (System.Diagnostics.Process (winver):Process) [Stop-Process], ProcessCommandException
    + FullyQualifiedErrorId : CouldNotStopProcess,Microsoft.PowerShell.Commands.StopProcessCommand

PS C:\Users\benoit>

Using JEA we can allow user benoit to terminate processes based on their name or any other attribute that can be read.

The account the process is running under is surprisingly difficult to find using PowerShell. Try it out. Run __Get-Process winver Format-List *__ and you will find that you get every conceivable piece of information on the process but not its owner.

This example will allow user benoit (or rather a group) to terminate processes named winver and processes owner by user legrand.

PS C:\Program Files\WindowsPowerShell\Modules\JEA> New-PSSessionConfigurationFile -Path Processes.pssc -SessionType RestrictedRemoteServer -RunAsVirtualAccount -RoleDefinitions @{"JEA_Processes-winver"=@{"RoleCapabilities"="Processes-winver"};"JEA_Processes-legrand"=@{"RoleCapabilities"="Processes-legrand"}}
PS C:\Program Files\WindowsPowerShell\Modules\JEA> New-PSRoleCapabilityFile -Path .\RoleCapabilities\Processes-legrand.psrc -VisibleFunctions "legrandkill"
PS C:\Program Files\WindowsPowerShell\Modules\JEA> New-PSRoleCapabilityFile -Path .\RoleCapabilities\Processes-winver.psrc -VisibleFunctions "winverkill"
PS C:\Program Files\WindowsPowerShell\Modules\JEA>

The two role capability files have to be equipped with the respective functions:

# file Processes-winver.psrc
FunctionDefinitions = @{
    Name = 'winverkill';
    ScriptBlock = {
        param([int]$processid)
        $process = Get-Process -Id $processid
        if ("winver" -eq $process.Name) {Stop-Process $process -Force}
    }
}

# file Processes-legrand.psrc
FunctionDefinitions = @{
    Name = 'legrandkill';
    ScriptBlock = {
        param([int]$processid)
        $process = Get-WmiObject Win32_Process | Where-Object {$processid -eq $_.ProcessId}
        if ("legrand" -eq $process.GetOwner().User) {Stop-Process -Id $processid -Force}
    }
}

Then, after creating the two groups and adding user benoit to them and after registerting the new JEA configuration…

PS C:\Program Files\WindowsPowerShell\Modules\JEA> ("JEA_Processes-winver","JEA_Processes-legrand")|%{New-LocalGroup $_}

Name                  Description
----                  -----------
JEA_Processes-winver
JEA_Processes-legrand


PS C:\Program Files\WindowsPowerShell\Modules\JEA> ("JEA_Processes-winver","JEA_Processes-legrand")|%{Add-LocalGroupMember $_ benoit}
PS C:\Program Files\WindowsPowerShell\Modules\JEA> Register-PSSessionConfiguration Processes -Path .\Processes.pssc
WARNING: Register-PSSessionConfiguration may need to restart the WinRM service if a configuration using this name has recently been unregistered, certain system data structures may still be cached. In that case, a
restart of WinRM may be required.
All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session configurations that are created with the Register-PSSessionConfiguration cmdlet, are disconnected.


   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin

Type            Keys                                Name
----            ----                                ----
Container       {Name=Processes}                    Processes
WARNING: Set-PSSessionConfiguration may need to restart the WinRM service if a configuration using this name has recently been unregistered, certain system data structures may still be cached. In that case, a restart of
 WinRM may be required.
All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session configurations that are created with the Register-PSSessionConfiguration cmdlet, are disconnected.
WARNING: Register-PSSessionConfiguration may need to restart the WinRM service if a configuration using this name has recently been unregistered, certain system data structures may still be cached. In that case, a
restart of WinRM may be required.
All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session configurations that are created with the Register-PSSessionConfiguration cmdlet, are disconnected.

PS C:\Program Files\WindowsPowerShell\Modules\JEA>

…user benoit can import the JEA configuration and kill winver using either function:

  1. winverkill
PS C:\> Import-PSSession(New-PSSession -ConfigurationName Processes)
WARNING: Proxy creation has been skipped for the following command: 'clear, cls, exsn, gcm, measure, select, Clear-Host', because it would shadow an existing local command.  Use the
AllowClobber parameter if you want to shadow existing local commands.

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0        tmp_s0txkquu.aln                    winverkill


PS C:\> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    184      13     2244      15404              8604   3 winver


PS C:\> winverkill 8604
PS C:\> Get-Process winver
Get-Process : Cannot find a process with the name "winver". Verify the process name and call the cmdlet again.
At line:1 char:1
+ Get-Process winver
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (winver:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand

PS C:\>
  1. legrandkill
PS C:\> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    184      13     2252      15296              1080   3 winver


PS C:\> legrandkill 1080
PS C:\> Get-Process winver
Get-Process : Cannot find a process with the name "winver". Verify the process name and call the cmdlet again.
At line:1 char:1
+ Get-Process winver
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (winver:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand

PS C:\>

Yes, this is still not very elegant. But it will work for a very special (and also very common case).

  1. You have a service and your user or group has permission to start and stop it (see Services) and
  2. Sometimes the service hangs and the user cannot stop the service and hence
  3. The user needs to be able to terminate the service process.

In this case, likely both the process name and the process owner account are clearly known.

It is likely that your user should indeed be able to terminate all processes of that particular name or owned by that particular account. And then this solution works.

(But if you write a batch scheduler, please do start the jobs suspended and add a resource group to the process ACLs. Thank you.)

Next: Impersonate Privilege