iSCSI, iscsicli, and WMI, Oh My!

I have been doing a lot of work with clustering Hyper-V lately and our storage is all iSCSI. Without going into all the gory details, iSCSI supports multipathing. My iSCSI SAN has two heads, each head has 3 NIC’s. On my Hyper-V hosts, we have two NIC’s that are used for iSCSI. Each NIC has a “target” for each IP on each head. Some quick math and you realize that’s a lot of connections, and a pain the butt to configure when you have a ton of nodes using this configuration. So naturally I started looking at scripting and didn’t find any cmdlets to work with iSCSI. However, there is a tool called ISCSICLI.

To add a an iSCSI target you can use the QAddTargetPortal command. Assuming your SAN’s iSCSI IP address is 192.168.168.10 you would use this command

iscsicli QAddTargetPortal 192.168.168.10

That’s fine, but what if you want to specify a source IP Address. This is pretty straight forward using the iSCSI Control Panel. In advanced settings you can choose both the “Microsoft iSCSI initiator” and the Initiator IP.

image

It turns out QAddTarget is “Quick Add Target” which gives you very few options. You can also use AddTargetPortal.

image

So there are a few things you should know. TargetPortalAddress is the IP address of the SAN you are connecting to. TargetPortalSocket is not really the socket, but just the port number, which is typically 3260. Normally a socket consists of an IP Address and a port number. The HBA name actually refers to Initiator Adapter. In this case it would be “Microsoft iSCSI Initiator.” Finally we get to the Port Number. It turns out that this port number is what is mapped to a source IP Address. The problem was that I could not find any documentation telling me how this port number was associated with an IP address on the server. At first I thought it might be the index of an interface, but quickly learned that was not the case, as you could have multiple IP’s on one interface anyway.

When something doesn’t show up in the GUI, I go exploring with WMI and PowerShell. It turns out there is a ton of iSCSI info buried in the root\wmi namespace

image

Looking around I found a msIScsi_portalinfoclass.

image

The PortalInformation property looked like it had some good info in it as well so I went digging into that.

image

Sweet! I see IPAddr and a port number. This looks promising. But when I crack open IPAddr I don’t see what I was expecting to see

image

Seriously.. since when is 1865687562 an IP V4 address? I was so close and then remembered that there is an IPAddress type in System.Net. Let’s just test something out here.

image

Woo Hoo! Given this I can now write my Get-IscsiPortNumber function in PowerShell.

001
002
003
004
005
006
007
Function Get-IscsiPortNumber {
$query = "select portalinformation from MSiSCSI_PortalInfoClass" 
$portalInfo = get-wmiobject -namespace root\wmi -query $query
$eScriptBlock ={([Net.IPAddress]$_.ipaddr.IPV4Address).IPAddressToString}
$customLabel = @{Label="IpAddress"; expression = $eScriptBlock}
$portalInfo.portalInformation | select port,$customlabel
}

Now that we have that info, we can use it in our iscsicli command

iscsicli addtargetportal 192.168.168.10 3260 ROOT\ISCSIPRT\0000_0 2 * * * * * * * * * *

Oh yeah, the ROOT\ISCSIPRT\0000_0 means MS Iscsi Initiator. There are some login flags as well that you would probably want to set for multipath as well.

image

So if your port number is 2 the final command would be

iscsicli addtargetportal 192.168.168.10 3260 ROOT\ISCSIPRT\0000_0 2 * 0x2 * * * * * * * *