无法从C#中的托管Powershell会话导出证书

时间:2019-04-24 07:49:31

标签: c# powershell

我正在尝试运行Powershell脚本以从C#应用程序内部创建和操作证书。我正在使用https://github.com/PowerShell/PowerShell/tree/master/docs/host-powershell的Powershell Github存储库中描述的库,可以访问在其中运行脚本的Powershell环境。

脚本如下:

$derPath = "C:\Certs\derRootCert.cer";
$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature -Subject "CN=P2SRootCert" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign;
New-SelfSignedCertificate -Type Custom -DnsName P2SChildCert -KeySpec Signature -Subject "CN=P2SChildCert" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My" -Signer $cert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2");
Export-Certificate -FilePath $derPath -Type CERT -NoClobber -Cert $cert;

如果我自己在Powershell控制台中运行此脚本,则可以正常工作,并且我看到文件输出到该目录。

但是,如果我在以下C#中运行它,则不会看到创建的文件:

using (var ps = PowerShell.Create()) {
  ps.AddScript(stringContainingScript).Invoke();
}

为什么在此托管上下文中运行时不写入文件,我该怎么做才能使其按预期显示?

谢谢!

编辑: 在评论的建议下,我查看了错误流并找到以下消息:

  

“ New-SelfSignedCertificate”一词不被识别为   cmdlet,函数,脚本文件或可操作程序。检查   名称的拼写,或者如果包含路径,请验证路径   是正确的,然后重试。

这引起了一个相关的问题-为什么非高架式PowerShell窗口能够找到该cmdlet,而我的托管控制台却无法找到该cmdlet?

1 个答案:

答案 0 :(得分:0)

最终,我走上了另一条路。在探究为何无法使用New-SelfSignedCertificate时,我尝试在脚本的开头明确添加“ Import-Module pki”。这产生了另一个错误:

  

模块   'C:\ WINDOWS \ system32 \ WindowsPowerShell \ v1.0 \ Modules \ pki \ pki.psd1'确实   不支持当前的PowerShell版本“ Core”。受支持的版本   是“桌面”。使用“导入模块-SkipEditionCheck”忽略   该模块的兼容性。

因此,我修改了导入以添加-SkipEditionCheck以查看会发生什么。这次我有很多非特定的异常,表明各种模块无法加载。

我朝另一个方向前进。由于我的脚本不会将任何内容写到控制台,而只是将我的证书写到目录,因此我开始将脚本从程序中写到临时文件中,然后将Powershell作为进程启动,将脚本位置放入参数中,然后在继续处理脚本之前对其进行一些清理,如下所示:

var fileName = Path.GetFileNameWithoutExtension(Path.GetTempFileName()) + ".ps1";
var tempFile = Path.Combine(Path.GetTempPath(), fileName);

var sb = new StringBuilder();
//Build the script
using (var sw = new StreamWriter(tempFile)) {
  sw.Write(sb.ToString());
}

var pi = new ProcessStartInfo("powershell.exe", $"-File {tempFile}") {
  CreateNoWindow = true,
  UseShellExecute = false
};
var p = Process.Start(pi);
p.WaitForExit();

var errorLevel = process.ExitCode; //If 0, the script ran without errors
p.Close()
File.Delete(tempFile);