Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to explore old Windows VHDs.
Hey, Scripting Guy! It is time for spring clean-up around our datacenter. I am not talking about chasing out dust bunnies, although that is part of it. What I am talking about is trying to determine what can be safely deleted without annoying the users too badly.
We have a lot of virtual machines that could have data on them, but I do not know the passwords, and I do not want to go to the trouble of creating virtual machines, mounting the drives, and launching the things to see if there is any user data on the virtual drive. How can I do this quickly and easily—and safely? To be honest I am a bit concerned about the safety of launching a virtual machine that may not have been updated in over a year. Any tips would be appreciated.
—JB
Hello JB,
Microsoft Scripting Guy, Ed Wilson, is here. Today it is cold and rainy, but I guess that is a good thing. In fact, we even turned the heat on for a little while. I am sipping a nice cup of cinnamon tea that I made: a spoon of English Breakfast tea, two cinnamon sticks, and a splash of nutmeg for fun. It is great with a little bit of milk in it—kind of like drinking a cup of cinnamon toast, only not.
Anyway, JB, you need to approach your virtual hard disk (VHD) issue as a disk or folder issue, and not as a Windows issue. So it is like mounting a VHD, only not.
The trick is to mount the Windows image into a folder so that I can use normal Windows PowerShell cmdlets to peruse it for any data that might need to be archived. When I have the data archived, I can delete the VHD and reclaim my lost disk space. My laptop running Windows 8.1 has the necessary cmdlets. In fact, for my purposes, I need the following Windows PowerShell commands:
- Get-ChildItem to find the Windows images
- MD to create a folder that I will use to mount the Windows image
- Mount-WindowsImage to actually mount the Windows image to the newly created folder
- Dismount-WindowsImage to dismount the Windows image after I am finished looking at it
- RD to delete the folder that I used to mount the Windows image
Here is how it all works...
The first thing I do is use the Get-ChildItem cmdlet to search for virtual hard disks that contain the name 2003. In my naming scheme, this will work because I tend to use the version of the operating system as part of the virtual hard disk name. I also use a wildcard character because I cannot remember if the virtual hard disks are VHD or VHDX.
It seems that at some time, Hyper-V changed the file extension, but to be honest, I do not remember when that change actually took place, so I use a wildcard character to ensure that I get the required files. In addition, even if I did actually create a VHD, it is possible that at some date, I may have upgraded the version to a VHDX, so it is always better to be safe than to be sorry. Here is my command:
$image = Get-ChildItem -Path e: -Filter *2003*.vhd* -Recurse -File
Now I create a folder that I will use to mount the Windows image. To do this, I use MD because it is quick. I store the returned directory info object so I can pick up my path. This command is shown here:
$path = md c:\image
I use the Mount-WindowImage cmdlet to mount the Windows image in the virtual hard disk to the C:\image folder. There are three required parameters:
- ImagePath: The complete path to the virtual hard disk that contains the version of Windows to mount. It points to an actual file, not to a folder.
- Path: The path to the folder that will hold the mounted Windows image.
- Index: For a virtual hard disk type of file, it is always an index of 1. This can be different if mounting a WIM, but that is not what I am doing here, so Index is 1.
Here is the command:
Mount-WindowsImage -ImagePath $image.FullName -Path $path.FullName -Index 1
When I run the command, I see a progress bar appear, and then the output tells me the path to find my mounted image, if it is online, and if it needs to be restarted. The progress bar is shown here:
I can navigate to the C:\Image folder. It looks exactly like it would if I was to load Windows and navigate around. As shown here, I even see the page file:
If I click something, it might tell me that I do not have permission to the folder. I can click Continue to obtain permission, and then see what is there. Here is the message:
I can easily copy anything I need to from the VHD. When I am done, I dismount the installation of Windows, and remove my folder. Because I am not making any changes, I do not need to worry about saving changes or anything like that. Here is the script I wrote to dismount Windows:
$path = "C:\image"
Set-Location c:\
Dismount-WindowsImage -Path $path -Discard
RD $path -Force
This works a lot better than having to create a bunch of virtual machines for potentially obsolete versions of Windows that one finds laying around on miscellaneous virtual hard disks.
JB, that is all there is to using Windows PowerShell to explore old Windows VHDs. Join me tomorrow for more Hardware Week when I will talk about more cool Windows PowerShell stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy