PowerShell Script to provision storage to a VMware vSphere

advertisement

<#

PowerShell Script to provision storage to a VMware vSphere datastore cluster

Requires

_____________________________

1. EMC Storage Integrator 2.1

2. VMware PowerCLI 5.1

3. Solutions Enabler 7.6

4. Windows PowerShell

_____________________________

Authored by Cody Hosterman

July 2013

#>

#Initial setup

Set-ExecutionPolicy RemoteSigned -force

<#

IMPORTANT:Configure these variables: These are the only values the scripts needs hard-coded prior to running.

-------------------------------------------------------------------------

-------------------------------------

Descriptions:

-dsCluster is the name of the VMware datastore cluster

-SElocality indicates whether the Solutions Enabler server is local or remote

-SEserver is the value configured in the local Solutions Enabler netcnfg file. Refer to SE Install Guide for info. Only needed if SE locality is

REMOTE

-SEinstall is the location of the netcnfg file. Indicate the FULL path of the file.

-scriptpath defines where temporary files and logs should go.

-viserver is the name/IP of the vCenter. If a name is used it must be resolvable.

-viuser is a login username for the vCenter

-vipassword is the password for viuser

-dsprefix is the desired name for the to-be-created datastore, a random number between 5 and 200 will be appended

-symmsn is the serial number of the array to be configured for ESI cmdlet operations. Use the full SN with leading zeroes (e.g. 000195701238). This will be matched against the existing datastores serial number and if it doesn't match the script will fail

-SMISserver is the IP/name of the SMI-S server. If a name is used it must be resolvable.

-SMISuser is the username for the SMI-S server

-SMISpwd is the password for the above SMI-S user

-------------------------------------------------------------------------

--------------------------------------

#>

$dsCluster = "VMAX1238"

$SElocality = "REMOTE"

$SEserver = "SMIS"

$SEinstall = "C:\Program Files\EMC\SYMAPI\config\netcnfg"

$scriptpath = "c:\pshell\"

$viserver = "ch-srm51-1"

$viuser = "ebc\hostec"

$vipassword = "Password

$dsprefix = "VMAX_DS"

$symmsn = "000195701238"

$SMISserver = "10.10.82.65"

$SMISuser = "admin"

$SMISpwd = "#1Password"

<#

Note that this script assumes a SSL connection to SMI-S over port 5989

(default).

If non-default port is desired edit the values for "Port" and "UseSSL" in section "Connect to SMI-S server with EMC ESI cmdlets"

Also note the script assumes the built-in ECOM user account system is in use for SMI-S (default) and not Windows Authentication.

If Windows Authentication is configured on the SMI-S server, edit the value "UseWindowsAuth" in section "Connect to SMI-S server with EMC ESI cmdlets"

#> cd $scriptpath

#create log file "PS-Script-mmddhhmmss.log"

$logfile = get-date -uformat '%m%d%H%M%S'

$logfile = "PS-Script-" + $logfile + ".log"

"Log file created... Starting script" |set-content $logfile

Function log-file ($input)

{

$timestamp = get-date

$timestamp = "$timestamp" + "-->"

$timestamp |add-content $logfile

$input |add-content $logfile

$input

}

$ErrorActionPreference = 'Stop' trap

{

"An error has occurred. Cleaning up connections and ending script..." |log-file

$_ |log-file

"Disconnecting vCenter Server connection..." |log-file disconnect-VIServer $viserver -confirm:$false

"SUCCESS: vCenter Server connection is terminated" |log-file

"Disconnecting ESI cmdlets vCenter Server connection..." |log-file

$vCenter | Disconnect-EmcHostSystem -force

"SUCCESS: vCenter Server ESI cmdlets connection is terminated"

|log-file

"Disconnecting ESI cmdlets SMI-S connection..." |log-file

$symmarray | Disconnect-EmcStorageSystem -force

"SUCCESS: SMI-S ESI cmdlets connection is terminated" |log-file exit 1

}

