将数组列表从第一个脚本传递到第二个脚本

时间:2019-08-03 16:11:35

标签: powershell

我需要将数组列表从脚本n.1传递到脚本n.2,并用while周期对其进行修改

脚本n.1-PS-GetBak.ps1

[System.Collections.Arraylist]$ArrBkp=@()

$ArrObj = New-Object psobject -Property @{Type="Full";Id=1001}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Diff";Id=1002}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Full";Id=1003}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Diff";Id=1004}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Diff";Id=1005}
[void]$ArrBkp.Add($ArrObj)

$ArrBkp

脚本n.2-PS-Rest.ps1

[CmdletBinding()]Param(
[Parameter(ValueFromPipeline=$true)]
$ArrBkp,
[Parameter()]
$Id
)

$ArrBkp.Reverse()

foreach ($Bkp in $ArrBkp) {
    while ($Bkp.Id -gt $Id) {$Bkp;$ArrBkp.Remove($Bkp)}
}

$ArrBkp

我期望的是:

PS C:\Users\dio\Documents\script\PS-Rest> .\PS-GetBak.ps1 | .\PS-Rest.ps1 -Id 1004
   Id Type
   -- ----
 1004 Diff
 1003 Full
 1002 Diff
 1001 Full

说明:while循环应从ID值为gt 1004的arraylist中删除对象

实际结果: 只有arraylist中的最后一个值通过管道传递到脚本n.2,导致while循环错误

In C:\Users\dio\Documents\script\PS-Rest\PS-Rest.ps1:11 car:49
+     while ($Bkp.Id -gt $Id) {$Bkp;$ArrBkp.Remove <<<< ($Bkp)}
    + CategoryInfo          : InvalidOperation: (Remove:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

2 个答案:

答案 0 :(得分:1)

退后一步:

PowerShell按需创建([object[]])阵列,“修改”阵列通常意味着简单地自动创建带有修改的原始阵列的副本已应用。

除非性能和内存保留至关重要,否则通常没有理由在PowerShell中使用[System.Collections.ArrayList]之类的类型

这包括数组的初始构造,假设:

  • 从脚本中输出多个对象通过管道将它们逐个发送,并在分配给变量时隐式地将它们收集在数组中。 >

  • PowerShell的,运算符用于显式构造数组非常灵活。

因此,您的PS-GetBak.ps1脚本可以简化如下:

# Construct multiple custom objects and send them all to the pipeline.
[pscustomobject] @{Type="Full";Id=1001}
[pscustomobject] @{Type="Diff";Id=1002}
[pscustomobject] @{Type="Full";Id=1003}
[pscustomobject] @{Type="Diff";Id=1004}
[pscustomobject] @{Type="Diff";Id=1005}

现在,您可以让PS-Rest.ps1对输入执行过滤操作,并简单地忽略不想要的输入,而将其他输入传递给:

[CmdletBinding()]
Param(
  [Parameter(ValueFromPipeline = $true)]
  $Bkp
  ,
  $Id
)

process {
  if ($Bkp.Id -le $Id) {
    $_ # pass through
  }
}

请注意使用process块,它是一次处理所有管道输入所必需的。

但是,这不能解决结果数组(列表)的所需反转 ,但是您可以在事实发生之后进行

# Chain the two scripts in a pipeline and collect the result.
$resultArray = @(PS-GetBak.ps1 | PS-Rest.ps1 -Id 1004)
[array]::Reverse($resultArray) # reverse the array in place.

请注意管道周围的@(...),可确保输出始终为 数组,因为PowerShell会按原样报告单个输出对象,而不是一个单元素数组。


如果您确实想将阵列的反转集成到PS-Rest.ps1 中,则需要使用System.Collections.Stack实例进行更多工作:

[CmdletBinding()]
Param(
  [Parameter(ValueFromPipeline = $true)]
  $Bkp
  ,
  $Id
)

begin {
  # Create a stack as an aux. data structure for output in reverse order.
  $stack = [Collections.Stack]::new()
}

process {
  if ($Bkp.Id -le $Id) {
    $stack.Push($_) # add to stack
  }
}

end {
  # Output the stack, which enumerates the elements in reverse order.
  $stack
}

然后将呼叫简化为:

$reversedResultArray = @(PS-GetBak.ps1 | PS-Rest.ps1 -Id 1004)

答案 1 :(得分:0)

好吧,我对其进行了重新设计,因此与原始版本非常接近。除了我要通过属性名称传递管道。我有点在子属性下走私arraylist。由于某种原因,PS脚本无法返回顶级数组列表。而且管道无论如何一次只能处理一个元素。并收集要删除的元素,然后在第二个循环中删除。这样,它不会中断第一个循环。另外,使用while语句也没有意义,因为删除后条件永远不会改变。

ps-getbk.ps1:

[System.Collections.Arraylist]$ArrBkp=@()

$ArrObj = New-Object psobject -Property @{Type="Full";Id=1001}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Diff";Id=1002}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Full";Id=1003}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Diff";Id=1004}
[void]$ArrBkp.Add($ArrObj)

$ArrObj = New-Object psobject -Property @{Type="Diff";Id=1005}
[void]$ArrBkp.Add($ArrObj)

[pscustomobject]@{ArrBkp=$ArrBkp}

ps-rest.ps1:

[CmdletBinding()]Param(
  [Parameter(ValueFromPipelineByPropertyName=$true)]
  $ArrBkp,
  [Parameter()]$Id
)

$ArrBkp.Reverse()

$dellist = foreach ($Bkp in $ArrBkp) {
    if ($Bkp.Id -gt $Id) {$Bkp}
}

foreach ($Bkp in $dellist) {
    $ArrBkp.remove($Bkp)
}

$ArrBkp

.\PS-GetBak.ps1 | .\PS-Rest.ps1 -Id 1004的输出

  Id Type
  -- ----
1004 Diff
1003 Full
1002 Diff
1001 Full