Share via


Using Powershell remoting & iSCSIcli.exe to connect your Clustered Shared Volumes

When deploying larger nubers of server with numerous volumes it's much easier and reliable to script the process. In our data center this is typically the case with large number of Hyper-V Failover Cluster nodes and the use of iSCSI Targets.

 Here's a sample of the script we use - keeping in mind that we're making Powershell Inoke-Command calls (icm as noted in the script) and have Windows Remote Management enabled:

# Making life easier by creating the iSCSI drive mappings via Powershell.

# However, the Microsoft Initiator isn't natively powershell enabled, the calls

# must be made through the command line interface of iscsicli.exe.

# This script addresses the pain involved in dealing with larger numbers of servers,

# in our data center this includes numerous Hyper-V Clusters with

# Clustered Shared Volumes where we'd have quite a lot of UI clicking to do.

### Import CSV for the list of Hostnames, Portals and Targets (volumes)

### The comma seperated file is easily managed with native powershell cmdlets.

#

### The file header includes: Hostname,Cluster,IP,InitiatorIQN,iSCSI_Portal,iSCSI_Target

### Hostname: Server Hostname, ie: "command prompt 'hostname'"

### IP: Preferred source IP for the initiator

### InitiatorIQN: Not required for the scripts, but useful as a reference

### iSCSI_Portal: IP of the target portal

### iSCSI_Target: Full IQN of the target volume

$FileName = "\\jamels-server\scripts\iscsi\VolumeMaps.csv"

# check for second argument, which would be a ServerName

# in this case we only need to execute commands for that specfic server

# rather than the entire Data Center

if($args.count -gt 1)

{

      $args[1]

      $VolumeMaps = Import-CSV $FileName

      $ServerName = $args[1]

      $VolumeMaps = $VolumeMaps | ? {$_.Hostname -ilike $ServerName}

}

else

{

      $VolumeMaps = Import-CSV $FileName

}

# Constants - if using standard target ports, the Microsoft iSCSI Initiator

# and leveraging MPIO

$iSCSI_Port = "3260"   

$iSCSI_Initiator = "Root\ISCSIPRT\0000_0"

$iSCSI_MPIO = "0x00000002"

if($args.count -eq 1)

{

      ForEach($MapItem in $VolumeMaps)

      {

            # Dynamic Variables

           

            $iSCSI_Portal = $MapItem.iSCSI_Portal

            $iSCSI_Target = $MapItem.iSCSI_Target

            $ServerName = $MapItem.HostName

           

            # Get the iSCSI Port Number for the specified IP address

            # We first convert the needed iSCSI source address to the IPv4 format within WMI

            # Then Via WMI we query into the MSiSCSI_PortalInfoClass to find the correct Interface Index Number

            # this index number will be used for several iscsicli.exe invoke-expression calls

           

            $IPAddress = [system.Net.IPAddress]$MapItem.IP

            $PortalList = get-wmiobject -ComputerName $ServerName -namespace root\wmi -query "select portalinformation from MSiSCSI_PortalInfoClass"

            $iSCSIPortID = ($PortalList.PortalInformation | ? {$_.IpAddr.IPV4Address -match $IPAddress.Address} | select port)

           

            # Always refresh the target portal list and the currently connected target volumes

           

            $Command = [scriptblock]::Create("iscsicli.exe refreshtargetportal $iSCSI_Portal $iSCSIPort")

            icm $ServerName -ScriptBlock $Command

            start-sleep 2

           

            #Verify info

            $ServerName

            $MapItem.IP

            $iSCSIPortID.Port

            $iSCSI_Portal

            $iSCSI_Target

                 

            ### Add the Target to the Favorites list, doesn't login until a reboot (reconnects for every reboot)

     

            if($args[0] -ilike "Favorites")

            {

                  $Command = [scriptblock]::Create("iscsicli PersistentLoginTarget $iSCSI_Target T $iSCSI_Portal $iSCSI_Port $iSCSI_Initiator $iSCSIPortID.Port * $iSCSI_MPIO * * * * * * * * * 0")

                  icm $Servername -ScriptBlock $Command

                  start-sleep 2

            }

           

            ### Login to the target for this session since PersistentLoginTarget Doesn't Login until reboot

     

            if($args[0] -ilike "LoginTarget")

            {

                  $Command = [scriptblock]::Create("iscsicli LoginTarget $iSCSI_Target T $iSCSI_Portal $iSCSI_Port $iSCSI_Initiator $iSCSIPortID.Port * $iSCSI_MPIO * * * * * * * * * 0")

                  icm $Servername -ScriptBlock $Command

                  start-sleep 2

            }

      }

}