Как запустить PowerShell из C# (CSharp) и получить результат в виде объектов

· · C#, CSharp, PowerShell, Windows, .NET, Автоматизация, Использование существующих активов

Ситуации, когда нужно запустить PowerShell из C#, часто встречаются в бизнес-приложениях и внутренних утилитах. Например:

  • получить список служб Windows;
  • изучить процессы или журнал событий;
  • вызвать существующий скрипт PowerShell из C#-приложения;
  • выполнить команду PowerShell из небольшого GUI-инструмента для администраторов;
  • постепенно переносить существующие автоматизированные наработки на PowerShell в .NET-приложение.

Если нужен просто запуск, работает и такой способ: запустить powershell.exe или pwsh.exe как внешний процесс и прочитать стандартный вывод как строку. Но при этом теряется то, что делает PowerShell удобным, — «конвейер объектов».

Результат работы PowerShell по своей сути не просто текст. Результат Get-Process — это объекты процессов, а результат Get-Service — объекты служб. Если C#-сторона может получить эту структуру в сохранённом виде, парсинг строк становится не нужен, и обработка становится заметно надёжнее.

В этой статье разберём основы запуска PowerShell из C# с получением результата в виде PSObject.

Код из этой статьи опубликован на GitHub как полный набор примеров, готовый к сборке и запуску: библиотека с оболочкой выполнения и логикой преобразования, консольная демонстрация, показывающая каждый раздел статьи, и юнит-тесты, проверяющие получение PSObject и обработку ошибок.

csharp-run-powershell-receive-objects - komurasoft-blog-samples (GitHub)

1. Используем PowerShell SDK, а не запуск внешнего процесса

Способов вызвать PowerShell из C# в целом два.

Способ Особенности Когда подходит
Запустить powershell.exe / pwsh.exe через ProcessStartInfo Стандартный вывод и стандартная ошибка читаются как строки Простой запуск существующих batch-сценариев, обработка, где нужно только оставить лог
Использовать System.Management.Automation.PowerShell Результат можно получить как PSObject Обработка результата на стороне C#, управляющие утилиты, бизнес-приложения

В этой статье речь пойдёт о втором подходе. System.Management.Automation.PowerShell позволяет собрать и выполнить конвейер PowerShell прямо из кода C#. Важно, что возвращаемое значение — не строка, а по сути Collection<PSObject>.

Иными словами, логика такая:

Выполняем команду PowerShell
  ↓
Получаем результат как коллекцию PSObject
  ↓
Извлекаем значения через BaseObject или Properties
  ↓
При необходимости преобразуем в DTO / record / class C#

Ключевая идея — с самого начала работать с выводом PowerShell как с объектами, а не разбирать его как строки.

2. Требования к окружению

В этой статье в качестве примера используется консольное приложение .NET 8. PowerShell SDK для разных версий рассчитан на разные версии .NET, поэтому версию выбирают под целевой фреймворк проекта.

По состоянию на июнь 2026 года удобно ориентироваться, например, так:

Целевой фреймворк C#-приложения Пример версии PowerShell SDK Примечание
.NET 8 Microsoft.PowerShell.SDK серии 7.4 Удобно использовать в приложениях .NET 8
.NET 10 Microsoft.PowerShell.SDK серии 7.6 Вариант, если нужен более новый PowerShell SDK
.NET Framework Microsoft.PowerShell.5.1.ReferenceAssemblies Для Windows PowerShell 5.1; для новой разработки стоит уточнить требования

Здесь в качестве примера для .NET 8 используем Microsoft.PowerShell.SDK версии 7.4.16.

dotnet new console -n PowerShellObjectSample
cd PowerShellObjectSample
dotnet add package Microsoft.PowerShell.SDK --version 7.4.16

Файл .csproj при этом выглядит, например, так:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.4.16" />
  </ItemGroup>

</Project>

Версию рекомендуется фиксировать. PowerShell SDK удобен, но зависит от среды выполнения приложения, целевой версии .NET и совместимости модулей PowerShell. Для бизнес-приложений безопаснее явно фиксировать версию, которую вы проверили, чем просто использовать «последнюю версию, которая заработала в среде разработки».

3. Минимальный код: запускаем PowerShell и получаем PSObject

Для начала получим через PowerShell процесс самого текущего C#-приложения.

using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;

int currentProcessId = Environment.ProcessId;

using PowerShell ps = PowerShell.Create();

