param ( [parameter(Mandatory = $true, HelpMessage = "Server with SnapDrive")] [string]$server, [parameter(Mandatory = $true, HelpMessage = "Cluster Name/IP address")] [string]$Cluster, [parameter(Mandatory = $true, HelpMessage = "Storage Virtual Machine")] [string]$vserver ) if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { throw 'This script needs to be run "As Administrator"' } if (!(Get-Command sdcli -errorAction SilentlyContinue)){throw 'This script requires snapdrive for windows, and sdcli and sdcli could not be found.'} function Parse-sdcli_iscsi_initiator_list { param ($raw) $raw = $raw -split '[\r\n]' $iscsitargetinfo = @() $line = 1 while ($line -lt $raw.count) { if ($raw[$line] -like '*connected iSCSI target*' -and $raw[$line]) { #Get-WFALogger -Info -message IGNORE : $raw[$line] $line ++$line } elseif ($raw[$line] -like '*Target name:*' -and $raw[$line]) { #Get-WFALogger -Info -message TARGET : $raw[$line] $target_name = $raw[$line].trim().replace("Target name: ", "") $target_lun_count = [int]($raw[++$line].split(":")[1].trim()) $target_session_count = [int]($raw[++$line].trim().split(" ")[0]) ++$line $sessioninfo = @() while ($raw[$line] -notlike "*Target name:*" -and $raw[$line]) { #Get-WFALogger -Info -message $raw[$line] $session_id = $raw[$line].split(":")[1].trim() $line = $line + 5 $connection_count = $raw[$line++].trim().split(" ")[0] #Get-WFALogger -Info -message " " SESSION_ID : $session_id $connectioninfo = @() while ($raw[$line] -notlike "*Session ID:*" -and $raw[$line] -and $raw[$line] -notlike "*Target name:*") { $connection_id = $raw[$line].split(":")[1].trim() #Get-WFALogger -Info -message " " CONNECTION_ID : $connection_id $line = $line + 3 if ($raw[$line] -like "*Portal ID:*") { $connection_portal_id = [int]($raw[$line++].split(":")[1].trim()) } if ($raw[$line] -like "*IP address:*") { $connection_initiator_ip_address = $raw[$line].split(":")[1].trim() } $connection_initiator_ip_port = [int]($raw[++$line].split(":")[1].trim()) ++$line $connection_target_ip_address = $raw[++$line].split(":")[1].trim() $connection_target_ip_port = [int]($raw[++$line].split(":")[1].trim()) $line = $line + 2 $connectioninfo += [PSCustomObject]@{ connection_id = $connection_id initiator_portal_id = $connection_portal_id initiator_ip_address = $connection_initiator_ip_address initiator_ip_port = $connection_initiator_ip_port target_ip_address = $connection_target_ip_address target_ip_port = $connection_target_ip_port } } $sessioninfo += [PSCustomObject]@{ session_id = $session_id connection_count = $connection_count connection_info = $connectioninfo } } $iscsitargetinfo += [PSCustomObject]@{ target = $target_name lun_Count = $target_lun_count session_count = $target_session_count session_info = $sessioninfo } } else { ++$line } } return $iscsitargetinfo } function Parse-sdcli_sysconfig_list { param ($raw) $raw = $raw -split '[\r\n]' $line = 0 $config_info = @() $sd_version = $raw[$line].trim() while ($raw[++$line] -notlike '*driver*' -and $raw[$line]) { #Get-WFALogger -Info -message $line $raw[$line] if ($raw[$line] -like '*Virtual machine datastore type:*') { $VM_datastore_type = $raw[$line].split(':')[1].trim() } elseif ($raw[$line] -like '*ESX VERSION:*') { $ESXVersion = $raw[$line].split(':')[1].trim() } elseif ($raw[$line] -like '*Machine name:*') { $machine_name = ($raw[$line].split(':'))[1].trim() } elseif ($raw[$line] -like '*MPIO is*') { $mpio_state = ($raw[$line].trim().replace("MPIO is ", "").trim()) } elseif ($raw[$line] -like '*Available drive letters:*') { $available_drives = $raw[$line].trim().replace("Available drive letters: ", "") } } if ($raw[$line] -like '*1 driver*') { $line = $line + 3 $iSCSI_initiator = $raw[$line].replace("iSCSI initiator:", "").trim() $line = $line + 2 $iSCSI_HBA_ID = [int]($raw[$line].split(":")[1].trim()) $iSCSI_HBA_name = $raw[++$line].split(":")[1].trim() ++$line $iSCSI_portal_count = [int]($raw[++$line].trim().replace(" portals(s):", "")) $iscsi_portal = @() while ($raw[++$line] -like '*Portal ID*') { $iscsi_portal += [PSCustomObject]@{ Portal_ID = [int]($raw[$line].split(":")[1].trim()) IP_Address = $raw[++$line].split(":")[1].trim() } } } $config_info = [PSCustomObject]@{ machine_name = $machine_name sd_version = $sd_version VM_datastore_type = $VM_datastore_type ESX_Version = $ESXVersion mpio_state = $mpio_state available_drives = $available_drives iscsi_initiator = $iSCSI_initiator iSCSI_HBA_ID = $iSCSI_HBA_ID iSCSI_HBA_Name = $iSCSI_HBA_name iSCSI_portal_count = $iSCSI_portal_count iscsi_portals = $iscsi_portal } return $config_info } function Get-BroadcastAddress { param ( [IpAddress]$ip, [IpAddress]$Mask ) $IpAddressBytes = $ip.GetAddressBytes() $SubnetMaskBytes = $Mask.GetAddressBytes() if ($IpAddressBytes.Length -ne $SubnetMaskBytes.Length) { throw "Lengths of IP address and subnet mask do not match." exit 0 } $BroadcastAddress = @() for ($i = 0; $i -le 3; $i++) { $a = $subnetMaskBytes[$i] -bxor 255 if ($a -eq 0) { $BroadcastAddress += $ipAddressBytes[$i] } else { $BroadcastAddress += $a } } $BroadcastAddressString = $BroadcastAddress -Join "." return [IpAddress]$BroadcastAddressString } function Get-NetwotkAddress { param ( [IpAddress]$ip, [IpAddress]$Mask ) $IpAddressBytes = $ip.GetAddressBytes() $SubnetMaskBytes = $Mask.GetAddressBytes() if ($IpAddressBytes.Length -ne $SubnetMaskBytes.Length) { throw "Lengths of IP address and subnet mask do not match." exit 0 } $BroadcastAddress = @() for ($i = 0; $i -le 3; $i++) { $BroadcastAddress += $ipAddressBytes[$i] -band $subnetMaskBytes[$i] } $BroadcastAddressString = $BroadcastAddress -Join "." return [IpAddress]$BroadcastAddressString } function Test-IsInSameSubnet { param ( [IpAddress]$ip1, [IpAddress]$ip2, [IpAddress]$mask ) $Network1 = Get-NetwotkAddress -ip $ip1 -mask $mask $Network2 = Get-NetwotkAddress -ip $ip2 -mask $mask return $Network1.Equals($Network2) } Connect-WfaCluster $Cluster #Get LIFs to compare to what is configured. $lifs = Get-NcNetInterface -DataProtocols 'iscsi' -Vserver $vserver $vserver_iscsi_service = Get-NcIscsiService -vserver $vserver Get-WFALogger -Info -message ("Target: "+$vserver_iscsi_service.nodename) #Get iSCSI Configs off the Server $sd_sysconfig = Parse-sdcli_sysconfig_list (sdcli sysconfig list -m $server) $initiator_list = Parse-sdcli_iscsi_initiator_list (sdcli iscsi_initiator list -s -m $server) #Figure out which HBA Portals have an IP address on the Same subnet, and use those IP(s) for new sessions. $portalstouse = @() foreach ($portal in $sd_sysconfig.iscsi_portals) { if (Test-IsInSameSubnet -ip1 $portal.ip_address -ip2 $lifs[0].address -mask $lifs[0].netmask) { $portalstouse += $portal } } #Check to see if the target already has an existing connection. If So, let's do the update process. $initiator_to_eval = $initiator_list | Where-Object { $_.target -eq $vserver_iscsi_service.NodeName } if ($initiator_to_eval) { #Check to find if there are missing targets from the current configuration, and fix it foreach ($lif in $lifs) { if ($initiator_to_eval.session_info.connection_info.target_ip_address -notcontains $lif.address) { Get-WFALogger -Info -message ("Need to add " + $lif.address) Get-WFALogger -Info -message ("sdcli iscsi_initiator establish_session -m " + $server + " -h " + $sd_sysconfig.iSCSI_HBA_ID + " -hp " + $portalstouse.Portal_ID + " -t " + $vserver_iscsi_service.nodename + " -np " + $lif.address + " 3260") $output = sdcli iscsi_initiator establish_session -m $server -h $sd_sysconfig.iSCSI_HBA_ID -hp $portalstouse.Portal_ID -t $vserver_iscsi_service.nodename -np $lif.address 3260 | out-string Get-WFALogger -Info -message ($output) } } } else #Add each LIF without checking { foreach ($lif in $lifs) { Get-WFALogger -Info -message ("Need to add " + $lif.address) $output = sdcli iscsi_initiator establish_session -m $server -h $sd_sysconfig.iSCSI_HBA_ID -hp $portalstouse.Portal_ID -t $vserver_iscsi_service.nodename -np $lif.address 3260 | out-string Get-WFALogger -Info -message ("sdcli iscsi_initiator establish_session -m "+$server+" -h "+$sd_sysconfig.iSCSI_HBA_ID+" -hp "+$portalstouse.Portal_ID+" -t "+$vserver_iscsi_service.nodename+" -np "+$lif.address+" 3260") Get-WFALogger -Info -message ($output) } }