#Import ESI cmdlets

"Importing ESI PowerShell toolkit..." |log-file import-module “C:\Program Files\emc\EMC Storage

Integrator\ESIPSToolKit\ESIPSToolkit”

"SUCCESS: ESI PowerShell toolkit imported" |log-file

#Import VMware PowerCLI

"Importing VMware PowerCLI..." |log-file

Add-PSSnapin VMware.VimAutomation.Core set-PowerCLIConfiguration -invalidCertificateAction "ignore" confirm:$false |log-file

"SUCCESS: PowerCLI imported" |log-file

#Connect to vCenter server with PowerCLI

"Connecting PowerCLI to vCenter Server..." |log-file

Connect-VIServer -Server $viserver -User $viuser -Password $vipassword

|log-file

"SUCCESS: Connected PowerCLI to vCenter server " + $viserver + " with user account " + $viuser + "." |log-file

#Connect to vCenter server with EMC ESI cmdlets

"Connecting ESI PowerShell cmdlets to vCenter Server..." |log-file

$vCcreds =

@{"UserFriendlyName"="MyHost";"UseCurrentDomainCredential"="False";"Usern ame"="$viuser";"Password"="$vipassword";"IsCluster"="False";"Server"="$vi server"}

$vCenter = Connect-EMCSystem -SystemType "VMware" -CreationParameters

$vCcreds

"SUCCESS: Connected ESI PowerShell cmdlets to vCenter server " +

$viserver + " with user account " + $viuser + "." |log-file

#Connect to SMI-S server with EMC ESI cmdlets

"Connecting ESI PowerShell cmdlets to SMI-S server..." |log-file

$SMISCreds =

@{"UserFriendlyName"="Symmetrix";"SerialNumber"="$symmSN";"Host"="$SMISse rver";"Port"="5989";"UseSSL"="True";"UseWindowsAuth"="False";"Username"="

$SMISuser";"Password"="$SMISpwd";"IgnoreServerCACheck"="True";"IgnoreServ erCNCheck"="True"}

$symmarray = Connect-EMCSystem -SystemType "VMAX" -CreationParameters

$SMISCreds

"SUCCESS: Connected ESI PowerShell cmdlets to SMI-S server " +

$SMISserver + " and found " + $symmarray.Name + " " +

$symmarray.SerialNumber |log-file

"Working Path is " + $scriptpath |log-file

"Solutions Enabler Server is " + $SElocality |log-file

"Solutions Enabler connection name is " + $SEserver |log-file

"Datastore Cluster is " + $dsCluster |log-file

#Testing Solutions Enabler and checking for correct Symmetrix array

"Verifying presence of connection " + $SEserver + " in SYMAPI netcnfg file."|log-file

IF (test-path $SEinstall)

{

"SUCCESS: Netcnfg file location [" + $SEinstall + "] verified."

|log-file

}

ELSE

{

"FAILED: Provided netcnfg file location [" + $SEinstall + "] is invalid. Please verify location of file or that Solutions Enabler is installed. Exiting..." |log-file throw "File not found."

}

$netcnfg = Get-Content $SEinstall | where-object {$_ -notmatch "#"}

IF ($netcnfg| select-string $SEserver)

{

"SUCCESS: Local SYMAPI netcnfg file contains a connection named " +

$SEserver + "." |log-file

}

ELSE

{

"FAILED: Local SYMAPI netcnfg file is not configured with a connection named " + $SEserver + ". Exiting..." |log-file throw 'Connection not found'

}

#Configuring Solutions Enabler connection variables

$SElocality = "set SYMCLI_CONNECT_TYPE=" + $SElocality

$SEserver = "set SYMCLI_CONNECT=" + $SEserver

"Connecting to Solutions Enabler and checking presence of " +

$symmarray.Name + " " + $symmarray.SerialNumber |log-file

$SElocality | set-content checkSE.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content checkSE.cmd}

