如何使用C#在x64或x86中运行PowerShell?

6
我正在使用这段C#代码通过PowerShell读取我的已安装程序。
我需要它通过PowerShell读取x64和x86注册表,我该如何做?
是否有一种重定向的方式?或者可能在x64中运行PowerShell,然后在x86中运行?
public void conf() {
process p1 = new Process();
ProcessStartInfo psi1 = new ProcessStartInfo("powershell", "Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Select-Object DisplayName");
psi1.RedirectStandardOutput = true;
psi1.CreateNoWindow = true;
p1.StartInfo = psi1;
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.Verb = "runas";
p1.Start();
string output = p1.StandardOutput.ReadToEnd();
Console.WriteLine(output);
p1.WaitForExit(400);
}

我认为HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\键不受x64重定向的影响。那个PowerShell命令应该列出x64和x86程序。问题到底是什么?你只看到x64还是只看到x86程序? - Jcl
当我在Visual Studio的配置管理器中将平台从“任何CPU”更改为x64时,它不会列出x64程序。但是,当我更改为x86时,它只会列出x86程序。 - Tom S
1
没错,我没有想到它被重定向了...我会进行一些测试,并在一分钟内给你答复。 - Jcl
1
顺便问一下,如果您只是读取注册表,为什么需要PowerShell呢?C#Microsoft.Win32.Registry也可以做到同样的事情。Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") - mswietlicki
1个回答

3

如果您的进程在x64中运行(或者是在x86操作系统上运行的x86进程),那么这应该可以实现。

bool is64 = IntPtr.Size == 8;
var cmdline = "Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* " 
       + (is64 ? ",HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*" : "") 
       + " | Select-Object DisplayName";
ProcessStartInfo psi1 = new ProcessStartInfo("powershell", cmdline);

如果进程是在x64操作系统上运行的32位进程,则此方法不起作用,但对于.NET,只要您不选择“首选32位”,使用AnyCPU应该可以正常工作。

更新

如果您只想获取显示名称,则可能会出现“显示名称重复项”(在两个注册表键中)...因此,您可以从输出中删除它们。这将删除重复项并进行排序:

var result = new StringBuilder();
var resultArr = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Distinct().ToArray();
Array.Sort(resultArr, StringComparer.InvariantCulture);
foreach (string s in resultArr)
    result.AppendLine(s);
output = result.ToString(); 

更新2

如果您不想与进程和输出捕获打交道,可以安装System.Management.Automation nuget包并直接使用powershell。

整个等效程序如下:

PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-ItemProperty");
var parm = new List<string> {
     @"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
};
if(IntPtr.Size == 8)
  parm.Add(@"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*");
var pso = ps.Invoke(parm);
var result = new StringBuilder();
foreach (var ob in pso)
{
  if(ob.Members["DisplayName"] != null)
    result.AppendLine(ob.Members["DisplayName"].Value.ToString());
}
Console.WriteLine(result.ToString());

这应该比调用进程更好 :)

非常感谢。但是如果我在 x84 计算机上运行我的进程怎么办?有什么解决方案吗? - Tom S
1
你说的x84是什么意思?在x86计算机上无法运行x64进程,也无法在x86计算机上安装x64程序。因此,只要您的进程是“AnyCPU”且不“prefer 32-bit”,这应该可以正常工作。 - Jcl
我使用的是x64计算机,我选择了“AnyCPU”。 - Tom S
1
@Tom,在进行AnyCPU编译时,你是否勾选了“优先使用32位”?正如我在帖子中所解释的那样,这可能会导致问题。 - Jcl
1
@Tom,我又添加了一个更新,展示如何直接在C#中使用PowerShell cmdlet,无需调用进程并捕获输出。 - Jcl
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接