VMware Cloud Community
bansne
Enthusiast
Enthusiast

Filter output for specific vlans

Hi @LucD ,

Hope you are doing well. I need small help from you .

I am trying to get list of vm's inside specific vlan but for some reason csv shows repetetive output.For exapmle on console output i see vlan 123 got vmabc but in csv i get same entry for vmabc twice/thrice.

 

Following is my code i am trying to run. All i am after is list of vms (even if not connected to n/w but part of vlan123) in the csv output just once.

 
$VCServer = "vc123","vc235","vc987"
$ReportExport = "/tmp/"
$vcUser = "admin"
$vcPass = "xxxx"
$VLANs = "1234","5678","0986"
$connectedVMCsvPath = "/tmp/list.csv"
$migrationCsvPath = "/tmp/$($migrationgroup).csv"
# Get the Migration Group (change#) from the environment variable
$migrationgroup = "Group9"
 
# Initialize an empty array to store all results
$allResults = New-Object System.Collections.Generic.List[PSCustomObject]
#$allResults = New-Object System.Collections.ArrayList
 
# Define the CSV headers for connected VMs
$connectedVMHeader = "vCenter Server,VM Name,VM IP Address,PowerState,PortGroup"
$connectedVMCsv = New-Object System.Collections.ArrayList
 
# Define the CSV headers for migration list
$migrationHeader = "VM_Name,MIGRATION_GROUP"
$migrationCsv = New-Object System.Collections.ArrayList
 
 
function Get-VMsForVLAN {
    param (
        [string]$VCServer,
        [string]$VLAN
    )
 
    if ($?) {
        Write-Host "Connected to $VCServer"
 
        $portGroups = Get-VDPortgroup | Where-Object { $_.Name -like "*$VLAN*" }
 
 
        foreach ($port in $portGroups) {
            Write-Host "Found VLAN $($port); Proceeding with checking of VMs" -foreground green
 
            $networks = Get-View -ViewType Network -Property Name -Filter @{"Name" = $($port.name)}
            $networks | ForEach-Object {
                ($_.UpdateViewData("Vm.Name", "Vm.Runtime.PowerState", "Vm.Guest.IPAddress"))
            }
 
            foreach ($network in $networks) {
                $vms = $network.LinkedView.Vm
 
                if ($vms) {
                    foreach ($vm in $vms) {
                        $vmName = $vm.Name
                        $existingEntry = $results | Where-Object { $_.'VM Name' -eq $vmName -and $_.'VLAN Name' -eq $vlan }
 
                        if ($existingEntry) {
                            # VM entry already exists for this VM and VLAN, skip adding it
                            continue
                        }
 
                        $connectedVMRow = [PSCustomObject]@{
                            'vCenter Server' = $VCServer
                            'VLAN Name'      = $vlan
                            'VM Name'        = $vmName
                            'VM IP Address'  = ($vm.Guest.IPAddress | Where-Object { $_ -match '^10\.' }) -join ", "
                            'PowerState'     = $vm.Runtime.PowerState
                            'PortGroup'      = $network.Name
                        }
                        $null = $connectedVMCsv.Add($connectedVMRow)
 
                        # Print VM information when found
                        Write-Host "VM Name: $($connectedVMRow.'VM Name'), Power State: $($connectedVMRow.PowerState), IP Address: $($connectedVMRow.'VM IP Address')" -foreground cyan
                        $migrationRow = [PSCustomObject]@{
                            'VM_Name'         = $vm.Name
                            'MIGRATION_GROUP' = $MIGRATIONGROUP
                        }
                        $null = $migrationCsv.Add($migrationRow)
                    }
                }
            }
        }
        # Do not disconnect here
        return $results
    }
    else {
        Write-Warning "Error connecting to vCenter Server $VCServer"
        return $null
    }
}
 
function Get-UniqueVMs {
    param (
        [array]$results
    )
 
    $uniqueVMs = @{}
 
    foreach ($result in $results) {
        $vmName = $result.VMName
 
        if ($uniqueVMs.ContainsKey($vmName)) {
            $uniqueVM = $uniqueVMs[$vmName]
            $uniqueVM.PortGroup += ", " + $result.PortGroup
        }
        else {
            $uniqueVMs[$vmName] = $result
        }
    }
 
    return $uniqueVMs.Values
}
 
