PowerCLI – Automate adding NFS Datastores to a cluster of ESX or ESXi hosts


The other day I needed to add three NFS datastores to a bunch vSphere ESX hosts in a specific cluster. Rather than go through each host in vCenter individually, adding the datastore using the Add Storage wizard, I thought I would script the process in PowerCLI and get it done in a more automated fashion. Using PowerCLI automation, this helped me save some time. I had about 7 ESX hosts to add the Datastores to, so doing this manually would have taken twice the time it took me to whip up this script and run it. Plus, this can be used in the future for other Datastores or other clusters by simply modifying the script and re-running it.


Here is the script:


# PowerCLI script to add NFS datastores to ESX/ESXi hosts in a specified Cluster
# Only does this to hosts marked as "Connected"
$hostsincluster = Get-Cluster "Cluster 1 - M" | Get-VMHost -State "Connected"
ForEach ($vmhost in $hostsincluster)
    "Adding NFS Datastores to ESX host: $vmhost"
    "1st - MER001 - NAS-SATA-RAID6 (Veeam Backups)"
    New-Datastore -VMHost $vmhost -Name "MER001 - NAS-SATA-RAID6 (Veeam Backups)" -Nfs -NfsHost -Path /share/VeeamBackup01
    "2nd - MER002 - NAS-SATA-RAID6 (ISOs)"
    New-Datastore -VMHost $vmhost -Name "MER002 - NAS-SATA-RAID6 (ISOs)" -Nfs -NfsHost -Path /share/Images01
    "3rd - MER003 - NAS-SATA-RAID6 (XenStore01)"
    New-Datastore -VMHost $vmhost -Name "MER003 - NAS-SATA-RAID6 (XenStore01)" -Nfs -NfsHost -Path /share/XenStore01
"All Done. Check to ensure no errors were reported above."


So the script above looks for ESX or ESXi hosts in a specified cluster that are in a “Connected” state – i.e. they are not disconnected in vCenter (we wouldn’t want to try add Datastores to hosts that don’t exist!). So we use the Get-Cluster cmdlet to say we are only concerned with hosts in this particular cluster (specified by the “Cluster 1 – M” name in my case. Obviously change this to the name of your cluster you will be working with.) We then use Get-VMHost -State “Connected” to list all of the hosts in this cluster that are in a connected state. In my example I had 2 x ESX hosts that were in a disconnected state, and I didn’t want to include these, so this part worked nicely. This list of hosts in then assigned to the $hostsincluster variable. We then use the ForEach loop to iterate through each host in this list of hosts and do the bit in-between the curly brackets for each host.


In my case you may notice that I am adding Datastores from the same NFS (NAS) server. They are just being mounted to different paths on the server and being given different names. I had three Datastores to add, so therefore use the New-Datastore cmlet three times for each host. You will need to adjust this to your needs – maybe you just need to add one datastore to each host, therefore remove the two extra New-Datastore cmdlet parts. Also remember to adjust the -NfsHost and -Path sections to suit your own environment.


We could improve on the above script by making it more customisable for future / others to use. Lets give that a quick go then and use variables to define everything at the top of the script. This means that the variables can be changed at the top of script without worrying too much about reading through the whole script to check for things to change. We’ll also add a Connect-VIServer cmdlet in there in case you have not already connected to your vCenter server and authenticated in your PowerCLI session that is running the script.


# PowerCLI script to add NFS datastores to ESX/ESXi hosts in a specified Cluster
# Only does this to hosts marked as "Connected"

# Define our settings
$vcserver = "vcenter01"
$clustername = "Cluster 1 - M"
$nfshost = ""
$nfspath1 = "/share/VeeamBackup01"
$nfspath2 = "/share/Images01"
$nfspath3 = "/share/XenStore01"

# Connect to vCenter server
Connect-VIServer $vcserver

# Do the work
$hostsincluster = Get-Cluster $clustername | Get-VMHost -State "Connected"
ForEach ($vmhost in $hostsincluster)
    "Adding NFS Datastores to ESX host: $vmhost"
    "1st - MER001 - NAS-SATA-RAID6 (Veeam Backups)"
    New-Datastore -VMHost $vmhost -Name "MER001 - NAS-SATA-RAID6 (Veeam Backups)" -Nfs -NfsHost $nfshost -Path $nfspath1
    "2nd - MER002 - NAS-SATA-RAID6 (ISOs)"
    New-Datastore -VMHost $vmhost -Name "MER002 - NAS-SATA-RAID6 (ISOs)" -Nfs -NfsHost $nfshost -Path $nfspath2
    "3rd - MER003 - NAS-SATA-RAID6 (XenStore01)"
    New-Datastore -VMHost $vmhost -Name "MER003 - NAS-SATA-RAID6 (XenStore01)" -Nfs -NfsHost $nfshost -Path $nfspath3