Collection<PSObject> results = ps
    .AddCommand("Get-Process")
    .AddParameter("Id", currentProcessId)
    .Invoke();

foreach (PSObject item in results)
{
    Console.WriteLine($"PSObject type: {item.GetType().FullName}");
    Console.WriteLine($"BaseObject type: {item.BaseObject.GetType().FullName}");

    if (item.BaseObject is Process process)
    {
        Console.WriteLine($"Id: {process.Id}");
        Console.WriteLine($"Name: {process.ProcessName}");
        Console.WriteLine($"Memory: {process.WorkingSet64:N0} bytes");
    }
}

Здесь важны три момента: PowerShell.Create() создаёт объект выполнения PowerShell; AddCommand("Get-Process") и AddParameter("Id", currentProcessId) собирают команду и её параметры; а возвращаемое значение Invoke() — это Collection<PSObject>.

PSObject — это обёртка вокруг значения, которое выводит PowerShell. Чтобы увидеть внутри исходный .NET-объект, обращаются к BaseObject. В этом примере содержимое результата Get-Process можно извлечь как System.Diagnostics.Process.

4. Когда использовать BaseObject, а когда Properties

При работе с результатом PowerShell в C# первое, с чем возникают сомнения, — вот эти два варианта:

item.BaseObject
item.Properties["Name"]?.Value

Ориентир для выбора такой:

Способ извлечения Когда используется
BaseObject Когда нужен исходный .NET-объект, возвращённый PowerShell, как есть
Properties["..."] Когда нужно извлечь столбцы, сформированные через Select-Object или [pscustomobject]

Если выполнить такую команду, как Get-Process, напрямую, в BaseObject может оказаться исходный .NET-объект. С другой стороны, если на стороне PowerShell столбцы были оформлены через Select-Object, результат чаще возвращается как пользовательский объект PowerShell. В этом случае естественнее извлекать значение по имени столбца из Properties.

5. Читаем в C# результат Select-Object

На практике редко нужны все свойства, которые возвращает PowerShell. Чтобы передать на сторону C# только нужные столбцы, используют Select-Object в конвейере PowerShell.

using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;

using PowerShell ps = PowerShell.Create();

Collection<PSObject> rows = ps
    .AddCommand("Get-Process")
    .AddCommand("Sort-Object")
        .AddParameter("Property", "CPU")
        .AddParameter("Descending", true)
    .AddCommand("Select-Object")
        .AddParameter("First", 10)
        .AddParameter("Property", new[] { "Name", "Id", "CPU", "WorkingSet" })
    .Invoke();

foreach (PSObject row in rows)
{
    string name = Convert.ToString(row.Properties["Name"]?.Value, CultureInfo.InvariantCulture) ?? "";
    int id = Convert.ToInt32(row.Properties["Id"]?.Value, CultureInfo.InvariantCulture);
    double? cpu = row.Properties["CPU"]?.Value is null
        ? null
        : Convert.ToDouble(row.Properties["CPU"]!.Value, CultureInfo.InvariantCulture);
    long workingSet = Convert.ToInt64(row.Properties["WorkingSet"]?.Value, CultureInfo.InvariantCulture);

    Console.WriteLine($"{id}: {name}, CPU={cpu}, WorkingSet={workingSet:N0}");
}

Этот код соответствует следующему конвейеру в PowerShell:

Get-Process |
  Sort-Object -Property CPU -Descending |
  Select-Object -First 10 -Property Name, Id, CPU, WorkingSet

Со стороны C# последовательные вызовы AddCommand строят конвейер PowerShell:

.AddCommand("Get-Process")
.AddCommand("Sort-Object")
.AddCommand("Select-Object")

При такой записи вывод каждой предыдущей команды передаётся в следующую.

После того как Select-Object сузил столбцы, значения извлекаются по имени столбца, например row.Properties["Name"]?.Value.

6. Преобразуем в record C#

Если передавать PSObject по всему приложению как есть, последующий код становится слишком зависимым от PowerShell. Для отображения на экране или бизнес-логики удобнее преобразовать результат в тип на стороне C#.

Например, преобразуем информацию о процессе в такой record:

public sealed record ProcessSummary(
    string Name,
    int Id,
    double? Cpu,
    long WorkingSet);

Если вынести логику преобразования отдельно, код становится нагляднее:

using System.Globalization;
using System.Management.Automation;

