我有一个 PowerShell 脚本,它会在退出之前侦听按下的键。我使用自定义的
TypeDefinition
来完成此操作;这是代码:
param(
[string]$quitKey = "F16"
)
$keyLogger = @"
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace KeyLogger{
public static class Program {
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static HookProc hookProc = HookCallback;
private static IntPtr hookId = IntPtr.Zero;
private static int keyCode = 0;
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public static int WaitForKey() {
hookId = SetHook(hookProc);
Application.Run();
UnhookWindowsHookEx(hookId);
return keyCode;
}
private static IntPtr SetHook(HookProc hookProc) {
IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
}
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
keyCode = Marshal.ReadInt32(lParam);
Application.Exit();
}
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
}
}
"@
Add-Type -TypeDefinition $keyLogger -ReferencedAssemblies system.Windows.Forms
while ($keyPress -ne $quitKey) {
$keyPress = [System.Windows.Forms.Keys][KeyLogger.Program]::WaitForKey()
}
Write-Host "`nCaught $quitKey, ending recording..." -ForegroundColor Green
exit
上面的代码在 Windows 11 上预安装的 PowerShell 5.1 中完美执行。但是,我无法让该脚本在 PowerShell 7(具体是 7.3.4)中运行;我收到此错误:
InvalidOperation:
Line |
62 | $keyPress = [System.Windows.Forms.Keys][KeyLogger.Program]::WaitFor …
| ~~~~~~~~~~~~~~~~~~~
| Unable to find type [KeyLogger.Program].
在网上到处搜索类似的问题,但没有找到任何东西。
Add-Type
似乎可以在我的其他脚本中工作,甚至在 PowerShell 7 中也是如此。但由于某种原因,这个特定的自定义 TypeDefiniton
失败了。
较新版本的 PowerShell 中存在一个长期存在的错误,当使用
-ReferenceAssemblies
时,默认情况下不会包含标准程序集,请参阅 GitHub 问题 #9599。
您可以使用我在这个答案中使用的相同解决方法,对于您的情况,代码将如下所示以使其与两个版本兼容:
# Top of your code goes this:
Add-Type -AssemblyName System.Windows.Forms
$refAssemblies = @(
[System.Windows.Forms.Form].Assembly.Location
if ($IsCoreCLR) {
$pwshRefAssemblyPattern = [IO.Path]::Combine($PSHOME, 'ref', '*.dll')
Convert-Path $pwshRefAssemblyPattern
}
)
# Definition stays the same:
$keyLogger = @'
...
...
'@
# Here you include the assembly you want plus the default ones:
Add-Type -TypeDefinition $keyLogger -ReferencedAssemblies $refAssemblies