1

I am trying to execute multiple PS commands in single script but it is throwing an exception. I tried different options but did not work.

 using (powershell = PowerShell.Create())
 {
    command = new PSCommand();
    command.AddCommand("Invoke-Command");
    command.AddParameter("ScriptBlock",
          System.Management.Automation.ScriptBlock.Create(
           "New-MailContact -Name '" + txtEmail.Text + "' -ExternalEmailAddress '" + txtEmail.Text + "';" ));
     command.AddParameter("ScriptBlock",
           System.Management.Automation.ScriptBlock.Create(
           "Set-MailContact -Identity '" + txtEmail.Text + "'-HiddenFromAddressListsEnabled $true"));


    command.AddParameter("Session", session);
    powershell.Commands = command;
    powershell.Runspace = runspace;
    result = powershell.Invoke();
    if (powershell.Streams.Error.Count > 0 || result.Count != 1)
    {
         if (powershell.Streams.Error[0].ToString().ToLowerInvariant().Contains("already exists"))
         {
               return;
          }
          else
          {
               throw new Exception("Fail to establish the connection");
           }
       }
      }

Cannot bind parameter because parameter 'ScriptBlock' is specified more than once. To provide multiple values to parameters that can accept multiple values, use the array syntax. For example, "-parameter value1,value2,value3".

I also tried

command.AddParameter("ScriptBlock",
   System.Management.Automation.ScriptBlock.Create(
   "New-MailContact -Name '" + txtEmail.Text + "' -ExternalEmailAddress '" + txtEmail.Text + "';" +  " Set-MailContact -Identity '" + txtEmail.Text + "'-HiddenFromAddressListsEnabled $true"));

and

command.AddParameter("ScriptBlock",
   System.Management.Automation.ScriptBlock.Create(
   "(New-MailContact -Name '" + txtEmail.Text + "' -ExternalEmailAddress '" + txtEmail.Text + "')" +  " Set-MailContact -Identity '" + txtEmail.Text + "'-HiddenFromAddressListsEnabled $true"));
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
James123
  • 11,184
  • 66
  • 189
  • 343
  • 2
    Just add another: `var anotherCommand = powershell.Commands.AddCommand();` – Mathias R. Jessen Oct 30 '19 at 16:12
  • 1
    I feel compelled to point out that you have command injection vulnerability. You need to escape apostrophes by doubling them (similar to SQL) so that an apostrophe in the input doesn't close the string and allow a user-entered command to follow. An input like this could be very dangerous: `'; Remove-Item \ -Recurse -Force #` – madreflection Oct 30 '19 at 16:24

1 Answers1

1

I think you can simplify your code quite a bit - you don't need the Invoke-Command and ScriptBlock elements just to call a single command each - you can call the cmdlets directly instead.

You can also address the script injection concern raised by @madreflection at the same time if you build up your commands with parameters.

Here's a version in PowerShell (it was easier for me to test than spinning up a sample C# project :-)) that you could convert to C#:

$p = [System.Management.Automation.PowerShell]::Create()

$c = new-object System.Management.Automation.Runspaces.Command("New-MailContact");
$c.Parameters.Add("Name", $name)
$c.Parameters.Add("ExternalEmailAddress", $address)
$null = $p.Commands.AddCommand($c)

$c = new-object System.Management.Automation.Runspaces.Command("Set-MailContact");
$c.Parameters.Add("Identity", $identity)
$c.Parameters.Add("HiddenFromAddressListsEnabled", $hidden)
$null = $p.Commands.AddCommand($c)

$p.Invoke()

Update - ah, just noticed you're using the Session parameter on Invoke-Command - if you're executing it with remoting then you probably do need Invoke-Command after all. Maybe this answer will help...

Set Paramerters in ScriptBlock when Executing Powershell Commands with C#

mclayton
  • 8,025
  • 2
  • 21
  • 26