Выполнить сценарий PowerShell из C# с аргументами командной строки
Мне нужно выполнить скрипт PowerShell из C#. Скрипту нужны аргументы командной строки.
Это то, что я сделал до сих пор:
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 содержит что-то вроде "C:\Program Files\MyProgram\Whwhat.ps1".
Скрипт использует аргумент командной строки, такой как "-key Value", тогда как Value может быть чем-то вроде пути, который также может содержать пробелы.
Я не получаю это на работу. Кто-нибудь знает, как передать аргументы командной строки в сценарий PowerShell из C# и убедиться, что пробелы не являются проблемой?
9 ответов
Попробуйте создать скрипт-файл отдельной командой:
Command myCommand = new Command(scriptfile);
Затем вы можете добавить параметры с
CommandParameter testParam = new CommandParameter("key","value");
myCommand.Parameters.Add(testParam);
и наконец
pipeline.Commands.Add(myCommand);
Вот полный отредактированный код:
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();
У меня есть другое решение. Я просто хочу проверить, успешно ли выполняется сценарий PowerShell, потому что, возможно, кто-то может изменить политику. В качестве аргумента я просто указываю путь к скрипту, который должен быть выполнен.
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));
С содержанием сценария:
$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable
Есть ли шанс, что я мог бы получить больше ясности в отношении передачи параметров в метод Commands.AddScript?
C: \ Foo1.PS1 Hello World Hunger C: \ Foo2.PS1 Hello World
scriptFile = "C: \ Foo1.PS1"
параметры = "parm1 parm2 parm3" ... переменная длина параметров
Решено это... передача нулевого значения в качестве имени и параметра в качестве значения в коллекцию CommandParameters
Вот моя функция:
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<CommandParameter> commandParameters = new Collection<CommandParameter>();
foreach (string scriptParameter in scriptParameters.Split(' '))
{
CommandParameter commandParm = new CommandParameter(null, scriptParameter);
commandParameters.Add(commandParm);
scriptCommand.Parameters.Add(commandParm);
}
pipeline.Commands.Add(scriptCommand);
Collection<PSObject> psObjects;
psObjects = pipeline.Invoke();
}
Для меня самый гибкий способ запуска скрипта PowerShell из C# - это использование PowerShell.Create().AddScript()
Фрагмент кода
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<User>();
foreach (var errorRecord in _powershell.Streams.Error)
Console.WriteLine(errorRecord);
Вы можете проверить наличие ошибок, проверив Streams.Error. Было действительно удобно проверить коллекцию. Пользователь - это тип объекта, который возвращает скрипт PowerShell.
Мой немного меньше и проще:
/// <summary>
/// Runs a PowerShell script taking it's path and parameters.
/// </summary>
/// <param name="scriptFullPath">The full file path for the .ps1 file.</param>
/// <param name="parameters">The parameters for the script, can be null.</param>
/// <returns>The output from the PowerShell execution.</returns>
public static ICollection<PSObject> RunScript(string scriptFullPath, ICollection<CommandParameter> 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;
}
Вы также можете просто использовать конвейер с методом AddScript:
string cmdArg = ".\script.ps1 -foo bar"
Collection<PSObject> psresults;
using (Pipeline pipeline = _runspace.CreatePipeline())
{
pipeline.Commands.AddScript(cmdArg);
pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
psresults = pipeline.Invoke();
}
return psresults;
Он будет принимать строку и любые параметры, которые вы передадите.
Вот способ добавить параметры в скрипт, если вы использовали
pipeline.Commands.AddScript(Script);
Это происходит при использовании HashMap в качестве параметров, ключом является имя переменной в скрипте, а значением является значение переменной.
pipeline.Commands.AddScript(script));
FillVariables(pipeline, scriptParameter);
Collection<PSObject> results = pipeline.Invoke();
И метод заполнения переменной:
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);
}
}
}
таким образом, вы можете легко добавить несколько параметров в скрипт. Я также заметил, что если вы хотите получить значение из переменной в вашем скрипте, вот так:
Object resultcollection = runspace.SessionStateProxy.GetVariable("results");
// в результате получается имя v
вам придется сделать это так, как я показал, потому что по какой-то причине, если вы сделаете это так, как предлагает Kosi2801, список переменных скрипта не будет заполнен вашими собственными переменными.
Вот что у меня сработало, включая случаи, когда аргументы содержат пробелы:
using (PowerShell PowerShellInst = PowerShell.Create())
{
PowerShell ps = PowerShell.Create();
string param1= "my param";
string param2= "another param";
string scriptPath = <path to script>;
ps.AddScript(File.ReadAllText(scriptPath));
ps.AddArgument(param1);
ps.AddArgument(param2);
ps.Invoke();
}
Я считаю этот подход очень простым для понимания и ясным.
Если ваш код не может найти пространство имен, вам нужно добавить зависимость кSystem.Management.Automation.dll
. Эта DLL поставляется с PowerShell и по умолчанию находится в каталоге:C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0
Чтобы добавить ссылку, откройте свой проект и щелкните правой кнопкой мыши «ссылки> добавить ссылку» и нажмите кнопку «Обзор», чтобы перейти в указанное выше место и выбрать нужный файл .dll. Нажмите «Добавить», и ссылка появится на вкладке просмотра с установленным флажком рядом с ней.
После добавления ссылкиSystem.Management.Automation.Runspaces
Вы можете запустить другой упомянутый код, чтобы добавить параметры и выполнить сценарий PowerShell. Мне очень удобно использовать кортеж для хранения пар "ключ", "значение".
/// <summary>
/// Run a powershell script with a list of arguments
/// </summary>
/// <param name="commandFile">The .ps1 script to execute</param>
/// <param name="arguments">The arguments you want to pass to the script as parameters</param>
private void ExecutePowerShellCommand(string commandFile, List<Tuple<string, string>> arguments)
{
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
//commandFile is the PowerShell script you want to execute, e.g. "FooBar.ps1"
Command cmd = new Command(commandFile);
// Loop through all the tuples containing the "key", "value" pairs and add them as a command parameter
foreach (var parameter in arguments)
cmd.Parameters.Add(new CommandParameter(parameter.Item1, parameter.Item2));
pipeline.Commands.Add(cmd);
// Execute the PowerShell script
var result = pipeline.Invoke();
}
и код вызова:
string commandFile = @"C:\data\test.ps1";
List<Tuple<string, string>> arguments = new List<Tuple<string, string>>();
arguments.Add(new Tuple<string, string>("filePath", @"C:\path\to\some\file"));
arguments.Add(new Tuple<string, string>("fileName", "FooBar.txt"));
ExecutePowerShellCommand(commandFile, arguments);