Category Archives: PowerCLI

Quick PowerCLI for NMP/SATP changes

Had a question today about how to script a custom SATP for SolidFire systems. The attached solidfire-satp.ps1 file will create a customer SATP for SolidFire devices setting the PSP to VMW_PSP_RR with ‘iops=1’. solidfire-satp.ps1 Also, the attached fixnmp.ps1 file will change any existing devices to the appropriate PSP as well if storage was presented to the hosts before creating the custom SolidFire SATP.  fixnmp.ps1

Create datastores from output of Get-ScsiLun

I rebuild my environment often and I found myself looking for a programatic way to create datastores based on a volume name. After a fair amount of #fail I was able to get the following to work and thought I’d share in case anyone else was looking for something similar. To start, both the volume name we are looking for as well as the canonical name of the device can be found using Get-ScsiLun:
$paths = Get-ScsiLun -vmhost "esxhostIP" | Get-ScsiLunPath -Name *desktop*
This gives me the following output (abridged):
To filter out just the volume name I want to use for the datastore, this did the trick:
$datastores = $ | foreach-object {$_.split(',')[1]} | foreach-object {$_.split('.')[4]} | get-unique
Similarly, the naa device name was generated as so:
$canonicalNames = $ | foreach-object {$_.split(',')[3]} | foreach-object {$_.split('-')[1]} | get-unique
The datastores can then be built using the following:
new-datastore -vmhost $vmhost -name $datastores[$i] -Path $canonicalNames[$i] -vmfs
Full sample script:
#Format datastores based on volume name
Connect-VIServer -Server view-vcenter.vdi.sf.local -User vdi\administrator -Password [email protected]
$vmhost = "vdi1.vdi.sf.local"

#get a list of the paths available which will also show volume name and canonical (naa) device name
write-host "Getting list of paths available on $vmhost"
$paths = Get-ScsiLun -vmhost vdi1.vdi.sf.local | Get-ScsiLunPath -Name *desktop*

#from the paths, get a list of the unique volume names and naa devices
$datastores = $ | foreach-object {$_.split(',')[1]} | foreach-object {$_.split('.')[4]} | get-unique
$canonicalNames = $ | foreach-object {$_.split(',')[3]} | foreach-object {$_.split('-')[1]} | get-unique

#print out what pairings we are about to make
write-host "About to create the following datastore to canonical device pairings"
for ($i = 0; $i -lt $datastores.count; $i++) {
  write-host $datastores[$i] "<->" $canonicalNames[$i]

Read-host "Press Enter to continue or Ctrl-C to quit" | Out-Null

#Loop to create datastores matching $datastores[$i] to $canonicalNames[$i]
for ($i = 0; $i -lt $datastores.count; $i++) {

  write-host "Creating datastore" $datastores[$i] "on device" $canonicalNames[$i]
  new-datastore -vmhost $vmhost -name $datastores[$i] -path $canonicalNames[$i]

Write-Host "Done creating datastores" -ForegroundColor Green
write-host "Disconnecting from vCenter"
Disconnect-VIServer -Server * -Force -Confirm:$false
Yesterday I was having issues assigning storage to my ESXi hosts from multiple tenant accounts on my SolidFire array and I wanted to share my experience in dealing with it. In short, there are two methods for adding iSCSI targets to an ESXi system, either through dynamic discovery (send targets) or static discovery (static targets). Specifying a dynamic discovery address is the simplest (and therefore preferred  – KISS) method. With dynamic discovery the ESXi host will log into the storage virtual IP (SVIP) for SolidFire and the array will return the list of available targets the host is allowed to see. The list of available targets is limited to the account specified when configuring CHAP. (Volume Access Groups are another story for later). Screen Shot 2014-10-31 at 8.15.01 AM In my case, I have two tenant accounts I want to provision storage from for reporting purposes. I thought this would be easy, but when I tried to add the same SVIP, but with different CHAP/account credentials I ran into the following error when trying to add through PowerCLI:
New-IScsiHbaTarget : 10/27/2014 9:17:28 AM    New-IScsiHbaTarget        The specified target '' already exists.
At line:1 char:62
+ get-vmhost "vdi1.vdi.sf.local" | Get-VMHostHba -Type iScsi | New-IScsiHbaTarget  ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [New-IScsiHbaTarget], VimException
    + FullyQualifiedErrorId : Client20_StorageServiceImpl_TryValidateUniqueIScisTargetAddress_NonU
Turns out ESXi doesn’t support duplicate dynamic discovery addresses, even if the login information is different. So I fell back to trying this with multiple static discovery entries. The first entry went in fine, however, the subsequent static discovery entries (I have 22 to add to the same discovery IP) failed with the same issue. Not being able to add multiple static iSCSI entries under the same IP with “New-IscsiHbaTarget” turns out to be a limitation of PowerCLI 5.8, not ESXi itself. Therefore, I had to write a quick script leveraging $esxcli to get the job done.
#Add static iSCSI targets to hosts
$cred = get-credential
Connect-VIServer -Server view-vcenter.vdi.sf.local -credential $cred
$hosts = get-vmhost

#Define the IQNs to add
#Set $iqnprefix to cut down on length of commands
$iqnprefix = ""
$volumeNames = @("desktop01","desktop02","desktop03","desktop04","desktop05","desktop06","desktop07","desktop08","desktop09","desktop10","desktop11","desktop12","desktop13","desktop14","desktop15","desktop16","desktop17","desktop18","desktop19","desktop20")
$volumeIDs = @(2514..2530 + 2535..2537)
#Storage virtual IP for the SolidFire system
$svip = ""
$chapsecret = "j0iT18i17Vp4su&gt;r"
$account = "VDI-Desktops"

foreach ($esx in $hosts) {

write-host "Getting iSCSI adapter for host $esx"
$hba = get-vmhost $esx | Get-VMHostHba -Type iScsi | Where {$_.Model -eq "iSCSI Software Adapter"}

write-host "Setting up esxcli"
$esxcli = get-esxcli -vmhost $esx

write-host "Configuring targets on host $esx"
for ($i = 0; $i -le 19; $i++) {

$target = $iqnprefix + $volumeNames[$i] + "." + $volumeIDs[$i]
write-host "Adding static target $target"
$esxcli.iscsi.adapter.discovery.statictarget.add($hba, $svip, $target)
$$hba, $svip, $account, $null, "uni", $false, "required", $target, $chapsecret)

#Disconnect-VIServer -Server * -Force -Confirm:$false
Write-Host "Done adding static targets" -ForegroundColor Green
Screen Shot 2014-10-31 at 9.03.14 AM You can see now, the first two targets are discovered using a dynamic discovery entry and all the “desktopxx” targets are statically created by the script. This could be useful if you have different applications separated out on the SolidFire array by tenant account for reporting purposes but using the same ESXi hosts/clusters. I’m not a programmer at heart, so please excuse the crudeness of the script, especially the $volumenames array 🙂 I’m hoping that PowerCLI can be updated to allow for multiple iSCSI targets with same IP if different authentication parameters are passed. I’m looking at you @alanrenouf