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

Posted

技术标签:

【中文标题】在开始作业脚本块中使用 \\\\?\\UNC\\ (长 unc 路径)时,get-itemPropertyValue 不绑定路径【英文标题】:get-itemPropertyValue doesn't bind Path when using \\?\UNC\ (long unc path) in start-job scriptblock在开始作业脚本块中使用 \\?\UNC\ (长 unc 路径)时,get-itemPropertyValue 不绑定路径 【发布时间】:2021-09-28 20:05:46 【问题描述】:

我正在尝试多线程

$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
    

其中$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 澳大利亚 + 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 : 本地主机

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

提前致谢。

【问题讨论】:

更改$file > $using:file。工作范围与您当前的范围不同。 我还鼓励您将循环遍历的数组分成块并将该块传递给作业,而不是逐个文件传递,因为它比foreach 循环要慢得多。 Santiago 关于范围界定是正确的,他关于一次处理文件块的建议是可靠的,但如果您通过Get-ChildItem 获得文件列表,您不应该已经拥有数据吗?重新尝试多线程?这不是和$var3 = $var2 | Select fullName,CreationTime,lastAccessTime,LastWriteTime,length本质上一样吗? @TheMadTechnician,这确实解决了我的根本问题,我想知道为什么我最终会使用 get-itemPropertyValue。是否还有一个开关可以摆脱输出中的字段标题? @SantiagoSquarzon,这行得通,是问题的正确答案:) 您能否详细说明范围部分并写一个答案,以便我接受? 【参考方案1】:

在我的评论中,作业的范围与您当前的范围不同,这意味着,您开始的作业无法看到在其范围之外定义的变量(即:$file) .您需要使用$using:foo-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's 的评论,他是对的,如果你已经打电话给Get-ChildItem,则无需使用Get-ItemProperty,但为了解释我在下一条评论中的意思:。 ..将您循环的数组划分为块并将该块传递给作业而不是逐个文件...,为每个文件启动作业不仅比正常速度慢很多倍foreach 循环但也会消耗大量内存。 Start-Job 通常比线性循环慢,如果您正在寻找多线程替代方案,您应该查看 ThreadJob 模块中的 RunSpace 或 Start-ThreadJob。我已经做了一些测试比较性能 Linear Loops vs ThreadJob vs Runspace 在循环本地目录和文件时,如果你有兴趣可以从我的 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

【讨论】:

以上是关于在开始作业脚本块中使用 \\?\UNC\ (长 unc 路径)时,get-itemPropertyValue 不绑定路径的主要内容,如果未能解决你的问题,请参考以下文章

需要很长执行时间的 php 脚本的 Cron 作业

Windows上的python长路径 - os.stat()失败了相对路径?

UTF-8 中的所有汉字字符都是 3 个字节长吗?

Powershell - 如何为 Start-Job 预先评估脚本块中的变量

在 C# 中将 UNC 路径转换为本地路径

Sql Server 备份到 UNC