PowerShell中空格参数的奇怪引用

yzxexxkh  于 2023-03-08  发布在  Shell
关注(0)|答案(2)|浏览(144)

我试图开发一个非常简单的所谓的 * SendLet *。它包含一个PowerShell脚本,通过Windows资源管理器上下文菜单中的 * Send to * 快捷方式运行。调用任意文件或文件夹时,这些文件或文件夹将作为脚本的参数。我的方法如下:

    • 发送信件. ps1**
param (
    [Parameter(ValueFromRemainingArguments=$true)]
    $FilePath
)

Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
  Write-Host $_
}

Pause
    • 任意文件**
PowerShell 7.3.2
PS C:\Users\user\Desktop\Arbitrary Files> Get-ChildItem

    Directory: C:\Users\user\Desktop\Arbitrary Files

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          29.01.2023    16:44      276246528 Baz qux.AVI
-a---          29.01.2023    16:44        3787047 Foo bar.JPG

PS C:\Users\user\Desktop\Arbitrary Files>
    • 设置**

1.将SendLet脚本另存为C:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1
1.在shell:sendto中创建一个快捷方式(例如C:\Users\user\AppData\Roaming\Microsoft\Windows\SendTo\SendLet.lnk),目标为C:\Users\user\AppData\Local\Microsoft\WindowsApps\pwsh.exe C:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1
1.通过"发送到"上下文菜单将任意文件或文件夹发送到脚本。

    • 快跑**

在我的Windows 11 22H2计算机上运行上述方法会产生以下输出:

C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:

含义:找到两个要处理的具有绝对路径的文件...
然而,在我的Windows 10 Pro 22H2计算机上运行完全相同的方法会导致以下错误:

Get-ChildItem: D:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1:6
Line |
   6 |  Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'D:\Users\user\Documents\PowerShell\Scripts\Files\' because it does not exist.
Get-ChildItem: D:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1:6
Line |
   6 |  Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'D:\Users\user\Documents\PowerShell\Scripts\Files\' because it does not exist.
Press Enter to continue...:

