在 C#(CSharp)中執行 PowerShell 並以物件形式接收結果

· · C#, CSharp, PowerShell, Windows, .NET, 自動化, 既有資產活用

在業務應用程式或內部工具中,經常會遇到想從 C# 執行 PowerShell 的場景,例如以下這些處理:

  • 取得 Windows 的服務清單
  • 查詢處理程序或事件記錄
  • 從 C# 應用程式呼叫既有的 PowerShell 腳本
  • 從供管理員使用的小型 GUI 工具執行 PowerShell 命令
  • 把 PowerShell 端既有的自動化資產,逐步納入 .NET 應用程式

如果只是單純執行,把 powershell.exepwsh.exe 當作外部程序啟動、把標準輸出當成字串讀取的方法也能動。但這種做法會失去 PowerShell 的優點——「物件管線(object pipeline)」。

PowerShell 的結果原本就不只是純文字。Get-Process 的結果是處理程序物件,Get-Service 的結果是服務物件。如果在 C# 端也能保持這種結構來接收,就不需要解析字串,處理也會變得相當安全。

本文將整理從 C# 執行 PowerShell,並以 PSObject 形式接收結果的基本做法。

另外,本文出現的程式碼已整理成一套可建置、可執行的範例(執行包裝器與轉換處理的函式庫、演示文章各章節的主控台 demo,以及驗證 PSObject 接收與錯誤處理的單元測試),公開在 GitHub 上。

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

1. 不用啟動外部程序,改用 PowerShell SDK

從 C# 呼叫 PowerShell 的方法,大致可以分成兩種。

方法 特徵 適合的場景
ProcessStartInfo 啟動 powershell.exe / pwsh.exe 把標準輸出、標準錯誤當成字串讀取 單純執行既有批次作業、只需要留下記錄的處理
使用 System.Management.Automation.PowerShell 可以以 PSObject 的形式接收結果 需要在 C# 端加工結果的處理、管理工具、業務應用程式

本文要探討的是後者。使用 System.Management.Automation.PowerShell,就能從 C# 程式碼組裝並執行 PowerShell 的管線。重點在於,回傳值不是字串,基本上會是 Collection<PSObject>

換句話說,思路會變成這樣:

執行 PowerShell 命令
  ↓
以 PSObject 集合的形式接收結果
  ↓
從 BaseObject 或 Properties 中取出值
  ↓
必要時轉換成 C# 的 DTO / record / class

重點不是把 PowerShell 的輸出拆解成字串,而是從一開始就以物件的形式來處理。

2. 前提環境

本文以 .NET 8 的主控台應用程式為例。PowerShell SDK 依版本不同,對應的 .NET 也不同,因此要配合專案的目標框架來選擇。

以 2026 年 6 月的時間點來看,可以這樣理解:

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");
    }
}

這裡有 3 個重點:用 PowerShell.Create() 建立 PowerShell 的執行物件;用 AddCommand("Get-Process")AddParameter("Id", currentProcessId) 組裝命令與參數;以及 Invoke() 的回傳值是 Collection<PSObject>

PSObject 是包裝 PowerShell 輸出值的包裝器(wrapper)。想查看內部原始的 .NET 物件時,就看 BaseObject。在這個範例中,Get-Process 結果的內容可以用 System.Diagnostics.Process 的形式取出。

4. BaseObject 與 Properties 的使用區分

在 C# 中處理 PowerShell 的結果時,最先讓人猶豫的就是下面這兩種寫法。

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

該用哪一種,大致可以參考下表。

取值方式 使用場景
BaseObject 想直接使用 PowerShell 傳回的原始 .NET 物件時
Properties["..."] 想取出經由 Select-Object[pscustomobject] 建立的欄位時

若直接執行像 Get-Process 這樣的命令,BaseObject 裡通常會放著原始的 .NET 物件。另一方面,若在 PowerShell 端使用 Select-Object 整理過欄位,結果多半會以 PowerShell 的自訂物件形式傳回。這種情況下,改用 Properties 依欄位名稱取值會更自然。

5. 在 C# 中讀取 Select-Object 後的結果

