;; 
;;=====================================================================================----- 
;; 
;;FUNCTION       GetHbaInfo() 
;; 
;;ACTION         Gets data from all fibre channel HBA 
;; 
;;AUTHOR         Jason Dewith 
;; 
;;VERSION        1.0a - 2014/08/17 
;; 
;;HISTORY        1.0a - 2014/08/17 
;; 
;;SYNTAX         GetHbaInfo(Target) 
;; 
;;PARAMETERS     Target - OPTIONAL - String 
;;               - the target to query, null or "." for local host 
;; 
;;REMARKS        Used to pull information about the Fibre Channel HBAs installed in a host. 
;; 
;;		 Special Thanks To: Glenn Barnas for challenging me to try, this 
;;               is my first UDF. I have learned a lot this weekend. And also for writing the 
;;               ToHex() UDF, of which this UDF depends on. 
;; 
;;RETURNS        Array of Arrays - Adapter[adapterDetail] 
;;               Outer array contains array of per-adapter data, 
;;                inner array is adapter detail (below) 
;;		   0 : Model 
;;		   1 : HardwareVersion 
;;		   2 : DriverVersion 
;;		   3 : OptionRomVersion 
;;		   4 : FirmwareVersion 
;;		   5 : Drivername 
;;		   6 : Status - 0=Active; (list other states!) 
;;		   7 : Node - world wide Port Name of the Node 
;;		   8 : Port - Worlwide port names of the ports 
;; 
;;DEPENDENCIES   WMI, WwnToString(), _ToHex() (both dependent UDFs in this file 
;; 
;;TESTED WITH    W2K3, W2K8, W2K12 
;; 
;;EXAMPLES        
; 
Function GetHbaInfo(optional $_Server)
 
  Dim $_aAttr[], $_aTmp					; Array of Adapters, Attribute child array 
  Dim $_oWMIServices					; WMI Object pointer 
  Dim $_enumSetAdapters, $_oEltAdapter			; list of adapter objectss, enumerator 
  Dim $_enumSetPorts, $_oEltPort			; list of port data, enumerator 
  Dim $_nIndex						; adapter index pointer 
 
  $_Server = IIf($_Server, $_Server, '.')		; reference local host if not defined 
 
  ; Instantiate WMI, get data from queries 
  $_oWMIServices    = GetObject("winmgmts://" + $_Server + "/root/wmi")
  $_enumSetAdapters = $_oWMIServices.InstancesOf("MSFC_FCAdapterHBAAttributes")
  $_enumSetPorts    = $_oWMIServices.InstancesOf("MSFC_FibrePortHBAAttributes")
 
  $_nIndex = -1					; start with empty array pointer 
 
  ; Enumerate the adapters, gather parameters if valid instance is found 
  For Each $_oEltAdapter In $_enumSetAdapters
    For Each $_oEltPort In $_enumSetPorts
      If ($_oEltAdapter.InstanceName = $_oEltPort.InstanceName)
        ; valid instance - clear tmp array and extend Attr array 
        Dim $_aTmp[8]				; prep array for adapter values 
	$_nIndex = $_nindex +1			; increment array pointer 
        ReDim Preserve $_aAttr[$_nIndex]	; extend array for next adapter 
        $_aTmp[0] =  $_oEltAdapter.Model
        $_aTmp[1] =  $_oEltAdapter.HardwareVersion
        $_aTmp[2] =  $_oEltAdapter.DriverVersion
        $_aTmp[3] =  $_oEltAdapter.OptionROMVersion
        $_aTmp[4] =  $_oEltAdapter.FirmwareVersion
        $_aTmp[5] =  $_oEltAdapter.DriverName
        $_aTmp[6] =  $_oEltAdapter.HBAStatus
        $_aTmp[7] =  WwnToString($_oEltAdapter.NodeWWN)
        $_aTmp[8] =  WwnToString($_oEltPort.Attributes.PortWWN)
        $_aAttr[$_nIndex] = $_aTmp
      EndIf
    Next
  Next
 
  $GetHBAinfo = $_aAttr
  Exit 0
 
EndFunction
 
 
; Insure a properly formatted WWN string 
Function WwnToString($_aWWN)
 
  Dim $_I					; index counter 
 
  $WwnToString = DecToHex($_aWWN[0])
  For $_I = 1 To 7
    $WwnToString = $WwnToString + ':' + _ToHex($_aWWN[$_I])
  Next
 
  Exit 0
 
EndFunction
 
 
; Modified from the original ToHex() - no dependency on doubles in this version 
Function _ToHex($_V)
 
  Dim $_Hc					; hex charset 
  Dim $_aD[0], $_aV				; array segments 
  Dim $_Dv					; intermediate value 
  Dim $_sH					; hex string 
 
  $_Hc = '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
 
  ;If VarType($_V) <> 5 Exit 87 EndIf		; must get a double! 
 
  $_I = -1					; index pointer 
  $_Dv = 1.0					; initial value 
  While $_V > $_Dv				; determine required multipliers 
    $_I = $_I + 1
    ReDim Preserve $_aD[$_I]
    $_aD[$_I] = $_Dv
    $_Dv = 256.0 * $_Dv
  Loop
 
  ; evaluate each hex octet and convert to a hex string 
  For $_I = UBound($_aD) To 0 Step -1
    If $_V > $_aD[$_I]
      $_aV = Int($_V / $_aD[$_I])
      $_V = $_V - 1.0 * ($_aD[$_I] * $_aV)
      $_sH = $_sH + $_Hc[$_aV / 16] + $_Hc[$_aV Mod 16]
    Else
      $_sH = $_sH + '00'
    EndIf
  Next
 
  $_ToHex = $_sH
  Exit 0
 
EndFunction