如何在PowerShell中继续执行代码之前等待可执行文件打开?

oogrdqng  于 2023-04-07  发布在  Shell
关注(0)|答案(3)|浏览(153)

编者注

这个问题是关于一种基于事件的方式来运行PowerShell代码,每当一个新的进程(可能具有给定的可执行文件名称)被创建 * 系统范围 *。
我做了大量的研究,似乎找不到任何解决方案。
我试过使用Wait-Event -SourceIdentifier "ProcessStarted",但它似乎根本不起作用。它只是无限等待,不会使代码恢复。如果有一种方法可以等待可执行文件启动或等待特定的启动,请帮助兄弟!

3gtaxfhh

3gtaxfhh1#

据我所知,你有一个脚本,并希望暂停它,直到某个进程开始,一旦它开始继续与其余的脚本。
一个快速而肮脏的解决方案是使用get-process并查询进程名称,在这个例子中我使用vlc。输出将是$null,直到进程启动,一旦启动循环将退出。这只在进程尚未运行时才有效。例如,如果你已经在运行Chrome,并且正在尝试查找进程的新示例,则此代码将无法工作。

# some code
$processName = "vlc"
# wait until process starts
while ((Get-Process -name $processName -ErrorAction SilentlyContinue) -eq $null)
{
    write-host "waiting for process to start to continue"
    Start-Sleep -Seconds 2
}

# continue code 
write-host "Process started"

--
示例输出

.\wait_for_process.ps1
waiting for process to start to continue
waiting for process to start to continue
waiting for process to start to continue
waiting for process to start to continue
Process started
pdkcd3nj

pdkcd3nj2#

操作系统不会神奇地向你宣布进程启动事件-你需要指定你想知道的确切事件,然后注册目标事件:

# define an event polling query - this will poll WMI for new process creations every 2 seconds
$processCreationEventQuery = "SELECT TargetInstance FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'"

# add event registration to make PowerShell consume the event from WMI
Register-CimIndicationEvent -Query $processCreationEventQuery -SourceIdentifier ProcessStarted

现在我们已经设置了事件注册,Wait-Event将工作:

Wait-Event -SourceIdentifier ProcessStarted

如果你想等待一个更具体的进程启动,修改查询过滤器,例如:

$processCreationEventQuery = @"
SELECT TargetInstance 
  FROM __InstanceCreationEvent 
WITHIN 2 
 WHERE TargetInstance ISA 'Win32_Process'
   AND TargetInstance.Name LIKE '%RelevantProcessNameGoesHere%'
"@
qij5mzcb

qij5mzcb3#

补充Mathias R. Jessen's helpful answer
此处显示的基于**__InstanceCreationEvent的方法是基于周期性轮询**,这意味着短暂存在的进程可能会 * 丢失*,即那些在 * 轮询间隔(1秒是最小值)之间创建和终止的进程-这在实践中可能重要,也可能无关紧要。

  • This answer显示了一个次秒级分辨率的手动轮询循环(不涉及CIM/WMI事件),以及无限期处理事件的__InstanceCreationEvent示例代码。

然而,__InstanceCreationEvent方法的优点是它不需要提升(以管理员权限运行),这与专用的Win32_ProcessStartTrace事件不同。

如果可以选择elevation运行Win32_ProcessStartTrace的优势在于不会 * 错过事件;而且,它更容易设置。

下面是一个自包含的Win32_ProcessStartTrace示例,基于Register-CimIndicationEventWait-Event,可以无限地处理事件(按Ctrl-C停止)-如前所述,需要提升

#requires -RunAsAdmin

Write-Verbose -Verbose "Monitoring for new processes; press Ctrl-C to exit..."
try {

  # Note: This registers for *any* new process.
  #       To limit the scope, pass a -Query argument instead of -ClassName; e.g.:
  #       -Query 'Select * From Win32_ProcessStartTrace Where ProcessName = "cmd.exe"'
  Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace -SourceIdentifier ProcessStarted

  # Wait for and process events indefinitly.
  while ($true) {
    ($evt = Wait-Event -SourceIdentifier ProcessStarted) | Remove-Event
    # $evt.SourceEventArgs.NewEvent contains the event details.
    # For demo purposes, print them here.
    $evt.SourceEventArgs.NewEvent | Out-Host
  }
}
finally {
  UnRegister-Event -SourceIdentifier ProcessStarted
}

这里有一个变体,它使用**-Action参数在后台 * 执行事件处理 ,这将使前台活动 * 并行**-但请注意,事件处理只发生在 * PowerShell语句之间 *;它在长时间运行的命令期间被阻止,包括.NET方法调用:

#requires -RunAsAdmin

Write-Verbose -Verbose "Monitoring for new processes; press Ctrl-C to exit..."
try {

  # Pass the event-handler code to the -Action parameter.
  # Register-CimIndicationEvent then creates and returns an event job that must later be removed.
  # If your -Action block were to produce *data* to communicate to the main thread, you'd have to
  # to use Receive-Job in the main thread.
  $eventJob = 
    Register-CimIndicationEvent `
         -ClassName Win32_ProcessStartTrace `
         -Action {
           # For demo purposes, simply print the event details to the console (host).
           $EventArgs.NewEvent | Out-Host
          }

  # You can now perform other operations here in the foreground,
  # but note that event processing happens only *between* PowerShell
  # statements.
  while ($true) {
    Write-Host . -NoNewline       # simulate foreground activity
    Start-Sleep -Milliseconds 100 # sleep a little
  }

}
finally {
  # Remove the event job, which also unsubscribes from the CIM event.
  Remove-Job -Force $eventJob
}

相关问题