You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6 C# WPF 执行内嵌.ps1脚本及结果转DataTable实现问题

核心问题修复与功能实现

1. 现有代码致命问题修复

你当前代码的ConnectToExchange方法中使用了using块管理runspace和pipeline,会导致代码块执行结束后资源立即被释放,后续调用RunScript时拿到的都是已销毁的对象,直接删除这两处using即可,资源可以在类销毁时统一释放。

2. 依赖补充

如果还未安装PowerShell相关依赖,可通过NuGet安装Microsoft.PowerShell.SDK包适配.NET 6环境。

3. 完整实现代码

using System;
using System.Data;
using System.Linq;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Windows;

public class PowerShellStuff : IDisposable
{
    private readonly string PS_UserName = "";
    private readonly string PS_Password = "";
    private Runspace? runspace;
    private PowerShell? pipeline;
    private bool disposedValue = false;

    public void ConnectToExchange()
    {
        if (runspace != null && runspace.RunspaceStateInfo.State == RunspaceState.Opened)
            return;

        System.Security.SecureString securePassword = new System.Security.SecureString();
        foreach (char c in PS_Password)
        {
            securePassword.AppendChar(c);
        }
        PSCredential credential = new(PS_UserName, securePassword);
        WSManConnectionInfo connectionInfo = new(new Uri("https://outlook.office365.com/powershell-liveid/"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential)
        {
            AuthenticationMechanism = AuthenticationMechanism.Basic,
            MaximumConnectionRedirectionCount = 2
        };
        // 移除using,避免提前释放资源
        runspace = RunspaceFactory.CreateRunspace(connectionInfo);
        pipeline = PowerShell.Create();
        runspace.Open();
        pipeline.Runspace = runspace;
    }

    // 原有参数化命令执行方法,适配SET类无返回值命令
    public Collection<PSObject> RunScript(PSCommand command)
    {
        if (runspace == null)
        {
            try
            {
                ConnectToExchange();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "User Information", MessageBoxButton.OK, MessageBoxImage.Error);
                return new Collection<PSObject>();
            }
        }

        if (runspace.RunspaceStateInfo.State != RunspaceState.Opened)
            runspace.Open();

        pipeline.Commands.Clear();
        Command newCommand = new Command(command.Commands[0].ToString());
        foreach (var param in command.Commands[0].Parameters)
        {
            newCommand.Parameters.Add(param);
        }
        pipeline.Commands.AddCommand(newCommand);

        Collection<PSObject> results = new Collection<PSObject>();
        try
        {
            results = pipeline.Invoke();
            // 处理错误流
            if (pipeline.HadErrors)
            {
                foreach (var error in pipeline.Streams.Error)
                {
                    MessageBox.Show(error.ToString(), "PowerShell Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "User Information", MessageBoxButton.OK, MessageBoxImage.Error);
        }
        return results;
    }

    // 新增:执行PS1脚本并返回DataTable
    public DataTable RunPs1ScriptToDataTable(string ps1Content)
    {
        DataTable dt = new DataTable();
        if (string.IsNullOrWhiteSpace(ps1Content))
            return dt;

        var results = RunScript(new PSCommand().AddScript(ps1Content));
        if (results.Count == 0)
            return dt;

        // 自动生成列
        var properties = results[0].Members.Where(m => m.MemberType == PSMemberTypes.NoteProperty || m.MemberType == PSMemberTypes.Property).ToList();
        foreach (var prop in properties)
        {
            dt.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.Value.GetType()) ?? prop.Value.GetType());
        }

        // 填充行
        foreach (var psObj in results)
        {
            DataRow row = dt.NewRow();
            foreach (var prop in properties)
            {
                row[prop.Name] = psObj.Properties[prop.Name]?.Value ?? DBNull.Value;
            }
            dt.Rows.Add(row);
        }
        return dt;
    }

    // 资源释放
    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                pipeline?.Dispose();
                if (runspace != null && runspace.RunspaceStateInfo.State == RunspaceState.Opened)
                {
                    runspace.Close();
                    runspace.Dispose();
                }
            }
            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
}

4. 调用示例

执行内嵌PS1脚本获取DataTable

首先将项目中的.ps1文件属性设置为「嵌入的资源」,或者直接放到项目资源文件中,调用方式如下:

// 如果ps1放在Resources.resx中,直接读取字符串
using var psHelper = new PowerShellStuff();
DataTable dt = psHelper.RunPs1ScriptToDataTable(Resources.MyScript);

执行参数化SET类命令

和原有VB.NET写法一致:

using var psHelper = new PowerShellStuff();
PSCommand command = new PSCommand();
command.AddCommand("Set-User").AddParameter("Identity", "test@contoso.com").AddParameter("DisplayName", "Test User");
psHelper.RunScript(command);

内容的提问来源于stack exchange,提问作者Pawel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:27:08