Find/Kill 在 32 位 powershell 中按路径处理 64 位
Find/Kill 64 bit processes by path in 32 bit powershell
我有应用程序的 PowerShell 清理脚本。理想情况下,进程是通过它们的路径发现的,以免鲁莽地杀死系统上可能具有相似名称的其他进程。我们注意到一些进程没有 detected/killed,经过大量实验后我们意识到位数是问题所在。为了兼容性,该脚本在 32 位中引导,但有些进程不是。
Get-Process
可以在 32 位 PowerShell 和 returns 包括 64 位进程在内的所有进程中调用,但是如 This Ref:
中所述
On computers that are running a 64-bit version of Windows, the 64-bit version of PowerShell gets only 64-bit process modules and the 32-bit version of PowerShell gets only 32-bit process modules.
事实上,在发现进程时,进程模块信息(包括进程的路径)对于位数与 shell 不匹配的进程不可用。
这个问题有一些讨论:How can I get the executable path of a 64-bit process given its PID from a 32-bit process?
如图所示,建议的 Get-WmiObject
查询对我不起作用,它 returns 64 位进程缺少 ExecutablePath
信息,与 Get-Process
基本相同。
所以我的问题是:是否可以从 PowerShell 脚本调用 QueryFullProcessImageName()
或 GetModuleFileNameEx()
等 WinAPI 函数作为获取此信息的解决方法?或者还有其他我没有考虑的方法吗?
为了满足这个需求,我拼凑了这个。也许它会帮助别人。欢迎批评。
$pinvoke = Add-Type -PassThru -Name pinvoke -MemberDefinition @'
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool CloseHandle(
IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(
uint processAccess,
bool bInheritHandle,
int processId);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool QueryFullProcessImageName(
IntPtr hProcess,
int dwFlags,
System.Text.StringBuilder lpExeName,
ref int lpdwSize);
private const int QueryLimitedInformation = 0x00001000;
public static string GetProcessPath(int pid)
{
var size = 1024;
var sb = new System.Text.StringBuilder(size);
var handle = OpenProcess(QueryLimitedInformation, false, pid);
if (handle == IntPtr.Zero) return null;
var success = QueryFullProcessImageName(handle, 0, sb, ref size);
CloseHandle(handle);
if (!success) return null;
return sb.ToString();
}
'@
然后可以通过
获取32位或64位进程的路径
$pinvoke::GetProcessPath($pid)
过滤进程而不是:
Get-Process | Where-Object {$_.Path -like "*$filePath*"}
32/64位有问题,可以用
Get-Process | Where-Object {$pinvoke::GetProcessPath($_.Id) -like "*$filePath*"}
将其通过管道传输到 Stop-Process 或任何您想用它做的事情。
我有应用程序的 PowerShell 清理脚本。理想情况下,进程是通过它们的路径发现的,以免鲁莽地杀死系统上可能具有相似名称的其他进程。我们注意到一些进程没有 detected/killed,经过大量实验后我们意识到位数是问题所在。为了兼容性,该脚本在 32 位中引导,但有些进程不是。
Get-Process
可以在 32 位 PowerShell 和 returns 包括 64 位进程在内的所有进程中调用,但是如 This Ref:
On computers that are running a 64-bit version of Windows, the 64-bit version of PowerShell gets only 64-bit process modules and the 32-bit version of PowerShell gets only 32-bit process modules.
事实上,在发现进程时,进程模块信息(包括进程的路径)对于位数与 shell 不匹配的进程不可用。
这个问题有一些讨论:How can I get the executable path of a 64-bit process given its PID from a 32-bit process?
如图所示,建议的 Get-WmiObject
查询对我不起作用,它 returns 64 位进程缺少 ExecutablePath
信息,与 Get-Process
基本相同。
所以我的问题是:是否可以从 PowerShell 脚本调用 QueryFullProcessImageName()
或 GetModuleFileNameEx()
等 WinAPI 函数作为获取此信息的解决方法?或者还有其他我没有考虑的方法吗?
为了满足这个需求,我拼凑了这个。也许它会帮助别人。欢迎批评。
$pinvoke = Add-Type -PassThru -Name pinvoke -MemberDefinition @'
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool CloseHandle(
IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr OpenProcess(
uint processAccess,
bool bInheritHandle,
int processId);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool QueryFullProcessImageName(
IntPtr hProcess,
int dwFlags,
System.Text.StringBuilder lpExeName,
ref int lpdwSize);
private const int QueryLimitedInformation = 0x00001000;
public static string GetProcessPath(int pid)
{
var size = 1024;
var sb = new System.Text.StringBuilder(size);
var handle = OpenProcess(QueryLimitedInformation, false, pid);
if (handle == IntPtr.Zero) return null;
var success = QueryFullProcessImageName(handle, 0, sb, ref size);
CloseHandle(handle);
if (!success) return null;
return sb.ToString();
}
'@
然后可以通过
获取32位或64位进程的路径$pinvoke::GetProcessPath($pid)
过滤进程而不是:
Get-Process | Where-Object {$_.Path -like "*$filePath*"}
32/64位有问题,可以用
Get-Process | Where-Object {$pinvoke::GetProcessPath($_.Id) -like "*$filePath*"}
将其通过管道传输到 Stop-Process 或任何您想用它做的事情。