【问题标题】:Using Powershell RunspacePool multithreaded to remote server from C#从 C# 使用 Powershell RunspacePool 多线程到远程服务器
【发布时间】:2013-08-25 07:10:53
【问题描述】:

我正在尝试使用 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 解决它

【问题讨论】:

  • 在远程机器上注册 PSSessionConfiguration 时是否使用了-UseSharedProcess 参数?如果是这样,请尝试不使用该参数进行注册。
  • @Keith:不,我没有使用 -UseSharedProcess 参数
  • Add-Snapin 仅适用于 Powershell V1 兼容性。它要求 Snapin 是一个已注册的 DLL,具有注册表设置。 Import-Module 是 V2 及更高版本中的首选方法。模块可以是任何有效的 powershell 代码,并且不需要注册。

标签: c# .net powershell powershell-remoting


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-18
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 2014-11-18
    相关资源
    最近更新 更多