在實務上,很少會需要 PowerShell 傳回的所有屬性。如果只想把需要的欄位傳到 C# 端,可以在 PowerShell 管線中使用 Select-Object

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. 轉換成 C# 的 record

如果讓 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 交界的地方處理,應用程式內部則轉換成像 ProcessSummary 這樣一般的 C# 型別。

做好這層分離後,即使之後修改 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 命令時,應盡量使用 AddCommandAddParameter

string userInputPath = GetPathFromUser();

using PowerShell ps = PowerShell.Create();

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

AddParameter 傳遞的值,不會被當成 PowerShell 的程式碼字串串接,而是會被當作參數值處理。

在實務上,建議依下表區分使用方式:

寫法 適用情境
AddCommand / AddParameter 想從 C# 端安全地組裝命令時
AddScript 執行固定的短腳本,或載入既有腳本時
用字串串接組成的 AddScript 原則上應避免。若要使用,務必謹慎驗證與轉義輸入值

把 PowerShell 整合進 C# 之後,應用程式就能具備強大的操作能力。方便之餘,唯一必須堅守的一條底線是:不要把使用者輸入直接變成腳本。

9. Format-Table 只用於最後的畫面顯示,傳給 C# 之前不要用

如果想在 C# 中以物件形式接收 PowerShell 的結果,基本上不會使用 Format-TableFormat-List

舉例來說,下面這種 PowerShell 寫法對於讓人在畫面上檢視很方便:

Get-Service | Format-Table Name, Status

但是,如果在 C# 端接收之前使用了 Format-Table,結果就不再是服務物件,而會變成用於顯示的格式化資訊。如果要在 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 中,輸出與錯誤是不同的資料流(stream)。如果只看 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 的 cmdlet 分為會終止處理的錯誤,以及可以繼續處理的錯誤。如果想在 C# 端當作例外(exception)處理,可以把 ErrorAction 指定為 Stop

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 的應用程式中,如果每次都寫相同的錯誤處理,程式碼會變得雜亂。事先準備一個簡單的包裝器(wrapper)會很方便。

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);
}

不過,就像這個範例中的 Where-Object 一樣,把 PowerShell 特有的條件指定用 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 管理相關模組等,都需要事先釐清權限。

32bit / 64bit 的差異

在 Windows 中,32bit 處理程序與 64bit 處理程序看到的登錄檔或模組有時會不同。如果要做成 Windows 管理用工具,基本上以 x64 為前提來執行,可以減少麻煩。

執行環境中是否有模組

即使在 C# 應用程式中加入 PowerShell SDK,也不代表所有 PowerShell 模組都會自動安裝進去。例如要使用特定產品的管理模組或內部模組時,需要確認執行環境中是否存在該模組,以及會從哪個路徑載入。

畫面應用程式中不要阻塞 UI 執行緒

從 WinForms 或 WPF 執行 PowerShell 時,如果直接在 UI 執行緒上執行繁重處理,畫面會凍住。這種情況下,應該設計成以背景處理方式執行,完成後再更新 UI。PowerShell SDK 也提供非同步執行的 API,但首先要守住「不在 UI 執行緒上執行長時間的 Invoke()」這條方針。

應用程式部署時的大小

Microsoft.PowerShell.SDK 雖然方便,但也會增加應用程式所包含的相依性。對於小型工具程式來說可能還能接受,但依部署形式或更新方式的不同,大小有時會成為問題。建議儘早以 ClickOnce、MSIX、單一 exe 部署、內部部署工具等實際的部署方式進行驗證,比較安心。

14. 以物件而非字串接收的優點

最後,來談談為什麼要如此堅持使用 PSObject。以外部程序方式執行 PowerShell、讀取標準輸出的方法確實簡單。

PowerShell 的輸出
  ↓
字串
  ↓
Split / 正規表達式 / Substring
  ↓
C# 的值

不過,這種方法會依賴顯示格式。欄寬、地區設定(locale)、換行、空白、錯誤訊息,以及值中包含的分隔字元,都容易讓它壞掉。

另一方面,使用 PowerShell SDK 則會是下面這個流程:

