如何处理带有特殊字符的文件路径?
How to handle file paths with special characters?
我有一个 PowerShell 脚本,它需要能够从同一目录中使用提升的凭据调用另一个 PS 脚本。由于脚本需要可移植,因此无法提前知道脚本的文件路径,并且需要能够在不失败的情况下处理文件路径中的空格和特殊字符。
由于提升 PS 会话会导致当前工作目录更改为 "C:\Windows\System32",因此我需要能够将当前目录作为参数传递给脚本。现在,只要目录路径中没有特殊字符,我当前的脚本(如下)就可以很好地处理这个问题。
这是我当前的脚本(根据@mklement0 的建议更新):
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Start-Process Powershell -Verb runas -ArgumentList "-ExecutionPolicy","Bypass","-File","`"$dir\elevated.ps1`"","`"$dir`""
我试过转义一些特殊字符,例如:
$dir = $dir.Replace('&','`"&`"')
但是对于 Windows 在 folder/filename 中允许的所有不同字符,这并不是一致的。也不是所有的特殊字符都需要转义,但我需要确保这对那些需要转义的字符有效;至少那些可能出现在文件路径中的。
我主要关心的特殊字符(尽管有时也需要解决外来字符):!@#$%^_+-=.,{}`~&()[]
我正在测试的示例目录路径:
C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~&()[]
尝试从上述位置 运行 我的脚本 returns 出现以下错误:
The specified wildcard character pattern is not valid:
badname-!@#$%^_+-=.,{}\~&()[]
+ CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RuntimeException
那么,让脚本动态处理目录路径中的特殊字符的最佳方法是什么?
顺便说一句:在 PSv3+ 中,您可以使用 $PSScriptRoot
来指代脚本所在的目录。
如果你可以修改目标脚本,你可以将Set-Location -LiteralPath $PSScriptRoot
放在顶部以更改为该文件夹。
为避免 quoting/escaping 问题,将参数 单独 作为 数组 的不同元素传递给 -ArgumentList
(-Args
):
Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass',
'-File', "`"$dir\elevated.ps1`"", "`"$dir`""
不幸的是,仅此一项还不够:
当你使用-File
时,即使参数单独传递,脚本文件路径和目录路径仍然需要embedded "..."
引用 以便正确传递带有嵌入空格的值: "`"..."`"
传递带有 embedded 双引号的值 (`
是 PowerShell 的转义字符,因此 `"
转义双引号)。 提示 Ansgar Wiechers。
这个bug has been reported on GitHub.
- 如果您需要传递带有嵌入式
"
字符的参数(根据定义,文件系统路径从不包含),请使用类似:
('"{0}"' -f ($value -replace '"', '\"'))
遗憾的是,如果您的路径包含 [
个字符,而这些字符并不是语法上有效的通配符模式范围的每个部分(例如,[ab]
, [0-9]
), 因为 PowerShell - 自 Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.6 - 错误地将路径解释为 通配符模式,如果发现格式不正确则失败 - 请参阅 this GitHub issue。
- 换句话说:您的调用 可能会或可能不会 工作,这取决于您的路径中如何使用
[
并且可能 ]
;例如foo[1]
有效,但 foo[]
无效。
- 目前没有适用于所有 情况的解决方法。
替代-Command
:
-Commmand
允许您传递一段 PowerShell 代码 - 一个迷你脚本,如果您愿意的话 - 您可以使用它来 传递一个由 PowerShell 解析的带引号的字符串新实例的规则:
Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass',
'-Command', "& `"$dir\elevated.ps1`" `"$dir`""
请注意需要使用 &
来调用脚本,因为它是作为带引号的字符串给出的,并且 $dir
的扩展是由 current届会。
不幸的是,文件名恰好看起来像格式错误的通配符模式(上面讨论过)的问题也适用于此调用场景。
因此,只要括号不为空 []
.
,我就能找到一个可行的解决方案
这是我得到的:
Start-Process Powershell -Verb runas -ArgumentList "-ExecutionPolicy","Bypass","-File","`"$(Get-Item -LiteralPath $PSScriptRoot\elevated.ps1)`""
以此为测试路径:
C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~[&]()
带有空括号的路径 []
仍然不起作用,但 return 不会出错。我假设这意味着它无法在预期路径中找到文件,同时仍将括号解释为通配符。不确定是否真的有什么可以解决这个问题,除了可能检查 运行 之前的路径并抛出错误。
我有一个 PowerShell 脚本,它需要能够从同一目录中使用提升的凭据调用另一个 PS 脚本。由于脚本需要可移植,因此无法提前知道脚本的文件路径,并且需要能够在不失败的情况下处理文件路径中的空格和特殊字符。
由于提升 PS 会话会导致当前工作目录更改为 "C:\Windows\System32",因此我需要能够将当前目录作为参数传递给脚本。现在,只要目录路径中没有特殊字符,我当前的脚本(如下)就可以很好地处理这个问题。
这是我当前的脚本(根据@mklement0 的建议更新):
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Start-Process Powershell -Verb runas -ArgumentList "-ExecutionPolicy","Bypass","-File","`"$dir\elevated.ps1`"","`"$dir`""
我试过转义一些特殊字符,例如:
$dir = $dir.Replace('&','`"&`"')
但是对于 Windows 在 folder/filename 中允许的所有不同字符,这并不是一致的。也不是所有的特殊字符都需要转义,但我需要确保这对那些需要转义的字符有效;至少那些可能出现在文件路径中的。
我主要关心的特殊字符(尽管有时也需要解决外来字符):!@#$%^_+-=.,{}`~&()[]
我正在测试的示例目录路径:
C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~&()[]
尝试从上述位置 运行 我的脚本 returns 出现以下错误:
The specified wildcard character pattern is not valid: badname-!@#$%^_+-=.,{}\~&()[] + CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : RuntimeException
那么,让脚本动态处理目录路径中的特殊字符的最佳方法是什么?
顺便说一句:在 PSv3+ 中,您可以使用 $PSScriptRoot
来指代脚本所在的目录。
如果你可以修改目标脚本,你可以将Set-Location -LiteralPath $PSScriptRoot
放在顶部以更改为该文件夹。
为避免 quoting/escaping 问题,将参数 单独 作为 数组 的不同元素传递给 -ArgumentList
(-Args
):
Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass',
'-File', "`"$dir\elevated.ps1`"", "`"$dir`""
不幸的是,仅此一项还不够:
当你使用
-File
时,即使参数单独传递,脚本文件路径和目录路径仍然需要embedded"..."
引用 以便正确传递带有嵌入空格的值:"`"..."`"
传递带有 embedded 双引号的值 (`
是 PowerShell 的转义字符,因此`"
转义双引号)。 提示 Ansgar Wiechers。
这个bug has been reported on GitHub.- 如果您需要传递带有嵌入式
"
字符的参数(根据定义,文件系统路径从不包含),请使用类似:
('"{0}"' -f ($value -replace '"', '\"'))
- 如果您需要传递带有嵌入式
遗憾的是,如果您的路径包含
[
个字符,而这些字符并不是语法上有效的通配符模式范围的每个部分(例如,[ab]
,[0-9]
), 因为 PowerShell - 自 Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.6 - 错误地将路径解释为 通配符模式,如果发现格式不正确则失败 - 请参阅 this GitHub issue。- 换句话说:您的调用 可能会或可能不会 工作,这取决于您的路径中如何使用
[
并且可能]
;例如foo[1]
有效,但foo[]
无效。 - 目前没有适用于所有 情况的解决方法。
- 换句话说:您的调用 可能会或可能不会 工作,这取决于您的路径中如何使用
替代-Command
:
-Commmand
允许您传递一段 PowerShell 代码 - 一个迷你脚本,如果您愿意的话 - 您可以使用它来 传递一个由 PowerShell 解析的带引号的字符串新实例的规则:
Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass',
'-Command', "& `"$dir\elevated.ps1`" `"$dir`""
请注意需要使用 &
来调用脚本,因为它是作为带引号的字符串给出的,并且 $dir
的扩展是由 current届会。
不幸的是,文件名恰好看起来像格式错误的通配符模式(上面讨论过)的问题也适用于此调用场景。
因此,只要括号不为空 []
.
这是我得到的:
Start-Process Powershell -Verb runas -ArgumentList "-ExecutionPolicy","Bypass","-File","`"$(Get-Item -LiteralPath $PSScriptRoot\elevated.ps1)`""
以此为测试路径:
C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~[&]()
带有空括号的路径 []
仍然不起作用,但 return 不会出错。我假设这意味着它无法在预期路径中找到文件,同时仍将括号解释为通配符。不确定是否真的有什么可以解决这个问题,除了可能检查 运行 之前的路径并抛出错误。