错误消息中所抱怨的路径是完全错误的并且不存在。这就是为什么它不存在!所以错误消息本身是正确的。但是为什么脚本要寻找一个错误的路径参数呢?我想参数引用没有正常工作。

  • */UPDATE:**我能看到的唯一区别是测试数据被放在C:驱动器。在我的故障机器上,测试数据放在D:开车,但这有什么关系呢?
  • */更新2:**现在,我进行了测试,将测试数据放在C:驱动器。奇怪的是,所有的工作!?所以,我的Sendlet工作的文件或文件夹在C:而不是D:驱动器:-(
  • */UPDATE 3:**我测试了@zett42建议的两个脚本作为解决方案。结果有点奇怪。

在我正在工作的Windows 11计算机上的Arbitrary Files文件夹(上面提到的)上运行,第二个脚本将打印:

Processing file: C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
Processing file: C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:

在包含的两个文件上运行的第二个脚本将打印:

Processing file: C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
Processing file: C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:

到目前为止一切顺利...现在在我有问题的Windows 10 Pro机器上也是如此。
在文件夹上运行的第二个脚本将打印:

Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files
Press Enter to continue...:

直接在打印的两个包含文件上运行:

Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files\Baz
Processing file: qux.AVI
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files\Foo
Processing file: bar.JPG
Press Enter to continue...:

这是什么?我的Windows 10专业版机器是怎么回事?
看起来我的Windows 11机器在文件夹上运行PowerShell脚本,参数为"C:\Users\user\Desktop\Arbitrary Files"
然而,我的Windows 10 Pro机器似乎在参数为C:\Users\user\Desktop\Arbitrary Files的文件夹上运行脚本,导致两个参数由空格分隔。
同样的行为似乎也适用于直接在文件夹中的两个测试文件上运行的脚本(作为引用参数):
"C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI" "C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG" =〉两个带引号的参数
...或未引用的参数:
C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG =〉6个无引号的参数
这不可能是正常的行为。是吗?
也许我漏掉了什么?有什么建议吗?

  • */更新4:**我发现了这个问题-__-结果非常非常烦人...我再次检查了两台机器上的SendTo-Links。唯一的区别是解释器pwsh.exe的绝对路径,因为PowerShell的安装方式不同。

在好的机器上,到pwsh.exe的路径指向C:\Program Files\PowerShell\7\pwsh.exe。到目前为止一切顺利。
在有问题的机器上,指向pwsh.exe的路径是C:\Users\user\AppData\Local\Microsoft\WindowsApps\pwsh.exe。所以,我在想,这只是一个不同的路径。但当我在资源管理器中打开文件夹时,我产生了怀疑,因为pwsh.exe文件的大小为0字节:-O然后我在PowerShell终端中打开了同一个文件夹,并键入ls,显示了一些我没有预料到的东西。所有的EXE文件都只是指向其他地方的链接,但我不知道指向哪里?箭头->是什么意思?

PowerShell 7.3.2
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps> ls

    Directory: C:\Users\user\AppData\Local\Microsoft\WindowsApps

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          10.01.2023    18:44                Backup
d----          25.01.2023    10:57                Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
d----          20.12.2022    11:50                Microsoft.MicrosoftEdge_8wekyb3d8bbwe
d----          28.01.2023    23:08                Microsoft.PowerShell_8wekyb3d8bbwe
d----          26.01.2023    17:18                Microsoft.SkypeApp_kzf8qxf38zg5c
d----          28.01.2023    14:19                Microsoft.WindowsTerminal_8wekyb3d8bbwe
d----          10.02.2023    10:50                Microsoft.XboxGamingOverlay_8wekyb3d8bbwe
d----          03.02.2023    15:55                SpotifyAB.SpotifyMusic_zpdnekdrzrea0
la---          10.02.2023    10:50              0 GameBarElevatedFT_Alias.exe ->
la---          20.12.2022    11:50              0 MicrosoftEdge.exe ->
la---          28.01.2023    23:08              0 pwsh.exe ->
la---          25.01.2023    10:57              0 python.exe ->
la---          25.01.2023    10:57              0 python3.exe ->
la---          26.01.2023    17:18              0 Skype.exe ->
la---          03.02.2023    15:55              0 Spotify.exe ->
la---          25.01.2023    10:57              0 WindowsPackageManagerServer.exe ->
la---          25.01.2023    10:57              0 winget.exe ->
la---          28.01.2023    14:19              0 wt.exe ->

PS C:\Users\user\AppData\Local\Microsoft\WindowsApps>

正如我的结论,这里的问题是,所有传递给解释器链接的参数都没有正确传递给PowerShell解释器(引用丢失)!
设置指向解释器本身而不是链接的Sendlet解决了我的问题。
感谢@all

vhipe2zx

vhipe2zx1#

我不认为你应该用-recurse开关传递 file 路径到Get-ChildItem。至少我得到了奇怪的行为,因为包含文件的目录被枚举,即使我通过SendTo菜单只传递了一个文件。除此之外,脚本正确地接收所有路径,无论空间和磁盘驱动器上的位置。
因此,为了确保Get-ChildItem的行为符合预期,首先对作为参数接收到的路径进行循环,并测试哪个路径实际上是目录。另外,如果只想迭代文件,请确保使用参数-File调用Get-ChildItem

param (
    [Parameter(ValueFromRemainingArguments=$true)]
    $FilePath
)

foreach( $path in $FilePath ) {

    if( (Test-Path $path -PathType Container) ) {
        "Is directory: $path"
        Get-ChildItem -Recurse -File -Path $path | ForEach-Object {
            $_
        }
    }
    else {
        "Is file: $path"
    }
}

Pause

注意,我已经删除了Write-Host,因为不需要它。未赋值的表达式被认为是PowerShell的隐式输出。
尽管为了获得更好的结构,我还是将文件枚举代码 Package 到一个函数中。

param (
    [Parameter(ValueFromRemainingArguments=$true)]
    $FilePath
)

# A function that outputs only file paths, regardless if file
# paths or directory paths are passed. Directories are processed recursively.
Function EnumerateFilesRecursive( [string[]] $FileOrDirectoryPaths ) {

    foreach( $path in $FileOrDirectoryPaths ) {

        if( (Test-Path $path -PathType Container) ) {
            Get-ChildItem -Recurse -File -Path $path | ForEach-Object Fullname
        }
        else {
            $path
        }
    }
}

# Call the function and process its output (file paths)
EnumerateFilesRecursive $FilePath | ForEach-Object {
    "Processing file: $_"
}

pause
0md85ypi

0md85ypi2#

在这里我根据**/UPDATE 4**(见上文)之类的回答我自己的问题。

注意你的 Send to 快捷方式(放在shell:SendTo中)指向的是哪个PowerShell解释器的EXE文件。它是真正的EXE文件(例如版本7的pwsh.exe)还是一个符号链接?事实证明,将文件参数发送到符号链接根本不处理包含空格的路径!

可以通过Windows资源管理器中0字节的大小或PowerShell终端中ls命令打印的右箭头->来识别符号链接。

PowerShell 7.3.2
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps> ls

    Directory: C:\Users\user\AppData\Local\Microsoft\WindowsApps

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          10.01.2023    18:44                Backup
d----          25.01.2023    10:57                Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
d----          20.12.2022    11:50                Microsoft.MicrosoftEdge_8wekyb3d8bbwe
d----          28.01.2023    23:08                Microsoft.PowerShell_8wekyb3d8bbwe
d----          26.01.2023    17:18                Microsoft.SkypeApp_kzf8qxf38zg5c
d----          28.01.2023    14:19                Microsoft.WindowsTerminal_8wekyb3d8bbwe
d----          10.02.2023    10:50                Microsoft.XboxGamingOverlay_8wekyb3d8bbwe
d----          03.02.2023    15:55                SpotifyAB.SpotifyMusic_zpdnekdrzrea0
la---          10.02.2023    10:50              0 GameBarElevatedFT_Alias.exe ->
la---          20.12.2022    11:50              0 MicrosoftEdge.exe ->
la---          28.01.2023    23:08              0 pwsh.exe ->
la---          25.01.2023    10:57              0 python.exe ->
la---          25.01.2023    10:57              0 python3.exe ->
la---          26.01.2023    17:18              0 Skype.exe ->
la---          03.02.2023    15:55              0 Spotify.exe ->
la---          25.01.2023    10:57              0 WindowsPackageManagerServer.exe ->
la---          25.01.2023    10:57              0 winget.exe ->
la---          28.01.2023    14:19              0 wt.exe ->

PS C:\Users\user\AppData\Local\Microsoft\WindowsApps>

相关问题