static ProcessSummary ToProcessSummary(PSObject row)
{
    string name = GetString(row, "Name");
    int id = GetInt32(row, "Id");
    double? cpu = GetNullableDouble(row, "CPU");
    long workingSet = GetInt64(row, "WorkingSet");

    return new ProcessSummary(name, id, cpu, workingSet);
}

static string GetString(PSObject row, string propertyName)
{
    return Convert.ToString(row.Properties[propertyName]?.Value, CultureInfo.InvariantCulture) ?? "";
}

static int GetInt32(PSObject row, string propertyName)
{
    return Convert.ToInt32(row.Properties[propertyName]?.Value, CultureInfo.InvariantCulture);
}

static long GetInt64(PSObject row, string propertyName)
{
    return Convert.ToInt64(row.Properties[propertyName]?.Value, CultureInfo.InvariantCulture);
}

static double? GetNullableDouble(PSObject row, string propertyName)
{
    object? value = row.Properties[propertyName]?.Value;
    return value is null ? null : Convert.ToDouble(value, CultureInfo.InvariantCulture);
}

Со стороны вызова это выглядит так:

List<ProcessSummary> processes = rows
    .Select(ToProcessSummary)
    .ToList();

foreach (ProcessSummary process in processes)
{
    Console.WriteLine($"{process.Id}: {process.Name}");
}

PSObject обрабатывают на границе с PowerShell, а внутри приложения преобразуют в обычные типы C#, такие как ProcessSummary.

Если заложить это разделение заранее, изменение команды PowerShell в будущем затронет меньшую область кода.

7. Если возвращать PSCustomObject, с C# работать проще

Когда на стороне PowerShell нужно вернуть сразу несколько значений, удобно использовать [pscustomobject].

using System.Collections.ObjectModel;
using System.Management.Automation;

string script = @"
[pscustomobject]@{
    MachineName       = [System.Environment]::MachineName
    PowerShellVersion = $PSVersionTable.PSVersion.ToString()
    CurrentDirectory  = (Get-Location).Path
}
";

using PowerShell ps = PowerShell.Create();

Collection<PSObject> rows = ps
    .AddScript(script, useLocalScope: true)
    .Invoke();

foreach (PSObject row in rows)
{
    Console.WriteLine($"MachineName: {row.Properties["MachineName"]?.Value}");
    Console.WriteLine($"PowerShell:  {row.Properties["PowerShellVersion"]?.Value}");
    Console.WriteLine($"Directory:   {row.Properties["CurrentDirectory"]?.Value}");
}

Если скрипт PowerShell в конце возвращает [pscustomobject], на стороне C# можно извлекать значения по имени из Properties. Это заметно безопаснее, чем возвращать сложную строку и разбивать её на части на стороне C#.

Пример, которого стоит избегать, — такой вывод:

"$MachineName,$PowerShellVersion,$CurrentDirectory"

Этот способ выглядит простым, но ломается, как только в значении появляется запятая или перенос строки.

PowerShell возвращает объекты, а C# читает их как свойства. При такой форме легко справляться с добавлением новых столбцов в будущем.

8. Не встраивайте пользовательский ввод напрямую в AddScript

Даже при использовании PowerShell SDK собирать скрипт через конкатенацию строк опасно. Например, кода вроде этого стоит избегать:

// Пример, которого стоит избегать
string userInputPath = GetPathFromUser();
string script = $"Get-ChildItem -Path '{userInputPath}'";

using PowerShell ps = PowerShell.Create();
ps.AddScript(script).Invoke();

При такой записи пользовательский ввод может быть интерпретирован как код PowerShell. Когда нужно передать значение в команду PowerShell, по возможности используйте AddCommand и AddParameter.

string userInputPath = GetPathFromUser();

using PowerShell ps = PowerShell.Create();

Collection<PSObject> files = ps
    .AddCommand("Get-ChildItem")
    .AddParameter("Path", userInputPath)
    .AddParameter("File", true)
    .Invoke();

Значение, переданное через AddParameter, обрабатывается не как строка кода, соединённая конкатенацией, а как значение параметра.

На практике разумно придерживаться такого разделения:

Способ записи Когда используется
AddCommand / AddParameter Когда нужно безопасно собрать команду на стороне C#
AddScript Для выполнения фиксированного короткого скрипта или загрузки уже существующего скрипта
AddScript со строковой конкатенацией В принципе стоит избегать; если всё же используете — тщательно проверяйте и экранируйте входные значения

