Microsoft Virtualization Discussions

Help with Vmware Netapp script Figure out where rdms map to on a netapp filer. Small issue

TONY_UNGER
3,368 Views

I have been hacking together this script to query all Vcenter VMs raw iscsi disks and return the following in a nice little csv file which my script sort of does. I know there is some optimization needed but I will get to that later. I am pretty new to powershell so i hope i am just overlooking something

HostnameDiskIDCapacityGHD PathScsiCanonicalNameLunIDNetapp Path)
server nameHard disk 340.00255108[VMFS_RDM] servername\servername.vmdknaa.603/vol/volname/data.lun

I have one issue i hope is simple

1. When returning the GetNetappPath function value i am getting System.Object you can see that i am calling that function at the bottom of this script  $NetappPath = GetNetappPath $VMHost $VMHDLunID  When i call function SearchFilers from the GetNetappPath function it seems to return the correct value and i put in Write-Host "GetNetappPath Function: $c" in the getnetapppath function and it seems to have the correct value. It looks like i returning the value from each function correctly, does anyone see something i did wrong to cause this?

I wrote in the SearchFilers function to search each filer then return a value. I have not put in that logic yet because I have the issue with problem 1

param([string]$VC)

#################Functions##############################################

function GetNetappPath([string]$VMHost,[string]$VMHDLunID) {

$stor = get-view (Get-VMHostStorage -VMHost $VMHost)

$IscsiWWN = $stor.StorageDeviceInfo.HostBusAdapter | where {$_.GetType().Name -eq "HostInternetScsiHba"} | Select -First 1 -expandproperty IScsiName

Write-Host "Found ISCSI NAME: $IscsiWWN on Host $VMHost"

$c = SearchFilers $IscsiWWN

Write-Host "GetNetappPath Function: $c" <-------- this value contains the name of the filer which shouldn't be returning along with the path

return $c <-----------------------This return is where i am having the issue

}

function SearchFilers([string]$IscsiWWN){

connect-nacontroller servername

$Igroup = get-nalun | Get-Nalunmap | Select Name,Initiators | Where {$_.Initiators -like $IscsiWWN} | Select -First 1 -expandproperty Name

$a = get-nalunbyigroup $Igroup $VMHDLunID | Select -ExpandProperty Path

Write-Host "SearchFilers function: $a"

return $a

}

function GetLunInfo([string]$VMHost,[string]$SCSICanonicalName) {

$Lun = Get-SCSILun $SCSICanonicalName -VMHost $VMHost #(Get-VM $VMName).VMHost

$VMHDLunID = $Lun.RuntimeName.Substring($Lun.RuntimeName.LastIndexof(“L”)+1)

  return $VMHDLunID

}

#################Functions##############################################

########################

Import-Module DataONTAP

########################

If ($VC){$strVC = $VC}

ELSE{$strVC = Read-Host "What is the Vcenter hostname?"}

If (!$strVC){Write-Host "Error: Vcenter not entered";exit}

Connect-VIServer -Server $strVC           #Enter your vCenter Server

$PathtoCSV = "C:\temp\VMlunID.csv"

"Hostname,DiskID,CapacityG,HD Path,ScsiCanonicalName,LunID,Netapp Path)" > $PathtoCSV

Write-Host "This will take a bit to run"

$Disks = Get-VM | Get-HardDisk | Where {$_.DiskType -eq "RawPhysical"}

Write-Host "Finished getting disk info"

Write-Host ""

Write-Host "Figuring out lun information"

Foreach ($Disk in $Disks) {

$VMName = $Disk.Parent

$VMHDname = $Disk.Name

$VMCapacityGB = $Disk.capacityGB

$VMHDPath = $Disk.filename

$VMScsiCanonicalName = $Disk.ScsiCanonicalName

$VMHost = Get-VM $VMName | Select -ExpandProperty Host

#Write-Host $VMName,$VMHDname,$VMCapacityGB,$VMHDPath,$VMScsiCanonicalName

#LunID

Write-Host "Figuring out lun ID"

$VMHDLunID = GetLunInfo $VMHost $Disk.SCSICanonicalName

Write-Host "Figuring out Netapp Igroup Information and Path"

$NetappPath = GetNetappPath $VMHost $VMHDLunID

$Combine = $VMName,$VMHDname,$VMCapacityGB,$VMHDPath,$VMScsiCanonicalName,$VMHDLunID,$NetappPath

Write-Host "Writing $Combine"

$Combine -join "," >> $PathtoCSV

}

1 ACCEPTED SOLUTION

bsti
3,368 Views

Hi, i think your issue is in your SearchFilers function:

Change this:

connect-nacontroller servername

To  this:

connect-nacontroller servername | out-null

Connect-NaController returns an object of type NetApp.Ontapi.Filer.NaController.  One thing  that is very different about Powershell is how it handles output.  In a function, if any command you issue returns output, then the function returns it, regardless of whether you include the "return" keyword or not.  You can avoid this when it happens by either piping it to Out-Null or assigning it to a variable (e.g.   $x = Connect-NaController ...)

So your SearchFilers is actually (and I'm sure unexpectedly) returning an array of two values:

1)  THe NaController object output from your Connect-NaController cmdlet call

2)  $a, from your return $a call

View solution in original post

3 REPLIES 3

bsti
3,369 Views

Hi, i think your issue is in your SearchFilers function:

Change this:

connect-nacontroller servername

To  this:

connect-nacontroller servername | out-null

Connect-NaController returns an object of type NetApp.Ontapi.Filer.NaController.  One thing  that is very different about Powershell is how it handles output.  In a function, if any command you issue returns output, then the function returns it, regardless of whether you include the "return" keyword or not.  You can avoid this when it happens by either piping it to Out-Null or assigning it to a variable (e.g.   $x = Connect-NaController ...)

So your SearchFilers is actually (and I'm sure unexpectedly) returning an array of two values:

1)  THe NaController object output from your Connect-NaController cmdlet call

2)  $a, from your return $a call

TONY_UNGER
3,368 Views

Thank for the great explanation on functions, worked like a charm.

now i just have to add the logic for the scsi target.

TONY_UNGER
3,368 Views

Here is my working script, It is a mess and you have to hardcode runtimes names to filers in the SearchFilers function (unless someone knows how to get that from vcenter) and it is slow but it works at least for my purposes.One thing you may have to do is edit the searchfilers function to handle credentials based on your setup

I have not tested the new way i am getting the lunids but i assume it will work

param([string]$VC)
Import-Module DataONTAP
#########################
####Tony Unger

####Run from Vsphere PowerCLI
#########################


#################Functions##############################################
function GetNetappPath([string]$VMHost,[string]$VMHDLunID,[string]$RuntimeName) {
$stor = get-view (Get-VMHostStorage -VMHost $VMHost)
$IscsiWWN = $stor.StorageDeviceInfo.HostBusAdapter | where {$_.GetType().Name -eq "HostInternetScsiHba"} | Select -First 1 -expandproperty IScsiName
Write-Host "Found ISCSI NAME: $IscsiWWN on Host $VMHost"
$c = SearchFilers $IscsiWWN $RuntimeName
Write-Host "Netapp path: $c"
return $c
}

function SearchFilers([string]$IscsiWWN,[string]$RuntimeName){

switch -wildcard ($RuntimeName)
    {
       #Add all you runtime names here with what filer
        "vmhba40:C0:T0*" {$NetappFiler = "x.x.x.x"}
       
        default {Write-host "Error! determining filer - $RuntimeName not found";read-host}
    }

Write-host "Connecting to $NetappFiler"
connect-nacontroller $NetappFiler | out-null

$Igroup = get-nalun | Get-Nalunmap | Select Name,Initiators | Where {$_.Initiators -like $IscsiWWN} | Select -First 1 -expandproperty Name
$a = get-nalunbyigroup $Igroup $VMHDLunID | Select -ExpandProperty Path
Write-Host "SearchFilers function: $a"
$a = "$NetappFiler$a"
return $a
}

function GetScsiTarget([string]$VMHost,[string]$SCSICanonicalName) {
$Lun = Get-SCSILun $SCSICanonicalName -VMHost $VMHost #(Get-VM $VMName).VMHost
$RuntimeName = $Lun | Select -ExpandProperty RuntimeName
#$VMHDLunID = $Lun.RuntimeName.Substring($Lun.RuntimeName.LastIndexof(“L”)+1)
  return $RuntimeName
}

#################Functions##############################################

########################
$PathtoCSV = "C:\temp\VMlunID.csv"
########################
If ($VC){$strVC = $VC}
ELSE{$strVC = Read-Host "What is the Vcenter hostname?"}
If (!$strVC){Write-Host "Error: Vcenter not entered";exit}
Connect-VIServer -Server $strVC  #Enter your vCenter Server

#Create Header
"Hostname,DiskID,CapacityG,HD Path,ScsiCanonicalName,LunID,ESX Host,Netapp Path" > $PathtoCSV

Write-Host "Getting VM Information from Vcenter. This can take awhile based on how many VM you have"
$Disks = Get-VM | Get-HardDisk | Where {$_.DiskType -eq "RawPhysical"}
Write-Host "Completed getting VM Information from Vcenter"


Foreach ($Disk in $Disks) {

$VMName = $Disk.Parent

write-host "VM Name: $VMName"

$VMHDname = $Disk.Name

write-host "Hard drive ID: $VMHDname"

$VMCapacityGB = $Disk.capacityGB

write-host "Lun Capacity(GB): $VMCapacityGB"

$VMHDPath = $Disk.filename

write-host "RAW VMDK Path: $VMHDPath"

$VMScsiCanonicalName = $Disk.ScsiCanonicalName

write-host "$ScsiCanonicalName: $VMScsiCanonicalName"

$VMHost = Get-VM $VMName | Select -ExpandProperty Host

write-host "ESX Host: $VMHost"

$RuntimeName = GetScsiTarget $VMHost $Disk.SCSICanonicalName

write-host "RuntimeName: $RuntimeName"

$VMHDLunID = $RuntimeName.Substring($RuntimeName.LastIndexof(“L”)+1)

Write-Host "LunID: $VMHDLunID"

$NetappPath = GetNetappPath $VMHost $VMHDLunID $RuntimeName

Write-host "PathtoNetapp: $NetappPath"

$Combine = $VMName,$VMHDname,$VMCapacityGB,$VMHDPath,$VMScsiCanonicalName,$VMHDLunID,$VMHost,$NetappPath

Write-Host "Writing to $PathtoCSV"

$Combine -join "," >> $PathtoCSV

}

Public