1

I have below command and it returns me null object . When I run the command separately in PowerShell window I get the right result. Below is my PowerShell method which is calling the command and the also the PowerShell command which I have defined. I am basically looking to return a string value. Please let me know what wrong am I doing?

C# method:

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

My Powershell GetRowAndPartitionKey cmdlet definition, which the code above is trying to call:

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
            } );
        }
    }
}
3
  • What is EntityProperty, and is ps.HadErrors=true after Invoke()? Commented Feb 19, 2021 at 15:09
  • EntityProperty is Microsoft.Azure.Cosmos.Table.EntityProperty. I havent checked ps.HadErrors. Commented Feb 19, 2021 at 15:12
  • just checked its false after BeginInvoke() Commented Feb 19, 2021 at 15:14

1 Answer 1

3

When using the PowerShell SDK, if you want to pass parameters to a single command with .AddParameter() / .AddParameters() / AddArgument(), use .AddCommand(), not .AddScript()

.AddScript() is for passing arbitrary pieces of PowerShell code that is executed as a script block to which the parameters added with .AddParameters() are passed.

That is, your invocation is equivalent to & { Get-RowAndPartitionKey } <your-parameters>, and as you can see, your Get-RowAndPartitionKey command therefore doesn't receive the parameter values.

See this answer or more information.


Note: As a prerequisite for calling your custom Get-RowAndPartitionKey cmdlet, you may have to explicitly import the module (DLL) that contains it, which you can do:

  • either: with a separate, synchronous Import-Module call executed beforehand (for simplicity, I'm using .AddArgument() here, with passes an argument positionally, which binds to the -Name parameter (which also accepts paths)):

    ps.AddCommand("Import-Module").AddArgument(@"<your-module-path-here>").Invoke();
    
  • or: as part of a single (in this case asynchronous) invocation - note the required .AddStatement() call to separate the two commands:

    IAsyncResult async = 
      ps.AddCommand("Import-Module").AddArgument(@"<your-module-path-here>")
        .AddStatement()
          .AddCommand("GetRowAndPartitionKey").AddParameter("Properties", parameterList)
              .BeginInvoke();
    

"<your-module-path-here>" refers to the full file-system path of the module that contains the Get-RowAndPartitionKey cmdlet; depending on how that module is implemented, it is either a path to the module's directory, its .psd1 module manifest, or to its .dll, if it is a stand-alone assembly.

Alternative import method, using the PowerShell SDK's dedicated .ImportPSModule() method:

This method obviates the need for an in-session Import-Module call, but requires extra setup:

  • Create a default session state.
  • Call .ImportPSModule() on it to import the module.
  • Pass this session state to 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.

Caveat: A PowerShell instance reflects its initial session state in .Runspace.InitialSessionState, but as a conceptually read-only property; the tricky part is that it is technically still modifiable, so that mistaken attempts to modify it are quietly ignored rather than resulting in exceptions.


To troubleshoot these calls:

  • Check ps.HadErrors after .Invoke() / .EndInvoke() to see if the PowerShell commands reported any (non-terminating) errors.

  • Enumerate ps.Streams.Errors to inspect the specific errors that occurred.

See this answer to a follow-up question for self-contained sample code that demonstrates these techniques.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.