PowerShell 的輸出
  ↓
PSObject
  ↓
Properties / BaseObject
  ↓
C# 的型別

這種方式是根據資料結構而非顯示格式來取值。對業務應用程式或管理工具來說,後者更容易維護。

15. 總結

如果要從 C# 執行 PowerShell 並處理結果,除了單純啟動 powershell.exe 讀取標準輸出之外,值得考慮使用 PowerShell SDK 的做法。

基本流程如下:

加入 Microsoft.PowerShell.SDK
  ↓
用 PowerShell.Create() 建立執行物件
  ↓
用 AddCommand / AddParameter / AddScript 組裝處理
  ↓
用 Invoke() 執行
  ↓
以 Collection<PSObject> 形式接收
  ↓
從 BaseObject 或 Properties 取出值
  ↓
轉換成 C# 的 DTO / record / class

在實務上特別重要的是下面這 3 點:

  • 若要在 C# 中做後續處理,應使用 Select-Object[pscustomobject],而不是 Format-Table
  • 不要把使用者輸入直接嵌入 AddScript 的字串,盡量透過 AddParameter 傳遞
  • PSObject 只在交界處處理,應用程式內部則轉換成 C# 的型別

PowerShell 擅長 Windows 管理與運用既有資產,C# 擅長應用程式化、畫面化,以及型別安全的業務處理。把兩者妥善連接起來,就能不捨棄既有的 PowerShell 腳本,逐步整理成 .NET 應用程式。

參考資料

  • 本文的範例程式碼一整套(函式庫、demo、單元測試) https://github.com/gomurin0428/komurasoft-blog-samples/tree/main/csharp-run-powershell-receive-objects
  • Microsoft Learn:Windows PowerShell 主機的快速入門
    https://learn.microsoft.com/ja-jp/powershell/scripting/developer/hosting/windows-powershell-host-quickstart
  • Microsoft Learn:新增並呼叫命令
    https://learn.microsoft.com/ja-jp/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/ja-jp/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/

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

從 C# 執行 PowerShell,該用哪種方法比較好?
大致可以分成兩種方式:用 ProcessStartInfo 將 powershell.exe / pwsh.exe 當作外部程序啟動,以及使用 System.Management.Automation.PowerShell(PowerShell SDK)。如果只是要把標準輸出當成字串讀取,前者也能動;但在 C# 端需要加工結果的管理工具或業務應用程式中,能以 PSObject 集合形式接收結果的後者更為合適。這樣就不需要解析字串,也能寫出不依賴顯示格式的安全處理邏輯。
PSObject 的 BaseObject 與 Properties 該如何區分使用?
當你想直接使用 PowerShell 傳回的原始 .NET 物件時,就使用 BaseObject。例如直接執行 Get-Process 的結果,可以以 System.Diagnostics.Process 的形式取出。另一方面,經由 Select-Object 或 [pscustomobject] 整理過欄位的結果,通常會以 PowerShell 的自訂物件形式傳回,這種情況下用 Properties["欄位名稱"]?.Value 依欄位名稱取值會更自然。
從 C# 將使用者輸入傳給 PowerShell 時,該注意什麼?
應避免用字串串接的方式,把使用者輸入直接嵌入 AddScript 的腳本中,因為輸入內容有可能被當成 PowerShell 程式碼解讀,相當危險。若要傳遞值,使用 AddCommand 搭配 AddParameter,值就會被當作參數值處理,而不是程式碼字串。建議將 AddScript 限定用於固定的短腳本,或載入既有腳本這類情境。
在 C# 接收 PowerShell 結果時,為什麼不該使用 Format-Table?
因為經過 Format-Table 或 Format-List 之後,結果會變成用於顯示的格式化資訊,而不是原本的物件,導致 C# 端無法以屬性的方式取出值。若要在 C# 中做後續處理,應改用 Select-Object 篩選欄位,或在 PowerShell 端整理成傳回 [pscustomobject] 的形式。可以這樣區分:「只在畫面上檢視就用 Format 系列,要傳給 C# 就用 Select-Object」。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