在开始作业脚本块中使用 \\?\UNC\(长 unc 路径)时,get-itemPropertyValue 不绑定路径
get-itemPropertyValue doesn't bind Path when using \\?\UNC\ (long unc path) in start-job scriptblock
我正在尝试对此进行多线程处理
$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'
一起使用,但是当我从开始作业将它放入 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 : localhost
当我尝试将它与 get-itemPropertyValue -LocalPath '\?\UNC\some long path in Webdav'
绑定时,它也失败了,但出现了以下错误消息:
Das Argument kann nicht an den Parameter "LiteralPath" gebunden werden, da es NULL ist.
+ CategoryInfo : InvalidData: (:) [Get-ItemPropertyValue], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand
+ PSComputerName : localhost
任何人都可以检查一下,如果这是真的,这行不通,或者显示一个 运行 示例吗?我是 运行 PS 5.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
至于 comment, he is right, there is no need to use Get-ItemProperty
if you're already calling Get-ChildItem
but for the sake of explaining what I meant in my next comment: ...divide the array you're looping through into chunks and passing that chunk to a job instead of file by file as it..., starting a job for each file would be not only many times slower than a normal foreach
loop but also would consume a lot of memory. Start-Job
in general is slower than a linear loop, if you're looking for a multithread alternative, you should be looking at either RunSpace or Start-ThreadJob
from the ThreadJob Module. I have done some testing comparing the performance 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
我正在尝试对此进行多线程处理
$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'
一起使用,但是当我从开始作业将它放入 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 : localhost
当我尝试将它与 get-itemPropertyValue -LocalPath '\?\UNC\some long path in Webdav'
绑定时,它也失败了,但出现了以下错误消息:
Das Argument kann nicht an den Parameter "LiteralPath" gebunden werden, da es NULL ist. + CategoryInfo : InvalidData: (:) [Get-ItemPropertyValue], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand + PSComputerName : localhost
任何人都可以检查一下,如果这是真的,这行不通,或者显示一个 运行 示例吗?我是 运行 PS 5.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
至于 Get-ItemProperty
if you're already calling Get-ChildItem
but for the sake of explaining what I meant in my next comment: ...divide the array you're looping through into chunks and passing that chunk to a job instead of file by file as it..., starting a job for each file would be not only many times slower than a normal foreach
loop but also would consume a lot of memory. Start-Job
in general is slower than a linear loop, if you're looking for a multithread alternative, you should be looking at either RunSpace or Start-ThreadJob
from the ThreadJob Module. I have done some testing comparing the performance 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