How to search array of objects contains an item in another array?
Asked Answered
D

2

8

I have two arrays.

An array of objects containing Virtual Machine Information called $vms one of the attributes called Name. Here's the type:

PowerCLI > $vms.GetType()

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

I have another array imported from a CSV file called $importVMs where one of the fields is also called Name.

I want to do some work if $importVMs.Name does not exist in $vms (i.e. it doesn't match any $vms.Name). I'm wondering if I can do this with pipelining, or do I have to iterate through both arrays?

can I do something like if (! $vms | ? {$_.Name -neq $importVms.Name) { # work }

Can't seem to get it to work. Do I need to foreach the $importVms in that if condition?

EDIT

My complete script so far:

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 looks like

"Name","VmPathName","Location"
"test","[RAID5] test/test.vmx","testfolder"
Deutoplasm answered 1/8, 2014 at 16:15 Comment(0)
A
9

Use to -notin or -notcontains operator for that.

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

Alias ? used for Where, and % used for ForEach.

Ok, it that doesn't work we can try building a regex match string out of your array of current VM names, and matching each imported VM against that to see if it already exists. Try this script:

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
Appointed answered 1/8, 2014 at 16:34 Comment(3)
Hi, I believe -notin is Powershell3+? I'm using Powershell 2.Deutoplasm
Also, using -notcontains instead always results in a positive match when it shouldn't.Deutoplasm
Thanks, I had to change the if statement to if ($vm.Name -notmatch $VMNameFilter) to get it to work.Deutoplasm
H
0

Another way, which would be better used in a script:

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

The Foreach is looping through the VM names in the array $ImportVMs, putting each individual VM name from $ImportVMs in the variable $ImportVM at each loop.

Then , the "if" statement checks if the array of names in $vms doesn't contain the $ImportVM currently in the loop. If this "if" statement evaluates to true, then the script will do whatever is inside the { }. I just put { DO STUFF } here, because you didn't mention what you want to do with these VMs.

Hoosegow answered 1/8, 2014 at 18:37 Comment(4)
Second Lal, this could use some explanation. It's currently in the automated Low Quality Posts queue. I'm recommending it not be deleted, but you need to flesh it out a bit.Herein
I added some explanations to my answer.Hoosegow
I added some explanations to my answer. There is not that much to explain, this is just a basic Foreach loop with an "If" statement inside of it. For the basics on Foreach in Powershell , I would recommend this article : blogs.technet.com/b/heyscriptingguy/archive/2014/04/28/…Hoosegow
If I use Foreach ($ImportVm in $ImportVms.name) then I don't get access to other properties of $ImportVm such as $ImportVm.VmPathName in the execute script block. If I use Foreach ($ImportVm in $ImportVms) then the if condition always matches (when it shouldn't).Deutoplasm

© 2022 - 2024 — McMap. All rights reserved.