动机:我正在尝试使用简单的 powershell 作业测试一些与进程相关的命令。但是,所有 powershell 作业在进程表中都被命名为“powershell”。所以我需要进程句柄,我可以用它来过滤
Get-Process
输出。
因此,“更大”的问题可能更容易回答,但就目前情况而言,我认为只要我能够将 powershell 作业连接到其进程 ID(“句柄”),我就有了一个解决方案。
如何从 powershell 作业中获取进程 ID? (这不是 JobID)。
$job = Start-Job -Name $jobName -ScriptBlock {
while ($true) {
sleep -Seconds 1
}
}
$processes = Get-Process
$jobHandle = ???
$jobProcess = $processes | where {$_.Handle -eq $jobHandle}
如何获取以“???”表示的缺失信息?
处理 XY 问题并更一般地说,如果这是不可能的,因为所有内容都被继承到当前的 powershell 会话中,那么更大的问题是:如何创建一个任意命名或处理的进程,我可以从 powershell 执行任何操作,用于测试?
# how do I start this code block as an arbitrary named process?
# name = "test-Get-Foo.1.2"
{
while ($true) {
sleep -Seconds 2
}
}
# ???
$proc = Get-Process | where {$_.Name -like "test-Get-Foo*"}
Job
类不会公开幕后生成的底层进程,而获得其ProcessId
的方法是进行之前和之后比较:
$before = Get-CimInstance win32_process -Filter "ParentProcessId = $pid"
$job = Start-Job -ScriptBlock {
while ($true) {
Start-Sleep -Seconds 1
}
}
$after = Get-CimInstance win32_process -Filter "ParentProcessId = $pid"
$process = $after | Where-Object { $_.ProcessId -notin $before.ProcessId }
$jobHandle = $process.ProcessId
关于第二个问题,解释一下:
如何创建一个任意命名或处理的进程,我可以从 PowerShell 对其执行任何操作以进行测试?
NamedPipeConnectionInfo
类。一个简单的例子:
try {
$proc = Start-Process powershell -PassThru -ArgumentList '-WindowStyle', 'Hidden'
$pipe = [System.Management.Automation.Runspaces.NamedPipeConnectionInfo]::new($proc.Id)
$rs = [runspacefactory]::CreateRunspace($pipe)
$rs.Open()
$ps = [powershell]::Create().AddScript({ "Hi there! I'm $PID" })
$ps.Runspace = $rs
$ps.Invoke() # `$task = $ps.BeginInvoke()` here for Async
}
finally {
if ($ps) {
$ps.Dispose()
}
if ($rs) {
$rs.Dispose()
}
# Remove this if you don't want to kill the underlying process :)
if ($proc) {
$proc.Kill()
}
}
PowerShell 作业当然会有一个
PID
,您可以使用 Named Pipes
让作业告诉父 PowerShell 进程它是 PID
。
$Job = Start-Job -ScriptBlock {
$PipeServer = New-Object System.IO.Pipes.NamedPipeServerStream('JobPipe', 'InOut')
$PipeServer.WaitForConnection() #Waits for parent process to connect
$StreamWriter = New-Object System.IO.StreamWriter($PipeServer)
$StreamWriter.AutoFlush = $true
$StreamWriter.WriteLine($PID) #Put the PID in the JobPipe
$StreamWriter.Close()
$PipeServer.Close()
Start-Sleep -Seconds 10
}
$PipeClient = New-Object System.IO.Pipes.NamedPipeClientStream('.', 'JobPipe', 'In')
$PipeClient.Connect()
$StreamReader = New-Object System.IO.StreamReader($PipeClient)
$JobPid = $StreamReader.ReadLine() #Get the PID of the Job from the JobPipe
$StreamReader.Close()
$PipeClient.Close()
$JobPid
Get-Job # Just to show that the Job hasn't finished yet