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

时间:2013-08-22 13:51:02

标签: c# .net powershell powershell-remoting

我正在尝试使用Powershell RunspacePool创建一些C#代码到远程服务器。 当maxRunspaces设置为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的会话配置。该配置使用一个加载snapin的startupscript(Add-PSSnapin'MySnapin')。 如上所述,当使用最多1个运行空间时,这可以正常工作。但是,如果第一个任务完成最多2个运行空间,则下一个任务会出现错误“运行启动脚本引发错误:已添加具有相同密钥的项目”。由于连接损坏,其他任务失败。似乎加载spanin 2次有问题。 所以我把我的startupscript改为

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

在这种情况下,打开池已失败并显示错误: 运行启动脚本引发错误:未找到与模式“MySnapin”匹配的Windows PowerShell管理单元。检查模式,然后再次尝试该命令。 注释Add-PSSnapin行仍会抛出错误,因此抛出该错误的是Get-PSSnapin命令。所以看起来不会引用ErrorAction SilentlyContinue。

有什么想法吗?

第二个问题:pool.ApartmentState和pool.ThreadOptions的推荐设置是什么?找不到必须的文件。

更新

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

显然这是PSSnapin cmdlet的一个问题。在正常的Powershell过程中,多次调用Add-PSSnapin并没有问题,并且Get-PSSnapin cmdlet会遵守ErrorAction SilentlyContinue。这两件事似乎都不适用于startupscript。很奇怪。

但是我现在尝试使用Import-Module来加载程序集,而不是使用Add-PSSnapin,而且工作正常。

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

更新2

好的,我现在已经使用简单的Start-Sleep命令进行测试,我可以清楚地看到多线程工作正常。

因此,仍然存在的最终问题在于上面的粗体斜体文本。虽然我可以使用Import-Module

解决它

1 个答案:

答案 0 :(得分:0)

首先:-ErrorAction SilentlyContinue仅适用于“非终止”错误。终止错误被抛出,而不是写入,必须被捕获,而不是被抑制。 请不要让我开始。

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

第二:你为什么要尝试将其作为snapin加载? Snapins 基本上已弃用。 MSDN文档中的措辞是“请注意,Windows PowerShell 2.0引入了对模块的支持,这是添加cmdlet和提供程序的首选方法。”

它们是一个死机功能,不会扩展,此时完全被模块取代。你说它适用于Import-Module。那是你的答案。导入模块。不要用旧方式。