Monday, January 28, 2013

How To: Use PowerCLI to find (and disconnect) all CD Drives on VMs [Field Notes]


VMs that leave ISOs mounted cause problems. I'd like to find all the VMs that have CD-ROM drives loaded with ISOs, look over that list, and then remove them if necessary.

Solution (NOTE: Update)

The first solution I provided here wasn't that great, so I'm updating this post. The original contents have been changed because they previously would disconnect the entire CD-ROM drive, vs. just unmounting the ISO. As you can imagine, pulling the equivalent of ripping a CD-ROM drive out while a machine is running can cause some interesting behavior. The solution below outlines a much better way to do this.

Two one-line PowerCLI scripts will help us with this.

Firstly, to search for all Connected CD-ROMs for all VMs:

 Get-VM | Where-Object {$_.PowerState –eq “PoweredOn”} | Get-CDDrive | FT Parent, IsoPath

And as long as there aren't any you need to keep up, you can just select them all and then set the state to "No Media" for each CD-Drive:

Get-VM | Where-Object {$_.PowerState –eq “PoweredOn”} | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$False

Note the -Confirm:$False to allow it to just proceed with what it needs to do.

How To: Run VMWare PowerCLI (PowerShell) Scripts as a Scheduled Task [Field Notes]


I need to create a scheduled task that runs a powershell script that takes actions against my VMWare environment.

For this article, we'll use the example of shutting down all VMs in a Non-Production folder when we're not scheduled to be at our desk (a real problem I'd faced).


Before you Begin: This solution assumes that you've already got PowerCLI configured and know your way around a little bit of PowerCLI/PowerShell.

Step 1: Create a VMWare Credential Store in a File

Firstly, your script will need login permissions to connect to a VI server. We can set this up ahead of time by  creating an encrypted credential store for your server.
  • Open PowerCLI as an Administrator.
  • Run the following command:

NOTES: When creating the credential store, you'll want to create it as the same user that will eventually need to access it. If you create the credential file as user X but run the Scheduled Task as user Y, your task will be unable to read the file. Also, you don't need to have a file extension, but I use "creds" just to make it clearer to me. Obviously, replace the host, username, password, and path with something that makes sense to you.

Step 2: Create a Script that Uses the Credential Store

Create a PowerShell Script Similar to the following:

Step 3: Set up the Scheduled Task

  • Create a scheduled task in the task scheduler.
  • Run the task with the highest privileges.
  • In the action for the task, run the program/script "powershell.exe" (no quotes). 
  • For the arguments, use "c:\Path\To\YourScript.ps1" (with quotes in case of spaces -- good habit).
Test your task manually several times. Make sure the log output looks right.

Taking it Live: Removing the -WhatIf
When the task is scheduled and you're satisfied it will run as you intended it, edit the script to remove the -WhatIf line. This means the Guest OSes will actually be shut down.

Afterwards: Gotchas
I gained some insights from this process, mostly by trial and error. I thought I should share the fruits of my errors with you:

  • Do not run a powershell script directly as a scheduled task. It does not work. Use the powershell.exe "C:\Path\To\script.ps1" format to execute.