首页 > 解决方案 > 在开始作业脚本块中使用 \\?\UNC\ (长 unc 路径)时,get-itemPropertyValue 不绑定路径

问题描述

我正在尝试多线程

$var3 = Get-ItemPropertyValue $var2 -Name fullName,CreationTime,lastAccessTime,LastWriteTime,length;

通过将其替换为:

$var3 = forEach($file in $var2) {
        start-job -name "bla" -scriptblock {Get-ItemPropertyValue $file.FullName -Name fullName,LastWriteTime,CreationTime,lastAccessTime,length} | out-null
    }

where$var2保存通过 检索的文件列表gci

这适用于普通路径,但不适用于以 . 为前缀的长 UNC 路径\\?\UNC\

长路径本身可以正常工作,get-itemPropertyValue '\\?\UNC\some long path in Webdav'但一旦我从 start-job 将它放入 scriptBlock 就不行了。

错误消息说(德语):

"Das Argument für den Parameter "Path" kann nicht überprüft werden. Das Argument ist NULL oder leer. Geben Sie ein Argument an, das nicht NULL oder leer ist, und führen Sie den Befehl erneut aus. + CategoryInfo : InvalidData: (:) [Get-ItemPropertyValue]、ParameterBindingValidationException + FullyQualifiedErrorId:ParameterArgumentValidationError、Microsoft.PowerShell.Commands.GetItemPropertyValueCommand + PSComputerName:本地主机

当我尝试将它与它绑定时,get-itemPropertyValue -LocalPath '\\?\UNC\some long path in Webdav'它也会失败,但会出现以下错误消息:

Das Argument kann nicht an den 参数“LiteralPath”gebunden werden,da es NULL ist。+ CategoryInfo : InvalidData: (:) [Get-ItemPropertyValue], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand + PSComputerName : localhost

任何人都可以检查,如果这是真的,这不起作用,或者显示一个运行的例子?我正在运行 PS 版本 5.1 并且必须使用此版本。

提前致谢。

标签: powershellunccharacter-limit

解决方案


正如我在评论中所说,工作的范围与您当前的范围不同,这意味着您开始的工作无法看到在其范围之外定义的变量(即:)$file。您需要将变量传递给它的范围,无论是 with$using:foo还是 with -ArgumentList

$props = 'FullName','LastWriteTime','CreationTime','LastAccessTime','Length'

$var3 = forEach($file in (Get-ChildItem -File))
{
    Start-Job -Name "bla" -ScriptBlock {
        Get-ItemPropertyValue $using:file.FullName -Name $using:props
    }
}

$var3 | Receive-Job -Wait -AutoRemoveJob

# OR

$var3 = forEach($file in (Get-ChildItem -File))
{
    Start-Job -Name "bla" -ScriptBlock {
        param($file, $props)

        Get-ItemPropertyValue $file.FullName -Name $props
    } -ArgumentList $file, $props
}

$var3 | Receive-Job -Wait -AutoRemoveJob

至于@TheMadTechnician 的Get-ItemProperty评论,他是对的,如果您已经在打电话,则无需使用,Get-ChildItem但为了解释我在下一条评论中的意思:...将您循环的数组分成块并将该块传递给一个作业而不是一个文件一个文件作为它...,为每个文件启动一个作业不仅比正常foreach循环慢很多倍,而且会消耗大量内存。Start-Job通常比线性循环慢,如果您正在寻找多线程替代方案,您应该查看RunSpaceStart-ThreadJobThreadJob 模块。我已经做了一些测试,比较了线性循环、线程作业和运行空间的性能循环浏览本地目录和文件时,如果您有兴趣,可以从我的 GitHub 下载脚本(请记住,它需要安装 ThreadJob 模块)。

  • 为了向您展示我将块传递给作业的简单示例,首先将所有目录存储在一个变量中并定义您要使用的线程数(同时运行的作业数):
$directories = Get-ChildItem . -Directory -Recurse
$numberOfThreads = 10
  • 然后我们将这个目录数组划分为线程数,在本例中为 10:
$groupSize = [math]::Ceiling($directories.Count / $numberOfThreads)
$counter = [pscustomobject]@{ Value = 0 }
$groups = $directories | Group-Object -Property {
    [math]::Floor($counter.Value++ / $groupSize)
}
  • 最后,我们将这 10 个文件夹块传递给每个作业。每个作业将计算每个文件夹上的文件数:
$var3 = foreach($chunk in $groups)
{
    Start-Job -ScriptBlock {
        $folders = $using:chunk.Group.FullName
        foreach($folder in $folders)
        {
            [pscustomobject]@{
                DirectoryFullName = $folder
                NumberOfFiles = (Get-ChildItem $folder -File).count
            }
        }
    }
}

$result = $var3 | Receive-Job -Wait -AutoRemoveJob |
Sort-Object NumberOfFiles -Descending |
Select-Object * -ExcludeProperty RunspaceID,PSSourceJobInstanceId

如果你在你的电脑上试试这个,你会得到类似的东西:

DirectoryFullName      NumberOfFiles
-----------------      -------------
X:\ExampleUser\Folder0          1954
X:\ExampleUser\Folder1           649
X:\ExampleUser\Folder2            64
X:\ExampleUser\Folder3            36
X:\ExampleUser\Folder4            23
X:\ExampleUser\Folder5            16
X:\ExampleUser\Folder6            15
X:\ExampleUser\Folder7            15
X:\ExampleUser\Folder8            12
X:\ExampleUser\Folder9            10

推荐阅读