В Windows 10 щелчок правой кнопкой мыши по папке или в фоновом режиме в проводнике файлов с нажатой клавишей Shift добавляет в контекстное меню команду «Открыть окно PowerShell здесь».
Однако команда, используемая для открытия окна PowerShell, определена некорректно (по крайней мере, для версии W10 с идентификатором 1709), поскольку она ошибочно предполагает, что имена папок никогда не содержат встроенных '
символов:
# !! Breaks with folder names such as "a'b"
powershell.exe -noexit -command Set-Location -literalPath '%V'
Ниже приведено решение этой проблемы, но учтите, что для этого требуются права администратора.
решение1
Обновление: Автономная команда — без зависимости от файла скрипта.
Скопируйте, вставьте и выполните этот код вPowerShellконсоль для мгновенной демонстрации «концепции»:
$msg = @'
$Args[0] : {0}
$Args[1] : {1}
'@
&{echo ($msg -f $Args[0], $Args[1])} --% I'm an unquoted string with an apostrophe and spaces.
Выход:
PS C:\> $msg = @'
>> $Args[0] : {0}
>> $Args[1] : {1}
>> '@
>> &{echo ($msg -f $Args[0], $Args[1])} --% I'm an unqoted string with an apostroohe and spaces.
$Args[0] : --%
$Args[1] : I'm an unqoted string with an apostroohe and spaces.
PS C:\>
- (интересно, что
--%
это и функционально, и отражено в качестве аргумента)
«Волшебная пуля» — этоОстановить анализ токена: --%
. Согласно документации:
Символ остановки анализа (--%), представленный в PowerShell 3.0, предписывает PowerShell воздержаться от интерпретации входных данных как команд или выражений PowerShell.
...
При обнаружении символа остановки анализа PowerShell обрабатывает оставшиеся символы в строке как литерал.
Хотя он предназначен для использования с аргументами исполняемых файлов, он также работает с аргументами блоков скриптов, как показано в приведенном выше коде.
Таким образом, для выполнения Set-Location
с путем без кавычек синтаксис будет следующим:
&{Set-Location -LiteralPath $Args[1]} --% <unquoted path>
И таким образом наша команда реестра становится такой:
powershell.exe -NoExit -Command &{Set-Location -LiteralPath $Args[1]} --%% %V
- Обратите внимание, что двойной знак процента (
%%
) необходим для создания буквального%
символа в результирующей команде.
Чтобы изменить команду на уровне машины, отредактируйте реестр напрямую. Соответствующие ключи:
HKLM\SOFTWARE\Classes\Directory\Background\Shell\PowerShell\Command
HKLM\SOFTWARE\Classes\Directory\Shell\PowerShell\Command
Возьмите ключ во владение и предоставьте себе полный контроль.
Отредактируйте
(Default)
значение, изменив его на:powershell.exe -NoExit -Command &{Set-Location -LiteralPath $Args[1]} --%% %V
Удалите
Full Control
разрешение, которое вы добавили для своего пользователя.Измените владельца обратно на ,
TrustedInstaller
указавNT Service\TrustedInstaller
в качестве имени пользователя действия, которые вы выполнили для принятия права собственности.
Чтобы изменить команду для каждого пользователя, просто создайте и отредактируйте разделы реестра:
HKCU\Softwar\Classes\Directory\Background\Shell\PowerShell\Command
HKCU\Software\Classes\Directory\Shell\PowerShell\Command
Изменим значение на(Default)
:powershell.exe -NoExit -Command &{Set-Location -LiteralPath $Args[1]} --%% %V
или просто скопируйте, вставьте и выполните следующее:
'Background\','' | ForEach{
$splat = @{
'Path' = ('HKCU:\Software\Classes\Directory\{0}Shell\PowerShell\Command' -f $_)
'Value' = 'powershell.exe -NoExit -Command &{Set-Location -LiteralPath $Args[1]} --%% %V'
}
New-Item @splat -Force
}
Оригинальный ответ
Для обхода 5.1 я не могу придумать способ с помощью простогоPowerShellкомандная строка, но вызов однострочного скрипта, похоже, решает проблему:
(Изменение/улучшение кода согласно комментарию @mklement0)
### OpenHere.ps1
Set-Location -LiteralPath $Args[0]
### (HKCU|HKLM)\Software\Classes\Direcory[\Background]\Shell\PowerShell\Command
###
###powershell.exe -noexit -File "C:\Path\to\OpenHere.ps1" "%V"
###
- Сохраните как «OpenHere.ps1» в подходящем месте.
- Затем вы можете изменить одно из следующих действий:
HKLM\SOFTWARE\Classes\Directory\Shell\PowerShell\Command
если у вас есть доступ администратора и вы хорошо разбираетесь в правах собственности и разрешениях.
В противном случае вы можете создать записи для каждого пользователя в разделе:HKCU\Software\Classes\Directory\Shell\PowerShell\Command
Синтаксис командной строки реестра следующий:
powershell.exe -noexit -File "C:\Path\to\OpenHere.ps1" "%V"
Вот «самоустанавливающаяся» версия приведенного выше кода, которая создаст пункты контекстного меню в разделе HKCU
(мод для каждого пользователя).
- Сохраните следующий текст как
.ps1
файл в каталоге, где он будет находиться. - Запустите скрипт изPowerShellconsole без аргументов. Код использует текущий Path\FileName файла
.ps1
в командной строке, которую он создает.
### OpenHere.ps1
If ($Args) { ### Launched from context menu
Set-Location -LiteralPath $Args[0]
} Else { ### Create HKCU registry entries
'Background\','' | ForEach {
$splat = @{
'Path' = ('HKCU:\Software\Classes\Directory\{0}Shell\PowerShell\Command' -f $_)
'Value' = ('powershell.exe -NoExit -File "{0}" "%V"' -f $PSCommandPath)
'Type' = 'ExpandString'
}
New-Item @splat -Force
}
}
### The "(Default)" value is created as a REG_EXPAND_SZ to allow for subsequent
### editing that can include environmental variables
решение2
Предисловие
Полезный ответ Кита Миллераэто прагматичное, автоматизированное решение - единственное, что следует отметить, это то, что оно работает толькоуровень пользователя.
Ответ ниже может быть интересен длявсе пользователирешение и для технической справки;
OpenHere.ps1
ответ Кейта может быть в равной степени использован в решении для всех пользователей (за исключением части с самостоятельной установкой).
Снимаю шляпуLesFerchза весь его вклад.
Примечание:
- Это исправлениетребуются административные привилегии(бегс возвышением).
Открыть regedit.exe
ипримените следующие шаги, чтобыобаиз следующих ключей реестра: HKEY_CLASSES_ROOT\Directory\shell\Powershell\command
и
HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell\command
:
Подготовка:изменить разрешениячтобы стало возможным изменение значения (команда PowerShell):
Альтернативы ручному изменению разрешений:
@LesFerch упоминает следующие сторонние утилиты какальтернативыдля ручного изменения разрешений, позволяя вам работать
regedit.exe
непосредственно какNT SERVICE\TrustedInstaller
пользователь:PowerRun(мой любимый вариант),AdvancedRun. Это гораздо более безопасный вариант, чем возиться с разрешениями (которые люди часто путают и все портят).
Полезный ответ Кита Миллераупоминает определениеуровень пользователяключи в качестве альтернативы - которая не требует возвышения, но ограничивает решениетекущий пользователь.
Щелкните правой кнопкой мыши по
command
подразделу и выберитеPermissions...
Нажмите
Advanced
и:- сделать
Administrators
группувладелецключа - предоставить
Administrators
группе полный контроль над ключом
- сделать
Примечание: Я не знаю о каких-либо неблагоприятных эффектах этих изменений, но сообщите нам, если вы знаете о них.
Однако, чтобы быть в безопасности, вы можете отменить эти изменения после изменения команды, как описано ниже, что влечет за собой восстановлениеTrustedInstaller
принципала безопасности как владельца ключаcommand
; обратите внимание, что вы должны указать его как
NT SERVICE\TrustedInstaller
.
Теперь замените значение
command
ключа(Default)
на следующее (см. примечание о настройках консоли/цветах ниже):cmd /c set "_dir=%V%" & powershell.exe -NoExit -Command Set-Location -LiteralPath $env:_dir
Примечание:
Благодаря вызову через
cmd
вы получите настройки консоли последнего вместо настроек Windows PowerShell, которые, в частности, включают синий фон.Вы можете избежать этого, поместив
start
передpowershell.exe
, что открываетновое окнос обычными настройками и цветами, но недостатком является то, что исходное, временное окно, которое неизменно создается,cmd.exe
кратковременно мигает на экране.Ответ Кейта Миллерапредлагает альтернативу черезвспомогательный
.ps1
скрипт, что позволяет осуществлять прямой вызов черезpowershell.exe -File
и, следовательно, избегать проблемы мигания;-File
CLIпараметр обрабатывает свои аргументыбуквально, поэтому описанная ниже проблема при использовании-Command
не возникает.powershell.exe -NoExit -File "C:\Path\to\OpenHere.ps1" "%V"
Вызовс помощью
cmd /c
этосамый надежныйибезопасныйвариант:Значение
%V
может синтаксически нарушитьset
команду, только если она содержит"
символы, что по определению невозможно (имена файлов и папок не могут содержать"
).Однако, если имя папки содержит что-то похожее на
cmd.exe
ссылку на переменную средыдословно(например%OS%
)иуказанная переменная существует, ссылка расширяется, в результате чего переход в эту папку либо завершается неудачей, либо — гипотетически — в качестве целевой папки выбирается другая папка.Причина, по которой команда не может просто использоваться
cd
как часть вызова,cmd.exe
заключается в том, что онаpowershell.exe
дает сбои при вызове из папки, имя которой содержит[
или]
(напримерfoo[0]
). Эта ошибка была исправлена вPowerShell (ядро) 7+CLI,pwsh.exe
поэтому вы можете просто использовать:# PowerShell 7+ cmd /c cd /d "%V" & pwsh.exe
На самом деле,
pwsh.exe
это новый-WorkingDirectory
параметр включаетпрямойвызов (это не только более эффективно, но и позволяет избежать проблемы с настройками консоли): [1]pwsh.exe -WorkingDirectory "%V\."
powershell.exe
При прямом звонкеявляетсявариант, он неизменно подразумеваеткомпромиссы:Если имена ваших папок могут содержать буквенные
'
символы, но НИКОГДА не содержат буквенные символы`
или$
символы, вы можете использовать"..."
(расширяемый(интерполирующая) строка) вместо этого, но это идет со следующим ПРЕДОСТЕРЕЖЕНИЕ:В то время как команда простонеисправностьс дословными именами папок, такими как
foo`bar
или$foo
(или - гипотетически - указать надругойкаталог), это может привести кнежелательное выполнение команд, с помощью тщательно - вредоносно - созданных имен папок, содержащих$(...)
подвыражения.powershell.exe -NoExit -Command "Set-Location -LiteralPath \"%V\""
Должна быть возможность записать вышеописанные шаги.
[1] \.
добавлено для того, чтобы гарантировать, чтокореньпути, такие как C:\
также обрабатываются должным образом; в противном случае PowerShell CLI (оправданно) интерпретировал бы "C:\"
, например, как C:
за которым следуетсбежал "
характер, т.е. по сути какдословно C:"
, которыйперерывы.