'symcfg discover' | add-content checkSE.cmd

'symcfg list -sid ’ + $symmarray.SerialNumber + ' >>checkSE.txt' | addcontent checkSE.cmd

./checkSE.cmd |log-file

IF (get-content checkSE.txt| select-string $symmarray.SerialNumber)

{

"SUCCESS: Solutions Enabler connectivity to Symmetrix array " +

$symmarray.SerialNumber + " confirmed." |log-file

}

ELSE

}

{

"FAILED: Solutions Enabler connectivity to Symmetrix array " +

$symmarray.SerialNumber + " failed. Array not present. Please verify SE host configuration. Exiting..." |log-file rm checkSE.txt rm checkSE.cmd throw 'Array not found' rm checkSE.txt rm checkSE.cmd

<#

Find datastore in cluster

Uses PowerCLI to find a datastore name in the cluster (stores as $ds01)

Then the Symm dev ID (stores as $deviceID) using a text response file and

ESI cmdlets

#>

"Getting existing datastore Symmetrix device ID..." |log-file get-emcstoragesystem |update-emcsystem |log-file

Get-Datastore -relatedobject $dsCluster | format-table -property name | out-file DS.txt

$ds01 = (get-content DS.txt -totalcount 4)[-1]

$ds01 = $ds01 | Foreach {$_.TrimEnd()}

$deviceID = get-emcdatastore -id $ds01 |get-emclun

$deviceID = $deviceID.ArrayLunID rm DS.txt

"SUCCESS: Found existing datastore " + $ds01 + " which is on Symmetrix device " + $deviceID |log-file

<#

Find Symm Serial Number

Gets the SN from the device backing that datastore identified in previous step. Parses it from the text file

#>

"Finding Symmetrix Serial Number of device " + $deviceID + "..."|log-file

$symmID = get-emcdatastore -id $ds01 |get-emclun | get-emcstoragesystem

$symmID = $symmID.SerialNumber

"SUCCESS: Device " + $deviceID + " is on Symmetrix " + $symmID |log-file

#Comparing Symmetrix Serial Number of datastore to SN in SMI-S connection

IF ($symmID -eq $symmSN)

{

"SUCCESS: Serial number of Symmetrix array containing datastore " +

$ds01 + " matches the SN of SMI-S array" |log-file

}

ELSE

{

"FAILED: Serial number of Symmetrix array containing datastore " +

$ds01 + " does not match the SN of array configured in the SMI-S connection. Exiting..." |log-file throw "Mismatched arrays"

}

<#

Find pool of that datastore

Finds the pool object ($pool1) via ESI cmdlets and pool name ($poolID) via text response file

#>

"Finding pool of device " + $deviceID + "..."|log-file

$pool1 = get-emcdatastore -id $ds01 |get-emclun |get-emcstoragepool

$poolID = $pool1.Name

"SUCCESS: Device " + $deviceID + " is on pool " + $poolID |log-file

<#

Identify Meta

This section identifies if the existing device is a metavolume.

Creates a CMD file that starts a Solutions Enabler sesssion to a remote

SE server

If device is meta, config checks are run (meta config, meta member count)

#>

"Checking if device " + $deviceID + " is a metavolume..." |log-file

$SElocality | set-content checkmeta.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content checkmeta.cmd}

'symdev show ’ + $deviceID + ‘ -sid ' + $symmid + ' |find "Meta Stripe

Size" >>devconfig.txt' | add-content checkmeta.cmd

./checkmeta.cmd |log-file

$metadecision = get-content devconfig.txt rm devconfig.txt rm checkmeta.cmd

if ($metadecision -like '*Meta Stripe Size*')

{

#Find number of members

#Runs symdev show and parses columns/rows to find meta member number. Creates and removes two files to do so

#Creates $metacount to store number of members

"Device " + $deviceID + " is a metavolume." |log-file

"Checking number of members in metavolume..." |log-file

$SElocality | set-content checkmeta.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content checkmeta.cmd}