foreach ($server in $VCServer) {
    Connect-VIServer -Server $server -User $vcUser -Password $vcPass -ErrorAction SilentlyContinue
    if ($?) {
        Write-Host "Connected to $server"
    }
    else {
        Write-Warning "Error connecting to vCenter Server $server"
        continue
    }
 
    foreach ($vlan in $VLANs) {
        Write-Host "Running for VLAN: $vlan on vCenter Server: $server"
 
        $vmResults = Get-VMsForVLAN -VCServer $server -VLAN $vlan
        $uniqueVMResults = Get-UniqueVMs -results $vmResults
            # Add unique VM entries to the results
    foreach ($uniqueVMResult in $uniqueVMResults) {
    $null = $allResults.Add($uniqueVMResult)  # Adding to $allResults only once
    }
 
}
 
    # Convert ArrayList to arrays before exporting to CSV
    $connectedVMArray = $connectedVMCsv.ToArray()
    $migrationArray = $migrationCsv.ToArray()
 
 
    # Output the CSV data for connected VMs
    if ($connectedVMArray.Count -gt 0) {
Write-Host "Exporting connected VMs to CSV..."
        $connectedVMArray | Export-Csv -Path $connectedVMCsvPath -NoTypeInformation -Append
    }
    else {
        Write-Output "No virtual machines found on vCenter: $server"
    }
 
    # Output the CSV data for migration list
    if ($migrationArray.Count -gt 0) {
        $migrationArray | Export-Csv -Path $migrationCsvPath -NoTypeInformation -Append
    }
    else {
        Write-Output "No virtual machines found on vCenter: $server"
    }
 
    # Disconnect from vCenter Server at the end of processing all VLANs
     Write-Host "##[warning] Disconnecting from vCenterServer: $server" -ForegroundColor Red
     Disconnect-VIServer -Server $server -Confirm:$false
Start-Sleep -Seconds 10
}
 
 

 

Reply
0 Kudos
6 Replies
LucD
Leadership
Leadership

Could this be because you are Appending  to the CSV without initialising it at the start of the script?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
fannol
Enthusiast
Enthusiast

Here is another script for almost or maybe the same purpose as yours, though it is slightly easier to track/troubleshoot.

The migrationGroup variable is commented out. Uncomment it (on both locations) in order to have it in the same CSV report.

 

 

# Define the variables here
$vCenter = "vcenter0.local","vcenter1.local","vcenter2.local"
$VLAN = "123","321"
$ReportExportCSVFile = "C:\report.csv"
$vCenterUser = "user1"
$vCenterPassword = "Password123"
#$migrationgroup = "Group9"

# Set the powercli configuration DefaultVIServer to Multiple, so that you can work with all vCenters at once
Set-PowerCLIConfiguration -Scope Session -DefaultVIServerMode Multiple -Confirm:$false

# Connect to all vCenters. If it can't, stop the command.
try{
    Connect-VIServer -Server $vCenter -User $vCenterUser -Password $vCenterPassword
}
catch{
    break
}

# Function that will find all VMs on a specific vlan
function Get-VMsForVLAN {
    param([int]$vlanID)

    # Get all distributed port groups accross all vCenters
    $VDPortGroups = Get-VDPortgroup | Where { $_.VlanConfiguration.VlanId -eq $vlanID}

    $networks = @()
    foreach($vlanName in $VDPortGroups){
        $networks += Get-View -ViewType Network -Property Name -Filter @{"Name" = $($vlanName.name)}
    }

    $networks | ForEach-Object {
        ($_.UpdateViewData("Vm.Name", "Vm.Runtime.PowerState", "Vm.Guest.IPAddress"))
    }

    # Create an empty array
    $VMsForVLanResult = @()
    foreach($VDPG in $networks){
        # Find the vCenter where that PG resides.
        $PGvCenter = (($VDPG.Client.ServiceUrl -split "//")[1] -split "/")[0]

        # Get all VMs that use that PG in that particular vCenter
        if($VDPG.LinkedView.Vm.Name){
            $VMsInPG = $VDPG.LinkedView.Vm
        }
        else{
            continue
        }

        foreach($VMPG in $VMsInPG){
            # Build a hash table with all the necessary information
            $props = [ordered]@{}
            $props.'vCenter' = $PGvCenter
            $props.'VM' = $VMPG.Name
            $props.'PowerState' = $VMPG.Runtime.PowerState
            #$props.'MigrationGroup' = $migrationgroup
            $props.'PortGroup' = $VDPG.Name
            $props.'VLAN' = $vlanID
            $props.'IP' = $VmPG.Guest.IPAddress
            
            # Store it in the Array defined above
            $VMsForVLanResult += New-Object -TypeName PScustomObject -Property $props  
        }
    }
    # When all VPGs are processed, return the result.
    return $VMsForVLanResult
}

# Store the information into a Variable
$VLANResult = $VLAN | ForEach-Object {Get-VMsForVLAN -vlanID $_}

# Print the result in the console
$VLANResult | ft -AutoSize

# Export the result to a CSV.
$VLANResult | Export-Csv -NoTypeInformation -Path $ReportExportCSVFile

# Disconnect from all vCenters
Disconnect-VIServer -Server * -Force -Confirm:$false

 

 

 

Blog: PowerCli.net
Reply
0 Kudos
bansne
Enthusiast
Enthusiast

@fannol 

thanks for the reply but it would work if vm in vlan but in broken state, it will only show one which are healthy 🙂

Tags (1)
Reply
0 Kudos
bansne
Enthusiast
Enthusiast

but i am initializing it 

$connectedVMCsv = New-Object System.Collections.ArrayList
$migrationCsv = New-Object System.Collections.ArrayList 

or i missed something 😕 

Reply
0 Kudos
fannol
Enthusiast
Enthusiast

What do you mean with "broken state"? Which part of the script shows you the VMs that are in broken state? Can you elaborate a little bit?

 

Blog: PowerCli.net
Reply
0 Kudos
miladmeh8
Hot Shot
Hot Shot

what is broken state?

Reply
0 Kudos