У меня есть простой скрипт .ps1
, который просто создает каталог. Когда я щелкаю правой кнопкой мыши сценарий в проводнике Windows и выбираю «Запустить с помощью PowerShell», появляется следующее сообщение об ошибке:
Get-ExecutionPolicy: Windows PowerShell успешно обновила вашу политику выполнения, но этот параметр переопределяется политикой, определенной в более конкретной области. Из-за переопределения ваша оболочка сохранит текущую эффективную политику выполнения Unrestricted. Введите «Get-ExecutionPolicy -List», чтобы просмотреть параметры политики выполнения. Для получения дополнительной информации см. «Get-Help Set-ExecutionPolicy».
(Я записал свой экран и напечатал все вышеперечисленное, так как окно быстро мигало. Кроме того, если я запускаю «powershell -NoExit C:\path\to\script.ps1», ошибки не будет.
Интересно, что папка все еще создается.
Однако если я сам открою PowerShell и запущу скрипт, например .\script.ps1
, ошибок не будет.
Вот результат Get-ExecutionPolicy -List
:
Scope ExecutionPolicy
----- ---------------
MachinePolicy Unrestricted
UserPolicy Undefined
Process Undefined
CurrentUser Undefined
LocalMachine Unrestricted
Я думаю, что «Запуск с PowerShell» пытается что-то сделать (например, установить политику выполнения) перед запуском сценария, но я не вижу полной команды, которую он вызвал, и не знаю, для какой области он пытается установить политику выполнения. . Кроме того, что из вышеперечисленного является более конкретным, чем что из остальных?
У меня также нет прав администратора, чтобы переопределить этот пункт контекстного меню. Как мне добиться чистого исполнения?
Может отличаться от Невозможно выполнить сценарий PowerShell с использованием опции «Запустить с Powershell», поскольку кажется, что мое выполнение действительно удалось.
Я ожидаю, что сценарий будет запущен без проблем из проводника Windows, т. е. не должно быть никаких ошибок.
В Windows 10 команда контекстного меню Windows PowerShell Run with PowerShell
(определенная в реестре) пытается переопределить политику выполнения для конкретного процесса через CLI, вызывая Set-ExecutionPolicy -Scope Process Bypass
как часть кода, переданного в параметр -Command
.
Однако, поскольку политика выполнения вашего компьютера управляется объектом групповой политики (GPO), на что указывает выходная строка MachinePolicy
, имеющая значение, отличное от Undefined
, ни переопределения через параметр -ExecutionPolicy
CLI, ни через Set-ExecutionPolicy не эффективны.
Это то, что пытается сказать вам сообщение об ошибке; в частности, это означает: я применил запрошенное вами изменение, но оно не имеет никакого эффекта.
Сама ошибка не останавливает выполнение, которое продолжается при действующей политике, контролируемой объектом групповой политики.
Учитывая, что в вашем случае действующей политикой объекта групповой политики является Unrestricted
(что, вероятно, должно быть RemoteSigned
для большей безопасности), ваши сценарии все равно будут выполняться, и вы можете игнорировать сообщение об ошибке.
Чтобы сообщение об ошибке исчезло, можно удалить вызов Set-ExecutionPolicy
из определения команды в реестре.
Его модификация требует повышения прав, то есть административных привилегий, поскольку он находится в кусте реестра HKEY_LOCAL_MACHINE
; однако в кусте HKEY_CURRENT_USER
можно определить эквиваленты для конкретного пользователя, которые, следовательно, не требуют повышения прав — см. ниже.
Другой вариант — деактивировать соответствующий объект групповой политики, который, учитывая, что это MachinePolicy
, по крайней мере, также требует повышения прав, но обычно не находится под вашим контролем в среде домена.
Set-Execution
и, следовательно, подавления предупреждения:В Windows 10 должно работать следующее (я больше не могу лично проверить), основываясь на информации в нижней части этого ответа, адаптированной для любого типа файла, зарегистрированного в данный момент для .ps1
файлов, который может отличаться от по умолчанию, особенно если у вас установлен код Visual Studio:
# Determine the registry key path, based on the HKEY_CURRENT_USER
# equivalent of the file-type key.
$regKey = 'registry::HKEY_CURRENT_USER\Software\Classes\{0}\shell\Run with PowerShell\Command' -f (Get-ItemPropertyValue registry::HKEY_CLASSES_ROOT\.ps1 '(Default)')
# Create the key, if necessary.
if (-not (Test-Path $regKey)) { $null = New-Item -Force -ErrorAction Stop $regKey }
# Define the command line, without Set-ExecutionPolicy and with -NoExit.
Set-ItemProperty $regKey '(Default)' '"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoExit -File "%1"'
Это создает HKEY_CURRENT_USER
эквивалент (потенциально) HKEY_LOCAL_MACHINE
определения команды контекстного меню, которое должно переопределять последнее, учитывая, что куст HKEY_CLASSES_ROOT
, через который загружаются определения контекстного меню, представляет собой составное представление первых двух ульев. ' Software\Classes
пути, причем определения на уровне пользователя имеют приоритет.
Также обратите внимание, что -NoExit
был добавлен, чтобы сохранить сеанс после выполнения скрипта и, следовательно, открыть окно.
Если у вас есть права администратора, вы можете заменить HKEY_CURRENT_USER
на HKEY_LOCAL_MACHINE
в приведенном выше коде и запустить его с повышенными правами.
В Windows 11 проблема больше не возникает, поскольку настроенный там вызов CLI Windows PowerShell больше не пытается изменить политику выполнения.
Однако вы все равно можете изменить вызов, а именно включить переключатель -NoExit
(чтобы сеанс оставался активным и окно оставалось открытым после выполнения скрипта): см. этот ответ.
В PowerShell (Core) 7, который больше не поддерживается в Windows 10, проблема также не возникает: не предпринимается никаких попыток установить политику выполнения.
По сути, команды контекстного меню доступны только в том случае, если вы устанавливаете PowerShell 7 через пакет MSI, где вы получаете возможность устанавливать команды для папок и дисков, а также для запуска отдельных *.ps1
файлов (как в Windows PowerShell). .
Чтобы их увидеть, необходимо удерживать Shift и щелкнуть правой кнопкой мыши.
Команды уровня папки/диска (подменю PowerShell 7
) открывают интерактивный сеанс в целевой папке или диске.
Команда уровня файла *.ps1
, хранящаяся в HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\PowerShell7x64\Command
, начиная с PowerShell 7.4.3:
кажется сломанным: по крайней мере, на моей машине это никогда не отображается.
неверно определено:
C:\Program Files\PowerShell\7\pwsh.exe -Command "$host.UI.RawUI.WindowTitle = 'PowerShell 7 (x64)'; & '%1'"
"..."
, которое требуется для пути, содержащего пробелы - как ни странно, это само по себе не является проблемой (это также влияет на команды уровня папки/диска, которые действительно работают).'...'
не является надежным, учитывая, что '
является допустимым символом в путях.Даже если это сработало так, как задумано, вы также можете изменить его, включив -NoExit
, чтобы предотвратить автоматическое закрытие окна после выполнения скрипта.
@charlesz, да, как (сейчас) отмечено в ответе, вы можете создать эквивалентные определения в кусте реестра HKEY_CURRENT_USER
.
«но было решено не менять это в интересах обратной совместимости» — постоянное препятствие на пути прогресса PowerShell..
@mklement0 Да. Я использую Windows 10. Позвольте мне попробовать в следующий раз, когда я буду над этим работать.
@mklement0 Я предполагаю, что вы имеете в виду HKCU\Software\Classes\Microsoft.PowerShellScript.1
(потому что подобная вещь есть в HKLM? -- Этот ключ не существует. Я, вероятно, могу создать его, но как мне просто добавить пункт контекстного меню, но не устанавливать его в качестве метода открытия по умолчанию? С этого момента «Запуск с PowerShell» не используется по умолчанию. Если я дважды щелкну файл PS1, откроется VS Code.
@charlesz, да, извини; это часть \0\
, которая относится к команде «Выполнить с помощью PowerShell», если мне не изменяет память, и я думаю, что запись в аналогичное место в кусте HKCU должна переопределить настройку HKLM. Пожалуйста, посмотрите новый нижний раздел, который я добавил к ответу.
Заставил это работать сейчас. Спасибо! @mklement0 Единственное предостережение: я использую VS Code, поэтому он должен находиться в разделе «VSCode.ps1» вместо «Microsoft.PowerShellScript.1». «0» может быть чем угодно, и пока для него установлено значение по умолчанию, оно использует это значение в качестве текста контекстного меню.
Кажется, не было способа добавить это независимо от класса, определяющего открытый метод. Могу поспорить, что это должен быть либо «Microsoft.PowerShellScript.1», либо «VSCode.ps1», либо что-то еще, что вы используете для его открытия. Я пробовал добавлять прямо в .ps1
в классах, но не получилось.
@charlesz, вы можете попытаться выбрать любой тип файла, определенный для файлов .ps1
(хотя, если вы измените тип файла позже, вам, возможно, придется повторить его); пожалуйста, посмотрите мое обновление.
О... Теперь это имеет смысл... Могу ли я создать локальную для пользователя версию «Запуск с PowerShell», которая запускает сценарий без установки политики выполнения на уровне процесса?