Execute PowerShell Script from C# with Commandline Arguments

匿名 (未验证) 提交于 2019-12-03 01:59:02

问题:

I need to execute a PowerShell script from within C#. The script needs commandline arguments.

This is what I have done so far:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();  Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration); runspace.Open();  RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);  Pipeline pipeline = runspace.CreatePipeline(); pipeline.Commands.Add(scriptFile);  // Execute PowerShell script results = pipeline.Invoke(); 

scriptFile contains something like "C:\Program Files\MyProgram\Whatever.ps1".

The script uses a commandline argument such as "-key Value" whereas Value can be something like a path that also might contain spaces.

I don't get this to work. Does anyone know how to pass commandline arguments to a PowerShell script from within C# and make sure that spaces are no problem?

回答1:

Try creating scriptfile as a separate command:

Command myCommand = new Command(scriptfile); 

then you can add parameters with

CommandParameter testParam = new CommandParameter("key","value"); myCommand.Parameters.Add(testParam); 

and finally

pipeline.Commands.Add(myCommand); 

Here is the complete, edited code:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();  Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration); runspace.Open();  RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);  Pipeline pipeline = runspace.CreatePipeline();  //Here's how you add a new script with arguments Command myCommand = new Command(scriptfile); CommandParameter testParam = new CommandParameter("key","value"); myCommand.Parameters.Add(testParam);  pipeline.Commands.Add(myCommand);  // Execute PowerShell script results = pipeline.Invoke(); 


回答2:

I have another solution. I just want to test if executing a PowerShell script succeeds, because perhaps somebody might change the policy. As the argument, I just specify the path of the script to be executed.

ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = @"powershell.exe"; startInfo.Arguments = @"& 'c:\Scripts\test.ps1'"; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; Process process = new Process(); process.StartInfo = startInfo; process.Start();  string output = process.StandardOutput.ReadToEnd(); Assert.IsTrue(output.Contains("StringToBeVerifiedInAUnitTest"));  string errors = process.StandardError.ReadToEnd(); Assert.IsTrue(string.IsNullOrEmpty(errors)); 

With the contents of the script being:

$someVariable = "StringToBeVerifiedInAUnitTest" $someVariable 


回答3:

Any chance I could get more clarity on the passing params to the Commands.AddScript method?

C:\Foo1.PS1 Hello World Hunger C:\Foo2.PS1 Hello World

scriptFile = "C:\Foo1.PS1"

parameters = "parm1 parm2 parm3" ... variable length of params

Resolved this ... passing null as the name and the param as value into a collection of CommandParameters

Here is my function:

private static void RunPowershellScript(string scriptFile, string scriptParameters) {     RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();     Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);     runspace.Open();     RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);     Pipeline pipeline = runspace.CreatePipeline();     Command scriptCommand = new Command(scriptFile);     Collection commandParameters = new Collection();     foreach (string scriptParameter in scriptParameters.Split(' '))     {         CommandParameter commandParm = new CommandParameter(null, scriptParameter);         commandParameters.Add(commandParm);         scriptCommand.Parameters.Add(commandParm);     }     pipeline.Commands.Add(scriptCommand);     Collection psObjects;     psObjects = pipeline.Invoke(); } 


回答4:

You can also just use the pipeline with the AddScript Method:

string cmdArg = ".\script.ps1 -foo bar"             Collection psresults; using (Pipeline pipeline = _runspace.CreatePipeline())             {                 pipeline.Commands.AddScript(cmdArg);                 pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);                 psresults = pipeline.Invoke();             } return psresults; 

It will take a string, and whatever parameters you pass it.



回答5:

Here is a way to add Parameters to the script if you used

pipeline.Commands.AddScript(Script); 

This is with using an HashMap as paramaters the key being the name of the variable in the script and the value is the value of the variable.

pipeline.Commands.AddScript(script)); FillVariables(pipeline, scriptParameter); Collection results = pipeline.Invoke(); 

And the fill variable method is:

private static void FillVariables(Pipeline pipeline, Hashtable scriptParameters) {   // Add additional variables to PowerShell   if (scriptParameters != null)   {     foreach (DictionaryEntry entry in scriptParameters)     {       CommandParameter Param = new CommandParameter(entry.Key as String, entry.Value);       pipeline.Commands[0].Parameters.Add(Param);     }   } } 

this way you can easily add multiple parameters to a script. I've also noticed that if you want to get a value from a variable in you script like so:

Object resultcollection = runspace.SessionStateProxy.GetVariable("results"); 

//results being the name of the v

you'll have to do it the way I showed because for some reason if you do it the way Kosi2801 suggests the script variables list doesn't get filled with your own variables.



回答6:

Mine is a bit more smaller and simpler:

///  /// Runs a PowerShell script taking it's path and parameters. ///  /// The full file path for the .ps1 file. /// The parameters for the script, can be null. /// The output from the PowerShell execution. public static ICollection RunScript(string scriptFullPath, ICollection parameters = null) {     var runspace = RunspaceFactory.CreateRunspace();     runspace.Open();     var pipeline = runspace.CreatePipeline();     var cmd = new Command(scriptFullPath);     if (parameters != null)     {         foreach (var p in parameters)         {             cmd.Parameters.Add(p);         }     }     pipeline.Commands.Add(cmd);     var results = pipeline.Invoke();     pipeline.Dispose();     runspace.Dispose();     return results; } 


回答7:

For me, the most flexible way to run PowerShell script from C# was using PowerShell.Create().AddScript()

The snippet of the code is

string scriptDirectory = Path.GetDirectoryName(     ConfigurationManager.AppSettings["PathToTechOpsTooling"]);  var script =         "Set-Location " + scriptDirectory + Environment.NewLine +     "Import-Module .\\script.psd1" + Environment.NewLine +     "$data = Import-Csv -Path " + tempCsvFile + " -Encoding UTF8" +          Environment.NewLine +     "New-Registration -server " + dbServer + " -DBName " + dbName +         " -Username \"" + user.Username + "\" + -Users $userData";  _powershell = PowerShell.Create().AddScript(script); _powershell.Invoke(); foreach (var errorRecord in _powershell.Streams.Error)     Console.WriteLine(errorRecord); 

You can check if there's any error by checking Streams.Error. It was really handy to check the collection. User is the type of object the PowerShell script returns.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!