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

How to search an array of PSobjects for a specific objects key using PSv2

我有一组对象。我想搜索数组以确定 $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"

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

$tempName = "kb2900986a"

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

$patch.newName = $tempName

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

我假设您使用的是 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 功能,该功能将自动访问 $patchlist 数组中每个项目的 .newname 属性 并将其显示为自己的数组我相信调用 $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 数组)但它有效,如果您需要额外的速度,您可以根据需要进行更改

包含指向解决方案的重要指示。

这是一个惯用的 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+).*', ''
      # 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