'symdev show ’ + $deviceID + ‘ -sid ' + $symmid + ' |find "Meta

Device Members" >>devconfig.txt' | add-content checkmeta.cmd

./checkmeta.cmd |log-file

$metacount =get-content devconfig.txt | Foreach {"$(($_ -split

'\s+',5)[4..4])"} | Foreach {"$(($_ -split '\s+',3)[0..0])"}

$metacount = $metacount -replace "\(", ''

$metacount = $metacount -replace "\)", '' rm devconfig.txt rm checkmeta.cmd

"SUCCESS: Metavolume has " + $metacount + " members." |log-file

#Find meta configuration

#Runs symdev show and parses columns/rows to find if meta is striped/concatenated. Creates and removes two files to do so

#Creates $metaconfig to store configuration

"Checking metavolume configuration..." |log-file

$SElocality | set-content checkmeta.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content checkmeta.cmd}

'symdev show ’ + $deviceID + ‘ -sid ' + $symmid + ' |find "Meta

Configuration" >>devconfig.txt' | add-content checkmeta.cmd

./checkmeta.cmd |log-file

$metaconfig = get-content devconfig.txt

IF ($metaconfig -like "*Striped*"){ $metaconfig="striped"} ELSE

{$metaconfig="concatenated"} rm devconfig.txt rm checkmeta.cmd

"SUCCESS: Metavolume is " + $metaconfig |log-file

}

ELSE

{

"Device " + $deviceID + " is not a metavolume." |log-file

}

#Finds size

#Runs symdev show and parses columns/rows to find size. Creates and removes two files to do so

#Creates $size to store size in MB

"Finding size of device..." |log-file

$SElocality | set-content checkdev.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content checkdev.cmd}

'symdev show ’ + $deviceID + ‘ -sid ' + $symmid + ' |find "MegaBytes"

>>devsize.txt' | add-content checkdev.cmd

./checkdev.cmd |log-file

$size = (get-content devsize.txt -totalcount 2)[-1] | Foreach {"$(($_ split '\s+',4)[3..4])"} rm devsize.txt rm checkdev.cmd

"SUCCESS: Device is " + $size + " MB." |log-file

#If device is a meta will divide the size by the member count to get member size if ($metadecision -like '*Meta Stripe Size*')

{ file

"Since device is a metavolume, calculating member size..." |log-

$size = ($size / $metacount)

$size = "{0:N0}" -f $size

$size = $size -replace ",",""

"SUCCESS: Device member size is " + $size + " MB, this size will be used for device creation." |log-file

}

#Create LUN with ESI cmdlets if ($metadecision -like '*Meta Stripe Size*')

{

"Creating new metavolume head device..." |log-file

}

ELSE

{

"Creating new device..." |log-file

}

$capacity = "$size" + "MB"

$newlun='$lun = new-emclun -pool $pool1' + " -capacity " + $capacity invoke-expression $newlun

#Find Symm device ID

$lunID = $lun.ArrayLunId

"SUCCESS: New Symmetrix device " + $lunID + " was created and bound to thin pool " + $poolID + " on Symmetrix " + $symmID |log-file if ($metadecision -like '*Meta Stripe Size*')

{

#Create meta members

"Creating " + ($metacount-1) + " additional Symmetrix devices for meta members..." |log-file

$SElocality | set-content createdevs.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content createdevs.cmd}

'symconfigure -cmd "create dev count=' + ($metacount-1) + ', size='

+ $size + 'mb, config=tdev, emulation=fba, dynamic_capability =dyn_rdf;"

-v commit -nop -sid ' + $symmid + ' >>devs.txt' |add-content createdevs.cmd

./createdevs.cmd |log-file rm createdevs.cmd

$members = get-childitem devs.txt | select-string -pattern "New symdevs:" | foreach {$_.line} | Foreach {"$(($_ -split '\s+',7)[3..3])"}

