使用Powershell RunspacePool多线程从C#到远程服务器

本文关键字:服务器 Powershell RunspacePool 多线程 使用 | 更新日期: 2023-09-27 18:28:42

我正试图使用Powershell RunspacePool在远程服务器上创建一些C#代码。当maxRunspace设置为1时,一切都很好,但将其设置为2会带来麻烦。

var connectionInfo = new WSManConnectionInfo(target, shellUri, credential);
using (RunspacePool pool = RunspaceFactory.CreateRunspacePool(1, 2,
                                                              connectionInfo))
{
  pool.ApartmentState = System.Threading.ApartmentState.STA;
  pool.ThreadOptions = PSThreadOptions.UseNewThread;
  pool.Open();
  var tasks = new List<Task>();
  for (var i = 0; i < 12; i++)
  {
    var taskID = i;
    var ps = PowerShell.Create();
    ps.RunspacePool = pool;
    ps.AddCommand("Get-NAVServerInstance");
    var task = Task<PSDataCollection<PSObject>>.Factory.FromAsync(
                                         ps.BeginInvoke(), r => ps.EndInvoke(r));
    System.Diagnostics.Debug.WriteLine(
                      string.Format("Task {0} created", task.Id));
    task.ContinueWith(t => System.Diagnostics.Debug.WriteLine(
                      string.Format("Task {0} completed", t.Id)),
                      TaskContinuationOptions.OnlyOnRanToCompletion);
    task.ContinueWith(t => System.Diagnostics.Debug.WriteLine(
                      string.Format("Task {0} faulted ({1} {2})", t.Id,
                      t.Exception.InnerExceptions.Count,
                      t.Exception.InnerException.Message)),
                      TaskContinuationOptions.OnlyOnFaulted);
    tasks.Add(task);
  }
  Task.WaitAll(tasks.ToArray());
}

在服务器上,我已经向shellUri所指向的Register-PSSessionConfiguration注册了会话配置。该配置使用一个startupscript来加载管理单元(Add-PSSnapin'MySnapin')。如前所述,当使用最多1个运行空间时,这很好。但是,在第一个任务最多完成2个运行空间的情况下,下一个任务会出现错误"运行启动脚本时抛出错误:已经添加了具有相同密钥的项。"而另一个任务则由于连接损坏而失败。似乎它有一个问题加载2次跨度。所以我把我的启动脚本改为

if ((Get-PSSnapin -Name 'MySnapin' -ErrorAction SilentlyContinue) -eq $null)
{
    Add-PSSnapin 'MySnapin'
}

在这种情况下,打开池已经失败,并出现以下错误:运行启动脚本时引发错误:找不到与模式"MySnapin"匹配的Windows PowerShell管理单元。请检查模式,然后重试该命令。注释Add-PSSnapin行时,仍然抛出错误,因此是Get-PSSnapin命令抛出该错误。因此,看起来ErrorAction SilentlyContinue没有被重复。

有什么想法吗?

第二个问题:建议池的设置是什么。公寓状态和游泳池。ThreadOptions?找不到必须的文档。

更新

我尝试了ApartmentState和ThreadOptions的所有组合,但没有任何区别(除此之外,STA和UseCurrentThread的组合不起作用,因为服务器进程在MTA模式下运行,这很正常)。

所以很明显这是PSSnapin cmdlet的问题。在正常的Powershell进程中,多次调用Add-PSSnapin是没有问题的,Get-PSSnapin-cmdlet会遵守ErrorAction-SilentlyContinue。这两件事在创业脚本中似乎都不起作用。很奇怪

但是,我现在没有使用Add-PSSnapin,而是尝试使用ImportModule加载程序集,这很好。

我现在不明白的是,改变maxRunspace参数(1、2或3)似乎对总持续时间没有任何影响。但这可能是因为与网络流量和延迟相比,服务器上的操作相对较小。我应该尝试一个漫长的过程。

更新2

好的,我现在已经用一个简单的Start-Sleep命令进行了测试,我可以清楚地看到多线程运行得很好。

因此,仍然存在的最终问题在于上面的粗体斜体文本。尽管我可以通过使用导入模块来解决它

使用Powershell RunspacePool多线程从C#到远程服务器

第一:-ErrorAction SilentlyContinue仅适用于"非终止"错误。终止错误是抛出的,而不是写入的,必须捕获而不是抑制请不要让我开始

换句话说,将其封装在try { ... } catch { ... }块中,而不是使用ErrorAction标志。

第二:你为什么要把它作为管理单元加载?管理单元基本上是反对使用的。MSDN文档上的措辞是"请注意,Windows PowerShell 2.0引入了对模块的支持,这是添加cmdlet和提供程序的首选方法。"

它们是一个死特性,不会被扩展,目前已被模块完全取代。你说它与导入模块一起工作。这就是你的答案。导入模块。不要用老办法。