Как загрузить классы в модуль PowerShell глобально?

Я уже прочитал этот вопрос, и хотя по нему много пересказов, я изо всех сил старался следовать рекомендациям, но до сих пор не знаю, как это обойти.

Я определил несколько классов в файле ScriptsToProcess.ps1 следующим образом:

https://github.com/HotCakeX/Harden-Windows-Security/blob/WDACConfig-v0.3.4/WDACConfig/WDACConfig%20Module%20Files/Preloader.ps1

Проблема в том, что когда я устанавливаю модуль в чистой виртуальной машине (где модуль никогда раньше не существовал) и пытаюсь использовать командлеты, я получаю сообщение об ошибке, сообщающее, что тип не найден, но если я закрою и снова открою PowerShell или использую Import-Module с параметром -Force, то все в порядке.

Мне нужно знать, как обойти эту проблему, не вводя слишком много повторяющегося кода.

Я использую PowerShell 7.5

Можете ли вы поделиться манифестом модуля?

Mathias R. Jessen 27.02.2024 23:25

В какую папку вы скопировали модули? Они должны попасть в папку, указанную $ENV:PSModulePath.

Dennis 28.02.2024 13:25

Итак, вы копируете модуль в C:\Program Files\WindowsPowerShell\Modules. Правильно ли промаркированы компоненты? Т.е. файл модуля имеет то же имя, что и папка модуля?

