2014-03-05 191 views
0

我是PowerShell的新手。我想從C#執行PowerShell腳本。 PS腳本,我已經寫入從主機(運行PS腳本)傳輸xml文件到遠程計算機。腳本如下從C#執行多行PowerShell腳本

$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腳本行。我已經嘗試過一堆方法,包括上面提到的沒有用,所以任何與它有關的幫助將非常感激?

回答

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

非常感謝您的回答。它在C#中正常工作。將文件傳輸到遠程計算機。但是,我使用IronPython並將腳本從IronPtyhon傳遞給C#,並在C#中運行PS。它在這種情況下不起作用,而且它正是Invoke-Command不起作用。無論如何,謝謝你的解決方案在C#中工作。 – user2629172

+0

爲什麼所有這些powershell c#的東西不直觀? – Ronnie