问题描述
我有以下命令,它返回给我 null object 。当我在 PowerShell 窗口中单独运行命令时,我得到了正确的结果。下面是我的 PowerShell 方法,它调用命令以及我定义的 PowerShell 命令。我基本上希望返回一个字符串值。请让我知道我做错了什么?
C# 方法:
public string RunScript( string contentScript,Dictionary<string,EntityProperty> parameters)
{
List<string> parameterList = new List<string>();
foreach( var item in parameters )
{
parameterList.Add( item.Value.ToString() );
}
using( PowerShell ps = PowerShell.Create() )
{
ps.AddScript( contentScript );
// in ContentScript I get "Get-RowAndPartitionKey" on debugging
ps.AddParameters( parameterList );//I get list of strings
IAsyncResult async = ps.BeginInvoke();
StringBuilder stringBuilder = new StringBuilder();
foreach( PSObject result in ps.EndInvoke( async ) )
// here i get result empty in ps.EndInvoke(async)
{
stringBuilder.AppendLine( result.ToString() );
}
return stringBuilder.ToString();
}
}
}
我的 Powershell GetRowAndPartitionKey
cmdlet 定义,上面的代码试图调用它:
public abstract class GetRowAndPartitionKey : PSCmdlet
{
[Parameter]
public List<string> Properties { get; set; } = new List<string>();
}
[Cmdlet( VerbsCommon.Get,"RowAndPartitionKey" )]
public class GetRowAndPartitionKeyCmd : GetRowAndPartitionKey
{
protected override void ProcessRecord()
{
string rowKey = string.Join( "_",Properties );
string pKey = string.Empty;
WriteObject( new
{
RowKey = rowKey,PartitionKey = pKey
} );
}
}
}
解决方法
使用 PowerShell SDK 时,如果您想使用 .AddParameter()
/ .AddParameters()
/ {{1} 将参数传递给单个命令 },使用.AddCommand()
,而不是AddArgument()
.AddScript()
用于传递任意段 PowerShell 代码,这些代码作为 脚本块 执行,添加了 .AddScript()
的参数将传递给该代码块.
也就是说,您的调用等效于 .AddParameters()
,正如您所见,您的 & { Get-RowAndPartitionKey } <your-parameters>
命令因此不会接收参数值。
查看 this answer 或更多信息。
注意:作为调用自定义 Get-RowAndPartitionKey
cmdlet 的先决条件,您可能必须显式导入包含它的模块 (DLL),可以做:
-
任一:使用一个单独的同步
Get-RowAndPartitionKey
调用 预先执行(为简单起见,我在这里使用Import-Module
,并传递一个参数 位置,它绑定到.AddArgument()
参数(也接受路径)):-Name
-
或:作为单个(在本例中为异步)调用的一部分 - 请注意分隔两个命令所需的
ps.AddCommand("Import-Module").AddArgument(@"<your-module-path-here>").Invoke();
调用:.AddStatement()
IAsyncResult async =
ps.AddCommand("Import-Module").AddArgument(@"<your-module-path-here>")
.AddStatement()
.AddCommand("GetRowAndPartitionKey").AddParameter("Properties",parameterList)
.BeginInvoke();
是指包含 "<your-module-path-here>"
cmdlet 的模块的完整文件系统路径;根据该模块的实现方式,它可以是模块的目录、其 Get-RowAndPartitionKey
模块清单的路径,或者是其 .psd1
(如果它是独立的)组装。
替代导入方法,使用 PowerShell SDK 的专用 .ImportPSModule()
方法:
此方法无需在会话中调用 .dll
,但需要额外设置:
- 创建默认会话状态。
- 在其上调用
Import-Module
以导入模块。 - 将此会话状态传递给
.ImportPSModule()
PowerShell.Create()
警告:var iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new string[] { @"<your-module-path-here>" });
var ps = PowerShell.Create(iss);
// Now the PowerShell commands submitted to the `ps` instance
// will see the module's exported commands.
实例在 PowerShell
中反映其初始会话状态,但作为概念上的只读属性;棘手的部分是它技术上仍然可以修改,因此修改它的错误尝试被悄悄地忽略而不是导致异常。
要解决这些调用:
-
检查
.Runspace.InitialSessionState
/ps.HadErrors
之后的.Invoke()
以查看 PowerShell 命令是否报告了任何(非终止)错误。 -
枚举
.EndInvoke()
以检查发生的特定错误。
有关演示这些技术的自包含示例代码的后续问题,请参阅 this answer。