在 Windows 10 中,按住 Shift 键并右键单击文件夹或文件资源管理器中的背景会在上下文菜单中添加“在此处打开 PowerShell 窗口”命令。
但是,用于打开 PowerShell 窗口的命令定义不正确(至少从 W10 版本 ID 1709 开始),因为它错误地假定文件夹名称从不包含嵌入'
字符:
# !! Breaks with folder names such as "a'b"
powershell.exe -noexit -command Set-Location -literalPath '%V'
请参阅下文以找到解决方法,但请注意,它需要管理权限。
答案1
更新:独立命令---没有脚本文件依赖。
复制、粘贴并执行此代码电源外壳控制台进行即时“概念验证”演示:
$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:\>
- (有趣的是,它既
--%
具有功能性,又可以作为参数捕获)
“魔法子弹”是停止解析 token:--%
。根据文档:
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 的解决方案,我想不出只用电源外壳命令行,但调用单行脚本似乎可以解决问题:
(根据@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
所在目录中的文件。 - 从运行脚本电源外壳控制台,不带任何参数。代码
.ps1
在其创建的命令行中使用文件的当前 Path\FileName。
### 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
前言
Keith Miller 的有用答案是一个实用的自动化解决方案——唯一要注意的是,它只在用户级别。
以下答案可能会引起全部用户解决方案和技术背景;
OpenHere.ps1
Keith 的答案同样可以用于全用户解决方案(自安装部分除外)。
向莱斯费奇感谢他的所有贡献。
笔记:
- 此修复需要管理权限(跑步有海拔)。
开放regedit.exe
和应用以下步骤两个都以下注册表项:HKEY_CLASSES_ROOT\Directory\shell\Powershell\command
和
HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell\command
:
准备:修改权限这样就可以修改值(PowerShell 命令):
手动修改权限的替代方案:
@LesFerch 提到以下第三方实用程序备择方案手动修改权限,允许您
regedit.exe
直接以NT SERVICE\TrustedInstaller
用户身份运行:Keith Miller 的有用答案提到定义用户级钥匙作为替代方案 - 不需要提升,但将解决方案限制在当前用户。
右键单击
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
在屏幕上短暂闪烁。Keith Miller 的回答提供替代方案帮手
.ps1
脚本,允许直接通过 调用powershell.exe -File
,从而避免闪烁问题;-File
命令行界面参数将其参数视为字面上地,因此下面使用时描述的问题-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:"
, 哪个休息。