【问题标题】:Trying to find and kill a process by PowerShell script尝试通过 PowerShell 脚本查找并终止进程
【发布时间】:2018-01-03 20:29:23
【问题描述】:

我有以下脚本来查找进程“dotnet.exe”。在我的系统中,我有许多 dotnet.exe 进程正在运行。但我想杀死具有命令行参数“MyService\Web\argument”的“dotnet.exe”。我正在尝试通过以下脚本来做到这一点。但它没有找到任何东西,虽然我在任务管理器中看到了这个过程。

$process = Get-WmiObject Win32_Process | select name, commandline

foreach ($p in $process)
{
    if ($p.name -contains "dotnet.exe" -and $p.commandline -contains "web")
    {
        $kp =    Get-Process $p;
        $kp.CloseMainWindow();
        if (!$kp.HasExited)
        {
            $kp | Stop-Process -Force
        }
    }
    else
    {
        Write-Host name: $p.name and param: $p.commandline;
    }
}

【问题讨论】:

  • $process 是否包含您正在寻找的那个?
  • (Get-WmiObject Win32_Process -Filter "name like '%dotnet.exe%' and commandline like '%web%'").Terminate()?
  • 您使用了错误的比较运算符。 -contains 设计用于与单个元素进行数组比较。使用-like
  • 我收到错误:方法调用失败,因为 [Selected.System.Management.ManagementObject] 不包含名为“Terminate”的方法。在 C:\practice\kill_web.ps1:6 char:8 + $p.Terminate() + ~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (Terminate:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound
  • 显然您试图将我发布的代码修改为您问题中的代码。你为什么这么做?请不要在 开始工作之前发挥创意。使用我发布的代码,无需任何修改或添加。

标签: powershell process arguments kill-process


【解决方案1】:

您只需通过Get-WmiObject 直接过滤进程列表,然后终止匹配的进程:

$fltr = "name like '%dotnet.exe%' and commandline like '%web%'"
Get-WmiObject Win32_Process -Filter $fltr | ForEach-Object {
    $_.Terminate()
}

您也可以像这样直接在Get-WmiObject 的输出上调用Terminate()

(Get-WmiObject Win32_Process -Filter $fltr).Terminate()

但是,在某些情况下这可能会失败,例如如果 Get-WmiObject 不返回任何结果,或者如果您使用的是 PowerShell v2 或更早版本并且 Get-WmiObject 返回多个结果(将方法调用传递给数组的成员需要成员枚举,这是 PowerShell 引入的v3)。使用ForEach-Object 循环更健壮且向后兼容。

【讨论】:

  • 如果 (Get-WmiObject Win32_Process -Filter $fltr) 返回 null,则调用 Terminate() 将导致错误。所以我建议有一个空检查条件。
  • @masiboo 请再读一遍。我已经在回答中解决了这个问题。
  • 对不起,我说的是单行语句。 (Get-WmiObject Win32_Process -Filter $fltr).Terminate()
  • 请。读。再次。代码 sn-p 正下方的段落详细说明了警告。
【解决方案2】:

Get-WmiObject cmdlet 返回了非常有用的对象,但是您通过仅选择 NameCommandLine 参数剥离了所有内容:

$process = Get-WmiObject Win32_Process | select name, commandline

如果您删除 | select name, commandline 部分,您仍然可以循环遍历每个进程,但也可以使用仍然可用的 Terminate() 等方法。

根据@ansgar-wiechers 的评论,您可以一次性完成,或者如果您愿意,还可以使用循环并添加更多日志记录等:

$process = Get-WmiObject Win32_Process

foreach($p in $process){
    if($p.Name -eq "*dotnet.exe" -and $p.CommandLine -like "*web*"){
       $p.Terminate()
       # and so on... 
    }
}

还要注意@TheIncorrigible1 关于使用比较运算符的评论。我使用-eq 作为进程名称,使用-like 作为命令行。

【讨论】:

  • 我认为在您的代码中,您提到了 $p.Name -and $p.Name。它必须是 $p.commandline。无论如何,我收到类似方法调用失败的错误,因为 [Selected.System.Management.ManagementObject] 不包含名为“Terminate”的方法。在 C:\practice\kill_web.ps1:6 char:8 + $p.Terminate() + ~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (Terminate:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound
  • 我已经修正了属性名称的错字。
  • 确保您使用的是Get-WmiObject 返回的实际对象。您必须使用select 语句,因为这会使Terminate() 等方法不可用。我已经更新了我的答案以使其更加明确。
猜你喜欢
  • 2018-03-30
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-28
  • 1970-01-01
相关资源
最近更新 更多