【问题标题】:How to search array of objects contains an item in another array?如何搜索对象数组包含另一个数组中的项目?
【发布时间】:2014-09-24 21:47:56
【问题描述】:

我有两个数组。

包含名为$vms 的虚拟机信息的对象数组,其中一个属性名为Name。这是类型:

PowerCLI > $vms.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

我从名为 $importVMs 的 CSV 文件导入了另一个数组,其中一个字段也称为 Name。

如果$importVMs.Name 在$vms 中不存在(即它不匹配任何$vms.Name),我想做一些工作。我想知道我是否可以通过流水线来做到这一点,还是必须遍历两个数组?

我可以做类似if (! $vms | ? {$_.Name -neq $importVms.Name) { # work }的事情

似乎无法让它工作。我需要foreach $importVms 在那个if 条件下吗?

编辑

到目前为止我的完整脚本:

Connect-VIServer -Server vCenter -Protocol https -Force | out-null
$importVms = Import-Csv vCenterVMs.csv
$VMHost = "esxi"
$currentVms = Get-VM
Write-Host "Current registered VMs" -ForeGroundColor Cyan
$currentVMs

Write-Host "Saved VMs to import" -ForeGroundColor Yellow
$importVms

$registered = @()
Write-Host "Importing VMs..." -ForeGroundColor White
#$importVms | ?{$_.Name -notcontains $currentVms}

foreach ($vm in $importVms) {
    if (! $currentVms.Name -contains $vm) {
        Write-Host "Importing $($vm.Name)"
        # put in a try block here
        $registeredVM = New-VM -VMFilePath $vm.VmPathName -VMHost $VMHost -Location $vm.Location
        $registeredList += $registeredVM.Name
    }
}

$registeredList
Disconnect-VIServer -Server * -Confirm:$false

vCenterVMs.csv 看起来像

"Name","VmPathName","Location"
"test","[RAID5] test/test.vmx","testfolder"

【问题讨论】:

    标签: powershell powershell-2.0 vmware powercli


    【解决方案1】:

    使用 to -notin 或 -notcontains 操作符。

    $importvms | ?{$_.Name -notin $vms.name} | %{ Do Stuff }
    

    别名? 用于Where,% 用于ForEach。

    好的,它不起作用,我们可以尝试从您当前的 VM 名称数组中构建一个正则表达式匹配字符串,然后将每个导入的 VM 与之匹配以查看它是否已经存在。试试这个脚本:

    Connect-VIServer -Server vCenter -Protocol https -Force | out-null
    $importVms = Import-Csv vCenterVMs.csv
    $VMHost = "esxi"
    $currentVms = Get-VM
    Write-Host "Current registered VMs" -ForeGroundColor Cyan
    $currentVMs
    
    Write-Host "Saved VMs to import" -ForeGroundColor Yellow
    $importVms
    
    $registered = @()
    Write-Host "Importing VMs..." -ForeGroundColor White
    #$importVms | ?{$_.Name -notcontains $currentVms}
    
    $VMNameFilter = "($(($currentVms|%{[RegEx]::Escape($_.Name)}) -join "|"))"
    
    foreach ($vm in $importVms) {
        if (! $vm.Name -match $VMNameFilter) {
            Write-Host "Importing $($vm.Name)"
            # put in a try block here
            $registeredVM = New-VM -VMFilePath $vm.VmPathName -VMHost $VMHost -Location $vm.Location
            $registeredList += $registeredVM.Name
        }
    }
    
    $registeredList
    Disconnect-VIServer -Server * -Confirm:$false
    

    【讨论】:

    • 嗨,我相信 -notin 是 Powershell3+?我正在使用 Powershell 2。
    • 另外,使用-notcontains 总是会在不应该的情况下产生正匹配。
    • 谢谢,我必须将 if 语句更改为 if ($vm.Name -notmatch $VMNameFilter) 才能使其正常工作。
    【解决方案2】:

    另一种方式,在脚本中使用会更好:

    Foreach ($ImportVm in $ImportVms.name) { 
    if ($vms.name -notcontains $ImportVm) {
    DO STUFF }
    }
    

    Foreach 循环遍历数组 $ImportVMs 中的 VM 名称,在每个循环中将 $ImportVMs 中的每个单独的 VM 名称放入变量 $ImportVM 中。

    然后,“if”语句检查 $vms 中的名称数组是否不包含当前循环中的 $ImportVM。 如果这个“if”语句的计算结果为真,那么脚本将执行 { } 内的任何操作。 我只是把 { DO STUFF } 放在这里,因为你没有提到你想用这些虚拟机做什么。

    【讨论】:

    • 第二个拉尔,这可以使用一些解释。它目前在自动低质量帖子队列中。我建议不要删除它,但你需要充实一下。
    • 我在回答中添加了一些解释。
    • 我在回答中添加了一些解释。没有太多要解释的,这只是一个基本的 Foreach 循环,里面有一个“If”语句。对于 Powershell 中 Foreach 的基础知识,我推荐这篇文章:blogs.technet.com/b/heyscriptingguy/archive/2014/04/28/…
    • 如果我使用Foreach ($ImportVm in $ImportVms.name),那么我无法在执行脚本块中访问$ImportVm 的其他属性,例如$ImportVm.VmPathName。如果我使用Foreach ($ImportVm in $ImportVms),那么if 条件总是匹配(当它不应该匹配时)。
    猜你喜欢
    • 2023-01-19
    • 1970-01-01
    • 2017-03-12
    • 2012-07-23
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多