我是 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 脚本行。我已经尝试了很多方法,包括上面提到的方法,但没有用,所以任何与之相关的帮助将不胜感激?