"SUCCESS: Created " + ($metacount-1) + " additional Symmetrix devices (" + $members + ") for meta members." |log-file

#Form meta

"Forming metavolume from head device, " + $lun + " and members, " +

$members + "..." |log-file

$SElocality | set-content formmeta.cmd

IF ($SElocality -like "*REMOTE*") {$SEserver | add-content formmeta.cmd}

IF ($metaconfig -like "*Striped*")

{

$unbind = 'symconfigure -cmd "unbind tdev ' + $lunID + ' from pool ' + $poolID + ';" -v commit -nop -sid ' + $symmid

$unbind |add-content formmeta.cmd

"Since metavolume is going to be striped, the device head must be unbound from pool first. Unbinding..." |log-file

}

'symconfigure -cmd "form meta from dev ' + $lunID + ' config=' +

$metaconfig + '; add dev ‘ + $members + ‘ to meta ' + $lunID + ';" -v commit -nop -sid ' + $symmid |add-content formmeta.cmd

IF ($metaconfig -like "*Striped*")

{

'symconfigure -cmd "bind tdev ' + $lunID + ' to pool ' +

$poolID + ';" -v commit -nop -sid ' + $symmid |add-content formmeta.cmd

}

./formmeta.cmd |log-file

"SUCCESS: Metavolume formed in a " + $metaconfig + " configuration." |log-file

IF ($metaconfig -like "*Striped*")

{

"SUCCESS: Striped metavolume rebound to pool." |log-file

} rm devs.txt rm formmeta.cmd

}

#Present volume to host ESI cmdlets

"Performing masking operation to present new device " + $lun + " to ESXi host(s)..." |log-file

$esxhost = get-emcdatastore $ds01 |get-emcesxhost set-emclunaccess -lun $lun -hostsystem $esxhost –available |log-file

"SUCCESS: Masking records updated successfully." |log-file

#Rescan cluster PowerCLI

"Rescanning ESXi host(s) using PowerCLI..." |log-file

$servers = get-vmhost |sort name foreach ($server in $servers) {get-VMHostStorage -VMHost $server –

RescanAllHba}

"SUCCESS: ESXi host(s) rescanned." |log-file

#Formatting VMFS volume

"Formatting device with VMFS5..." |log-file

$random = Get-Random -minimum 5 -maximum 201

$dsname = "$dsprefix$random"

Update-EmcSystem -emcsystem $esxhost |log-file

$scsidev= Get-EmcScsiLun -esxhostsystem $esxhost -lun $lun

New-Datastore -vmhost $servers -Name "$dsname" -Path

$scsidev.CanonicalName -Vmfs |log-file

"SUCCESS: Device " + $deviceID + " (" + $scsidev.CanonicalName + ") formatted with VMFS5 and named " + $dsname + "." |log-file

#Move datatstore into cluster PowerCLI

"Moving datastore " + $dsname + " to datastore cluster " + $dsCluster +

"..." |log-file

Get-Datastore $dsname | Move-Datastore -Destination $dsCluster

"SUCCESS: Moved datastore " + $dsname + " to datastore cluster " +

$dsCluster + "." |log-file

#Disconnect connections

"Disconnecting PowerCLI vCenter Server connection..." |log-file disconnect-VIServer $viserver -confirm:$false

"SUCCESS: vCenter Server PowerCLI connection is terminated" |log-file

"Disconnecting ESI cmdlets vCenter Server connection..." |log-file

$vCenter | Disconnect-EmcHostSystem -force

"SUCCESS: vCenter Server ESI cmdlets connection is terminated" |log-file

"Disconnecting ESI cmdlets SMI-S connection..." |log-file

$symmarray | Disconnect-EmcStorageSystem -force

"SUCCESS: SMI-S ESI cmdlets connection is terminated" |log-file

"Script complete!" |log-file

#End of script

Download