Выполнение сценария PowerShell с аргументами из кода C#

Пытаюсь выполнить скрипт 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?

Santiago Squarzon 20.06.2024 19:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам следует использовать 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;
    }
}

Спасибо, я учту это и попробую

Dean Haklai 23.06.2024 10:30
Ответ принят как подходящий

Использование 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}\"",
  // ...

Примечание:

  // ...
  // 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.

mklement0 23.06.2024 12:06

Другие вопросы по теме