请考虑以下代码。我只是使用[Int32[]]
参数将一个32位有符号整数数组Start-Job
传入-InputObject
cmdlet。
$Job = Start-Job -ScriptBlock { $input.GetType().FullName; } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
此代码的结果是:
System.Management.Automation.Runspaces.PipelineReader`1+<GetReadEnumerator>d__0[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
查看PipelineReader .NET class的文档,它有一个ReadToEnd()
方法。因此,以下代码应该起作用:
$Job = Start-Job -ScriptBlock { $input.ReadToEnd(); } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
但相反,我收到一条错误消息:
方法调用失败,因为[System.Int32]不包含名为“ReadToEnd”的方法。 + CategoryInfo:InvalidOperation:(:) [],RuntimeException + FullyQualifiedErrorId:MethodNotFound + PSComputerName:localhost
那么我认为,我只会使用PSBase
属性来获取“真实”对象。
$Job = Start-Job -ScriptBlock { $input.psbase.ReadToEnd(); } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
但后来我收到类似的错误消息:
方法调用失败,因为[System.Management.Automation.PSInternalMemberSet]不包含名为“ReadToEnd”的方法。 + CategoryInfo:InvalidOperation:(ReadToEnd:String)[],RuntimeException + FullyQualifiedErrorId:MethodNotFound + PSComputerName:localhost
我注意到这个混乱有一个Microsoft Connect bug filed,但它让我更加困惑。显然PipelineReader
类有一个容易混淆的属性<>4__this
,它有一个Read()
方法,使用Get-Member
实际上无法看到。
底线:当通过{$input
参数提交输入时,是否有人知道如何简单地“解包”-InputObject
自动变量的内容1}} cmdlet,以便我可以单独使用这些对象吗?
此脚本应该只返回Start-Job
,而不是1
。
1, 2, 3
答案 0 :(得分:3)
据推测,$input
是一个枚举器,就像在标准管道中一样。
为了处理项目,我们应该使用process
块
自动变量$_
或在$input
的另一个管道中传递end
block(如果未指定则隐式)。
# process each item separately
$Job = Start-Job -ScriptBlock {process{$_}} -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
# process the whole $input
$Job = Start-Job -ScriptBlock {$input | %{$_}} -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
# compare with script blocks in standard pipelines
# each item
@(1,2,3) | . {process{$_}}
# whole input
@(1,2,3) | . {$input | %{$_}}
也许还有其他方法来枚举$input
的项目,但它们是。{
据我所知,在实践中并不经常使用。
答案 1 :(得分:2)
$Input Contains an enumerator that enumerates all input that is passed to a function. The $input variable is available only to functions and script blocks (which are unnamed functions). In the Process block of a function, the $input variable enumerates the object that is currently in the pipeline. When the Process block completes, there are no objects left in the pipeline, so the $input variable enumerates an empty collection. If the function does not have a Process block, then in the End block, the $input variable enumerates the collection of all input to the function.
总结:$input
是一个自动变量,它包含枚举器形式的WHOLE管道,不像$_
,它是管道中的“当前对象”。
以下是如何使用它的示例。
function test {
#$input is an enumerator that you should use $input | foreach-object { } to access the objects.
#To to get all items you could e.g. convert the enumerator to an array.
$arr = @($input)
#If you need to use the $input enumerator for something else, you need to call .Reset() first as the enumerator has reached the end.
$input.Reset()
#Print some values from the data
$arr.count
$arr[0]
}
PS> "hello", "world" | test
2
hello
更新:以下证明这也适用于您Start-Job
方案。评论样本进行解释。
$Job = Start-Job -ScriptBlock {
#Read the complete pipeline to an array
$data= @($input)
"`$data is an $($data.GetType().Name) with $($data.count) objects"
#Unlike in a pipeline, where the `Start-Job` command would be called once per object like `Start-Job ...... -InputObject $_`,
#you're inputing a single `object[]` object the the pipeline. So you only have one item in your $input pipeline.
#Get our inputobject (our array)
$arr= $data[0]
"`$arr is an $($arr.GetType().Name)"
#Use array
"$($arr[0]) is less than $($arr[1]) which is less than $($arr[2])"
} -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
54 Job54 BackgroundJob Completed True localhost ...
$data is an Object[] with 1 objects
$arr is an ArrayList
1 is less then 2 which is less then 3
并证明我对管道的“理论”。这是流水线版本:
$Job = 1, 2, 3 | Start-Job -ScriptBlock {
#Read the complete pipeline to an array
$data= @($input)
"`$data is an $($data.GetType().Name) with $($data.count) objects"
#Now the command is run per object, so the $input enumerator contained our 3 seperate Int32 values.
#Get a single object in the pipeline
$OneOfTheValues= $data[0]
"`$OneOfTheValues is an $($OneOfTheValues.GetType().Name)"
#Use data
"$($data[0]) is less than $($data[1]) which is less than $($data[2])"
}
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
58 Job58 BackgroundJob Completed True localhost ...
$data is an Object[] with 3 objects
$OneOfTheValues is an Int32
1 is less then 2 which is less then 3
所以我坚持原来的答案。行为是相同的,您只是以不同的方式使用管道/ cmdlet。 :)
答案 2 :(得分:1)
这似乎有效:
$Job = Start-Job -ScriptBlock { $input.movenext();$input.current[0] } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;