Question

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"
Was it helpful?

Solution

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

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top