我正在尝试从C#调用Add-AppxPackage
cmdlet。我在running PowerShell from C# code上找到了MSDN文章。我引用了System.Management.Automation程序集并尝试了以下代码片段,所有这些代码片段在尝试调用powerShell.Invoke()时都会导致相同的异常:
System.Management.Automation.CommandNotFoundException未处理
术语“Add-AppxPackage”无法识别为cmdlet的名称, 功能,脚本文件或可操作程序。检查拼写 名称,或者如果包含路径,请验证路径是否正确 再试一次。
摘录1:
var powerShell = PowerShell.Create();
powerShell.AddCommand(string.Format("Add-AppxPackage '{0}'", appxFilePath));
foreach (PSObject result in powerShell.Invoke())
{
Console.WriteLine(result);
}
我理解为什么这不起作用,因为我不应该在AddCommand()函数中提供参数。
摘录2:
var powerShell = PowerShell.Create();
powerShell.AddCommand("Add-AppxPackage");
powerShell.AddParameter("Path", appxFilePath);
foreach (PSObject result in powerShell.Invoke())
{
Console.WriteLine(result);
}
摘录3:
var powerShell = PowerShell.Create();
powerShell.AddCommand("Add-AppxPackage");
powerShell.AddArgument(appxFilePath);
foreach (PSObject result in powerShell.Invoke())
{
Console.WriteLine(result);
}
我的C#项目目标.Net 4.5,如果我执行powerShell.AddCommand(“Get-Host”),它可以工作,它返回的版本是4.0。在PowerShell的v3.0中添加了Add-AppxPackage,因此命令应该存在,如果我从Windows PowerShell命令提示符手动运行此命令,它可以正常工作。
我在这里做错了什么想法?任何建议都表示赞赏。
- 更新 -
我找到了this post和this one,并意识到有一个AddScript()函数,所以我尝试了这个:
摘录4:
var powerShell = PowerShell.Create();
powerShell.AddScript(string.Format("Add-AppxPackage '{0}'", appxFilePath));
var results = powerShell.Invoke();
foreach (PSObject result in results)
{
Console.WriteLine(result);
}
它没有抛出异常,但它也没有安装metro应用程序,并且从powerShell.Invoke()返回的“结果”是空的,所以我仍然不知所措......
- 更新2 -
所以我决定尝试创建一个新的PowerShell进程来运行我的命令,所以我尝试了这个:
Process.Start(new ProcessStartInfo("PowerShell", string.Format("-Command Add-AppxPackage '{0}'; $key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyUp')", appxFilePath)));
但它仍然会抛出Add-AppxPackage不是可识别的cmdlet的相同错误。
如果您按照robert.westerlund的回答中的长评论主题进行操作,您将看到由于某些原因从Visual Studio运行/启动时,PowerShell不包括从PowerShell命令提示符直接运行时所执行的所有PSModulePaths ,这么多模块都不存在。解决方案是使用:
找到我需要的模块的绝对路径(在我的情况下是appx模块)(Get-Module appx -ListAvailable).Path
然后在尝试调用其中一个cmdlet之前导入该模块。所以这是适合我的C#代码:
var powerShell = PowerShell.Create();
powerShell.AddScript(string.Format(@"Import-Module 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Appx\Appx.psd1'; Add-AppxPackage '{0}'", appxFilePath));
var results = powerShell.Invoke();
您可以从this other post I opened看到,问题出在Visual Studio扩展中的错误(在我的案例中是StudioShell),导致并非所有PSModulePath都被加载。卸载该扩展后,所有模块都已正确加载,我不再需要手动导入模块。
答案 0 :(得分:7)
在PowerShell中,终止错误(停止执行)和非终止错误(仅写入错误流)之间存在差异。
如果要在自己的函数中创建非终止错误,只需使用Write-Error
cmdlet。如果要创建终止错误,请使用Throw
关键字。如果您运行Get-Help Write-Error
,Get-Help about_Throw
和Get-Help about_Try_Catch_Finally
,则可以详细了解这些概念。
将Add-AppxPackage
与非现有包一起使用是一个非终止错误,因此将写入错误流,但不会抛出执行暂停异常。以下代码尝试添加非现有包,然后将错误写入控制台。
var powerShell = PowerShell.Create();
powerShell.AddScript("Add-AppxPackage NonExistingPackageName");
// Terminating errors will be thrown as exceptions when calling the Invoke method.
// If we want to handle terminating errors, we should place the Invoke call inside a try-catch block.
var results = powerShell.Invoke();
// To check if a non terminating error has occurred, test the HadErrors property
if (powerShell.HadErrors)
{
// The documentation for the Error property states that "The command invoked by the PowerShell
// object writes information to this stream whenever a nonterminating error occurs."
foreach (var error in powerShell.Streams.Error)
{
Console.WriteLine("Error: " + error);
}
}
else
{
foreach(var package in results)
{
Console.WriteLine(package);
}
}