1

我有以下命令,它返回我 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 GetRowAndPartitionKeycmdlet 定义,上面的代码试图调用它:

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

1 回答 1

2

使用 PowerShell SDK 时,如果要将参数传递给带有.AddParameter()//的单个命令.AddParameters()AddArgument()使用.AddCommand(),而不是.AddScript()

.AddScript()用于传递任意的PowerShell 代码,这些代码作为脚本块执行,添加的参数.AddParameters()传递到该脚本块。

也就是说,您的调用等效于& { Get-RowAndPartitionKey } <your-parameters>,并且如您所见,您的Get-RowAndPartitionKey命令因此不会接收参数值。

请参阅此答案或更多信息。


注意:作为调用自定义 cmdlet 的先决条件Get-RowAndPartitionKey,您可能必须显式导入包含它的模块 (DLL),您可以这样做:

  • 要么:预先执行一个单独的同步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>"指包含Get-RowAndPartitionKeycmdlet 的模块的完整文件系统路径;根据该模块的实现方式,它可以是模块目录.psd1模块清单的路径.dll,如果是独立程序集,则可以是模块的路径。

替代导入方法,使用 PowerShell SDK 的专用.ImportPSModule()方法

此方法无需会话中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()/之后检查.EndInvoke()PowerShell 命令是否报告了任何(非终止)错误。

  • 枚举ps.Streams.Errors以检查发生的特定错误。

有关演示这些技术的自包含示例代码,请参阅后续问题的答案。

于 2021-02-19T15:12:56.233 回答