4

私のユースケースは次のとおりです。

Visual Studio では、デバッグ時に powershell を起動し、いくつかのアクションと共にスクリプトをフィードして、次のようにプロジェクトの実行可能ファイルを開始します。

&$exeToStart $exeParams | Out-Host

これは、PowerShell コンソールからスクリプトを実行するとうまく機能します。このスクリプトを実行するpowershellプロセスを本質的に強制終了するVS停止アイコンを介してデバッグを停止すると、問題が発生し、後で手動で強制終了する必要があるハングしたexeプロセスが残ります。

それで、私の質問は、ビジュアルスタジオが親のpowershellプロセスを強制終了したときに、子プロセスも一緒に強制終了されるようにする方法です?

4

3 に答える 3

3

デバッグを停止したときに、Visual Studio にすべての子プロセスを終了させる方法があるとは思えません。

1 つの解決策は、PowerShell スクリプトを実行してクリーンアップすることです。Win32_Process CimInstance で ParentProcessId プロパティを使用できます。次のようになります (PowerShell V3 を使用):

 Get-CimInstance win32_process |
    ? { (Get-Process -id $_.ParentProcessId -ea Ignore) -eq $null } |
    Stop-Process -WhatIf

これにより、親プロセスが存在しなくなったプロセスのリストが返されます。これを確実に使用するには、開始したことがわかっているプロセスをフィルタリングする必要があることに注意してください。たとえば、上記のコマンドで返されたすべてのプロセスを強制終了しようとすると、csrss.exe、wininit.exe、およびその他の強制終了したくないプロセスを強制終了しようとします。

Visual Studio で実行するマクロを作成して、デバッグを停止し、PowerShell スクリプトを実行することもできます。パッケージ コンソールは PowerShell を使用します。これがどのように見えるかについては、 http: //www.wintellect.com/blogs/jrobbins/using-nuget-powershell-to-replace-missing-macros-in-dev-11 を参照してください。

于 2013-09-24T20:34:41.903 に答える
3

「仕事」をするものの下にここにあります。以下のコードは概念実証です。これを関数に入れて、埋め込まれたすべてのスクリプトの最初に呼び出す必要があります。

#TestJob.ps1
$CreateJobObjectSignature = @"
using System;
using System.Text;
using System.Runtime.InteropServices;
public class ClsNativ
{
  public enum JOBOBJECTINFOCLASS
  {
    AssociateCompletionPortInformation = 7,
    BasicLimitInformation = 2,
    BasicUIRestrictions = 4,
    EndOfJobTimeInformation = 6,
    ExtendedLimitInformation = 9,
    SecurityLimitInformation = 5,
    GroupInformation = 11
  }

  [StructLayout(LayoutKind.Sequential)]
  struct JOBOBJECT_BASIC_LIMIT_INFORMATION
  {
    public Int64 PerProcessUserTimeLimit;
    public Int64 PerJobUserTimeLimit;
    public UInt32 LimitFlags;
    public UIntPtr MinimumWorkingSetSize;
    public UIntPtr MaximumWorkingSetSize;
    public UInt32 ActiveProcessLimit;
    public Int64 Affinity;
    public UInt32 PriorityClass;
    public UInt32 SchedulingClass;
  }


  [StructLayout(LayoutKind.Sequential)]
  struct IO_COUNTERS
  {
    public UInt64 ReadOperationCount;
    public UInt64 WriteOperationCount;
    public UInt64 OtherOperationCount;
    public UInt64 ReadTransferCount;
    public UInt64 WriteTransferCount;
    public UInt64 OtherTransferCount;
  }

  [StructLayout(LayoutKind.Sequential)]
  struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
  {
    public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
    public IO_COUNTERS IoInfo;
    public UIntPtr ProcessMemoryLimit;
    public UIntPtr JobMemoryLimit;
    public UIntPtr PeakProcessMemoryUsed;
    public UIntPtr PeakJobMemoryUsed;
  }

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

  [DllImport("kernel32.dll")]
  public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

  [DllImport("kernel32.dll")]
  public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);

  [DllImport("kernel32.dll")]
  public static extern IntPtr GetCurrentProcess();


  private const UInt32 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000;
  public ClsNativ()
  {
    IntPtr hJob = CreateJobObject(IntPtr.Zero, "JobName");

    JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
    info.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;

    JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
    extendedInfo.BasicLimitInformation = info;

    int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
    IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
    Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

    SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.ExtendedLimitInformation, extendedInfoPtr, (uint)length);

    IntPtr hProcess = GetCurrentProcess();
    bool blRc = AssignProcessToJobObject(hJob, hProcess);

    Marshal.FreeHGlobal(extendedInfoPtr);
  }
}
"@



Add-Type -TypeDefinition $CreateJobObjectSignature 
$a = New-Object ClsNativ

& notepad.exe
Start-Process -FilePath "c:\windows\system32\calc.exe"

Read-Host "Push return key !"

コンセプト:スケジュールされたジョブや PowerShell ジョブではなく、ジョブ、システム オブジェクトを作成します。「JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE」で構成して、ジョブの最後のハンドルが閉じられると、内部のすべてのプロセスが閉じられるようにします。次に、PowerShell プロセスをジョブに割り当てます。すべてのサブ プロセスはジョブに属し、唯一のジョブ ハンドルが PowerShell プロセス内にあるため、この 1 つが終了すると、他のすべてが消えます。それで、それはトリックを行います。

x64 PowerShellを使用してSevenでテストしました。問題は、既にジョブに属しているプロセスにジョブを追加できないことです (これは、VS 2010 の通常の起動の場合です)。

x64 PowerShellを使用してWindows 8でテストします。

これをテストする方法は次のとおりです。

powershell -file "C:\temp\TestJob.ps1"

Windows Seven を使用して、Visual Studio を正常に起動すると、次のスクリーンショットでわかるように、既にジョブ内にあります。

ここに画像の説明を入力

ただし、次のように WMI を使用して Visual Studio 2010 を起動すると:

Invoke-WmiMethod -path win32_process -name create -argumentlist "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"

それはもはや Job に属していません:

ここに画像の説明を入力

したがって、サブプロセスを使用してデバッグで PowerShell を開始すると、PowerShell が停止すると、それらはすべて停止します。

ここに画像の説明を入力

于 2013-09-24T21:14:21.367 に答える
0

Powershell スクリプト:

Get-CimInstance win32_process -Filter "Name like 'myprocess.exe'" | ? { (Get-Process -id $_.ParentProcessId -ea Ignore) -eq $null } | Select-Object ProcessId | ? { Stop-Process $_.ProcessId -Force }

これは、ジェイソンの答えを読んだ後に私のために働いたPowershellスクリプトです。

于 2015-05-27T14:37:48.333 に答える