如何使用PSv2在PSobjects数组中搜索特定对象键

时间:2016-12-09 14:00:48

标签: arrays powershell powershell-v2.0

我有一个对象数组。我想搜索数组以确定$ obj.NewName中是否存在特定值。如果值是唯一的,则将值放在$ obj.NewName中。如果确实存在,则递增值并再次搜索,直到该值为唯一。

Function CreateObject ($origionalName)
{
    $newName = $null
    $obj = $null

    $obj = New-Object PSObject
    $obj | Add-Member -type NoteProperty -Name OrigionalName -Value $origionalName
    $obj | Add-Member -type NoteProperty -Name NewName -Value $newName
    Return ($obj)
}

Function Get-NewPatchName ($patch)
{
    $patch.OrigionalPatchName.split("-") | Foreach {
        ## Pipelined string is $_.  Check if it starts with "KB".
        If ($_.substring(0,2) -like "kb" ) 
        {
            ## This create the new name based on the substring containing "KB...", and adds the existing file extension.
            $tempName = $_

            ## If there is a version number in the original file name, include that in the new name
            If ($patch.OrigionalPatchName -like "*-v*") 
            {
                $intPosition = ($patch.OrigionalPatchName.ToUpper()).IndexOf("-V")
                $tempName += ($patch.OrigionalPatchName.substring($intPosition+1,2))
            }

            ## Determine if name is unique
            {
                ## STUCK HERE!!!!!!!!!!
            }
        }
    }
}

$patchList = @()
$nameList = "AMD64-all-windows6.0-kb2900986-x64_63", `
            "AMD64-all-windows6.0-kb3124275-x64_57", `
            "AMD64-all-windows6.0-kb2900986-x64_63" 

Foreach ($name in $nameList){
    $patchList += CreateObject $name }

Foreach ($patch in $patchList) {
    Get-NewPatchName $patch }

Foreach ($patch in $patchList) {
    Write-Host "Origional Patch Name: " $patch.OrigionalName
    Write-Host "New Patch Name      : " $patch.NewName
}

预期结果:

Origional Patch Name:  AMD64-all-windows6.0-kb2900986-x64_63
New Patch Name      :  kb2900986
Origional Patch Name:  AMD64-all-windows6.0-kb3124275-x64_57
New Patch Name      :  kb3124275
Origional Patch Name:  AMD64-all-windows6.0-kb2900986-x64_63
New Patch Name      :  kb2900986a

我会将$ origionalName处理为它的kb#,例如:

$tempName = "kb2900986"

然后我想看看$ patchName在任何$ patch.newName下的patchList中是否已存在。如果是,那么我会将$ tempName增加到

$tempName = "kb2900986a"

再次运行搜索。一旦$ tempName是唯一的

$patch.newName = $tempName

我已经想出如何处理和增加$ tempName。我只是停留在如何搜索$ patchList以确定$ tempName当前是否存在任何$ patch.newName。

2 个答案:

答案 0 :(得分:0)

我正在假设您正在使用更新版本的PS,这将不会在PS2中工作,因为它使用了一些有点粗糙的新版本shell的功能你要解决的任务要容易得多。下面的代码将出现在您使用评论标识的区域。

if($patchlist.newname -contains $tempname){
  *do whatever you need to do if the list already contains the name*
} else {
  *do whatever you need to do if the list doesn't contain the name*    
}

这使用了powershell功能,该功能将自动访问.newname数组中每个项目的$patchlist属性,并在调用$patchlist.newname时将其显示为自己的值数组我相信在PS3中引入了有趣的数组功能。我还要通过传递补丁列表(最好使用不同的名称)来确保你的函数保持原子性,但这并不是必需的。

PS2版本

$templist = foreach($name in $patchlist){
  $name.NewName
}
if($templist -contains $tempname){
  *do whatever you need to do if the list already contains the name*
} else {
  *do whatever you need to do if the list doesn't contain the name*    
}

这适用于任何版本的powershell,它没有完全优化(为每次迭代创建$ templist数组)但它可以工作,如果你需要额外的速度,你可以根据需要进行更改

答案 1 :(得分:0)

Mike Garuccio's helpful answer包含解决方案的重要指示。

这是一个惯用的PowerShell v2 +解决方案,它还简化了问题中的代码:

# Convert an array of patch names to custom objects containing
# an .OriginalName property with the input patch name, and a yet-to-be-assigned
# .NewName property.
Function CreateObjects ([string[]] $originalNames)
{
  foreach ($name in $originalNames) {
    [pscustomobject] @{ OriginalName = $name; NewName = $null }
  }
}

# Assign a unique name to the .NewName property of all input objects.
Function Set-NewPatchNames ([pscustomobject[]] $patches)
{
    # Initialize an aux. hashtable in which we'll keep track of the unique 
    # new names assigned so far.
    $htNewNames = @{}
    foreach ($patch in $patches) {
      # Extract the KB number from the original name.
      # Note: For brevity, the "-v" version-number extraction mentioned in the 
      #       question is skipped. 
      $newNameCandidate = $patch.OriginalName -replace '.*-kb(\d+).*', '$1'
      # Is the candidate for the new name unique?
      if ($htNewNames.Contains($newNameCandidate)) { # Name already used.
        # Find a unique variation of the name.
        $rootName = $newNameCandidate
        # Loop and append 'a', 'b', ... until a unique name is found.
        # Note: With more than 26 duplicates, you'll run out of letters, 
        #       at which point seemingly random Unicode chars. will be used.
        $suffixCharCode = ([int] [char] 'a') - 1
        do {
          ++$suffixCharCode
          $newNameCandidate = $rootName + [char] $suffixCharCode
        } while ($htNewNames.Contains($newNameCandidate))
      }
      # Assign the new name and record it in the hashtable of names used so far. 
      $patch.NewName = $newNameCandidate
      $htNewNames.Add($newNameCandidate, $null)
    }
}

# The input list of patch names.
$nameList = "AMD64-all-windows6.0-kb2900986-x64_63",
            "AMD64-all-windows6.0-kb3124275-x64_57",
            "AMD64-all-windows6.0-kb2900986-x64_63" 

# Create a collection of custom objects with the original patch name
# stored in .OriginalName, and a yet-to-be-filled .NewName property.
$patchList = CreateObjects $nameList

# Fill the .NewName properties with unique names.
Set-NewPatchNames $patchList

# Output the resulting objects.
$patchList

在PSv5.1中,这会产生(代码 在PSv2中正常工作,但输出的可读性稍差):

OriginalName                          NewName 
------------                          ------- 
AMD64-all-windows6.0-kb2900986-x64_63 2900986 
AMD64-all-windows6.0-kb3124275-x64_57 3124275 
AMD64-all-windows6.0-kb2900986-x64_63 2900986a