#c# #powershell #.net-core
#c# #powershell #.net-ядро
Вопрос:
Вопросы:
- Можно ли запустить оболочку PowerShell из C # и поддерживать ее в рабочем состоянии, одновременно (синхронно) выполняя несколько сценариев PowerShell в этой оболочке из одного и того же приложения на C #?
- В качестве альтернативы, возможно ли выполнять сценарии с использованием 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 мс (по-видимому, из-за некоторой настройки / кэширования / …? только при первом выполнении сценария).
Мы хотим добиться такой же функциональности с новым приложением:
- Заставьте PowerShell запустить существующий сценарий для создания почтовых ящиков.
- Достичь таких же скоростей, как и в текущем приложении.
- Иметь стабильную и надежную функциональность для создания почтовых ящиков.
Сначала я попытался использовать класс 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) — возможно, вам не захочется начинать другой вопрос.