9

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"

2 Answers 2

10

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
Sign up to request clarification or add additional context in comments.

3 Comments

Hi, I believe -notin is Powershell3+? I'm using Powershell 2.
Also, using -notcontains instead always results in a positive match when it shouldn't.
Thanks, I had to change the if statement to if ($vm.Name -notmatch $VMNameFilter) to get it to work.
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.

4 Comments

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.
I added some explanations to my answer.
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/…
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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.