Tuesday, December 3, 2024

VMware ESXi PowerCLI Setup Script for Port groups, VLANs, VMkernel ports and iSCSI

If you are like me, you are these days trying to automate as much as possible. It is just the best way to go since it makes it much easier to be consistent and uniform across the board. If you have a new VMware ESXi cluster you are standing up, creating a PowerCLI setup script is a great way to automatically create VLANs, VMkernel ports, and iSCSI configurations.

PowerCLI to the rescue

In case you didn’t know, VMware PowerCLI is the VMware-specific PowerShell module that allows you to interact with the APIs on a VMware ESXi host directly or a vCenter Server. Using PowerCLI, you can automate just about anything you want, including creating your port groups, VLANs, VMkernel ports, and iSCSI configuration.

Generic VMware ESXi PowerCLI Setup Script for Port groups, VLANs, VMkernel ports, and iSCSI

Let’s take a look at a generic script that will allow you to pluin your ESXi hosts in your vSphere cluster, and then populate these with the information needed for configuring things like port groups, VLAN tags, VMkernel ports, and iSCSI software adapter, etc.

vmware esxi powercli setup script running
vmware esxi powercli setup script running

The sections are pretty explanatory with the comments, but below is a high-level overview:

  • Define the hostnames and IP addresses for things like the vMotion networks, iSCSI networks
  • Define which vmnics are backing the vSwitch0 configuration and setting these to active
  • Create a new vSwitch1 for vMotion01 and iSCSI01 networks
  • Create a new vSwitch2 for vMotion02 and iSCSI02 networks
  • Set jumbo frames where needed
  • Set up NTP to point to an NTP server
  • Add the iSCSI Software Adapter
# Define hostnames and IPs with the updated network configuration
$esxiHosts = @(
    @{Name = "esxiHost01.local"; vMotion01 = "192.168.1.1"; vMotion02 = "192.168.2.1"; iSCSI01 = "172.16.1.1"; iSCSI02 = "172.16.2.1"},
    @{Name = "esxiHost02.local"; vMotion01 = "192.168.1.2"; vMotion02 = "192.168.2.2"; iSCSI01 = "172.16.1.2"; iSCSI02 = "172.16.2.2"},
    @{Name = "esxiHost03.local"; vMotion01 = "192.168.1.3"; vMotion02 = "192.168.2.3"; iSCSI01 = "172.16.1.3"; iSCSI02 = "172.16.2.3"}
)