"All Done. Check to ensure no errors were reported above."

So as you can see we have now defined the name of the cluster, our NAS/NFS server and three paths to different NFS shares at the top of the script, then just referenced these variables later on in the script. This means we can now easily adjust the defined variables at the top of our script in the future to work with different clusters, NAS/NFS servers or paths. The output of your final script when run should give you a nice view of what has happened too. It will output that it is adding NFS Datastores to each host it iterates through, and if it comes across any errors those should be marked in red as PowerShell / PowerCLI normally would do, allowing you to amend or update any details as necessary. PS, don’t forget to change the name of each Datastore in the script to something of your own choice (it is the part after the -Name parameter in each New-Datastore line).


Here is the download for the full script (with latest improvements):

[download id=”5″]


More PowerCLI basics – Host operations


On my quest to learn more about PowerCLI, I have been playing around with some more cmdlets in my lab. As a simple task, I have figured out how to tell ESX or ESXi hosts to enter and exit maintenance mode. Here’s how we do this. First of all ensure you are connected to your vCenter server instance using Connect-VIServer ServerName.


Enter maintenance mode:

Set-VMHost ESXi-01.noobs.local -State "Maintenance"


Exit maintenance mode:

Set-VMHost ESXi-01.noobs.local -State "Connected"


Set host to “disconnected” state:

Set-VMHost ESXi-01.noobs.local -State "Disconnected"


So now that we know the basics of setting the state of a VMware host, how about we get slightly more technical and perform one of the above operations on a bunch of hosts in one go? Powershell / PowerCLI is all about automation after all! Note that in the following script, I have also include a simple “if / else” statement to prompt the user running the script manually as we are about to send all ESX(i) hosts into maintenance mode! Use this at your own risk of course, it is just for demonstration purposes. You may want to modify to select hosts to enter maintenance mode on certain criteria. For example, all hosts in a particular cluster, or all hosts with a certain property. Here is the script I would use to perform the operation on all the ESX(i) hosts found in vCenter:


$VCServer = “yourvcservername”
Connect-VIServer $VCServer
$confirm = Read-Host “Are you sure you want all hosts to enter maintenance mode? (type yes to continue) “
if ($confirm -eq "yes")
	Get-VMHost | Set-VMHost -State "Maintenance"
	"Script aborted (you didn't confirm by typing yes)"


Once the script is executed, you should get a progress indicator whilst hosts are being dealt with. Afterwards you’ll get some output from each host listing its relevant Connection Status and statistics. Like so:


In the above example, we set some variables, and use some basic logic checking with an IF ELSE statement and an equal to (-eq) operator. We also see how to perform a few operations on ESX or ESXi hosts. I hope this helps anyone starting out with PowerCLI. Please do leave any comments, suggestions or improvements in the comments section!


PowerCLI – checking for snapshots on VMs and emailing the report back

Checking for any snapshots running on VMs in various clusters can be quite repetitive if done manually, looking through vCenter at each of your VMs. In the clusters I work with there are a LOT of VMs to check, and naturally I wanted to automate this process. Sure, I could rely on the vCenter alarms for snapshot size warning, but these are not completely reliable, as they only alert me when snapshots start growing large in size. I wanted something that would alert me to the presence of a snapshot regardless of its size. I therefore set about learning the basics of PowerCLI (as you can see in my last post) and searched around for some sample cmdlets that would help me retrieve a list of VMs with snapshots on them.


