C#控制台调用PowerShell脚本返回空字符串,求原因排查
问题:C#调用PowerShell脚本返回空字符串,但直接执行脚本正常
用户提供的C#代码如下:
static void Main(string[] args) { string powershellCommand = @"Get-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object { $_.DisplayName -match 'SOLIDWORKS PDM Client' } | Select-Object DisplayName, DisplayVersion, InstallLocation | ConvertTo-Json"; ExecuteScript(powershellCommand); } public static void ExecuteScript(string powershellCommand) { var processStartInfo = new ProcessStartInfo { FileName = "powershell.exe", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, Arguments = $"-ExecutionPolicy Bypass -Command \"{powershellCommand}\"" }; using (var process = new Process()) { process.StartInfo = processStartInfo; process.Start(); string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); Console.WriteLine("Output:"); Console.WriteLine(output); if (!string.IsNullOrWhiteSpace(error)) { Console.WriteLine("Error:"); Console.WriteLine(error); } } }
直接在Windows PowerShell中执行该脚本可正常返回结果,但通过上述C#代码调用时始终返回空字符串,求原因及解决办法。
原因分析及解决方案
1. 32位/64位进程注册表重定向问题(最可能原因)
Windows系统中,32位进程访问HKLM:\Software路径时,会被自动重定向到HKLM:\Software\Wow6432Node分支。如果SOLIDWORKS PDM Client是64位程序,其卸载信息会存放在64位的HKLM:\Software路径下,而你的C#控制台程序如果默认以32位模式运行(比如VS中默认Any CPU选项勾选了“首选32位”),就会读不到目标注册表项,导致输出为空。
解决办法:
- 在Visual Studio中,右键项目 → 属性 → 生成 → 目标平台,选择
x64后重新编译运行。 - 或者强制调用对应位数的PowerShell:
string powershellPath; if (Environment.Is64BitProcess) { powershellPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"System32\WindowsPowerShell\v1.0\powershell.exe"); } else { // 32位进程调用64位PowerShell需用Sysnative路径绕过重定向 powershellPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"Sysnative\WindowsPowerShell\v1.0\powershell.exe"); }
2. PowerShell命令参数转义问题
原代码用双引号包裹PowerShell命令,当命令包含花括号、管道符等特殊字符时,可能出现转义错误,导致命令未正确执行。
解决办法:
修改Arguments格式,用& { ... }包裹命令,避免引号嵌套问题:
Arguments = $"-ExecutionPolicy Bypass -Command & {{ {powershellCommand} }}"
3. 进程未等待完成导致输出读取不完整
原代码未等待PowerShell进程执行完毕就读取输出,可能导致输出未完全写入就被读取,出现空内容。
解决办法:
在process.Start()后添加进程等待代码:
process.WaitForExit();
修正后的完整代码示例
using System; using System.Diagnostics; using System.IO; class Program { static void Main(string[] args) { string powershellCommand = @"Get-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object { $_.DisplayName -match 'SOLIDWORKS PDM Client' } | Select-Object DisplayName, DisplayVersion, InstallLocation | ConvertTo-Json"; ExecuteScript(powershellCommand); } public static void ExecuteScript(string powershellCommand) { string powershellPath; // 根据当前进程位数选择对应PowerShell路径 if (Environment.Is64BitProcess) { powershellPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"System32\WindowsPowerShell\v1.0\powershell.exe"); } else { powershellPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"Sysnative\WindowsPowerShell\v1.0\powershell.exe"); } var processStartInfo = new ProcessStartInfo { FileName = powershellPath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, Arguments = $"-ExecutionPolicy Bypass -Command & {{ {powershellCommand} }}" }; using (var process = new Process()) { process.StartInfo = processStartInfo; process.Start(); // 等待进程执行完毕 process.WaitForExit(); string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); Console.WriteLine("Output:"); Console.WriteLine(output); if (!string.IsNullOrWhiteSpace(error)) { Console.WriteLine("Error:"); Console.WriteLine(error); } } } }
内容的提问来源于stack exchange,提问作者Sirja
相关产品推荐
相关产品推荐

