title: Execute multiple line PowerShell Script from C#
body: <p>I am new to PowerShell. I am trying to execute PowerShell script from C#. PS Script that I have written transfer xml file from host computer (running PS script) to a remote computer. Script is as follows</p>
  
  <pre><code>$Username = "User"
  $Password = "Pass"
  $SecurePass = ConvertTo-SecureString -AsPlainText $Password -Force"
  $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList     $Username,$SecurePass"
   $contents = [IO.File]::ReadAllBytes("D:\MyFile.xml")
   Invoke-Command -ComputerName ComputerName -Credential $Cred {[IO.File]::WriteAllBytes("D:\MyFile.xml",$using:contents)}
  </code></pre>
  
  <p>I store username and password of remote computer, to which I want to transfer my file, in variables. Convert password to secure string and create a credential object containing username and password. Use credential to copy the contents of file from my computer to remote computer. 
  This code works fine if I execute these commands one by one from my powershell or by running these lines from a .ps1 powershell script from my computer.</p>
  
  <p>I used following code in C# to execute above script and transfer the file.</p>
  
  <pre><code>        Runspace runSpace = RunspaceFactory.CreateRunspace();
  
          Pipeline pipeline = runSpace.CreatePipeline();
  
          runSpace.Open();
  
          string script = "";
          script = "$Username = \"User\"\n";
          script = script + "$Password = \"Pass\"\n";
          script = script + "$SecurePass  = ConvertTo-SecureString -AsPlainText $Password -Force\n";
          script = script + "$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$SecurePass\n";
          script = script + "$contents = [IO.File]::ReadAllBytes(\"D:\\MyFile.xml\")\n";
          script = script + "Invoke-Command -ComputerName ComputerName -Credential $Cred {[IO.File]::WriteAllBytes(\"D:\\MyFile.xml\",$using:contents)}\n";
  
          //   pipeline.Runspace.SessionStateProxy.SetVariable
  
          pipeline.AddScript(script);
  
  
          Collection&lt;PSObject&gt; results = pipeline.Invoke();
  </code></pre>
  
  <p>However, it did not transfer the file. So, I thought I need to Add each line in script one by one to the pipeline and then execute it. So I changed it to following.</p>
  
  <pre><code>        string[] commands = script.Split('\n');
  
          foreach (string command in commands)
          {
              pipeline.AddScript(command);
          }
  
          Collection&lt;PSObject&gt; results = pipeline.Invoke();
  </code></pre>
  
  <p>It did not work either. I executed single Invoke-Command from C# code on my computer and it worked fine. Also, if I try to execute other single PS commands they work. So I assessed that setting variable values like this $User = "user" is not working through C#.</p>
  
  <p>I used SessionStateSetProcy.SetVariable to Store variable values in powershell session as follows. </p>
  
  <pre><code>        pipeline.Runspace.SessionStateProxy.SetVariable("User", "User");
          pipeline.Runspace.SessionStateProxy.SetVariable("Password", "Pass");
          var value = pipeline.Runspace.SessionStateProxy.GetVariable("Password");
          Console.WriteLine(value);
  </code></pre>
  
  <p>So, I was able to set value and retrieve as well. But, since I was using Other cmdlets like ConvertTo-SecureString, I realized I need to execute these cmdlets separately in my code. </p>
  
  <p>I finally I came up with following piece of code.</p>
  
  <pre><code>        pipeline.Runspace.SessionStateProxy.SetVariable("User", "User");
          pipeline.Runspace.SessionStateProxy.SetVariable("Password", "Pass");
  
  
  
          Command command = new Command("ConvertTo-SecureString");
          string pass_value = pipeline.Runspace.SessionStateProxy.PSVariable.GetValue("Password").ToString();
          command.Parameters.Add("AsPlainText",pass_value);
          command.Parameters.Add("Force");
  
          pipeline.Runspace.SessionStateProxy.SetVariable("SecurePass",command);
  
          /*Build a command2*/
          Command command1 = new Command("New-Object");
          string user_name = pipeline.Runspace.SessionStateProxy.PSVariable.GetValue("User").ToString();
          command1.Parameters.Add("TypeName", "System.Management.Automation.PSCredential");
          string args = user_name + " , "+pass_value;
          command1.Parameters.Add("-ArgumentList", args);
  
  
          pipeline.Runspace.SessionStateProxy.SetVariable("Cred", command1);
  
          byte[] wifiXML = System.IO.File.ReadAllBytes(@"D:\MyFile.xml");
          pipeline.Runspace.SessionStateProxy.SetVariable("contents", wifiXML);
  
  
          Object a = pipeline.Runspace.SessionStateProxy.PSVariable.GetValue("contents");
          string script = "Invoke-Command -ComputerName ComputerName -Credential $Cred {[IO.File]::WriteAllBytes(\"D:\MyFile.xml\",$using:contents)}";
  
          pipeline.Commands.AddScript(script);
          Collection&lt;PSObject&gt; results = pipeline.Invoke();
  </code></pre>
  
  <p>It gave some weird error in System.Management.Automation. I know in SetVariable I am doing it wrong by passing command variable. </p>
  
  <p>I have tried PowerShell ps = PowerShell.Create() instead of pipeline as well and tried ps.AddCommand and ps.AddParameters followed by ps.AddArgument as well. But I am not sure that once I run cmdlet ConvertTo-SecureString through ps.AddCommad, ps.AddArgument etc., how should I set it's output value to $Cred variable? </p>
  
  <p>I am aware that solution to this won't be this complicated and someone must have executed multiple line powershell script through C#. All I want to accomplish is execute the .ps1 script lines mentioned in very start from C# code.I have tried bunch of methods including mentioned above to no use, so any help related to it would be much appreciated?</p>