从C#执行多行PowerShell脚本

时间:2014-03-05 02:46:44

标签: c# powershell

我是PowerShell的新手。我试图从C#执行PowerShell脚本。我编写的PS脚本将xml文件从主机(运行PS脚本)传输到远程计算机。脚本如下

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

我在变量中存储了我要传输文件的远程计算机的用户名和密码。将密码转换为安全字符串并创建包含用户名和密码的凭证对象。使用凭据将文件内容从我的计算机复制到远程计算机。 如果我从powershell中逐个执行这些命令,或者从我的计算机上运行.ps1 powershell脚本中的这些行,这段代码就可以正常工作。

我在C#中使用以下代码来执行上述脚本并传输文件。

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

但是,它没有传输文件。所以,我认为我需要将脚本中的每一行逐一添加到管道中,然后执行它。所以我把它改成了以下。

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

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

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

它也没用。我在计算机上从C#代码执行了单个Invoke-Command,它工作正常。此外,如果我尝试执行其他单个PS命令,他们的工作。所以我评估设置变量值,如$ User =“user”不能通过C#。

我使用SessionStateSetProcy.SetVariable在powershell会话中存储变量值,如下所示。

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

所以,我能够设置值并检索。但是,因为我使用像ConvertTo-SecureString这样的其他cmdlet,我意识到我需要在我的代码中单独执行这些cmdlet。

我终于想出了以下一段代码。

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

它在System.Management.Automation中给出了一些奇怪的错误。我知道在SetVariable中我通过传递命令变量做错了。

我已经尝试过PowerShell ps = PowerShell.Create()而不是管道,并尝试了ps.AddCommand和ps.AddParameters,然后是ps.AddArgument。但是我不确定一旦我通过ps.AddCommad,ps.AddArgument等运行cmdlet ConvertTo-SecureString,我应该如何将它的输出值设置为$ Cred变量?

我知道解决这个问题的方法并不复杂,有些人必须通过C#执行多行PowerShell脚本。我想要完成的只是执行从C#代码开始提到的.ps1脚本行。我已经尝试了一些方法,包括上面提到的没有用,所以任何与它相关的帮助都会非常感激吗?

1 个答案:

答案 0 :(得分:4)

尝试这种方式

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