获得实时powershell脚本输出

本文关键字:脚本 输出 powershell 实时 | 更新日期: 2023-09-27 18:07:01

我有一个c#函数来运行远程Powershell脚本。我可以看到脚本正在运行,并且在远程服务器上运行良好,但是我无法从Powershell获得任何实时输出。
ps1脚本运行了很长时间,并有许多输出。脚本正在运行rar.exe,因此输出应该来自rar.exe。

下面是c#函数:
public static bool RunBackupPowershell()
    {
        string password = "somepassword";
        string userName = "someuser";
        string shell = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
        var target = new Uri("http://someserver:5985/wsman");
        SecureString securepassword = String2SecureString(password);
        PSCredential credential = new PSCredential(userName, securepassword);
        WSManConnectionInfo connectionInfo = new WSManConnectionInfo(target,shell,credential);
        connectionInfo.OpenTimeout = 4 * 60 * 1000;
        connectionInfo.OpenTimeout = 1 * 60 * 1000;
        connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Credssp;
        Runspace remote = RunspaceFactory.CreateRunspace(connectionInfo);
        remote.Open();
        PowerShell PowerShellInstance = PowerShell.Create();
        PowerShellInstance.Runspace = remote;
        PowerShellInstance.AddScript("D:''backup''test.ps1");
        PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
        outputCollection.DataAdded += outputCollection_DataAdded;
        PowerShellInstance.Streams.Error.DataAdded += Error_DataAdded;
        IAsyncResult result = PowerShellInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection);
        while (result.IsCompleted == false)
        {
            hubs.Clients.All.SendPowerShellResults("Waiting for pipeline to finish...");
            Thread.Sleep(1000);
        }
        hubs.Clients.All.SendPowerShellResults("Execution has stopped. The pipeline state: " + PowerShellInstance.InvocationStateInfo.State);
        foreach (PSObject outputItem in outputCollection)
        {
            hubs.Clients.All.SendPowerShellResults(outputItem);
        }
        return true;
    }
   static void outputCollection_DataAdded(object sender, DataAddedEventArgs e)
    {
        hubs.Clients.All.SendPowerShellResults("Object added to output."+e);
    }
    static void Error_DataAdded(object sender, DataAddedEventArgs e)
    {
        hubs.Clients.All.SendPowerShellResults("An error was written to the Error stream!"+e);
    }

hubs.Clients.All.SendPowerShellResults函数是一个websocket,它正在工作-所以我可以接收数据,但它不是来自Powershell输出的数据。

我想知道这是怎么回事

获得实时powershell脚本输出

查看此主题是否有帮助:

获取通过代码调用Powershell命令's的输出

流保存一个"PsDataCollection"类型,每个项目包含我们想要的输出。此类型包含"DateAdded"事件。您可以使用DateAdded事件在添加数据后立即输出数据!

https://learn.microsoft.com/en us/dotnet/api/system.management.automation.psdatacollection - 1. - dataadded?view=pscore 6.2.0

我有一个类似的问题,所以创建了下面的例子,允许使用Async Enumerable从PowerShell Pipeline获取结果,实时检索结果。

https://gist.github.com/OnKey/83cf98e6adafe5a2b4aaf561b138087b

static async Task Main(string[] args)
        {
            var script = @"
For ($i=0; $i -le 5; $i++) {
    $i
    Start-Sleep -s 1 
}
";
            var p = new Program();
            await foreach (var item in p.PowerShellAsyncEnumerable(script))
            {
                Console.WriteLine(item);
            }
        }
        private IAsyncEnumerable<PSObject> PowerShellAsyncEnumerable(string script)
        {
            var rs = RunspaceFactory.CreateRunspace();
            rs.Open();
            var pipeline = rs.CreatePipeline();
            pipeline.Commands.AddScript(script);
            return new PsAsyncEnumerable(pipeline);
        }
        internal class PsAsyncEnumerable : IAsyncEnumerable<PSObject>
        {
            private readonly Pipeline pipe;
            public PsAsyncEnumerable(Pipeline pipe) => this.pipe = pipe;
            public IAsyncEnumerator<PSObject> GetAsyncEnumerator(CancellationToken cancellationToken = new()) 
                => new PsAsyncEnumerator(this.pipe);
        }
        internal class PsAsyncEnumerator : IAsyncEnumerator<PSObject>
        {
            private readonly Pipeline pipe;
            private TaskCompletionSource dataReady = new();
            public PsAsyncEnumerator(Pipeline pipe)
            {
                this.pipe = pipe;
                this.pipe.Output.DataReady += NotificationHandler;
                this.pipe.Error.DataReady += NotificationHandler;
                this.pipe.InvokeAsync();
            }
            
            private void NotificationHandler(object sender, EventArgs e)
            {
                this.dataReady.SetResult();
            }
            
            public ValueTask DisposeAsync()
            {
                this.pipe.Dispose();
                return ValueTask.CompletedTask;
            }
            public async ValueTask<bool> MoveNextAsync()
            {
                while (!this.pipe.Output.EndOfPipeline)
                {
                    var item = this.pipe.Output.NonBlockingRead(1).FirstOrDefault();
                    if (item != null)
                    {
                        this.Current = item;
                        return true;
                    }
                
                    await this.dataReady.Task;
                    this.dataReady = new TaskCompletionSource();
                }
                return false;
            }
            public PSObject Current { get; private set; }
        }