foreach ($esxiHostConfig in $esxiHosts) {
    $esxHost = Get-VMHost -Name $esxiHostConfig.Name

    # Ensure vSwitch0 exists
    $vSwitch0 = Get-VirtualSwitch -VMHost $esxHost -Name "vSwitch0" -ErrorAction SilentlyContinue
    if ($vSwitch0 -eq $null) {
        # If vSwitch0 doesn't exist, create it with vmnic2 and vmnic4
        $vSwitch0 = New-VirtualSwitch -VMHost $esxHost -Name "vSwitch0" -Nic "vmnic2","vmnic4"
    } else {
        # Add vmnic2 and vmnic4 to vSwitch0 if they are not already present
        $currentNics = $vSwitch0.Nic
        $requiredNics = @("vmnic2", "vmnic4")
        $missingNics = $requiredNics | Where-Object { $_ -notin $currentNics }

        foreach ($nic in $missingNics) {
            $nicObject = Get-VMHostNetworkAdapter -VMHost $esxHost -Name $nic -Physical
            if ($nicObject) {
                Add-VirtualSwitchPhysicalNetworkAdapter -VirtualSwitch $vSwitch0 -VMHostPhysicalNic $nicObject
            }
        }
    }

    # Ensure NIC teaming policy is correctly set for vSwitch0
    Get-VirtualPortGroup -VMHost $esxHost -VirtualSwitch $vSwitch0 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive "vmnic2","vmnic4" -MakeNicUnused "vmnic0" -FailbackEnabled:$false

    # Add Port Groups to vSwitch0 with VLAN tags for VM connectivity
    $portGroups = @(
        @{Name = "Mgmt-VLAN10"; VlanId = 10},
        @{Name = "App-VLAN20"; VlanId = 20},
        @{Name = "DB-VLAN30"; VlanId = 30},
        @{Name = "Web-VLAN40"; VlanId = 40},
        @{Name = "Backup-VLAN50"; VlanId = 50},
        @{Name = "Storage-VLAN60"; VlanId = 60}
    )

    foreach ($pg in $portGroups) {
        if (-not (Get-VirtualPortGroup -VMHost $esxHost -Name $pg.Name -ErrorAction SilentlyContinue)) {
            New-VirtualPortGroup -VirtualSwitch $vSwitch0 -Name $pg.Name -VLanId $pg.VlanId
        }
    }

    # Create vSwitch1 for iSCSI01 and vMotion01 with jumbo frames backed by vmnic3
    $vSwitch1 = Get-VirtualSwitch -VMHost $esxHost -Name "vSwitch1" -ErrorAction SilentlyContinue
    if ($vSwitch1 -eq $null) {
        $vSwitch1 = New-VirtualSwitch -VMHost $esxHost -Name "vSwitch1" -Nic "vmnic3" -Mtu 9000
    }

    # Create Port Groups on vSwitch1 without VLAN tags (access ports)
    if (-not (Get-VirtualPortGroup -VMHost $esxHost -Name "vmotion01" -ErrorAction SilentlyContinue)) {
        New-VirtualPortGroup -VirtualSwitch $vSwitch1 -Name "vmotion01"
    }
    if (-not (Get-VirtualPortGroup -VMHost $esxHost -Name "iscsi01" -ErrorAction SilentlyContinue)) {
        New-VirtualPortGroup -VirtualSwitch $vSwitch1 -Name "iscsi01"
    }

    # Create VMKernel Ports on vSwitch1 (Corrected VirtualSwitch parameter)
    New-VMHostNetworkAdapter -PortGroup "vmotion01" -VirtualSwitch $vSwitch1.Name -IP $esxiHostConfig.vMotion01 -SubnetMask 255.255.255.0 -VMHost $esxHost -Mtu 9000
    New-VMHostNetworkAdapter -PortGroup "iscsi01" -VirtualSwitch $vSwitch1.Name -IP $esxiHostConfig.iSCSI01 -SubnetMask 255.255.255.0 -VMHost $esxHost -Mtu 9000

    # Create vSwitch2 for iSCSI02 and vMotion02 with jumbo frames backed by vmnic5
    $vSwitch2 = Get-VirtualSwitch -VMHost $esxHost -Name "vSwitch2" -ErrorAction SilentlyContinue
    if ($vSwitch2 -eq $null) {
        $vSwitch2 = New-VirtualSwitch -VMHost $esxHost -Name "vSwitch2" -Nic "vmnic5" -Mtu 9000
    }

    # Create Port Groups on vSwitch2 without VLAN tags (access ports)
    if (-not (Get-VirtualPortGroup -VMHost $esxHost -Name "vmotion02" -ErrorAction SilentlyContinue)) {
        New-VirtualPortGroup -VirtualSwitch $vSwitch2 -Name "vmotion02"
    }
    if (-not (Get-VirtualPortGroup -VMHost $esxHost -Name "iscsi02" -ErrorAction SilentlyContinue)) {
        New-VirtualPortGroup -VirtualSwitch $vSwitch2 -Name "iscsi02"
    }

    # Create VMKernel Ports on vSwitch2 (Corrected VirtualSwitch parameter)
    New-VMHostNetworkAdapter -PortGroup "vmotion02" -VirtualSwitch $vSwitch2.Name -IP $esxiHostConfig.vMotion02 -SubnetMask 255.255.255.0 -VMHost $esxHost -Mtu 9000
    New-VMHostNetworkAdapter -PortGroup "iscsi02" -VirtualSwitch $vSwitch2.Name -IP $esxiHostConfig.iSCSI02 -SubnetMask 255.255.255.0 -VMHost $esxHost -Mtu 9000
	
	# Remove vmnic0 from vSwitch0
    if ($currentNics -contains "vmnic0") {
		Get-VMhost $esxHost | Get-VMHostNetworkAdapter -Physical -Name "vmnic0" | Remove-VirtualSwitchPhysicalNetworkAdapter -Confirm:$false
    }

    # Configure NTP
    $ntpServers = "pool.ntp.org"
    $ntpConfig = Get-VMHostNtpServer -VMHost $esxHost
    if ($ntpConfig) {
        Remove-VMHostNtpServer -VMHost $esxHost -NtpServer $ntpConfig -Confirm:$false
    }
    Add-VMHostNtpServer -VMHost $esxHost -NtpServer $ntpServers
    Get-VMHostService -VMHost $esxHost | Where-Object { $_.Key -eq "ntpd" } | Start-VMHostService
    Get-VMHostService -VMHost $esxHost | Where-Object { $_.Key -eq "ntpd" } | Set-VMHostService -Policy "on"
	
	# Enable Software iSCSI Adapter
    Get-VMHostStorage -VMHost $esxHost | Set-VMHostStorage -SoftwareIScsiEnabled $true
    Write-Host "iSCSI Software Adapter enabled on host: $($esxiHostConfig.Name)"

    # Retrieve iSCSI HBA name
    $iscsiHBA = Get-VMHostHba -VMHost $esxHost -Type iScsi | Where-Object { $_.Model -eq "iSCSI Software Adapter" }	
}

