4

我正在尝试使用 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 注册了一个会话配置。该配置使用加载管理单元的启动脚本(Add-PSSnapin 'MySnapin')。如前所述,这在使用最多 1 个运行空间时效果很好。但是第一个任务完成最多 2 个运行空间,下一个任务会给出错误“运行启动脚本引发错误:已添加具有相同键的项目。” 另一个任务由于连接损坏而失败。似乎加载 spanin 2 次有问题。所以我将我的启动脚本更改为

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。这两件事似乎都不适用于启动脚本。很奇怪。

但是我现在没有使用 Add-PSSnapin,而是尝试使用 Import-Module 来加载程序集,并且效果很好。

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

更新 2

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

因此,仍然存在的最终问题在上面的粗斜体文本中。虽然我可以通过使用 Import-Module 来解决它

4

1 回答 1

0

First: -ErrorAction SilentlyContinue only applies to "non-terminating" errors. Terminating errors are thrown, not written, and must be caught, not suppressed. Please don't get me started.

In other words, wrap it in a try { ... } catch { ... } block instead of using the ErrorAction flag.

Second: Why are you trying to load it as a snapin anyway? Snapins are essentially deprecated. Te wording on the MSDN docs is "Be aware that Windows PowerShell 2.0 introduced support for modules, which is the preferred method to add cmdlets and providers."

They're a dead feature which won't be expanded and is fully replaced by modules at this point. You say that it works with Import-Module. That's your answer. Import-Module. Don't use the old way.

于 2014-04-16T21:52:38.597 回答