PowerShell String Manipulation and ESXi IP Addresses
One of my customers is migrating a lot of ESXi hosts (with a strong naming convention) from one network onto a new network with a pre-defined IP Addressing scheme based around fully populated HP C7000 blade enclosures (containing 16 blades). The host naming convention is <Site>-<Enclosure ID>-ESX<Blade Slot Number>.<FQDN>. Based on this, I've been tasked with automating as much of this migration as possible, and part of that is automatically assigning the new IP Addresses to the blades.
In order to do this, I'm using the new-vmhostnetworkadapter cmdlet. That cmdlet will need several parameters in order to work:
-virtualswitch
-portgroup
-IP
-subnetmask
Most of these are trivial, as they will be constant for every host in the environment. The big exception to that statement is the IP address parameter. As I said earlier though, due to the strong naming convention at this site we can derive the host's new IP address entirely from information contained within the hostname. For example, an ESXi host named SITE-enc1-esx1.customer.com would be assigned 192.168.100.1 as its IP Address (we're not using .1 as the gateway on this network). Site-enc1-esx15.customer.com would be assigned 192.168.100.15. SITE-enc2-esx2.customer.com would be assigned 192.168.100.18. So, by simply multiplying the enclosure ID - 1 by 16 and adding it to the slot number, I can determine the final octet of the assigned IP address.
That sounds a little confusing, and it is, but it breaks down clearly enough. Let's look at an example: SITE-enc2-esx11.customer.com; 192.168.100.27. The enclosure ID is 2. 2-1 is 1. 1 * 16 is still 16. The blade number is 11. Add that to the previous total and you get 27.
So, now that I've figured out how to calculate the final octet for my servers, how do I actually get that out of the hostname? String manipulation. This is another one of those situations where I've sacrificed human readability in favor of being able to paste a single line into my PowerCLI window, but here's the string that will output the correct IP Address for any host using that naming convention (as long as the SITE ID doesn't have an X in it):
"192.168.100.$([int]($_.name.substring($_.name.indexof('enc')+3,1)-1)*16+[int]($_.name.split('.')[0].split('x')[1]))"
What all is going on there? The first bit is plain enough; it's just the network portion of the IP address. The final octet is where it gets interesting. I put the whole rest of it within a $( ) in order to tell PowerShell to interpret this code despite it being contained within a string. I used single quotes for all of my manipulations because Notepad++'s syntax highlighting is imperfect. PowerShell is smart enough for you to use double quotes on all of the split("x") commands, but the odd syntax highlighting in NPP startles me.
I cast the first section within the $( ) as an integer; otherwise, PowerShell performs string operations instead of math operations. That integer section (all the way until I cast the next integer) is where I deal with the enclosure ID from the string. It searches the name for the start of "enc", then grabs a single character substring starting 3 characters after that point (so that it only grabs the single digit number that follows the "enc" string). Once that number is isolated (a 2 in our example), it subtracts 1 from it and multiplies that by 16.
The next section is also cast as an integer. It simply splits the hostname into an array using the "." as a delimiting character, allowing me to easily grab strip away the FQDN so that my blade ID is now the last one or two characters in the string. Since none of the site IDs have an "x" in them, I took a bit of a shortcut and just did the same thing again, splitting that string using "x" as the delimiting character. By grabbing the second element of that array, I was able to isolate just the blade number.
I then add those two numbers together (the 16 from the first section and the 11 from the second section) in order to get 27, which is the final octet number that I'm looking for. If you're curious, here's the full new-vmhostnetworkadapter command that I'm using:
get-vmhost | foreach {$_ | new-vmhostnetworkadapter -virtualSwitch (get-vdswitch "Management") -portGroup "vlan100_vmk" -ip "192.168.100.$([int]($_.name.substring($_.name.indexof('enc')+3,1)-1)*16+[int]($_.name.split('.')[0].split('x')[1]))" -subnetMask 255.255.255.0 | set-vmhostnetworkadapter -ManagementTrafficEnabled:$true -confirm:$false}
After the new interface is created, I pipe that into set-vmhostnetworkadapter in order to turn on Management traffic through that interface.
Messing around with ESXi host IP Addressing can be dangerous; I've posted this tip for educational purposes (and for my own notes). Please be very careful before running any commands in your environment and always test thoroughly.
In order to do this, I'm using the new-vmhostnetworkadapter cmdlet. That cmdlet will need several parameters in order to work:
-virtualswitch
-portgroup
-IP
-subnetmask
Most of these are trivial, as they will be constant for every host in the environment. The big exception to that statement is the IP address parameter. As I said earlier though, due to the strong naming convention at this site we can derive the host's new IP address entirely from information contained within the hostname. For example, an ESXi host named SITE-enc1-esx1.customer.com would be assigned 192.168.100.1 as its IP Address (we're not using .1 as the gateway on this network). Site-enc1-esx15.customer.com would be assigned 192.168.100.15. SITE-enc2-esx2.customer.com would be assigned 192.168.100.18. So, by simply multiplying the enclosure ID - 1 by 16 and adding it to the slot number, I can determine the final octet of the assigned IP address.
That sounds a little confusing, and it is, but it breaks down clearly enough. Let's look at an example: SITE-enc2-esx11.customer.com; 192.168.100.27. The enclosure ID is 2. 2-1 is 1. 1 * 16 is still 16. The blade number is 11. Add that to the previous total and you get 27.
So, now that I've figured out how to calculate the final octet for my servers, how do I actually get that out of the hostname? String manipulation. This is another one of those situations where I've sacrificed human readability in favor of being able to paste a single line into my PowerCLI window, but here's the string that will output the correct IP Address for any host using that naming convention (as long as the SITE ID doesn't have an X in it):
"192.168.100.$([int]($_.name.substring($_.name.indexof('enc')+3,1)-1)*16+[int]($_.name.split('.')[0].split('x')[1]))"
What all is going on there? The first bit is plain enough; it's just the network portion of the IP address. The final octet is where it gets interesting. I put the whole rest of it within a $( ) in order to tell PowerShell to interpret this code despite it being contained within a string. I used single quotes for all of my manipulations because Notepad++'s syntax highlighting is imperfect. PowerShell is smart enough for you to use double quotes on all of the split("x") commands, but the odd syntax highlighting in NPP startles me.
I cast the first section within the $( ) as an integer; otherwise, PowerShell performs string operations instead of math operations. That integer section (all the way until I cast the next integer) is where I deal with the enclosure ID from the string. It searches the name for the start of "enc", then grabs a single character substring starting 3 characters after that point (so that it only grabs the single digit number that follows the "enc" string). Once that number is isolated (a 2 in our example), it subtracts 1 from it and multiplies that by 16.
The next section is also cast as an integer. It simply splits the hostname into an array using the "." as a delimiting character, allowing me to easily grab strip away the FQDN so that my blade ID is now the last one or two characters in the string. Since none of the site IDs have an "x" in them, I took a bit of a shortcut and just did the same thing again, splitting that string using "x" as the delimiting character. By grabbing the second element of that array, I was able to isolate just the blade number.
I then add those two numbers together (the 16 from the first section and the 11 from the second section) in order to get 27, which is the final octet number that I'm looking for. If you're curious, here's the full new-vmhostnetworkadapter command that I'm using:
get-vmhost | foreach {$_ | new-vmhostnetworkadapter -virtualSwitch (get-vdswitch "Management") -portGroup "vlan100_vmk" -ip "192.168.100.$([int]($_.name.substring($_.name.indexof('enc')+3,1)-1)*16+[int]($_.name.split('.')[0].split('x')[1]))" -subnetMask 255.255.255.0 | set-vmhostnetworkadapter -ManagementTrafficEnabled:$true -confirm:$false}
After the new interface is created, I pipe that into set-vmhostnetworkadapter in order to turn on Management traffic through that interface.
Messing around with ESXi host IP Addressing can be dangerous; I've posted this tip for educational purposes (and for my own notes). Please be very careful before running any commands in your environment and always test thoroughly.
Comments
Post a Comment
Sorry guys, I've been getting a lot of spam recently, so I've had to turn on comment moderation. I'll do my best to moderate them swiftly after they're submitted,