我是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脚本行。我已经尝试了一些方法,包括上面提到的没有用,所以任何与它相关的帮助都会非常感激吗?
答案 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();