Встраивание PowerShell в C# даёт приложению мощные возможности. Но вместе с удобством нужно соблюдать одно правило: не превращать пользовательский ввод напрямую в скрипт.

9. Format-Table нужен только для финального отображения на экране — не используйте его перед передачей в C#

Если результат PowerShell нужно получить в C# как объект, Format-Table и Format-List, как правило, не используют.

Например, такой PowerShell удобен, когда человек смотрит на экран:

Get-Service | Format-Table Name, Status

Но если применить Format-Table до передачи результата в C#, вместо объектов служб вы получите информацию для форматирования отображения. Если результат нужен для обработки в C#, используйте Select-Object.

Get-Service | Select-Object Name, Status

Со стороны C# это выглядит так:

using PowerShell ps = PowerShell.Create();

Collection<PSObject> services = ps
    .AddCommand("Get-Service")
    .AddCommand("Select-Object")
        .AddParameter("Property", new[] { "Name", "Status" })
    .Invoke();

Идея простая:

Нужна только читаемость на экране → Format-Table / Format-List
Нужна дальнейшая обработка в C#    → Select-Object / PSCustomObject

Это справедливо и при использовании PowerShell самого по себе, но особенно важно становится при интеграции с C#.

10. Получаем ошибки

В PowerShell вывод и ошибки — это отдельные потоки. Если смотреть только на возвращаемое значение Invoke(), ошибки легко упустить. Базовая форма такая:

using System.Management.Automation;

using PowerShell ps = PowerShell.Create();

Collection<PSObject> output = ps
    .AddCommand("Get-Item")
    .AddParameter("Path", @"C:\no-such-file.txt")
    .Invoke();

if (ps.HadErrors)
{
    foreach (ErrorRecord error in ps.Streams.Error)
    {
        Console.WriteLine($"Error: {error.Exception.Message}");
        Console.WriteLine($"Category: {error.CategoryInfo.Category}");
        Console.WriteLine($"Target: {error.TargetObject}");
    }
}

У командлетов PowerShell есть ошибки, которые останавливают выполнение, и ошибки, при которых выполнение продолжается. Если на стороне C# нужно обрабатывать их как исключения, можно указать Stop для ErrorAction.

using System.Management.Automation;

try
{
    using PowerShell ps = PowerShell.Create();

    Collection<PSObject> output = ps
        .AddCommand("Get-Item")
        .AddParameter("Path", @"C:\no-such-file.txt")
        .AddParameter("ErrorAction", "Stop")
        .Invoke();
}
catch (RuntimeException ex)
{
    Console.WriteLine($"PowerShell failed: {ex.Message}");
}

Что лучше, зависит от характера приложения. Для управляющей утилиты, где нужно вывести список даже при частичных сбоях, удобнее собирать поток ошибок и показывать его на экране. Если же при сбое нужно остановить всю обработку целиком, понятнее обрабатывать это как исключение через ErrorAction Stop.

11. Создаём небольшую обёртку для выполнения

В приложении, которое многократно вызывает PowerShell, повторение одной и той же обработки ошибок каждый раз захламляет код. Удобно подготовить простую обёртку.

using System.Management.Automation;

public sealed record PowerShellRunResult(
    IReadOnlyList<PSObject> Output,
    IReadOnlyList<ErrorRecord> Errors);

public static class PowerShellRunner
{
    public static PowerShellRunResult Run(Action<PowerShell> build)
    {
        using PowerShell ps = PowerShell.Create();

        build(ps);

        List<PSObject> output;

        try
        {
            output = ps.Invoke().ToList();
        }
        catch (RuntimeException ex)
        {
            throw new InvalidOperationException($"PowerShell execution failed: {ex.Message}", ex);
        }

        return new PowerShellRunResult(
            Output: output,
            Errors: ps.Streams.Error.ToList());
    }
}

Со стороны вызова остаётся сосредоточиться только на сборке команды.

PowerShellRunResult result = PowerShellRunner.Run(ps => ps
    .AddCommand("Get-Service")
    .AddCommand("Where-Object")
        .AddParameter("Property", "Status")
        .AddParameter("EQ", "Running")
    .AddCommand("Select-Object")
        .AddParameter("First", 10)
        .AddParameter("Property", new[] { "Name", "DisplayName", "Status" }));

