by Klaus Graefensteiner
17. November 2011 06:06
Once upon a time…
there was a Windows 2008 R2 server in the network that behaved very strangely.

Figure 1: The ghost vm
The Windows Process Activation Service sometimes failed to start
There server would take what seems an eternity to start up. IIS wouldn’t start, because the Windows Process Activation Server is hung during startup. This behavior would come and go. Sometimes I would get emails from the past. Ping wouldn’t work reliably.
Very mysterious!
After a few month of blaming Microsoft
I had an idea. Imagine a second copy of the VM is running in the network. Would that explain the strange behavior? Especially, if the two virtual machines are on the same domain?
Hunting for the Zombie with PowerShell
First I shutdown the server and tried to ping it. Success. The zombie is alive. I don’t believe in zombies so I decided to assume that a second copy of the VM must be running on an unknown host. How would I find the host of this VM?
Fortunately each of our VMs have PowerShell Remoting enabled and are configured to use the physical CD Rom drive of the host as virtual drive in the VM. I goggled and found a PowerShell script that would eject the CD drives. I spiced the script up so it would run on a remote computer using PowerShell Remoting.
My script is based on the following example: http://powershell.com/cs/blogs/tips/archive/2009/04/24/ejecting-cds.aspx
PowerShell script to locally eject an array of CDs
Set-StrictMode -Version "Latest"
$DebugPreference = "Continue"
$Drives = 'D:' , 'E:', 'F:', 'G:'
$sa = New-Object -comObject Shell.Application
foreach( $Drive in $Drives)
{
try
{
Write-Debug "Ejecting $Drive"
$sa.Namespace(17).ParseName("$Drive").InvokeVerb("Eject")
Write-Debug "Ejected $Drive"
}
catch
{
Write-Debug "Failed to eject $Drive"
Write-Debug $_.Exception.Message
}
}
PowerShell script to remotely eject an array of CDs
Set-StrictMode -Version "Latest"
$DebugPreference = "Continue"
$Config = @{}
$Config.PSRemotingCredentialPassword = "002200200200200200200202....00776655.4.....444..333..22"
$Config.PSRemotingCredentialDomain = "neexm"
$Config.PSRemotingCredentialUserName = "SmartyP"
$Config.VMComputerName = "ZombieServer"
function Create-PSRemotingSession()
{
#The password key is only usable by the domain user who created it.
#Use the Create-SecretPasswordFile function to create one for your login
$SecurePassword = ConvertTo-SecureString $Config.PSRemotingCredentialPassword
$DomainUser = "{0}\{1}" -f $Config.PSRemotingCredentialDomain, $Config.PSRemotingCredentialUserName
Write-Debug $DomainUser
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $DomainUser, $SecurePassword
$Session = New-PSSession -ComputerName $Config.VMComputerName -credential $Cred
return $Session
}
function Get-DecryptedString($EncryptedString)
{
$Ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($EncryptedString)
$Result = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($Ptr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($Ptr)
$Result
}
function Create-SecretPasswordFile([string] $PasswordFilePath)
{
$Password = Read-Host "Enter your password" -AsSecureString
$EncryptedPassword = ConvertFrom-SecureString $Password
$EncryptedPassword | Out-File -FilePath $PasswordFilePath
}
function Eject-CD($Session)
{
$LocalCDEjectorScriptString = @'
$Drives = 'D:' , 'E:', 'F:', 'G:'
$sa = New-Object -comObject Shell.Application
foreach( $Drive in $Drives)
{
try
{
Write-Debug "Ejecting $Drive"
$sa.Namespace(17).ParseName("$Drive").InvokeVerb("Eject")
Write-Debug "Ejected $Drive"
}
catch
{
Write-Debug "Failed to eject $Drive"
Write-Debug $_.Exception.Message
}
}
'@
#The password key is only usable by the domain user who created it.
#Use the Create-SecretPasswordFile function to create one for your login
$LocalCDEjectorScriptString = $LocalCDEjectorScriptString
$LocalCDEjectorScript = [scriptblock]::Create($LocalCDEjectorScriptString)
Write-Debug $LocalCDEjectorScriptString
$job = Invoke-Command -Session $Session -Scriptblock $LocalCDEjectorScript -AsJob
$Null = Wait-Job -Job $Job
}
$Session = Create-PSRemotingSession
Eject-CD -Session $Session
Remove-PSSession -Session $Session
Download
The scripts can be downloaded here: CDEjector.zip
Ausblick
Too late for Halloween 2011, but quite early for Halloween2012.