So here is the end result of running this snapshot checking script. It uses powershell cmdlets to generate an HTML email and sends it across to the address you specify. You will of course need to ensure you can connect out on port 25 for mail and have authentication on your mail server (or being sending from and to a domain hosted on your mail server (i.e. connecting to relay mail internally). Enter your mail server, to, and from details in the script to customise it. You’ll also need to authenticate with your vCenter server before running the script of course – you could use a cmdlet in the script to do this automatically. I have just been manually authenticating for now as I have not yet deployed this in production and have just been testing.



So here is the all important PowerCLI script!


#These are the properties assigned to the HTML table via the ConvertTo-HTML cmdlet - this is used to liven up the report and make it a bit easier on the eyes!

$tableProperties = "<style>"
$tableProperties = $tableProperties + "TABLE{border-width: 1px;border-style: solid;border-color: black;}"
$tableProperties = $tableProperties + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;}"
$tableProperties = $tableProperties + "TD{text-align:center;border-width: 1px;padding: 5px;border-style: solid;border-color: black;}"
$tableProperties = $tableProperties + "</style>"

# Main section of check
Write-Host "Looking for snapshots"
$date = get-date
$datefile = get-date -uformat '%m-%d-%Y-%H%M%S'
$filename = "F:\VMwareSnapshots_" + $datefile + ".htm"

#Get your list of VMs, look for snapshots. In larger environments, this may take some time as the Get-VM cmdlet is not very quick.
$ss = Get-vm | Get-Snapshot
Write-Host "   Complete" -ForegroundColor Green
Write-Host "Generating snapshot report"
$ss | Select-Object vm, name, description, powerstate | ConvertTo-HTML -head $tableProperties -body "<th><font style = `"color:#FFFFFF`"><big> Snapshots Report (the following VMs currently have snapshots on!)</big></font></th> <br></br> <style type=""text/css""> body{font: .8em ""Lucida Grande"", Tahoma, Arial, Helvetica, sans-serif;} ol{margin:0;padding: 0 1.5em;} table{color:#FFF;background:#C00;border-collapse:collapse;width:647px;border:5px solid #900;} thead{} thead th{padding:1em 1em .5em;border-bottom:1px dotted #FFF;font-size:120%;text-align:left;} thead tr{} td{padding:.5em 1em;} tbody tr.odd td{background:transparent url(tr_bg.png) repeat top left;} tfoot{} tfoot td{padding-bottom:1.5em;} tfoot tr{} * html tr.odd td{background:#C00;filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='tr_bg.png', sizingMethod='scale');} #middle{background-color:#900;} </style> <body BGCOLOR=""#333333""> <table border=""1"" cellpadding=""5""> <table> <tbody> </tbody> </table> </body>" | Out-File $filename
Write-Host "   Complete" -ForegroundColor Green
Write-Host "Your snapshot report has been saved to:" $filename

# Create mail message

$server = "yourmailserveraddress.com"
$port = 25
$to      = "youremailaddress"
$from    = "youremailaddress"
$subject = "vCenter Snapshot Report"

$message = New-Object system.net.mail.MailMessage $from, $to, $subject, $body

#Create SMTP client
$client = New-Object system.Net.Mail.SmtpClient $server, $port
# Credentials are necessary if the server requires the client # to authenticate before it will send e-mail on the client's behalf.
$client.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials

# Try to send the message

try {
    # Convert body to HTML
    $message.IsBodyHTML = $true
    $attachment = new-object Net.Mail.Attachment($filename)
    # Send message
    "Message sent successfully"


# Catch an error

catch {

	"Exception caught in CreateTestMessage1(): "



Another point worth mentioning – you should change the path that the report is saved to on disk – in my script it is set to F:\, so just modify this to suit your environment. Kudos to Andrew at winception for his Snapshot checking code – I have used a lot of it above, but modified it somewhat to include additional information, and style the HTML table so that it is much easier on the eyes. I also added the e-mail functionality to the script. The following is a screenshot after I executed the script in PowerCLI manually. You would of course look to automate the process by scheduling this script in on your machine.



Enjoy, and please drop any comments, improvements or feedback in the comments section!

Hello PowerCLI


So today is the first time I am trying out PowerCLI for vSphere. Yes, I know I am late to the game in the VMware scene, but I hope to start learning more about PowerCLI and start automating some tasks that are currently being done manually where I work.


Here is my first try at connecting to my lab vCenter server 🙂


Pretty simple really, just as the banner text says, use:
Connect-VIServer servername and

to connect and get a list of VMs. I guess this is my “Hello World” start out with PowerCLI then. If anyone has any tips or quick and easy cmdlets to run in PowerCLI to get information back, please drop a comment with them below. I would also love to know how to iterate through a list of VMs and check whether they have snapshots or not! That would be a great start to what I am looking to achieve.