如何处理带有特殊字符的文件路径?

时间:2017-08-31 01:23:46

标签: powershell escaping special-characters filepath start-process

我有一个PowerShell脚本,需要能够使用提升的凭据从同一目录中调用另一个PS脚本。因为脚本需要是可移植的,所以脚本的文件路径不是提前知道的,并且需要能够处理文件路径中的空格和特殊字符而不会失败。

由于提升PS会话将导致当前工作目录更改为" C:\ Windows \ System32",我需要能够将当前目录作为参数传递给脚本。现在,只要目录路径中没有特殊字符,我当前的脚本(下面)就处理这个问题了。

这是我当前的脚本(根据@ mklement0&#39的建议更新):

$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允许在文件夹/文件名中使用的所有不同字符,它们并不一致。并非所有特殊字符都需要转义,但我需要确保这适用于那些;至少那些可能出现在文件路径中的文件。

我特别关注的特殊字符(虽然外语字符可能也需要在某个时候解决):!@#$%^_+-=.,{}`~&()[]

示例目录路径我正在测试:

C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~&()[]

尝试从上面的位置运行我的脚本会返回以下错误:

The specified wildcard character pattern is not valid:
badname-!@#$%^_+-=.,{}\~&()[]
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : RuntimeException

那么,让脚本动态处理目录路径中的特殊字符的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

暂且不说:在PSv3 +中,您可以使用$PSScriptRoot来引用脚本所在的目录。
如果您可以修改目标脚本,则可以将Set-Location -LiteralPath $PSScriptRoot置于顶部以更改为该文件夹。

要避免引用/转义问题,请将参数单独作为数组的不同元素传递给-ArgumentList-Args):

Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass', 
  '-File', "`"$dir\elevated.ps1`"", "`"$dir`""

不幸的是,仅此一点不足

  • 当您使用-File时,即使参数单独传递,脚本文件路径和目录路径仍需要 embedded "..."引用为了正确传递带有嵌入空格的值:"`"..."`"使用 embedded 双引号传递值(`是PowerShell的转义字符,因此{{1} }避免双引号)。帽子的提示Ansgar Wiechers
    bug has been reported on GitHub

    • 如果您需要传递带有嵌入式`"字符的参数(根据定义,文件系统路径从不包含),请使用以下内容:
      "
  • 遗憾的是,如果您的路径包含的('"{0}"' -f ($value -replace '"', '\"'))字符不是语法上有效的通配符模式范围的每一部分(例如[,{ {1}}),因为PowerShell - 从Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.6开始 - 错误地将路径解释为通配符模式,如果它失败发现它格格不入 - 请参阅this GitHub issue

    • 换句话说:您的调用可能会或可能不会工作,具体取决于您的路径中[ab][0-9]的使用方式;例如[有效,但]没有。
    • 目前没有适用于所有案例的解决方法。

替代foo[1]

foo[]允许您传递一段PowerShell代码 - 一个迷你脚本(如果您愿意) - 您可以使用它来传递由PowerShell规则解析的单个引用字符串通过新实例:

-Command

请注意需要使用-Commmand来调用脚本,因为它是作为带引号的字符串给出的,而Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass', '-Command', "& `"$dir\elevated.ps1`" `"$dir`"" 的扩展是由当前会话执行的

不幸的是,文件名碰巧看起来像格式错误的通配符模式(如上所述)的问题也适用于此调用场景。

答案 1 :(得分:0)

所以,只要括号不为空,我就能找到一个有效的解决方案 [0]->{'total_bytes'}

这就是我所拥有的:

Start-Process Powershell -Verb runas -ArgumentList "-ExecutionPolicy","Bypass","-File","`"$(Get-Item -LiteralPath $PSScriptRoot\elevated.ps1)`""

使用此作为测试路径:

[]

带有空括号C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~[&]() 的路径仍然不起作用,但不会返回错误。我假设这意味着它仍然无法在将括号解释为通配符的情况下在预期路径中找到文件。不确定是否有任何可以解决的问题,除非在运行之前检查路径并抛出错误。