Можно ли запустить оболочку PowerShell с C # и поддерживать ее в рабочем состоянии, одновременно (синхронно) выполняя в ней несколько сценариев PowerShell?

#c# #powershell #.net-core

#c# #powershell #.net-ядро

Вопрос:

Вопросы:

  1. Можно ли запустить оболочку PowerShell из C # и поддерживать ее в рабочем состоянии, одновременно (синхронно) выполняя несколько сценариев PowerShell в этой оболочке из одного и того же приложения на C #?
  2. В качестве альтернативы, возможно ли выполнять сценарии с использованием Windows PowerShell (версия 5), а не ядра PowerShell по умолчанию (версия 7) при использовании класса PowerShell (из System.Management.Автоматизация.Пространство имен Powershell) внутри приложения .NET Core?

Предыстория:

Мы перестраиваем существующее приложение .NET Framework 4.8 (текущее приложение) в новое ASP.NET Основное приложение (новое приложение). В текущем приложении, используя класс PowerShell (в System.Management.Автоматизация.Пространство имен Powershell), мы выполняем сценарий PowerShell (который затем выполняется в Windows PowerShell 5), который вызывает Exchange для начала создания почтовых ящиков (с помощью команды enable-remotemailbox; Exchange установлен на том же сервере, на котором выполняется текущее приложение и выполняется сценарий PowerShell). Каждый раз (обычно несколько десятков раз в день), когда должен быть создан почтовый ящик, сценарий PowerShell выполняется таким образом.

Наш опыт работы с текущим приложением показывает, что только при первом запуске команды Exchange (в данном случае enable-remotemailbox ) это занимает около 15 секунд. Пока приложение C # запущено (или вне приложения C #, но в PowerShell и пока открыта оболочка PowerShell), последующие команды Exchange выполняются очень быстро, занимая ~ 200 мс (по-видимому, из-за некоторой настройки / кэширования / …? только при первом выполнении сценария).

Мы хотим добиться такой же функциональности с новым приложением:

  1. Заставьте PowerShell запустить существующий сценарий для создания почтовых ящиков.
  2. Достичь таких же скоростей, как и в текущем приложении.
  3. Иметь стабильную и надежную функциональность для создания почтовых ящиков.

Сначала я попытался использовать класс PowerShell, как мы используем в текущем приложении, но поскольку Windows PowerShell (версия 5) построена на .NET Framework, а ядро PowerShell (версия 7) построено на .NET Core, а новое приложение является приложением .NET Core, при использовании класса PowerShell мы не можем использовать его.(по-видимому) автоматически использовать ядро PowerShell для выполнения сценариев. Тем не менее, я полагаю, что могу сделать вывод, что невозможно выполнить команду enable-remotemailbox в PowerShell Core (в Windows PowerShell после добавления оснастки enable-remotemaibox был доступен в остальной части скрипта, но оснастки в PowerShell Core больше не существуют, и яне удается найти модуль, который заменил оснастку).

Затем я попробовал использовать класс Process (из System.Диагностика.Пространство имен процессов), запустив процесс Windows PowerShell (версия 5) и выполнив в нем сценарий. Хотя это работает, каждый раз при запуске команды enable-remotemailbox требуется около 15 секунд, а не только в первый раз.

Существует одна альтернатива, которая, скорее всего, удовлетворит всем требованиям (т. Е. Также И требованиям скорости), и мы будем использовать ее, когда ответ на оба моих 2 вопроса выше будет «Нет», а именно: использовать службу Windows .NET Framework, которую мы сможем вызвать из приложения .NET Core. Однако, похоже, это связано с большими накладными расходами, когда в этом нет необходимости; поэтому я сначала ищу ответ на 2 вопроса выше.

Ответ №1:

Первые 15 секунд, которые вы испытываете, могут быть вызваны отсутствием модуля Powershell в вашем сеансе. При первом выполнении ps он будет загружен. отсюда и дополнительные 15 секунд.

Используя powershell sdk 7, теперь вы запускаете полный узел ps. В вашем предыдущем проекте вы только «подключались» к ps5 с помощью System.Management.Автоматизация.Сборка Powershell. Этот пакет использует установленный вами ps на хост-компьютере, и этот ps, возможно, уже имеет предварительно загруженный модуль 15second. Вот почему вы ощущаете эту разницу.

Вы можете настроить выполнение powershell, предварительно загрузив необходимый вам модуль. вот фрагмент кода:

     // a singleton in my project
    public class Runspace
    {
        public RunspacePool Pool { get; }

        public Runspace()
        {
            var session = InitialSessionState.CreateDefault();
            session.ImportPSModule("ActiveDirectory");
            Pool = RunspaceFactory.CreateRunspacePool(session);
        }
    }

    public class PsExecutor
    {
        private readonly Runspace _runspace;

        public PsExecutor(Runspace runspace)
        {
            _runspace = runspace;
        }

        public void Exec()
        {
            using (PowerShell ps = PowerShell.Create())
            {
                ps.RunspacePool = _runspace.Pool;
                ps.AddStatement().AddCommand("Get-ADUser").AddParameters();
                ps.Invoke();
            }
    }
 

Вы можете регистрировать время, затраченное конструктором Runspace. И сравните это с теми 15 секундами, которые вы испытываете сейчас. Плюс решения: вы можете контролировать выполнение конструктора.

Комментарии:

1. Спасибо за ваши интересные предложения. Однако одна из проблем заключается в том, что, похоже, не существует модуля PowerShell, который содержит команду ‘enable-remotemailbox’. Поэтому мне нечего заменить «ActiveDirectory» на «session. ImportPSModule(«ActiveDirectory»);». В ps5 я смог использовать оснастку («microsoft.exchange.management.powershell.snapin»), но я не могу найти модуль, который должен был его заменить (и думаю, мне, возможно, придется сделать вывод, что его не существует).

2. (Документация для Enable-RemoteMailbox на docs.microsoft.com/en-us/powershell/module/exchange / … предполагает, что он должен быть в модуле ExchangePowerShell, но, похоже, не существует основного модуля PowerShell от Microsoft с таким именем.)

3. чтобы найти модуль. запустите консоль powersell7 на рабочем столе. выполните команду / скрипт, который вы запускаете с помощью c #. после выполнения. выполните «Get-Module». вы увидите список загруженных модулей. возможно, вы найдете необходимые модули для предварительной загрузки в вашем ps-executor

4. Да, хорошая идея, однако я уже пробовал это; Я не могу выполнить команду из консоли powersell7 на рабочем столе («Термин»enable-remotemailbox» не распознается как имя командлета, функции, файла сценария или рабочей программы.»). Насколько я понимаю, PowerShell заменил оснастки модулями, а в PS7 оснастки больше нельзя использовать, поэтому необходимо использовать модули. И, похоже, не существует модуля, который заменяет оснастку, которую я использовал. использовать. Поэтому может оказаться необходимым продолжать использовать PS5 (но тогда возникает вопрос, как сделать это эффективно из .NET Core).

5. Этот вопрос задается (и помечается) как выполнение C # / Powershell. Если у вас возникли какие-либо проблемы с этим, вы можете смоделировать в powershell 7 и exchange (даже не выполняя его из c # или используя powershell core sdk) — возможно, вам не захочется начинать другой вопрос.