Dennis 28.02.2024 13:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
421
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не до конца понимаю проблему, связанную с виртуальной машиной, но, возможно, следующий подход обходит проблему:

  • Определите свой класс es как часть корневого модуля вашего скрипта (*.psm1, на который ссылается запись RootModule манифеста модуля) вместо текущего подхода с использованием файла *.ps1, который загружается в область вызывающего объекта через запись ScriptsToProcess манифеста.

    • Другими словами: тогда вам не понадобится запись ScriptsToProcess (по крайней мере, для экспорта ваших class и enum).
  • Само по себе это делает ваши классы доступными только для вызывающих абонентов, которые импортируют модуль с помощью оператора с использованием модуля, но обратите внимание на следующее:

    • Примечания к связанной документации (выделено нами):

      [using module] не всегда импортирует классы или перечисления, определенные во вложенных модулях или в скриптах, которые находятся в корневом модуле через точечный источник. Определите классы и перечисления, которые вы хотите сделать доступными для пользователей за пределами модуля, непосредственно в корневом модуле.

    • Только импортер и его дочерние области видят classперечисления) импортированного модуля.

    • Поскольку using module является оператором времени анализа, путь к целевому модулю не должен содержать переменных, но на модули, обнаруживаемые с помощью $env:PSModulePath, можно ссылаться только по имени (например, using module MyModule); относительные пути разрешаются по местоположению собственной файловой системы вызывающего объекта (а не по текущему каталогу).

    • Если модуль импортирован с помощью using module в данном сеансе, его нельзя принудительно повторно импортировать; то есть, если вы хотите изменить свои определения class и/или enum, вам нужно будет начать новый сеанс, чтобы увидеть изменения.

  • Однако в разделе Экспорт классов с ускорителями типов раздела справки about_Classes описан обходной путь, который делает классы по вашему выбору доступными для сеанса глобально, во всех областях видимости и пространствах выполнения, а также работает с автозагрузкой модуля . и Импорт-Модуль

  • Пример кода ниже демонстрирует этот подход, но со следующими оговорками:

    • Как и в случае с подходом на основе using module, вы не сможете перезагрузить измененные определения class в данном сеансе — вместо этого начните новый сеанс.

    • В отличие от подхода на основе using module (который вы все равно можете комбинировать с предлагаемым подходом), импортер (возможно, неявный) не должен полагаться на то, что class будут доступны во время синтаксического анализа, т. е. не должен пытаться ссылаться на них через тип. литералы в class собственном определении - подробности см. в этом ответе.

      • Хотя подход с ускорителем типов технически позволяет вам размещать определения class и enum во вложенном модуле или файле *.ps1, полученном из корневого модуля, этого лучше избегать, если вы хотите, чтобы ваш модуль также поддерживал технику импорта using module для синтаксического анализа. -время наличия занятий.
    • Поскольку предлагаемый подход (потенциально) открывает доступ к classes и другим пространствам выполнения, их следует украсить атрибутом [NoRunspaceAffinity(), который доступен только в версии 7.4+. Тем не менее, этот подход безопасно использовать в более ранних версиях, если используется только одно пространство выполнения (пространство выполнения по умолчанию).

    • Связанный раздел справки также включает основанный на событиях код для попытки удалить экспортированные class определения при выгрузке модуля (Remove-Module), однако это не работает (начиная с PowerShell 7.4.1) и поэтому опущено в приведенном ниже коде. .

Обратите внимание, что при любом из описанных выше подходов class и enum не будут доступны до тех пор, пока ваш модуль не будет импортирован в данный сеанс. То есть, в отличие от функций и командлетов в модулях автоматической загрузки, их невозможно обнаружить до импорта.

Пример *.psm1 содержимого корневого модуля:

# Since the quasi-exported class will be available *process-wide*
# and therefore also in *other runspaces*, be sure to define it with
# the [NoRunspaceAffinity()] attribute.
# Caveat: **v7.4+ only**
[NoRunspaceAffinity()]
class SomeClass { # Note: 'SomeClass' is both its .Name and .FullName.
  [int] Get() { return 42 }
}

# Define the types to export with type accelerators.
# Note: Unlike the `using module` approach, this approach allows
#       you to *selectively* export `class`es and `enum`s.
$exportableTypes = @(
  [SomeClass]
)

# Get the non-public TypeAccelerators class for defining new accelerators.
$typeAcceleratorsClass = [psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators')

# Add type accelerators for every exportable type.
$existingTypeAccelerators = $typeAcceleratorsClass::Get
foreach ($type in $exportableTypes) {
  # !! $TypeAcceleratorsClass::Add() quietly ignores attempts to redefine existing
  # !! accelerators with different target types, so we check explicitly.
  $existing = $existingTypeAccelerators[$type.FullName]
  if ($null -ne $existing -and $existing -ne $type) {
    throw "Unable to register type accelerator [$($type.FullName)], because it is already defined with a different type ([$existing])."
  }
  $typeAcceleratorsClass::Add($type.FullName, $type)
}

Любой (возможно, неявный) импортер модуля, связанного с этим *.psm1, будет иметь класс [SomeClass], доступный ему во время выполнения.

То есть [SomeClass]::new().Get() в области вызывающего абонента и любая последующая область должна давать 42

Спасибо, я поместил классы в файл .psm1 и импортировал его через Using Module во вложенный модуль. Это сработало, но я думаю, что нужно уделять особое внимание пути, поскольку он не поддерживает переменные. Я использую переменную для корневого пути модуля, чтобы вместо .\ или ..\ и т. д. я мог просто использовать переменную и предотвратить случайное указание на несуществующий файл при работе с вложенной структурой папок.

SpyNet 29.02.2024 09:11

Что касается предложенного вами второго метода, он работает очень хорошо! Я использовал Import-Module в ScriptsToProcess, чтобы импортировать этот .psm1 файл, содержащий эту логику (также перенес туда определение моего класса), и теперь он доступен глобально для всего модуля. Поскольку моему модулю уже требуется последняя версия PS, это не проблема. Я буду использовать только этот метод. Еще раз спасибо! 🙏

SpyNet 29.02.2024 09:31

Рад слышать, что это помогло, @SpyNet; Не за что. Да, поскольку using module — это оператор времени анализа, ссылки на переменные в путях модулей не поддерживаются.

mklement0 29.02.2024 15:52

@SpyNet: Что касается решения с ускорителем типов: при таком подходе вам на самом деле не нужен ScriptsToProcess. Я предлагаю поместить ваши классы и код экспорта непосредственно в корневой модуль вашего проекта. Хотя подход с ускорителем типов также поддерживает размещение их во вложенных модулях или сценариях, которые вы получаете непосредственно из корневого модуля, только размещение их в корневом модуле предсказуемо отображает их во время анализа, когда ваш модуль используется с using module. Я обновил ответ, чтобы прояснить все эти моменты.

mklement0 29.02.2024 15:52

Спасибо, я хочу сохранить все классы отдельно в отдельном файле .psm1, но сейчас я импортирую их в корневой модуль вот так Import-Module -FullyQualifiedName "$ModuleRootPath\CoreExt\Classes.psm1" -Force

SpyNet 29.02.2024 21:55

Другие вопросы по теме