Copy Files Between Datastores – PowerCLI

I had the need to automate moving about 50 ISO files from one datastore to another during a storage array migration a short while ago, so I wanted to share this script with you all in case you ever find the need for this or similar.

It’s rather simple, and you just need to edit this with the names of your datastores and folder structure (top folder only):

#Set's Old Datastore
$oldds = get-datastore "Old Datastore Name"

#Set's New Datastore
$newds = get-datastore "New Datastore Name"

#Set's ISO Folder Location
$ISOloc = "Subfolder_Name\"

#Map Drives
new-psdrive -Location $oldds -Name olddrive -PSProvider VimDatastore -Root "\"
new-psdrive -Location $newds -Name newdrive -PSProvider VimDatastore -Root "\"
#Copies Files from Old to New
copy-datastoreitem -recurse -item olddrive:\$ISOloc* newdrive:\$ISOloc

Line 1: Change the script to have the name of the datastore you are moving the files FROM.
Line 5: Change the script to have the name of the datastore you are moving the files TO.
Line 8: Change the script to have the name of your ISO subdirectory. Do not remove the “\” unless you have no subfolder.
Lines 11 & 12: Maps PowerShell drives to those datastores.
Line 14: Copies the files.

Gather VM IP Addresses using PowerCLI

Today I needed to find a way to gather a list of the IP’s for all of our VM’s so I came up with this little one-liner, so thought I’d share it with you:

get-vm | select Name,@{N="IP Address";E={@($_.guest.IPAddress[0])}} |
         out-file c:\VM_IP_Addresses.csv

It’ll get all of the VM’s in the environment, and then list out the first IP address for each one. If you have multiple IP’s on some hosts, then remove the “[0]” section in the above and it’ll list all of them. The output will be tab delimited text rather than comma separated.

VMware Labs finally release PowerCLI VDS cmdlet package!

At last!!! VMware Labs have released a package to add VDS functions into PowerCLI!

It is a Fling though that was only released yesterday, so it’s not going to have any official support from VMware, and currently only supports Windows XP, 2003 and 2008 (no mention of 2008 R2 here). You also need to be running PowerCLI 4.1.1 or later.

You can import the snap-ins like this:

Add-PSSnapin VMware.VimAutomation.VdsComponent

And list the cmdlets like this:

Get-Command –Module VMware.VimAutomation.VdsComponent

You can download them from here:

Vmware Labs PowerCLI VDS Download

And you can get some more information from here:

New Function: Get VM’s by Powerstate using VMware PowerCLI

Another ususal issue I keep finding is the need to see how many VM’s I have that are either Powered On, Powered Off or Suspended. Today I decided it was time to do two things:

1. Write a script for this so I don’t have to work this out “the hard way”.
2. Make it a function with parameters so that it has help information included for other people and can be modular. This was mainly due to Jonathan Medd and his talk at the last LonVMUG.

So, I decided I needed options to limit the scope of the script. Cluster level seemed like a good start to me, and I also added an option to connect to a particular host/vCenter instance (assumes you are running Powershell as a user with sufficient access permissions).

So, I came up with a script. Then made it into a function. And then fixed it after I broke it! I also realised that outputting large lists of VM’s went over the PowerShell console history length if you had enough VM’s listed, so I added an output to file option to relieve this issue.

If you want to be able to get a list of all VM’s dependant on their current power state, take a copy of this script, save it as a “.psm1” file and import is as a module (import-module). This way you can just run Get-VMByPowerState and you’ll get a full list.

Here’s the function:

