我的用例如下:
在visual studio中,在调试时我启动powershell并提供一个脚本以及几个动作,它启动项目可执行文件,如下所示:
&$exeToStart $exeParams | Out-Host
当我从PowerShell控制台运行脚本时,这很好用。当我通过VS停止图标停止调试时,我的问题开始了,它基本上杀死了运行此脚本的powershell进程,因此留下了一个挂起的exe进程,我必须在之后手动终止。
所以,我的问题是如何确保当visual studio杀死父权限shell进程时,子进程也会被它杀死?
答案 0 :(得分:2)
我怀疑当您停止调试时,Visual Studio有一种终止所有子进程的方法。
一种解决方案是运行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了解这可能是什么样的想法。
答案 1 :(得分:1)
你会在这里找到做“工作”的事情。这里的代码是一个概念证明。你必须将它放在一个函数中,并在所有嵌入式脚本的开头调用它。
#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 !"
概念:我创建了一个作业system object,而不是一个简单的作业,也没有PowerShell作业。我使用“JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE”配置它,这样如果作业的最后一个句柄被关闭,那么内部的所有进程都将被关闭。然后我将PowerShell流程分配给作业。所有子进程都属于该作业,并且作为唯一的作业句柄在PowerShell进程内部,当这个进程死掉时,所有其他进程都消失了。所以它可以解决问题。
我使用 x64 PowerShell在七上进行测试。麻烦的是,作业无法添加到已经属于作业的进程中(这是VS 2010正常启动的情况)
我使用 x64 PowerShell在 Windows 8 上进行测试。
以下是测试它的方法:
powershell -file "C:\temp\TestJob.ps1"
使用Windows 7,当你正常启动Visual Studio时,它已经在你的工作中,你可以在下面的sreenshot中看到:
但是,如果您使用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"
它不再属于工作:
那么,当您使用子进程进行调试时启动PowerShell时,当PowerShell停止时,所有内容都会停止:
答案 2 :(得分: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脚本,在阅读Jason的回答后,对我有用。