Adding a section to add your iSCSI bindings as well

If you want to add your iSCSI bindings to your cluster hosts, you can do that with something like the following code:

foreach ($hostConfig in $hosts) {
    $vmHost = Get-VMHost -Name $hostConfig.Name

    # Enable Software iSCSI Adapter
    Get-VMHostStorage -VMHost $vmHost | Set-VMHostStorage -SoftwareIScsiEnabled $true
    Write-Host "iSCSI Software Adapter enabled on host: $($hostConfig.Name)"

    # Retrieve iSCSI HBA name
    $iscsiHBA = Get-VMHostHba -VMHost $vmHost -Type iScsi | Where-Object { $_.Model -eq "iSCSI Software Adapter" }

    if ($iscsiHBA) {
        $iScsiHbaName = $iscsiHBA.Device

        # Sets up PowerCLI to be able to access esxcli commands
        $esxcli = Get-EsxCli -VMHost $vmHost -V2

        try {
            # Binds VMKernel ports created earlier to the iSCSI Software Adapter HBA
            $bindParams1 = @{
                adapter = $iScsiHbaName
                nic     = "vmk2"  # Replace with the appropriate VMkernel adapter name
                force   = $true
            }
            $esxcli.iscsi.networkportal.add.Invoke($bindParams1)
            Write-Host "VMKernel port 'vmk2' bound to iSCSI Software Adapter on host: $($hostConfig.Name)"
        } catch {
            Write-Host "Error binding VMKernel port 'vmk2' on host $($hostConfig.Name): $_"
        }

        try {
            # Binds another VMKernel port to the iSCSI Software Adapter HBA
            $bindParams2 = @{
                adapter = $iScsiHbaName
                nic     = "vmk4"  # Replace with the appropriate VMkernel adapter name
                force   = $true
            }
            $esxcli.iscsi.networkportal.add.Invoke($bindParams2)
            Write-Host "VMKernel port 'vmk4' bound to iSCSI Software Adapter on host: $($hostConfig.Name)"
        } catch {
            Write-Host "Error binding VMKernel port 'vmk4' on host $($hostConfig.Name): $_"
        }
    } else {
        Write-Host "No iSCSI Software Adapter found on host: $($hostConfig.Name)"
    }
}

Wrapping up

As you can see with the code we have demonstrated here, you can take basically configured ESXik hosts outside of having a hostname and IP address for connectivity in vCenter server, and then configure these with port groups, vSwitches, VLAN tags, jumbo frames, iSCSI storage adapter, NTP configuration, and even add the actual iSCSI bindings to each server. Pretty cool. Let me know if you have something similar worked up for your environment.

Brandon Lee
Brandon Leehttps://tek2cloud.com
Brandon Lee is the Senior Writer, Engineer and owner at tek2Cloud.com and has over two decades of experience in Information Technology. Brandon holds multiple industry certifications and loves IT automation, modern applications, and cloud technologies along with traditional servers and infrastructure.

Leave a Reply

Read more

Other Posts