Обновление: Автономная команда — без зависимости от файла скрипта.

Обновление: Автономная команда — без зависимости от файла скрипта.

В 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
  1. Возьмите ключ во владение и предоставьте себе полный контроль.

  2. Отредактируйте (Default)значение, изменив его на:

     powershell.exe -NoExit -Command &{Set-Location -LiteralPath $Args[1]} --%% %V  
    
  3. Удалите Full Controlразрешение, которое вы добавили для своего пользователя.

  4. Измените владельца обратно на , 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:", которыйперерывы.

Связанный контент