Пытаюсь выполнить скрипт PowerShell с аргументами, но это не сработает.
Я пытаюсь выполнить сценарий PowerShell из своей программы, но по какой-то причине IP-адрес не передается в аргумент должным образом. Если я запускаю его без него, он работает нормально. Любой совет, что я делаю неправильно?
private async void RunningGst()
{
byte[] scriptBytes = Manip2Cards.Properties.Resources.run_gst;
string script = System.Text.Encoding.UTF8.GetString(scriptBytes);
await Task.Run(() =>
{
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = "powershell.exe",
Arguments = $"-ExecutionPolicy Bypass -Command \"{script}\" -IPAddress {IPAddress}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
Process process = new Process
{
StartInfo = psi
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
Console.WriteLine(output);
});
}
Спасибо





Вам следует использовать PowerShell SDK вместо создания нового процесса. Вам будет гораздо проще с этим справиться, если оставить в стороне, что более эффективно вызывать сценарий PowerShell в новом пространстве выполнения в том же процессе, а не создавать новый процесс.
using System;
using System.Management.Automation;
using System.Net;
using System.Threading.Tasks;
async void RunningGst()
{
byte[] scriptBytes = Manip2Cards.Properties.Resources.run_gst;
string script = System.Text.Encoding.UTF8.GetString(scriptBytes);
using PowerShell powerShell = PowerShell.Create(RunspaceMode.NewRunspace);
PSDataCollection<PSObject> output = await powerShell
.AddScript(script, useLocalScope: true)
.AddParameter("IPAddress", IPAddress)
.InvokeAsync();
foreach (PSObject pso in output.ReadAll())
{
Console.WriteLine(pso.BaseObject);
}
}
// Only needed if below PowerShell SDK 7.2.0
internal static class Extensions
{
internal static async Task<PSDataCollection<PSObject>> InvokeAsync(
this PowerShell powerShell)
{
using PSDataCollection<PSObject> output = [];
await Task.Factory.FromAsync(
powerShell.BeginInvoke<PSObject, PSObject>(null, output),
powerShell.EndInvoke);
return output;
}
}
Спасибо, я учту это и попробую
Использование PowerShell SDK — и, следовательно, выполнение внутри процесса, которое не только быстрее, но и сохраняет точность типов — как показано в полезном ответе Сантьяго , действительно предпочтительнее.
Что касается того, что вы пробовали:
Проблема в том, что \"{script}\" -IPAddress {IPAddress} в конечном итоге рассматривается PowerShell как {script} -IPAddress {IPAddress}, то есть как единый фрагмент исходного кода, сшитый из отдельных -Command аргументов, после удаления синтаксических (неэкранированных) ".
Например, если script содержит param($IpAddress) Write-Output IPAddress: $IpAddress и IPAddress содержит foo, PowerShell выполняетсяparam($IpAddress) Write-Output IPAddress: $IpAddress -IpAddress foo, который не передает -IpAddress foo в качестве (именованного) аргумента кода, хранящегося в script.
В качестве отступления: если значение script содержит " символы., они фактически должны быть экранированы как \" в контексте вашего кода, что для буквального кода в вашем случае потребует \\\"
Решение состоит в том, чтобы заключить значение script в & { ... }, чтобы оно рассматривалось как скрипт, которому можно передавать аргументы:
// ...
Arguments = $"-ExecutionPolicy Bypass -Command \"& {{ {script} }} -IPAddress {IPAddress}\"",
// ...
Примечание:
-CommandWithArgs параметр CLI, который будет работать так, как вы задумали: первый аргумент после этого затем считается телом выполняемого сценария, и все последующие аргументы передаются этому сценарию: // ...
// Use of -CommandWithArgs
// NOTE: Only available in 7.4.x, i.e. only with pwsh.exe, not with powershell.exe
// and only if you run the following first, in a separate CLI call:
// Enable-ExperimentalFeature PSCommandWithArgs
Arguments = $"-ExecutionPolicy Bypass -CommandWithArgs \"{script}\" -IPAddress {IPAddress}",
// ...
Рад это слышать, @DeanHaklai.
почему вы используете процесс вместо экземпляра PowerShell?