在 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 管理相关模块等,都需要提前厘清权限划分。

32 位 / 64 位的差异

在 Windows 中,32 位进程与 64 位进程所能看到的注册表或模块有时会不同。如果要做成 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 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。

返回博客列表