问题
In this example, I'm trying to pass the results of Get-ChildItem
into a scriptblock, with limited success and unexpected results.
C:\temp
contains 3 files:
- A.txt
- B.txt
- C.txt
What I want is to pass $files
into the scriptblock here, and maintain the entire list of three files that Get-ChildItem
has returned. In other words, I would like for $files
to return A.txt, B.txt, and C.txt, both inside and outside the scriptblock.
I am able to do this, but I'm not able to do it reliably, and cannot explain why. I do not want to have to rely on a "dummy" variable to make this work properly, I'd like to understand what the difference is.
The first example here returns all of the files:
$files = Get-ChildItem -Path "C:\temp"
$test = $files.Get(0)
Write-Host $files.Count
Start-Job -ScriptBlock {
Param($test, $files)
Write-Host $files.Count
} -ArgumentList $test, $files | Out-Null
Wait-Job * | Out-Null
$results += Get-Job | Receive-Job
The second example only passes A.txt into the scriptblock:
$files = Get-ChildItem -Path "C:\temp"
Write-Host $files.Count
Start-Job -ScriptBlock {
Param($files)
Write-Host $files.Count
} -ArgumentList $files | Out-Null
Wait-Job * | Out-Null
$results += Get-Job | Receive-Job
Can someone help to explain the proper way to do this?
回答1:
PowerShell unrolls lists when passing them to a scriptblock, so that the first value goes to the first parameter, the second value to the second parameter, etc. instead of the entire list/array going to the first parameter.
In your first example you pass an argument list that consists of a single value and an array of values. When unrolling that (outer) list you still have two arguments (a single value and an array).
In your second example you pass just an array. When unrolling that parameter list you end up with a list of three individual values, the first of which goes to the first parameter of the scriptblock.
To prevent this behavior you need to "mask" lone arrays by wrapping the variable in another array with the unary array construction operator:
Start-Job -ScriptBlock {
Param($files)
Write-Host $files.Count
} -ArgumentList (,$files) | Out-Null
Alternatively use the using scope modifier instead of passing arguments:
Start-Job -ScriptBlock {
Write-Host $using:files.Count
} | Out-Null
来源:https://stackoverflow.com/questions/44634759/how-to-pass-results-of-get-childitem-into-a-scriptblock-properly