# ============================================================================ # READ-ONLY INVENTORY SCRIPT # ============================================================================ # Purpose # Enumerate virtual machine network configuration across all connected # vCenters (Enhanced Linked Mode supported). # # For each VM NIC, output: # - VM name # - Guest FQDN (from VMware Tools) # - Portgroup / network name # - VLAN ID (or TRUNK for VDS trunks) # - IPv4 address # - Subnet mask # - Default gateway # # Safety # • READ-ONLY. No configuration changes are made. # • Uses Get-View exclusively to read inventory objects. # • No Set-*, Invoke-*, or Reconfig tasks. # # Data sources (important) # • NetworkName, VLAN → vCenter configuration (reliable) # • IP, Subnet, Gateway, # FQDN → VMware Tools guest data (best available) # • If VMware Tools is absent or stale, guest fields will be blank. # # Assumptions # • You are already connected to one or more vCenters. # • Enhanced Linked Mode automatically expands scope. # # ============================================================================ # ---------------------------------------------------------------------------- # BUILD VLAN LOOKUP TABLES (ONCE) # ---------------------------------------------------------------------------- # We pre-load VLAN information into hash tables so we don’t repeatedly query # vCenter while iterating VMs. This keeps the script fast and predictable. # --- Distributed vSwitch portgroups ----------------------------------------- # Key : Portgroup name # Value : VLAN ID, 'TRUNK', or 'UNKNOWN_VDS' $vdsVlanByPg = @{} Get-View -ViewType DistributedVirtualPortgroup ` -Property Name, Config.DefaultPortConfig | ForEach-Object { $name = $_.Name $vlanSpec = $_.Config.DefaultPortConfig.Vlan # Single VLAN ID if ($vlanSpec -is [VMware.Vim.VmwareDistributedVirtualSwitchVlanIdSpec]) { $vdsVlanByPg[$name] = $vlanSpec.VlanId } # VLAN trunk elseif ($vlanSpec -is [VMware.Vim.VmwareDistributedVirtualSwitchTrunkVlanSpec]) { $vdsVlanByPg[$name] = 'TRUNK' } # Anything else (rare but explicit) else { $vdsVlanByPg[$name] = 'UNKNOWN_VDS' } } # --- Standard vSwitch portgroups --------------------------------------------- # Key : Portgroup name # Value : VLAN ID $stdVlanByPg = @{} Get-View -ViewType HostSystem ` -Property Config.Network.Portgroup | ForEach-Object { foreach ($pg in $_.Config.Network.Portgroup) { # Multiple hosts can expose the same portgroup name. # We only need one VLAN ID per unique name. if (-not $stdVlanByPg.ContainsKey($pg.Spec.Name)) { $stdVlanByPg[$pg.Spec.Name] = $pg.Spec.VlanId } } } # ---------------------------------------------------------------------------- # PULL VM INVENTORY (SINGLE API CALL) # ---------------------------------------------------------------------------- # We request only the properties we actually use. This keeps Get-View fast # even in large environments. $vms = Get-View -ViewType VirtualMachine -Property ` Name, Guest.HostName, Guest.Net, Config.Hardware.Device # ---------------------------------------------------------------------------- # PROCESS EACH VM AND EACH NIC # ---------------------------------------------------------------------------- foreach ($vm in $vms) { # Guest FQDN from VMware Tools (may be null) $fqdn = $vm.Guest.HostName # Extract only virtual Ethernet adapters from the VM hardware $vmNics = $vm.Config.Hardware.Device | Where-Object { $_ -is [VMware.Vim.VirtualEthernetCard] } foreach ($vmNic in $vmNics) { # Portgroup / network name as shown on the VM NIC $networkName = $vmNic.DeviceInfo.Summary # Resolve VLAN using lookup tables $vlan = $null if ($vdsVlanByPg.ContainsKey($networkName)) { $vlan = $vdsVlanByPg[$networkName] } elseif ($stdVlanByPg.ContainsKey($networkName)) { $vlan = $stdVlanByPg[$networkName] } # Match guest network info to this NIC via MAC address # This is the only reliable join between config and guest data. $guestNic = $vm.Guest.Net | Where-Object { $_.MacAddress -eq $vmNic.MacAddress } # -------------------------------------------------------------------- # CASE 1: Guest network data exists (VMware Tools reported it) # -------------------------------------------------------------------- if ($guestNic) { $gateway = $guestNic.Gateway # A single NIC can have multiple IPs. # Emit one row per IPv4 address. for ($i = 0; $i -lt $guestNic.IpAddress.Count; $i++) { $ip = $guestNic.IpAddress[$i] # Skip IPv6 to keep output clean and predictable if ($ip -like '*:*') { continue } $mask = $null if ($guestNic.SubnetMask.Count -gt $i) { $mask = $guestNic.SubnetMask[$i] } [pscustomobject]@{ VMName = $vm.Name FQDN = $fqdn NetworkName = $networkName VLAN = $vlan IP = $ip Subnet = $mask DefaultGateway = $gateway } } } # -------------------------------------------------------------------- # CASE 2: No guest network data (Tools missing or not reporting) # -------------------------------------------------------------------- else { [pscustomobject]@{ VMName = $vm.Name FQDN = $fqdn NetworkName = $networkName VLAN = $vlan IP = $null Subnet = $null DefaultGateway = $null } } } } # ---------------------------------------------------------------------------- # Example usage: # # | Sort-Object VMName, NetworkName, IP # | Export-Csv .\vm_network_inventory.csv -NoTypeInformation # # ----------------------------------------------------------------------------