Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

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

$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)}

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.

I used following code in C# to execute above script and transfer the file.

        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<PSObject> results = pipeline.Invoke();

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.

        string[] commands = script.Split('\n');

        foreach (string command in commands)
        {
            pipeline.AddScript(command);
        }

        Collection<PSObject> results = pipeline.Invoke();

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#.

I used SessionStateSetProcy.SetVariable to Store variable values in powershell session as follows.

        pipeline.Runspace.SessionStateProxy.SetVariable("User", "User");
        pipeline.Runspace.SessionStateProxy.SetVariable("Password", "Pass");
        var value = pipeline.Runspace.SessionStateProxy.GetVariable("Password");
        Console.WriteLine(value);

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.

I finally I came up with following piece of 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<PSObject> results = pipeline.Invoke();

It gave some weird error in System.Management.Automation. I know in SetVariable I am doing it wrong by passing command variable.

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?

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?

share|improve this question

1 Answer 1

up vote 0 down vote accepted

Try in this way

 string script = @"
$Username = 'User'
$Password = 'Password'
$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)}
";

 pipeline.Commands.AddScript(script);
 Collection<PSObject> results = pipeline.Invoke();
share|improve this answer
    
Thank you very much for your answer. It works fine in C#. Transfers the file to remote computer. However, I am using IronPython and passing the script from IronPtyhon to C# and run in PS inside C#. It doesn't work in that case and it is exactly Invoke-Command that does not work. Anyways, thanks and your solution works in C#. – user2629172 Mar 6 '14 at 15:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.