Windows Subsystem for Linux (WSL) 已经从一个实验性的兼容层发展为成熟的 Linux 运行环境。WSL2 基于真正的 Linux 内核,支持 systemd、Docker 以及绝大多数原生 Linux 应用。对于日常在 Windows 上工作的运维工程师和开发者来说,WSL 提供了一条低成本的 Linux 工具链接入路径——无需双系统,无需虚拟机管理程序的开销。
PowerShell 与 WSL 的互操作不仅限于简单的命令转发。借助 wsl 命令行工具、\\wsl$ 网络路径以及双向的进程调用机制,可以在一个脚本中自由混合 Windows 和 Linux 工具。例如,用 PowerShell 采集 Windows 事件日志,再通过管道传给 WSL 中的 awk 做文本分析;或者反过来,在 WSL 中编译项目后调用 PowerShell 部署到 Windows 服务。这种混合工作流在 DevOps 和跨平台自动化场景中尤为实用。
# P/Invoke 调用 Win32 API 示例 # 注意:以下代码仅在 Windows 平台上运行
if ($IsWindows-or ($env:OS-eq"Windows_NT")) {
# 示例一:获取系统内存信息 $memorySignature = @" using System; using System.Runtime.InteropServices; public class MemoryHelper { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class MEMORYSTATUSEX { public uint dwLength; public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; public ulong ullAvailPageFile; public ulong ullTotalVirtual; public ulong ullAvailVirtual; public ulong ullAvailExtendedVirtual; public MEMORYSTATUSEX() { this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)); } } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer); } "@
# 示例二:获取精确的系统启动时间(比 Get-Date 更准确) $uptimeSignature = @" using System; using System.Runtime.InteropServices; public class UptimeHelper { [DllImport("kernel32.dll")] public static extern UInt64 GetTickCount64(); } "@
# 示例三:获取当前控制台窗口标题 $consoleSignature = @" using System; using System.Text; using System.Runtime.InteropServices; public class ConsoleHelper { [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern int GetConsoleTitle( StringBuilder lpConsoleTitle, int nSize); } "@
# 定义 MEMORYSTATUSEX 结构体和 GlobalMemoryStatusEx 函数签名 $memApiDefinition = @' using System; using System.Runtime.InteropServices; public class MemoryApi { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class MEMORYSTATUSEX { public uint dwLength; public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; public ulong ullAvailPageFile; public ulong ullTotalVirtual; public ulong ullAvailVirtual; public ulong ullAvailExtendedVirtual; public MEMORYSTATUSEX() { this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)); } } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer); } '@
剪贴板包含文本数据:True 剪贴板内容预览:Hello from PowerShell Win32 API! 内容长度:32 字符
上面的代码通过 OpenClipboard、GetClipboardData、GlobalLock 等一系列 API 调用完成了剪贴板文本的读取。注意每个 API 调用都有对应的错误检查,且使用 try/finally 确保资源被正确释放。这种编程模式在调用 Win32 API 时非常重要,因为原生 API 不会像 .NET 那样自动管理资源。
控制窗口的显示状态
在自动化测试和运维场景中,我们经常需要控制窗口的行为,比如隐藏某个窗口、最小化所有窗口、或者判断窗口是否处于响应状态。ShowWindow 和 IsWindow 等 Win32 API 为此提供了底层支持。下面的代码展示了如何查找窗口句柄并控制窗口的显示状态。