简体   繁体   English

PowerShell C#主机-多个并发远程命令调用

[英]PowerShell C# Host - multiple concurrent remote command invocations

I need to invoke a script (or several scripts) on multiple remote hosts. 我需要在多个远程主机上调用一个脚本(或多个脚本)。 Consider this as environment installation on several hosts that should be done in parallel to improve performance. 将其视为在几台主机上的环境安装,应并行执行以提高性能。 The application that instructs these scripts to be invoked is written in C#. 指示这些脚本被调用的应用程序用C#编写。 I'm using PowerShell C# Host to invoke scripts on remote target machines. 我正在使用PowerShell C#主机在远程目标计算机上调用脚本。

Example (I am trying to achieve parallel script invocation on remote machines): 示例(我正在尝试在远程计算机上实现并行脚本调用):

Parallel.ForEach(allActions.GroupBy(a=>a.TargetHostname), hostActions =>
{
    foreach (var action in hostActions)
    {
        action.Execute(); // Implementation of "execute" will contain remote PowerShell call
    }
});

The implementation in each "Execute" method will subsequently call the following: 每个“ Execute”方法中的实现随后将调用以下内容:

    public ICollection<string> InvokeCommandOnRemoteHost(string targetHost, string command, string arguments)
    {
        var runspaceConfiguration = RunspaceConfiguration.Create();
        using (var runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))
        {
            runspace.Open();

            using (var pipeline = runspace.CreatePipeline())
            {
                var psCommand = new Command(@"..\Remote-CommandInvocation.ps1");
                psCommand.Parameters.Add("targetHost", targetHost);
                psCommand.Parameters.Add("application", command);
                psCommand.Parameters.Add("arguments", arguments);

                pipeline.Commands.Add(psCommand);

                var result = pipeline.Invoke();
                //. . .

Note: although invoked in a local runspace, the Remote-CommandInvocation.ps1 will create a remote session and invoke commands on a remote PC (using "new-pssession" or "enter-pssession"). 注意:尽管在本地运行空间中调用,Remote-CommandInvocation.ps1将创建一个远程会话并在远程PC上调用命令(使用“ new-pssession”或“ enter-pssession”)。

I have noticed however that creating runspace takes quite a bit of time, for example invocation of "RunspaceConfiguration.Create();" 但是,我注意到创建运行空间需要花费大量时间,例如调用“ RunspaceConfiguration.Create();”。 takes around 500ms on my box (according to VS profiling). 在我的盒子上大约需要500毫秒(根据VS分析)。 "runspace.Open();" “ runspace.Open();” takes abour 1.5 seconds. 大约需要1.5秒。 All in all a cost of 2 seconds per command execution. 每次执行命令总共要花费2秒的时间。

Obviously, this is sub-optimal, since this cost will be paid for each remote command invocation. 显然,这不是最理想的,因为将为每次远程命令调用支付此费用。

The next improvement was to use shared RunspacePool for the lifetime of the application and reuse runspaces from it when invoking commands in parallel: 下一个改进是在应用程序的生存期内使用共享的RunspacePool,并在并行调用命令时从中重用运行空间:

    public RemoteCommandInvoker() // ctor, singleton class
    {
        var iss = InitialSessionState.CreateDefault2();
        rsp = RunspaceFactory.CreateRunspacePool(iss);
        rsp.SetMinRunspaces(5);
        rsp.SetMaxRunspaces(25);
        rsp.ThreadOptions = PSThreadOptions.UseNewThread;
        rsp.Open();
    }

    public ICollection<string> InvokeCommandOnRemoteHost(string targetHost, string command, string arguments)
    {
        var resultList = new List<string>();

        var ps = PowerShell.Create();
        ps.RunspacePool = rsp;
        ps.AddCommand(@"..\Remote-CommandInvocation.ps1");
        ps.AddParameter("targetHost", targetHost);
        ps.AddParameter("application", command);
        ps.AddParameter("arguments", arguments);
        var result = ps.Invoke();
        //...

Although the cost of runspace pool initialization is roughly the same (~2 seconds), it is now executed once per application lifetime and all further command invocations happen quickly enough. 尽管运行空间池初始化的成本大致相同(约2秒),但现在每个应用程序生命周期执行一次,并且所有其他命令调用的发生速度都足够快。

Question: 题:

Is this a correct approach for optimizing the invocation of multiple scripts on multiple remote machines, or it should be done differently, or done better? 这是优化多台远程计算机上多个脚本的调用的正确方法,还是应该以不同的方式进行,或者做得更好? Should constrained pools or remote pools be used in this case? 在这种情况下应该使用受约束的池还是远程池?

Thanks. 谢谢。

Check out the Remote Runspace Samples: https://msdn.microsoft.com/en-us/library/ee706591(v=vs.85).aspx 查看远程运行空间示例: https ://msdn.microsoft.com/zh-cn/library/ee706591(v = vs.85).aspx

You're probably loosing some time by using C# to call PowerShell to initiate a new powershell session. 通过使用C#调用PowerShell来启动新的powershell会话,您可能会浪费一些时间。

I think this might work a little quicker for you: 我认为这可能对您更快一点:

Collection<PSObject> results;
WSManConnectionInfo connectionInfo = new WSManConnectionInfo() { ComputerName = "COMPUTER" };
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
    runspace.Open();
    using (PowerShell ps = PowerShell.Create())
    {
        ps.Runspace = runspace;
        ps.AddScript("something to run");

        results = ps.Invoke();

        if(ps.HadErrors)
        {
            //Throw or log if you want
            //ps.Streams.Error.ElementAt(0).Exception;
        }
    }
    runspace.Close();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM