PowerShell with Windows Job Objects

Windows 的 Job Objects(作业对象)允许将进程组作为一个单元进行管理。 作业对象是可访问的、安全的、可共享的对象,用于控制与其关联的进程的属性。 针对某个作业对象执行的操作会影响与该作业对象关联的所有进程。 包括如限制工作集大小和设置进程优先级,或终止与作业对象关联的所有进程等。

本文给出的示例代码的功能为使用 PowerShell 脚本创建并关联进程信息到 Job Objects,然后再使用 PowerShell 命令获取与 Job Objects 关联的进程信息。

New Job Objects and Assign Process

脚本 New-JobObject.ps1 如下,在 PowerShell 中执行命令 .\New-JobObject.ps1 -Name mydemojobobject 创建一个名为 mydemojobobjectJob Objects 对象,并次当前进程关联到该对象。

param(
    [Parameter(Mandatory = $true, Position = 0, HelpMessage = "Windows Job Object Name")]
    [string] $Name
)

$signature = @"
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetCurrentProcess();
"@

Add-Type -MemberDefinition $signature -Namespace Win32 -Name JobObject

$jobHandle = [Win32.JobObject]::CreateJobObject([IntPtr]::Zero, "Global\$Name")

if ($jobHandle -eq [IntPtr]::Zero) {
    Write-Error "Failed to create job object"
    Exit 1
}
else {
    Write-Output "Job object '$Name' created successfully"
}

$ok = [Win32.JobObject]::AssignProcessToJobObject($jobHandle, [Win32.JobObject]::GetCurrentProcess())

if ($ok) {
    Write-Output "Current process $PID assigned to job object '$Name' successfully"
}
else {
    Write-Error "Failed to assign current process $PID to job object"
    Exit 1
}

Start-Sleep -Seconds 60

执行该脚本:

PS C:\Users\admin\Desktop\code\windows_job_objects> .\New-JobObject.ps1 -Name mydemojobobject
Job object 'mydemojobobject' created successfully.
Current process 6216 assigned to job object 'mydemojobobject' successfully.
PS C:\Users\admin\Desktop\code\windows_job_objects>

Get Process by Job Objects

在脚本 New-JobObject.ps1 执行期间,新打开一个 PowerShell 执行窗口,通过以下命令获取到关联到指定 Job Objects 的进程信息。

PS C:\Users\admin> $Obj = Get-CimInstance -ClassName Win32_NamedJobObject -Filter "CollectionID = 'mydemojobobject'"
PS C:\Users\admin>
PS C:\Users\admin> $Obj


Caption             :
CollectionID        : mydemojobobject
Description         :
BasicUIRestrictions : 0
PSComputerName      :



PS C:\Users\admin> Get-CimAssociatedInstance -InputObject $Obj -ResultClassName Win32_Process

ProcessId Name           HandleCount WorkingSetSize VirtualSize
--------- ----           ----------- -------------- -----------
6216      powershell.exe 559         67383296       2204011286528


PS C:\Users\admin>

Get Job Objects by Process

同理,也可以通过进程信息查找到该进程关联的 Job Objects 对象。

在脚本 New-JobObject.ps1 执行期间,打印了关联到 mydemojobobject 作业对象的进程 PID。 可以通过 PID 查找到其关联的 Job Objects 信息。

PS C:\Users\admin> $Process = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = 6216"
PS C:\Users\admin>
PS C:\Users\admin> $Process

ProcessId Name           HandleCount WorkingSetSize VirtualSize
--------- ----           ----------- -------------- -----------
6216      powershell.exe 560         67547136       2204013973504


PS C:\Users\admin>
PS C:\Users\admin> Get-CimAssociatedInstance -InputObject $Process -ResultClassName Win32_NamedJobObject


Caption             :
CollectionID        : mydemojobobject
Description         :
BasicUIRestrictions : 0
PSComputerName      :



PS C:\Users\admin>