如何搜索包含另一个数组项的对象数组?

8

我有两个数组。

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

PowerCLI > $vms.GetType()

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

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

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

我能否做出类似于以下的事情:if (! $vms | ? {$_.Name -neq $importVms.Name) { # work }

似乎无法让其正常工作。在该if条件中,我需要对$importVms进行foreach操作吗?

编辑

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

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"
2个回答

9
请使用-notin或-notcontains运算符来实现此功能。
$importvms | ?{$_.Name -notin $vms.name} | %{ Do Stuff }

Alias ? 用于 Where% 用于 ForEach

如果那样不起作用,我们可以尝试将您当前虚拟机名称数组构建为正则表达式匹配字符串,并将每个导入的虚拟机与其进行匹配,以查看它是否已经存在。请尝试使用此脚本:

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。 - Mark Allison
此外,使用-notcontains总是会产生正匹配,而实际上并不应该这样。 - Mark Allison
1
谢谢,我不得不将 if 语句更改为 if ($vm.Name -notmatch $VMNameFilter) 才能使其正常工作。 - Mark Allison

0

另一种更适合在脚本中使用的方法:

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

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

然后,“if”语句检查 $vms 中的名称数组是否不包含当前循环中的 $ImportVM。 如果此“if”语句计算为 true,则脚本将执行 { } 内的任何操作。 我在这里只是放置了 { DO STUFF },因为您没有提到您想要对这些 VM 进行什么操作。


第二个Lal,这需要一些解释。它目前在自动化的低质量帖子队列中。我建议不要删除它,但您需要稍微详细说明一下。 - Kelderic
我在我的回答中添加了一些解释。 - Mathieu Buisson
我在我的答案中添加了一些解释。 没有太多可以解释的,这只是一个带有一个“if”语句的基本Foreach循环。 关于Powershell Foreach的基础知识,我建议阅读这篇文章: http://blogs.technet.com/b/heyscriptingguy/archive/2014/04/28/basics-of-powershell-looping-foreach.aspx - Mathieu Buisson
如果我使用 Foreach ($ImportVm in $ImportVms.name),那么在执行脚本块时我将无法访问 $ImportVm 的其他属性,例如 $ImportVm.VmPathName。如果我使用 Foreach ($ImportVm in $ImportVms),则 if 条件始终匹配(但实际上不应该)。 - Mark Allison

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接