foreach (PSObject row in result.Output)
{
    Console.WriteLine($"{row.Properties["Name"]?.Value}: {row.Properties["Status"]?.Value}");
}

foreach (ErrorRecord error in result.Errors)
{
    Console.Error.WriteLine(error.Exception.Message);
}

Впрочем, сборка специфичного для PowerShell условия, как Where-Object в этом примере, из C# иногда получается не очень читаемой. Простые команды и параметры можно собирать через AddCommand / AddParameter, но для сложных фильтров и агрегаций иногда читабельнее подготовить фиксированный скрипт PowerShell. Даже в этом случае правило не соединять внешний ввод напрямую со строкой скрипта не меняется.

12. Сложную обработку оформляем в объекты на стороне PowerShell

При сочетании C# и PowerShell проектировать проще, если заранее разделить, кто за что отвечает.

Рекомендуем такое разделение ролей:

Отвечает Что делает
PowerShell Операции, близкие к Windows и её модулям, существующие скрипты, выполнение административных команд
C# UI, проверка ввода, преобразование типов, бизнес-логика, сохранение, интеграция с API

На стороне PowerShell итоговый вывод оформляют в [pscustomobject].

Get-Service |
  Where-Object Status -eq 'Running' |
  Select-Object Name, DisplayName, Status

Либо создают [pscustomobject] явно:

$services = Get-Service | Where-Object Status -eq 'Running'

[pscustomobject]@{
    Count = $services.Count
    Names = $services.Name
}

На стороне C# читают свойства полученного PSObject и преобразуют их в собственные типы приложения.

При такой форме детали реализации PowerShell не просачиваются в C# сверх необходимого.

13. Частые практические нюансы

Когда C# запускает PowerShell, недостаточно того, чтобы код просто работал. На практике стоит заранее проверить следующие моменты.

Права выполняющего пользователя

PowerShell работает с правами пользователя, от имени которого запущено C#-приложение. Команды, требующие прав администратора, завершатся ошибкой при запуске от обычного пользователя. При работе со службами, журналом событий, сертификатами, реестром, Hyper-V, модулями администрирования Microsoft 365 и подобным нужно заранее продумать разграничение прав.

Различия между 32-битным и 64-битным процессом

В Windows видимость реестра и модулей может отличаться между 32-битным и 64-битным процессом. Если вы создаёте инструмент для администрирования Windows, изначально ориентироваться на выполнение в x64 — это способ уменьшить число проблем.

Наличие нужных модулей в среде выполнения

Установка PowerShell SDK в C#-приложение не означает, что автоматически подтянутся все модули PowerShell. Например, при использовании модуля управления конкретным продуктом или внутрикорпоративного модуля нужно проверить, есть ли этот модуль в среде выполнения и из какого пути он будет загружен.

В GUI-приложении не блокируйте UI-поток

Если запускать PowerShell из WinForms или WPF и выполнять тяжёлую операцию прямо в UI-потоке, окно зависнет. В этом случае выполнение нужно вынести в фоновую обработку, а обновлять интерфейс после завершения. В PowerShell SDK есть и API для асинхронного выполнения, но начинать стоит с простого правила: не выполнять долгий Invoke() в UI-потоке.

Размер приложения при распространении

Microsoft.PowerShell.SDK удобен, но увеличивает число зависимостей приложения. Для небольшой утилиты это может быть приемлемо, но в зависимости от формата распространения и способа обновления размер может стать проблемой. Стоит заранее проверить это на реальном способе распространения — ClickOnce, MSIX, единый exe-файл, внутренний инструмент развёртывания и так далее.

14. Преимущества получения объектов вместо строк

Напоследок — почему так важно настаивать именно на PSObject. Запуск PowerShell как внешнего процесса с чтением стандартного вывода прост:

Вывод PowerShell
  ↓
Строка
  ↓
Split / регулярные выражения / Substring
  ↓
Значения C#

Однако этот способ зависит от формата отображения. Он легко ломается из-за ширины столбцов, локали, переносов строк, пробелов, текста ошибок и разделителей внутри самих значений.

С другой стороны, при использовании PowerShell SDK поток такой:

Вывод PowerShell
  ↓
PSObject
  ↓
Properties / BaseObject
  ↓
Тип C#

Здесь значения извлекаются на основе структуры данных, а не формата отображения. Для бизнес-приложений и управляющих утилит второй вариант заметно легче поддерживать.

15. Итог

