Powershell: Remove-Datastore
Here’s the cousin script to the add NFS datastore to multiple esx hosts.
$ds_name = (Read-Host "Enter datastore name to delete")
$vm_hosts = Get-VMHost -Datastore $ds_name
foreach($esx in $vm_hosts)
{
Remove-Datastore -VMHost $esx.Name -Datastore $ds_name -ErrorAction SilentlyContinue -Confirm:$false -RunAsync | Out-Null
Write-Host $ds_name removed from $esx.Name
}
Powershell: Count The Number Of VM’s On A Datastore
Getting information like number of VM’s on a specific datastore is easy within the VIC. You can get this information from the Datastores Summary tab. However, if for some reason you needed it scripted or were building a script that required this information to act on, here is how you could pull it.
param ($ds)
Get-Datastore -Name $ds| Foreach-Object {
$number = $_ | Get-VM | Select-Object Name
Write-Host $number.Count
}
Disconnect-VIServer -Confirm:$false
You can run this script from the command line by calling the script and specifying which datastore you want to run it against. For example: .\script.ps1 datastore1
Powershell: Check if IIS is Running on a Remote Server
This is a quick script that will tell you if IIS is running on a list of remote servers. Just like my other scripts this one requires a “servers.txt” file in the same location as the script. I enter all the servers I want to check in that file.
$servers = (Get-Content servers.txt)
foreach($vm in $servers){
$iis = get-wmiobject Win32_Service -ComputerName $vm -Filter "name='IISADMIN'"
if($iis.State -eq "Running")
{Write-Host "IIS is running on $vm"}
else
{Write-Host "IIS is not running on $vm"}
}
Powershell: Add NFS Datastore to Multiple ESX Hosts
Adding a datastore to an esx host isn’t to time consuming or difficult but to save a little bit of time and avoid the repetitiveness, here’s a script to do it for you. This script will mount an NFS datastore. Of course, you can change the protocol by using a different switch like -cifs.
$esx = (Get-Content esx_servers.txt)
$Host_Name = (Read-Host "Enter the server (ex:storage-server-san:")
$Path = (Read-Host "Enter the path (ex:/vol/vol/ds_name):")
$Name = (Read-Host "Enter the name of the datastore:")
foreach($server in $esx){
Get-VMHost $server | New-Datastore -Nfs -NfsHost $Host_Name -Path $Path -Name $Name
}
The script asks for the following information:
1. Storage server
2. Path to the storage location
3. Datastore Name
Note: The script will only mount the SAME datastore on each esx server you specify. You’ll need to create a text file called “esx_servers.txt” in the same location as the script and enter the esx server names in it.
UPDATE: I’ve had to modify this script to add multiple datastores to multiple esx hosts. Here is the updated code:
$servers = @()
$paths = @()
$datastores = @()
$answer = "y"
while($answer -eq "y"){
$servers += Read-Host "Enter the server (ex:usadc-nas05a-san)"
$paths += Read-Host "Enter the path (ex:/vol/vol/ds_name)"
$datastores += Read-Host "Datastore name ?"
$answer = Read-Host "Enter another NFS mount?"}
$Error.Clear()
Get-Content servers.txt | %{
$esx = Get-VMHost -Name $_
$countNFS = $servers.Count
if($countNFS -ne 0){
0..($countNFS - 1) | %{
$esx | New-Datastore -Nfs -NfsHost $servers[$_] -Path $paths[$_] -Name $datastores[$_] | Out-Null
if($Error.count -gt 0){
$Error | out-file ('c:\powershell scripts\logs\' + $esx + '.txt') -append
$Error.Clear()
}
}
}
}
Powershell: Mount Datastore ISO to Multiple VM’s
I had to install a piece of software on several vm’s a few days ago and got somewhat bored of the same repetitive task of mounting the ISO to all of the vm’s cd-rom drive. So, I wrote a script that will automatically mount the ISO that I specify and connect the cd-rom drive.
$VMs = (Get-Content servers.txt)
$ds = (Read-Host "Type the datastore name:")
$ISO_Path = (Read-Host "Type the path to the iso file:")
foreach($vm in $VMs){
Get-CDDrive $vm | Set-CDDrive -StartConnected:$true -Connected:$true -IsoPath [$ds] $ISO_Path -Confirm:$false
}
What this script does is prompt you for the datastore location that your ISO’s are located in. For example, if your ISO is located in the datastore “ISOs” you would type that. The script then prompts you for the full path to the iso. This is what your input should look like
1. Type the datastore name: vm_isos
2. Type the path to the iso file: folder/folder1/folder2/file.iso
On the flip side if you want to disconnect the cd-rom from multiple vm’s, you just need to modify the script a bit.
$VMs = (Get-Content servers.txt)
foreach($vm in $VMs){
Get-CDDrive $vm | Set-CDDrive -NoMedia -StartConnected:$false
-Connected:$false -Confirm:$false
}
Note: This will actually remove the mounted iso (-NoMedia) but it will also disconnect the cd-rom and set the startconnected switch to false.
Powershell: Shutdown VM and Delete From Disk
This is a fairly simple script but I thought I’d share. I needed to delete a group of about 6 virtual machines this morning. I could easily do this through the vSphere GUI but I figured I’d write a quick script so I could use it for future deletions.
$VMs = (Get-Content servers.txt)
foreach($vm in $VMs){
$active = Get-VM $vm
if($active.PowerState -eq "PoweredOn"){
Stop-VM -VM $vm -Confirm:$false
Start-Sleep -Seconds 10
Remove-VM -VM $vm -DeleteFromDisk -Confirm:$false -RunAsync}
else
{Remove-VM -VM $vm -DeleteFromDisk -Confirm:$false -RunAsync}
}
Updated Script:
$VMs = (Get-Content servers.txt)
$vmObj = Get-vm $vms
foreach($active in $vmObj){
if($active.PowerState -eq "PoweredOn"){
Stop-VM -VM $active -Confirm:$false -RunAsync | Out-Null}
}
Start-Sleep -Seconds 7
foreach($delete in $vmObj){
Remove-VM -VM $delete -DeleteFromDisk -Confirm:$false -RunAsync | Out-Null}
This script will run a lot quicker and the code is a bit cleaner.
Powershell: List VM Name, Hard Drive Name and Datastore Name
I recently had a request for a script that listed virtual machines hard drives and datastore locations. This is a fairly quick and easy script. The only problem is the formatting. Since some VM’s have more than one HD the formatting is a little odd. Instead of use the Export-CSV cmdlet I decided to use the Out-File cmdlet and save the results to a text file. It looks a bit cleaner to me.
$VMs = Get-vm
foreach ($vm in $VMs){
$ds = Get-HardDisk -VM $vm | Select-Object name,filename
$vm.Name,$ds | Format-Table | Out-File -Append -FilePath "c:\filename.txt}
Here’s a preview of the output:

Powershell: Clone Multiple Virtual Machines Simultaneously
One of my roles is to stand up environments for development or testing projects. I receive requests on a weekly basis for anywhere from 1-10 virtual machine environments. If I were to use the typical method of vSphere to clone a set of 10 it may take 4-5 hours. The thing about this script is in order to clone multiple VM’s the specs need to be the same, meaning vCPU, RAM and hard drives. You also need to determine the names you want to use for the virtual machines and then write them down in a text file called servers.txt. I’ll break down the code to show you exactly what it’s doing.
$VM_Location = "Example" $servers = (Get-Content servers.txt)
Line 1. Change this variable to suite your environment. This is the inventory location. Where your virtual machine will be stored in the inventory list.
Line 2. Read in the server names from the servers.txt file – Store in the same location as this script.
function clone_vms {
$template_name = (Read-Host "Enter the template name").Trim()
$ESX_host = (Read-Host "Enter the ESX host").Trim()
$datastore = (Read-Host "Enter the datastore location for the c:\ drive")
foreach($server in $servers)
{
New-VM -Location $VM_Location -VMHost $ESX_host -Name $server -Template $template_name -Datastore $datastore
}
}Line 1. Simply creating a function to clone the virtual machines. Makes the code a bit more organized and cleaner.
Line 2. Prompting the user for the name of the template. This needs to be exact.
Line 3. Prompting the user for the name of the esx host to place these virtual machines on.
Line 4. Prompting the user for the name of the datastore for the c:\ drive.
Line 5. Simple foreach statement which says for each server in the servers.txt file do the following block of code {xxxxx}
Line 7. New-VM is the cmdlet used to create a new virtual machine. Here we define the inventory location with the $VM_Location variable. We also define the ESX Host where we want to place this vm, the name of the VM, the template to use and the datastore location. Just a tip, if you want to run multiple clones at the same time use the -RunAsync at the end of line 6, inside the two }}. Be warned though if you run more than 4-5 at a time this will severely impact the performance of vCenter. Right now once one vm clone is finished it automatically starts the next one.
function change_vcpu{
$vCPU = Read-Host "Enter the number of vCPU's"
foreach($server in $servers)
{
Set-VM $server -NumCpu $vCPU -Confirm:$false -RunAsync
}
}Line 4. Set-VM cmdlet is used to change things like vCPU. We define the $server we want to change the vCPU on based on the foreach loop. We also need to let the cmdlet know how many vCPU we are changing to. The -Confirm:$false switch is telling the cmdlet to not prompt me for permission to change this. The -RunAsync switch says change all servers at the same time.
function add_harddrive {
$size = (Read-Host "Enter size in KB").Trim()
$datastore = (Read-Host "Enter DataStore Location").Trim()
foreach($server in $servers)
{
New-HardDisk -VM $server -CapacityKB $size -ThinProvisioned -DataStore $datastore
}
}
Line 6. The New-HardDisk cmdlet gives us the ability to add hard drives to a VM. The -VM switch lets the cmdlet know which VM we are adding a hard disk to. The -CapacityKB switch tells the cmdlet how large of a hard drive we are creating. I’ll talk more about the -ThinProvisioned switch in another blog.
function change_ram_amount {
$ram = Read-Host "Enter amount of RAM in MB"
foreach($server in $servers)
{
Set-VM $server -MemoryMB $ram -Confirm:$false -RunAsync
}
}
function power_on_vms {
foreach ($server in $servers)
{
Start-VM $server -RunAsync
}
Write-Host "$server has been powered on"
}
clone_vms
$change_vcpu = (Read-Host "Do you want to change the vCPU count [y] or [n]").Trim()
if($change_vcpu -eq "y") {change_vcpu}
$add_harddrive = (Read-Host "Do you want to add a harddrive [y] or [n]")
if($add_Harddrive -eq "y") {add_harddrive}
$change_ram = (Read-Host "Do you want to change the amount of RAM [y] or [n]")
if($change_ram -eq "y") {change_ram_amount}
power_on_vms
I’ve pretty much gone through all of the cmdlets used, all of the switches used, etc. The last section is changing the RAM amount with the Set-VM cmdlet and then defining the function power_on_vms which does exactly what it says. The next chunk is what actually makes the script run.
Lets take line 18-19 as an example. Line 18 is asking the user whether or not they want to change the RAM amount on the virtual machines and storing the response in a variable called $change_vcpu. Line 19 is a conditional statement saying if $change_vcpu is equal to “y” then call the change_vcpu function. If the user types anything other than “y” the conditional statement is not equal and moves on to the next one which is prompting to add a hard drive. The same procedure is followed through the rest.
What I do is run a set of 10 virtual machines, specify what I need to and move on to something else. Once I see in vCenter that the virtual machines are all done being created, I check my console again to modify the vCPU, RAM and hard drive specs.
Powershell: Identify all VMs using a particular NIC
Can you imagine going through hundreds or thousands of VM’s looking for a specific NIC. To do that manually would have taken hours if not days. I was asked if I had a way to identify which VM’s are running the “vmxnet3″ adapter. I wrote up this little script which gave us the answers we were looking for in about 20-30 minutes.
#Identify all VMs with a specific NIC name
$VMs = (Get-VM)
#Change the adapter_name variable to match the NIC name you are looking for
$adapter_name = "vmxnet3"
#Change the network_path variable to point to your text file that will store the results
$network_path = "c:\powershell scripts\network_adapter.txt"
ForEach ($VM in $VMs){
$VM_Name = $VM.name
$Get_Adapter = Get-NetworkAdapter $VM
$Get_Adapter_Type = $Get_Adapter.Type
if($Get_Adapter_Type -eq $adapter_name)
{$VM_name, $Get_Adapter_type | Out-File -FilePath $network_path -append}}
Note: This script took quite a while to run. I’ve modified it to run much much more efficiently. This script will finish in about 5 minutes for 1,500+ vm’s.
$VMs = Get-VM | Select-Object -Property Name,@{N="Adapter Type";E={(Get-NetworkAdapter -VM $_).Type}} |
`Export-Csv -NoTypeInformation -Path network_adapters.csv
The only thing about this script is right now it will only report the NIC type for vm’s with 1 NIC. If the VM has two NIC’s it won’t report a type. Also, it will report all NIC types. You will need to open the CSV file and apply a filter based on the type you’re looking for.
Powershell: Count the number of VMs with memory limits and determine the difference
I am in the process of building several very large dashboards in order for managers and executive managers to be able to quickly determine the state of our, VMware, NetApp and database environments. While writing this script I decided to include the number of “trimmed” virtual machines or virtual machines with memory limits. The reason I did this is because a lot of people don’t understand the difference between how physical memory on a single server is managed vs memory on a hypervisor. After taking a look at CapacityIQ I quickly realized the majority of our VMs were oversized. Half of the memory and cpu weren’t even being utilized nor had never been utilized. Because VMware doesn’t have the capability to reconfigure the RAM without resetting a server we decided to set limits. This doesn’t require a reboot and is easy to change if the ESX server decides to balloon the VM or force it to swap for one reason or another. It’s also a good statistic for management to see and be able to dissect. Here is the script I wrote to determine how many VMs have limits and what the difference between the configured memory and the limit is. This way we’re able to tell how much unused memory we’ve actually recovered.
#Get VM Objects
$VMs = Get-VM
#Initialize variables to 0
$count = 0
$Difference = 0
$Recovered_Memory = 0
$Total = 0
#Get limit data for each virtual machine
Write-Host "Collecting VM limit information..."
foreach($vm in $VMs){
$result = (Get-VMResourceConfiguration -VM $vm)
if($result.MemLimitMB -ne '-1')
{
$Count += "1"
$vm_memory = $vm.MemoryMB
$vm_limit = $result.MemLimitMB
$Difference = ($vm_memory - $vm_limit)
$Recovered_memory += $Difference
}
}
Write-Host "Generating results files..."
$final = ($Recovered_Memory/1024)
"{0:N2}" -f $final | Out-File -FilePath recovered_memory.txt
$count | Out-File -FilePath vms_with_limits.txt