:: PowerCLI | Remove VMs

:: PowerCLI | Remove VMs

Just a quick script from me that will help delete a bunch of VMs.
You need to have a list with all computer names in a .txt or .csv file for that.

Uncomment the get-credential part if you are not running the ISE with your admin that has access to the vCenter server.

<#
.SYNOPSIS Removes a VM from View and vCenter 
.EXAMPLE get-content "list-of-machines.csv" | remove-vm.ps1 
.EXAMPLE remove-vm.ps1 vm1 
.EXAMPLE remove-vm.ps1 vm1, vm2, vm3 
.PARAMETER VM One or more Virtual Machine names 
#>
[CmdletBinding()]param([Parameter(Mandatory=$True,ValueFromPipeline=$True)][string[]]$VM ) 

BEGIN { 
  $ErrorActionPreference = "Stop" 
} 

PROCESS { 
  ForEach ($a in $VM) { 
    try { 
      remove-vm -vm $a -DeletePermanently -confirm:$false 
      Write-Output "$a successful!" 
      } 

catch { 
  $ErrorMessage = $_.Exception.Message 
  Write-Output $ErrorMessage 
  Write-Output "$a failed!" 
} 

finally {} 
} 
} 
END {}

PowerCLI | Increase and Expand VM Guest OS Disk

:: Increase and Expand VM Guest OS Disk ::

Hi all,

as i finally have worked out two scripts that are able to increase and extend the Guest OS Disk (XP/Win7) i thought you might find it useful.

Please note that for the XP version to work both VMs (or all VMs) need to be powered off. Like that you can also increase/extend system disks.

 

hdd-increase-xp.ps1

<#
.SYNOPSIS
Increases Harddisks for Windows machines (including Guest OS extend)
.EXAMPLE
get-content "list-of-machines.csv" | hdd-increase.ps1
.EXAMPLE
hdd-increase.ps1 vm1
.EXAMPLE
hdd-increase.ps1 vm1, vm2, vm3
.PARAMETER VM
One or more Virtual Machine names
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
    [string[]]$VM
)

BEGIN {
    $ErrorActionPreference = "Stop"
    $admincred = Get-Credential
    $capacityKB = "62914560"
    $helpervm = '<insert helper vm here>'
    }

PROCESS {
    ForEach ($a in $VM) {
        Get-VM $a | Get-Harddisk | where {$_.Name -eq "Hard disk 1" } | Set-HardDisk –CapacityKB $capacityKB -ResizeGuestPartition -helpervm $helpervm -Confirm:$false -GuestCredential $admincred
        #Get-VM $a | Get-View -ViewType VirtualMachine -Filter @{"Name" = $_ } | write-output $_.Guest.Disk.Length
        Write-Output "$a successful!"
        Start-VM $a
        Write-Output "$a started."
        }
    }
END {}

hdd-increase-w7.ps1

<#
.SYNOPSIS
Increases Harddisks for Windows 7 machines (including Guest OS extend)
.EXAMPLE
get-content "list-of-machines.csv" | hdd-increase.ps1
.EXAMPLE
hdd-increase.ps1 vm1
.EXAMPLE
hdd-increase.ps1 vm1, vm2, vm3
.PARAMETER VM
One or more Virtual Machine names
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
    [string[]]$VM
)

BEGIN {
    $ErrorActionPreference = "Stop"
    $admincred = Get-Credential
    $capacityKB = "62914560"
    $harddisk = "Hard disk 1"
    }

PROCESS {
    try {
        foreach ($a in $VM) {
        Get-VM $a | Get-Harddisk | where { $_.Name -eq $harddisk } | Set-HardDisk –CapacityKB $capacityKB -ResizeGuestPartition -Confirm:$false
        Write-Output "$a successful!"
        }
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Output $ErrorMessage
        Write-Output "$a failed!"
        }
    finally {
    }
}
END {}

 

PowerCLI Script | Find orphaned VMDK & Snapshots

If find this script really useful for finding orphaned VMDKs.

Just put it as task once a week and you will be able to cleanup nicely 🙂

Make sure to change the variables on the top of the script to fit your needs.

 

#########################
# BEGIN: User Variables #
#########################

# Log File location
$LogFile = "Snapshot.log"

# Virtual Centre server to connect to
$VCServer = ""

# Email parameters for emailing logfile results
# emailTo is a comma separated list of strings eg. "email1","email2"
$emailEnable = $true
$emailFrom = "vcs"
$emailTo = "vcs"
$emailSubject = "VMware Health Check"
$emailServer = ""

#########################
#   END: User Variables #
#########################

###############################
# BEGIN: Function Definitions #
###############################

function Output-Data
{
<#
.SYNOPSIS       Outputs Data or messages in the desired method
.DESCRIPTION    This function is designed to use the $LogFile global variable to avoid
                having to specify the output file each time it is called.
                Data is output to the log file by default and optionally to the console as well.
.NOTES          Author:  Grant Brunton
.PARAMETER      Data:
                    The message or object to ouput to the log
.PARAMETER      ToHost:
                TH:
                    Optional switch to include displaying the output to the console
.EXAMPLE
                PS> Output-Data $object
.EXAMPLE
                PS> Output-Data "Message" -ToHost
#>

    [CmdletBinding()]
    Param
    (
        [parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
        [Object]$Data,
        [alias("TH")]
        [switch]$ToHost
    )
    
    Process
    {
        if ($ToHost) { $Data | fl }
        $Data | fl | Out-File $LogFile -Encoding ASCII -Append
    }
}

function Load-VMLibrary
{
<#
.SYNOPSIS       Loads VMware core modules and connects to VI Server
.DESCRIPTION    The function loads the VMware core modules required
                for processing VMware PowerCLI commands.
                This requires the PowerCLI modules to be installed.
                It will also connect to the VIServer ready for accepting commands.
.NOTES          Author:  Grant Brunton
.PARAMETER      VIServer:
                    The Virtual Centre Server to connect to.
                    The default is "VirtualCentre"
.PARAMETER      Credential:
                    A PSCredential object used to authenticate with the VIServer to connect to.
                    Credential objects can be created using the Get-Credential cmdlet
                    By default the logged on user credentials are used to authenticate.
.EXAMPLE
                PS> Load-VMLibrary
.EXAMPLE
                PS> Load-VMLibrary "server1"
.EXAMPLE
                PS> $cred = Get-Credential
                PS> Load-VMLibrary -VIServer "server1" -Credential $cred
.EXAMPLE
                PS> $cred = $host.ui.PromptForCredential("ESX/ESXi Credentials Required", "Please enter credentials to log into the ESX/ESXi host.", "", "")
                PS> "server1" | Load-VMLibrary -Credential $cred
#>

    [CmdletBinding()]
    Param
    (
        [parameter(ValueFromPipeline=$true,Position=0)]
        [String]$VIServer = "VirtualCentre",
        [object]$Credential = $null
        
    )
    
    Process
    {
        $vmwaretoolkit = Get-PSSnapin | where {$_.Name -eq "VMware.VimAutomation.Core"}

        if (!$vmwaretoolkit)
        {
            $vmwaretoolkit = Get-PSSnapin -registered | where {$_.Name -eq "VMware.VimAutomation.Core"}
            if ($vmwaretoolkit)
            {
                Add-PSSnapin "VMware.VimAutomation.Core"
                if (!$?) { Output-Data -TH "Failed to load VMware snapin. Ensure VMware vSphere PowerCLI is installed correctly." ; exit }
            }
            else
            {
                Output-Data -TH "Please install VMware vSphere PowerCLI to use this script."
                exit
            }
        }

        Set-PowerCLIConfiguration -DefaultVIServerMode Single -Confirm:$false > $null
        if ($Credential -ne $null)
        {
            if ($Credential.GetType().Name -ne "PSCredential")
            {
                Output-Data -TH "Invalid credential format supplied"
                exit
            }
            $VIServer = Connect-VIServer $VIServer -Credential $Credential
        }
        else
        {
            $VIServer = Connect-VIServer $VIServer
        }
        if (!$?) { Output-Data -TH "Failed to connect to VM host. Please ensure the correct VIServer is specified and you have correct logon credentials." ; exit }
    }
}

function Check-OrphanedData{
<#
.SYNOPSIS   Remove orphaned folders and VMDK files
.DESCRIPTION   The function searches orphaned folders and VMDK files
   on one or more datastores and reports its findings.
   Optionally the function removes  the orphaned folders   and VMDK files
.NOTES   Author:  Luc Dekens
         Modified by:  Grant Brunton
.PARAMETER Datastore
   One or more datastores.
   The default is to investigate all shared VMFS datastores
.PARAMETER Delete
   A switch that indicates if you want to remove the folders
   and VMDK files
.EXAMPLE
   PS> Remove-OrphanedData
.EXAMPLE
  PS> Get-Datastore ds* | Remove-OrphanedData
.EXAMPLE
  PS> Remove-OrphanedData -Datastore $ds -Delete
#>

  [CmdletBinding()]
  param(
      [parameter(ValueFromPipeline=$true)]
      [PSObject[]]$Datastore,
      [switch]$Delete
  )

  begin{
    $fldList = @{}
    $hdList = @{}

    $fileMgr = Get-View FileManager
  }

  process{
    if(!$Datastore){
      $Datastore = Get-Datastore
    }
    foreach($ds in $Datastore){
      if($ds.GetType().Name -eq "String"){
        $ds = Get-Datastore -Name $ds
      }
      if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess){
        Get-VM -Datastore $ds | %{
          $_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
            $fldList[$_.Name.Split('/')[0]] = $_.Name
            $hdList[$_.Name] = $_.Name
          }
        }
        Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{
          $_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
            $fldList[$_.Name.Split('/')[0]] = $_.Name
            $hdList[$_.Name] = $_.Name
          }
        }

        $dc = $ds.Datacenter.Extensiondata

        $flags = New-Object VMware.Vim.FileQueryFlags
        $flags.FileSize = $true
        $flags.FileType = $true

        $disk = New-Object VMware.Vim.VmDiskFileQuery
        $disk.details = New-Object VMware.Vim.VmDiskFileQueryFlags
        $disk.details.capacityKb = $true
        $disk.details.diskExtents = $true
        $disk.details.diskType = $true
        $disk.details.thin = $true

        $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
        $searchSpec.details = $flags
        $searchSpec.Query += $disk
        $searchSpec.sortFoldersFirst = $true

        $dsBrowser = Get-View $ds.ExtensionData.browser
        $rootPath = "[" + $ds.Name + "]"
        $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
        foreach($folder in $searchResult){
          if($fldList.ContainsKey($folder.FolderPath.TrimEnd('/'))){
            foreach ($file in $folder.File){
              if(!$hdList.ContainsKey($folder.FolderPath + $file.Path)){
                $obj = New-Object PSObject -Property @{
                  Datastore = $ds.Name
                  Folder = $folder.FolderPath
                  FileName = $file.Path
                  Size = $file.FileSize
                  #CapacityKB = $file.CapacityKb
                  #Thin = $file.Thin
                  #Extents = [string]::Join(',',($file.DiskExtents | %{$_}))
                  Problem = "Orphaned file"
                }
                Output-data $obj
                if($Delete){
                  $dsBrowser.DeleteFile($folder.FolderPath + $file.Path)
                }
              }
            }
          }
          elseif($folder.File | where {"cos.vmdk","esxconsole.vmdk" -notcontains $_.Path}){
            $obj = New-Object PSObject -Property @{
              Datastore = $ds.Name
              Folder = $folder.FolderPath
              Problem = "Orphaned folder"
            }
            Output-data $obj
            if($Delete){
              $fileMgr.DeleteDatastoreFile($folder.FolderPath,$dc.MoRef)
            }
          }
        }
      }
    }
  }
}

function Check-Snapshot
{
<#
.SYNOPSIS       Checks VM guests for invalid snapshot images
.DESCRIPTION    This function checks VM guests to see if their harddisks are pointing to snapshot files.
                If they are it reports a detected problem if there are no snapshots listed for the guest
                or if a Consolidate Helper snapshot exists for the guest.
                A Consolidate Helper snapshot is usually created by a VCB type backup process and can be left behind
                if a snapshot removal process failed or the datastore ran out of room.
                If the Consolidate Helper snapshot appears by itself this is an indicator of a failed process.
                If the Consolidate Helper exists with other snapshots it may still be in the middle of the
                removal process.
.NOTES          Author:  Grant Brunton
.PARAMETER      VMGuest:
                    Can be an array or a single VM guest to check.
                    Input should be either the VM object or a string of the VM name.
                    By default all VM guests are checked.
.EXAMPLE
                PS> Check-Snapshot
.EXAMPLE
                PS> Check-Snapshot [-VMGuest] "vmguest"
.EXAMPLE
                PS> $vm = Get-VM "vmguest"
                PS> $vm | Check-Snapshot
#>

    [CmdletBinding()]
    Param
    (
        [parameter(ValueFromPipeline=$true, Position=0)]
        [PSObject]$VMGuest
    )
    
    Process
    {
        if(!$VMGuest)
        {
          $VMGuest = Get-VM
        }
        
        foreach($vm in $VMGuest)
        {
            if($vm.GetType().Name -eq "String")
            {
                $vm = Get-VM -Name $vm
            }
        	
            $vm | Get-HardDisk | %{
        		if ($_.Filename -match ".*-[0-9]{6}.vmdk")
                {
                    $obj = $null
                    if (!(Get-Snapshot $vm))
                    {
                        $obj = New-Object PSObject -Property @{
                          VMName = $vm.Name
                          VMHost = $vm.Host
                          Problem = "Missing Snapshot from Snapshot Manager"
                        }
                    }
                    elseif (Get-Snapshot $vm | where{$_.Name -like "Consolidate*"})
                    {
                        if (@(Get-Snapshot $vm).Length -eq 1)
                        {
                            $obj = New-Object PSObject -Property @{
                              VMName = $vm.Name
                              VMHost = $vm.Host
                              Problem = "Consolidate Helper exists for VM with no snapshots"
                            }
                        } else {
                            $obj = New-Object PSObject -Property @{
                              VMName = $vm.Name
                              VMHost = $vm.Host
                              Problem = "Consolidate Helper exists for VM but has snapshots"
                            }
                        }
                    }
                    
                    if ($obj -ne $null) { Output-Data $obj }
                    Continue
                }
            }
        }
    }
}

###############################
#   END: Function Definitions #
###############################

####################
# BEGIN: MAIN CODE #
####################

if (Test-Path $LogFile) { del $LogFile }
Load-VMLibrary $VCServer

Check-Snapshot
Check-OrphanedData

if ($emailEnable -and (Test-Path $LogFile))
{
    Send-MailMessage -smtpserver $emailServer -to $emailTo -from $emailFrom -subject $emailSubject -body (Get-Content $LogFile | Out-String)
}

 

Report Guest Disk Sizes | PowerCLI

I already explained in my previous post how to grow/extend Guest OS disks with PowerCLI.

Now before we can increase harddrives we also need to identify them. I therefor created this script.

$MyCollection = @()
$AllVMs = Import-Csv -Header Desktop "hdd-check-input.csv" | foreach-object { Get-View -ViewType VirtualMachine -Filter @{"Name" = $_.Desktop}}
$SortedVMs = $AllVMs | Select *, @{N="NumDisks";E={@($_.Guest.Disk.Length)}} | Sort-Object -Descending NumDisks
ForEach ($VM in $SortedVMs){
 $Details = New-object PSObject
 $Details | Add-Member -Name Name -Value $VM.name -Membertype NoteProperty
 $DiskNum = 0
 Foreach ($disk in $VM.Guest.Disk){
 $Details | Add-Member -Name "Disk$($DiskNum)path" -MemberType NoteProperty -Value $Disk.DiskPath
 $Details | Add-Member -Name "Disk$($DiskNum)Capacity(MB)" -MemberType NoteProperty -Value ([math]::Round($disk.Capacity/ 1MB))
 $Details | Add-Member -Name "Disk$($DiskNum)FreeSpace(MB)" -MemberType NoteProperty -Value ([math]::Round($disk.FreeSpace / 1MB))
 $DiskNum++
 }
 $MyCollection += $Details
}
$MyCollection | export-csv hdd-check-output.csv
#Out-GridView
# Export-Csv, ConvertTo-Html or ConvertTo-Xml can be used above instead of Out-Gridview

The advantage using get-view is the nice performance if you run this script.

Try it out. You cant break things 🙂 It will give you a nice .csv as output.

Change & Grow VM Hard Disk

We are right now in the need of resizing all of our Hard Disks on the Virtual Desktop VMs from 40GB to 60GB.
I was looking quite some time to find the appropriate command and this is how you do it:

Get-HardDisk -vm "VMName" | where {$_.Name -eq "Hard Disk 1"} | Set-HardDisk –CapacityKB 62914560 -ResizeGuestPartition -Confirm:$false

A little bit of extra information (we ran into some issues performing this):

The second part of the script (Set-Harddisk) actually calls a library function that is using the “Invoke-VMScript” command.

You need to have following privileges on the vCenter System to execute it.
VirtualMachine.GuestOperations.Modify and VirtualMachine.GuestOperations.Execute.

vmware

Update:

This script makes it even more comfortable. You provide a list of desktops in the input file and it will do all of them in one run. After that you will see a report of the changes in the output file.

Import-Csv -Header Desktop "hdd-increase-input.csv" | foreach-object { Get-HardDisk -vm $_.Desktop | where {$_.Name -eq "Hard disk 1"} | Set-HardDisk –CapacityKB 62914560 -ResizeGuestPartition -Confirm:$false
Write-host "-----------------------------------------------------------------------------------------" -foregroundColor White -backgroundColor DarkGreen
} | export-csv "hdd-increase-output.csv"