Если вы запускаете PowerShell из C# и работаете с результатом, стоит рассмотреть не просто запуск powershell.exe с чтением стандартного вывода, а использование PowerShell SDK.

Базовый порядок действий такой:

Подключаем Microsoft.PowerShell.SDK
  ↓
Создаём объект выполнения через PowerShell.Create()
  ↓
Собираем обработку через AddCommand / AddParameter / AddScript
  ↓
Выполняем через Invoke()
  ↓
Получаем Collection<PSObject>
  ↓
Извлекаем значения через BaseObject или Properties
  ↓
Преобразуем в DTO / record / class C#

Особенно важны на практике три момента:

  • если результат используется для дальнейшей обработки в C#, применяйте не Format-Table, а Select-Object или [pscustomobject];
  • не встраивайте пользовательский ввод напрямую в строку AddScript, по возможности передавайте его через AddParameter;
  • обрабатывайте PSObject на границе, а внутри приложения преобразуйте его в типы C#.

PowerShell силён в администрировании Windows и использовании существующих наработок, а C# силён в построении приложений, интерфейсов и типобезопасной бизнес-логики. Если удачно связать их между собой, существующие скрипты PowerShell не придётся выбрасывать — их можно постепенно встраивать в .NET-приложение.

Справочные материалы

  • Полный набор примеров кода к этой статье (библиотека, демо, юнит-тесты) https://github.com/gomurin0428/komurasoft-blog-samples/tree/main/csharp-run-powershell-receive-objects
  • Microsoft Learn: Windows PowerShell Host Quickstart
    https://learn.microsoft.com/en-us/powershell/scripting/developer/hosting/windows-powershell-host-quickstart
  • Microsoft Learn: Adding and invoking commands
    https://learn.microsoft.com/en-us/powershell/scripting/developer/hosting/adding-and-invoking-commands
  • Microsoft Learn: PowerShell Class
    https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.powershell
  • Microsoft Learn: PSObject Class
    https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject
  • NuGet Gallery: Microsoft.PowerShell.SDK
    https://www.nuget.org/packages/Microsoft.PowerShell.SDK/
  • NuGet Gallery: Microsoft.PowerShell.5.1.ReferenceAssemblies
    https://www.nuget.org/packages/Microsoft.PowerShell.5.1.ReferenceAssemblies/

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Каким способом лучше запускать PowerShell из C#?
В целом есть два подхода: запустить powershell.exe / pwsh.exe как внешний процесс через ProcessStartInfo, или использовать System.Management.Automation.PowerShell (PowerShell SDK). Если нужно только прочитать стандартный вывод как строку, первый вариант тоже работает. Но для управляющих утилит и бизнес-приложений, где результат нужно обрабатывать на стороне C#, лучше подходит второй вариант — он позволяет получать результат как коллекцию PSObject. Тогда парсинг строк не нужен, и можно писать безопасную обработку, не зависящую от формата отображения.
Как выбрать между BaseObject и Properties у PSObject?
BaseObject используют, когда нужен исходный .NET-объект, который вернул PowerShell, как есть. Например, результат прямого выполнения Get-Process можно извлечь как System.Diagnostics.Process. С другой стороны, результат, у которого столбцы были оформлены через Select-Object или [pscustomobject], чаще возвращается как пользовательский объект PowerShell, и в этом случае естественнее извлекать значение по имени столбца через Properties["ИмяСтолбца"]?.Value.
На что обратить внимание при передаче пользовательского ввода из C# в PowerShell?
Не стоит встраивать пользовательский ввод в скрипт AddScript через конкатенацию строк — это опасно, поскольку ввод может быть интерпретирован как код PowerShell. Если нужно передать значение, используйте AddCommand и AddParameter: тогда значение обрабатывается не как строка кода, а как значение параметра. AddScript разумнее оставить для фиксированных коротких скриптов или загрузки уже существующих скриптов.
Почему не стоит использовать Format-Table, когда результат PowerShell нужно получить в C#?
Если пропустить результат через Format-Table или Format-List, вместо исходного объекта вы получите информацию для форматирования отображения, и извлечь значения как свойства на стороне C# уже не получится. Если результат нужен для дальнейшей обработки в C#, сужайте столбцы через Select-Object либо оформляйте результат на стороне PowerShell как [pscustomobject]. Правило простое: «для отображения на экране — команды Format-*, для передачи в C# — Select-Object».

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог