【问题标题】:C# calling PowerShell asynchronously but only importing modules onceC#异步调用PowerShell但只导入一次模块
【发布时间】:2016-06-11 21:43:49
【问题描述】:

我正在尝试找出一种有效的方法来异步调用 20-30 个文件的 Powershell cmdlet。 尽管下面的代码可以正常工作,但 Import-Module 步骤会针对每个处理的文件运行。不幸的是,这个模块需要 3 到 4 秒才能导入。

在网络上搜索我可以找到对 RunspacePools 和 InitialSessionState 的引用,但在尝试创建 CreateRunspacePool 重载中所需的 PSHost 对象时遇到了问题。

任何帮助将不胜感激。

谢谢

加文

.

.

我的应用程序中的代码示例:

我正在使用 Parallel ForEach 在线程之间分发文件。

Parallel.ForEach(files, (currentFile) => 
{
    ProcessFile(currentfile);
});



private void ProcessFile(string filepath)
{
    // 
    // Some non powershell related code removed for simplicity
    //


    // Start PS Session, Import-Module and Process file
    using (PowerShell PowerShellInstance = PowerShell.Create())
    {
        PowerShellInstance.AddScript("param($path) Import-Module MyModule; Process-File -Path $path");
        PowerShellInstance.AddParameter("path", filepath);
        PowerShellInstance.Invoke();
    }
}

【问题讨论】:

  • 尝试使用来自 here 的代码,使用 RunSpacePools 的 InitialSessionState 加载模块。
  • 谢谢,帖子上的答案仍然在 foreach 循环中为每个项目导入一次模块。虽然有一个博客链接描述了我需要的信息。感谢您为我指明正确的方向。
  • @user4317867 - 感谢您的链接,但这显示的 PowerShell 代码也使用 CreateRunspacePool($minRunspaces, $maxRunspaces, $iss, $Host),我仍然不知道如何创建要应用的 $Host 变量。
  • 似乎$Host 是在打开 Powershell 控制台时创建的 TypeName: System.Management.Automation.Internal.Host.InternalHost。您是否希望创建一个所有已加载所需模块的 RunSpace 池?

标签: c# powershell asynchronous runspace


【解决方案1】:

正如 cmets 中已经解释的那样,这不适用于 PSJobs,因为对象是序列化的,并且作业本身在单独的进程中运行。

您可以做的是创建一个 RunspacePool 和一个 InitialSessionState 并导入模块:

private RunspacePool rsPool;

public void ProcessFiles(string[] files)
{
    // Set up InitialSessionState 
    InitialSessionState initState = InitialSessionState.Create();
    initState.ImportPSModule(new string[] { "MyModule" });
    initState.LanguageMode = PSLanguageMode.FullLanguage;

    // Set up the RunspacePool
    rsPool = RunspaceFactory.CreateRunspacePool(initialSessionState: initState);
    rsPool.SetMinRunspaces(1);
    rsPool.SetMaxRunspaces(8);
    rsPool.Open();

    // Run ForEach()
    Parallel.ForEach(files, ProcessFile);
}

private void ProcessFile(string filepath)
{
    // Start PS Session and Process file
    using (PowerShell PowerShellInstance = PowerShell.Create())
    {
        // Assign the instance to the RunspacePool
        PowerShellInstance.RunspacePool = rsPool;

        // Run your script, MyModule has already been imported
        PowerShellInstance.AddScript("param($path) Process-File @PSBoundParameters").AddParameter("path", filepath);
        PowerShellInstance.Invoke();
    }
}

【讨论】:

    猜你喜欢
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 2019-12-17
    • 2016-11-12
    • 1970-01-01
    相关资源
    最近更新 更多