从C#调用PowerShell命令抛出CommandNotFoundException(Callin

2019-10-19 15:18发布

我试图调用Add-AppxPackage从C#cmdlet的。 我发现在MSDN文章从C#代码运行的PowerShell 。 我曾经引用System.Management.Automation组装和尝试下面的代码片段,试图调用powerShell.Invoke()时,所有这些都导致相同的异常:

System.Management.Automation.CommandNotFoundException了未处理

术语“添加-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(“获取 - 主机”),它的工作原理和Version则返回为4.0。 附加AppxPackage在PowerShell中的V3.0增加,因此命令一定要存在,如果我手动从Windows PowerShell命令提示符下此命令它工作正常。

任何想法,我做错了什么? 任何建议表示赞赏。

- 更新 -

我发现这个职位和这一个 ,并意识到有一个AddScript()函数,所以我尝试这样做:

片段四:

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)));

但它仍然抛出同样的错误添加-AppxPackage是无法识别的小命令。

回答

如果按照第robert.westerlund的回答长注释线程,你会看到,由于某些原因,当运行/从Visual Studio推出的PowerShell并没有包括所有的PSModulePaths的,它从一个PowerShell命令提示符直线行驶的时候,这么多呢模块不存在。 解决的办法是发现我需要(在我的情况下,APPX模块)使用该模块的绝对路径:

(Get-Module appx -ListAvailable).Path

然后试图调用它的命令之一之前导入模块。 因此,这是为我工作的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();

已更新ANSWER

你可以看到这等后我打开 ,这个问题是在一个Visual Studio扩展中的错误(在我的情况StudioShell)引起并不是所有的PSModulePaths的加载。 卸载该扩展所有的模块都正确装入,我不再需要手动导入模块后。

Answer 1:

在PowerShell中有终止错误之间的差(其停止执行)和非终止错误(这是刚写入错误流)。

如果你想在自己的函数来创建一个非终止错误,只是使用Write-Error cmdlet的。 如果你想创建一个终止错误,使用Throw关键字。 你可以阅读更多有关这些概念,如果你运行Get-Help Write-ErrorGet-Help about_ThrowGet-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);
    }
}


文章来源: Calling PowerShell cmdlet from C# throws CommandNotFoundException