C# вызывает PowerShell асинхронно, но импортирует модули только один раз

Я пытаюсь разработать эффективный способ асинхронного вызова командлета Powershell для 20-30 файлов. Хотя приведенный ниже код работает, шаг Import-Module выполняется для каждого обрабатываемого файла. К сожалению, импорт этого модуля занимает от 3 до 4 секунд.

При поиске в Интернете я могу найти ссылки на RunspacePools и InitialSessionState, но у меня возникли проблемы с попыткой создать объект PSHost, который требуется в перегрузке CreateRunspacePool.

Любая помощь будет оценена по достоинству.

Спасибо

Гэвин

.

.

Пример кода из моего приложения:

Я использую 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();
    }
}

person Gavin    schedule 11.06.2016    source источник
comment
Возможный дубликат PowerShell - How to Import-Module in runspace   -  person user4317867    schedule 12.06.2016
comment
Попробуйте использовать код из здесь, чтобы загрузить модуль, используя InitialSessionState для RunSpacePools.   -  person user4317867    schedule 12.06.2016
comment
Спасибо, ответ на сообщение по-прежнему импортирует модуль один раз для каждого элемента в цикле foreach. Хотя есть ссылка на блог, в котором описывается нужная мне информация. Так что спасибо, что указали мне правильное направление.   -  person Gavin    schedule 12.06.2016
comment
@ user4317867 - Спасибо за ссылку, но здесь показан код PowerShell, который также использует CreateRunspacePool($minRunspaces, $maxRunspaces, $iss, $Host), и я до сих пор не знаю, как создать переменную $Host для применения.   -  person Gavin    schedule 12.06.2016
comment
Кажется, $Host — это TypeName: System.Management.Automation.Internal.Host.InternalHost, который создается при открытии консоли Powershell. Вы хотите создать пул RunSpaces, на каждом из которых загружен нужный модуль?   -  person user4317867    schedule 12.06.2016
comment
Этот вопрос выглядит отличным образцом для создания RunSpacePool и загрузка модулей в InitialSessionState.   -  person user4317867    schedule 12.06.2016


Ответы (1)


Как уже было объяснено в комментариях, это не будет работать с 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();
    }
}
person Mathias R. Jessen    schedule 12.06.2016