function Get-VMByPowerState
        Gets a list of VM's dependant on power state.
        Gets a list of VM's dependant on power state.
    .PARAMETER Cluster
        Name of the cluster to retrieve VM's from. Supports Wildcards.
    .PARAMETER PowerState
        REQUIRED. The power state of the VM's that you are looking for.
		Valid state options are:
		The name or IP of the vCenter or ESX(i) host to connect to. This assumes that you have sufficient access rights as the logged on user.
		Name & path to an output file.
        Get-PowerState -Cluster ClusterName -State PoweredOn -Server -outfile filename.txt
        ,   Position = 0
        ,   ParameterSetName='ByName')]
        $Cluster = '*'
        ,   ParameterSetName='ByDatacenter')]
        ,   ParameterSetName='ByDatacenter')]
        $Server = $null
        ,   ParameterSetName='ByDatacenter')]
		[Alias("Output File Name")]
        $outfile = $null

if ($server -ne $null) {
	connect-viserver $server

$vms = get-vm | where {$_.PowerState -eq $PowerState} | select Name,PowerState

$vmcount = $vms.count

if ($vmcount -gt "0"){
	if ($outfile -eq $null) {
		write-host "List of all $PowerState VM's:"
		write-host "There are $vmcount $PowerState VM's"
	if ($outfile -ne $null){
		write-host "Outputting to file as requested."
		out-file -FilePath $outfile -InputObject $vms}
if ($server -ne $null) {
	disconnect-viserver $server -force:$true -confirm:$false

Finding the VMware datastore with the most diskspace using PowerCLI

Today I found that I needed to know which of my datastores had the most disk space so that I could add a new virtual hard disk on it temporarily for some temporary data upload. Knowing that I needed to exclude certain datastores I had to figure out how to get PowerCLI/PowerShell to check the name of the datastore against an “exclusion list”. So, with some help from @jonhtyler and @leveitan on Twitter, and using the PowerShell operators, I came up with the following script:

#Connects to vCenter/ESX(i)
connect-viserver $servername 

#Get's a list of datastores and excludes based on matches of "Name1" etc. Only gets free space and datastore Name
$datastores = get-datastore | where {$_.Name -notmatch "Name1|Name2|Name3"} | select Name,FreeSpaceMB

#Sets some static info
$LargestFreeSpace = "0"
$LargestDatastore = $null

#Performs the calculation of which datastore has most free space
foreach ($datastore in $datastores) {
	if ($Datastore.FreeSpaceMB -gt $LargestFreeSpace) {	
			$LargestFreeSpace = $Datastore.FreeSpaceMB
			$LargestDatastore = $

#Writes out the result to the PowerShell Console		
write-host "$LargestDatastore is the largest store with $LargestFreeSpace MB Free"

#Disconnects from all connected vCenter/ESX(i) hosts.
disconnect-viserver * -force:$true -confirm:$false

Now, all you need to do is replace $servername with the name of your vCenter server or ESX(i) host, and change “Name1”, “Name2” and “Name3” with the expressions that you want to remove. If you know that all of the disks you want to exclude contain a single word such as “LOCAL”, then just replace all 3 (and remove the all the “|”), if you want to exlude “LOCAL” and “TEMP” then you’ll need “LOCAL|TEMP” – with me?

Hope this helps more people than just me 🙂

Preparing for VMware vCenter Database Disaster – Part Two: Export Host information via PowerCLI

Hopefully you’ve all read Part One of this series, where I provide examples of gathering information from vCenter mainly for VM’s in order to recreate your environment from scratch, just in case you have a major vCenter database corruption or the like. If you have, sorry part two has taken so long!
Part Two will show how to export information regarding your ESX(i) hosts, including networking information, so that this part of your setup is also easy to recreate. I should note here, that I’ll be trying to export VSS information, as well as Service Console and VM Kernel port configuration, and get this all exported into CSV files.
So… Here goes…!
Exporting physcial NIC info for the vDS switch
This is a pretty simple script that uses the get-vmhostpnic function from the Distributed Switch module in I mentioned in part one (Thanks again Luc Dekens :¬)).
import-module distributedswitch

write-host "Getting vDS pNIC Info"

$vdshostfilename = "C:\vdshostinfo.csv"
$pnics = get-cluster "<em>ClusterName</em>" | get-vmhost | get-vmhostpnic
foreach ($pnic in $pnics) {
if ($pnic.Switch -eq "<em>dVS-Name</em>") {
$strpnic = $strpnic + $pnic.pnic + "," + $pnic.VMhost + "," + $pnic.Switch + "`n"
#Writes to CSV file
out-file -filepath $vdshostfilename -inputobject $strpnic -encoding ASCII

Simply change “ClusterName” to match that of your cluster, and change “dVS-Name” to match that of your dVS (vDS – whichever). Then the info exported will contain the physical nic info for your distributed switch.

Next it’s time for simply getting a list of hosts in the cluster, I know, it’s nothing major, but at least it’s in a CSV I can import later, and it makes life much easier!!!

$hostfilename = "c:\filename.csv"
write-host "Getting Host List"
$hosts = get-cluster $cluster | get-vmhost
foreach ($vmhost in $hosts) {
$outhost = $outhost + $vmhost.Name + "`n"

out-file -filepath $hostfilename -inputobject $outhost -encoding ASCII

Simply put, gather a list of hosts in the cluster called “ClusterName” and output their names to “c:\filename.csv”

OK, so now that we have that info, all I need to gather is a list of Standard Switches and their port groups, including IP information to make life easy… So, here goes:

$vssoutfile = "vssoutfile.csv"
$cluster = "Cluster Name"
$vmhosts = get-cluster $cluster | get-vmhost

$vssout = "Host Name, VSS Name, VSS Pnic, VSS PG" + "`n"
foreach ($vmhost in $vmhosts) {
$vmhostname = $
$switches = get-virtualswitch $vmhost
foreach ($switch in $switches) {
$vssname = $
$Nic = $switch.nic
$pgs = get-virtualportgroup -virtualswitch $switch
foreach ($pg in $pgs) {
$pgname = $
$vssout = $vssout + "$vmhostname" + "," + `
        "$vssname" + "," + "$Nic" + "," + `
        "$pgName" + "`n"

out-file -filepath $vssoutfile -inputobject $vssout -encoding ASCII
Now we just need the host IP’s. At the moment, I can find this info for VM Kernel ports on ESX hosts, but I can get service console information, and the vmkernel IP in ESXi hosts (it’s pulled from the same PowerCLI script, so that’s this one here:

$hostipoutfile = "hostip.csv"
$cluster = "Cluster Name"
$output = "Host Name" + "," + "IP Addresses" + "`n"

$vmhosts = get-cluster $cluster | get-vmhost
foreach ($vmhost in $vmhosts) {
$vmhostname = $
$ips = Get-VMHost $vmhostname | `
     Select @{N="ConsoleIP";E={(Get-VMHostNetwork $_).VirtualNic | `
$ipaddrs = $ips.ConsoleIP
$output = $output + "$vmhostname" + "," + "$ipaddrs" + "`n"

out-file -filepath $hostipoutfile -inputobject $output -encoding ASCII

Now, I’m slowly working on this project in my spare time at work (it’s actually for work but not as important as everything else I’m doing!), so part 3 is probably going to be some time away, and that’ll show you how to import all this info back into vCenter to reconfigure your hosts… bear with me, I’ll get this written 🙂

Preparing for vCenter Database Disaster – Part One: Export information via PowerCLI

In this new blog post I’m going to start showing you how to export data from vCenter using PowerCLI to provide you with all sorts of useful information that you may need in case of a vCenter database loss. I’m going to include the loss of a Virtual Distributed Switch (vDS) as well in case you’re using this fantastic option from VMware.

I’m starting this because recently I had just this problem. The vCenter DB at a customer’s site had corrupted, and this meant they lost the vDS configuration plane, and although they could work on systems, managing them just got a whole lot more difficult… The SQL database had actually been corrupted for a long time… their 3 months of archived backups wouldn’t restore and get the vCenter services operational again, all with the same error, leading to a VMware KB article telling them to reinitialize the database. Ouch.

So, using some PowerCLI commands I started gathering information about the VM’s, their networking information as well as the vDS information I needed (they had several VLAN’s in place which all needed recreating).

It was a tiresome process as I didn’t have time to get proper scripts running to export nicely to CSV, so I decided I’d change this later, once I had time to write-up this blog post!!

The main items the customer needed at the time were VM networking information (which VM was on which port group), the configuration of their vDS and the folder structure within vCenter. Below, I’ve listed scripts which will help with these three operations, scripts I’m going to implement on every install I ever do from now on – I certainly don’t want to go through all the pain I faced first time around…!!!

So, if you want to get networking information from each VM, into a CSV file, here’s a script I’ve done it with, and this takes multiple NIC’s into account too:

#Script to backup all VM Network info

#Connect to vCenter Server
Connect-VIServer -Server "servername" -User "username" -Password "password"

#Set Variables
$cluster = "Cluster Name"
$strout = "VMName,NIC Name,Network`n"
$vmsfilename = "filename.csv"

#Backup VM Networking information
$nics = get-cluster $cluster | get-vm | sort-object Name | get-networkadapter
foreach ($nic in $nics)
$strout = $strout + $nic.Parent + "," + $nic.Name + "," + $nic.networkname + "`n"

#Outputs $strtest into the file named in $vmsfilename
out-file -filepath $vmsfilename -inputobject $strout -encoding ASCII

#Disconnects from vCenter server
disconnect-viserver * -force -confirm:$false

The next set of information I’d like to have easily available would be the vDS switch configuration information. Now, we always setup vDS port groups with the “Route based on Physical NIC load” load balancing policy, so this wasn’t information I needed and so isn’t included below. Now, you’ll need Luc Dekens’ Distributed Switch module for PowerCLI to do this (his blog is here and I highly recommend it):

#Script to Export vDS config

#Import vDS module from Luc Dekens
import-module vmwaredistributedswitch.psm1

#Connect to vCenter Server
Connect-VIServer -Server "server" -User "username" -Password "password"

#Set Variables
$strdvpg = "PGName,VLAN ID,NumPorts,vDSName`n"
$vdsfilename = "filename.csv"

#Gets Distributed Virtual Switch information
$dvpg = get-distributedswitchportgroup
#Sets CSV output for each DVPG in $dvpg
foreach ($pg in $dvpg)
$strdvpg = $strdvpg + $pg.Name + "," + $pg.VLANID + "," + $pg.NumOfPorts + "," `
+ $pg.DistributedSwitch + "`n"

#Outputs $strdvpg to the file named in $vdsfilename
out-file -filepath $vdsfilename -inputobject $strdvpg -encoding ASCII

disconnect-viserver * -force -confirm:$false

So, that’s the first part over and done with. Networking info for the VM’s and vDS has been exported to CSV files in case we ever need to re-import them again, next we’ll take a look at how to export your folder configuration from under the “VM’s and Templates” view in the vSphere client:

#Script to Export vSphere folder structure to CSV

# Connect to vCenter
connect-viserver "servername" -user "username" -password "password"
#Set Variables
</em>$filename = "filename.csv"
$strout = "Name,Parent`n"

# Get Folder Structure
$list = get-folder
foreach ($folder in $list)
$strout = $strout + $ + "," + $folder.parent + "`n"
out-file -filepath $filename -inputobject $strout -encoding ASCII

#Disconnect from vCenter
disconnect-viserver * -force -confirm:$false

So, that’s a lot of the VM side complete, folders are exported, VM network information and vDS configuration is all sat in CSV files. Now, you can e-mail that out using standard Powershell e-mail cmdlets if you’d like, and set this up as a scheduled task too should you so wish… whatever you do, just ensure it’s not all held on the same server as your SQL database 🙂

Part Two will come along shortly, where I’ll be looking into pulling out the host configuration, and getting ready to import all of this back into a reinitialized database later on in part 3…

UPDATE: Part two is available here: Part Two