Skip to content

Instantly share code, notes, and snippets.

@MarkRobertJohnson
Last active June 1, 2016 10:09
Show Gist options
  • Save MarkRobertJohnson/5893554 to your computer and use it in GitHub Desktop.
Save MarkRobertJohnson/5893554 to your computer and use it in GitHub Desktop.
Function (VCDMount-Iso) to mount ISO images using Virtual Clone Drive
#requires -version 2.0
Add-Type @"
public class Shift {
public static int Right(int x, int count) { return x >> count; }
public static uint Right(uint x, int count) { return x >> count; }
public static long Right(long x, int count) { return x >> count; }
public static ulong Right(ulong x, int count) { return x >> count; }
public static int Left(int x, int count) { return x << count; }
public static uint Left(uint x, int count) { return x << count; }
public static long Left(long x, int count) { return x << count; }
public static ulong Left(ulong x, int count) { return x << count; }
}
"@
function VCDMount-Iso([string]$isoPath, [switch]$waitUntilDriveAvailable) {
<#
.SYNOPSIS
Uses Virtual Clone Drive to mount the specified ISO file
.DESCRIPTION
Mounts the specified image file and returns the PSDrive that was mounted
.PARAMETER isoPath
the Path of the image file
.EXAMPLE
PS C:\> $mountedDrive = VCDMount-Iso "c:\Stuff.iso"
.INPUTS
System.String
.OUTPUTS
PSDrive
.NOTES
Requires Virtual Clone Drive and at least one drive letter is configured in Virtual Clone Drive
#>
$vcdPath = ""
$path = (gi "Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\VCDMount.exe" -errorAction silentlycontinue)
if($path) {
$vcdPath = $path.GetValue($null)
if(-not [io.File]::exists($vcdPath)) {
throw "The file $vcdPath does not exist, please install Virtual Clone Drive"
}
} else {
throw "The registry key 'HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\VCDMount.exe' was not found. Please install Virtual Clone Drive"
}
$drives = VCDGet-PSDrives
$driveToMount = $null
if(-not $drives) { throw "Virtual Clone Drive does not have any drive letters assigned. Please assign at least one drive." }
foreach($drive in $drives) {
if(-not (Get-PSDrive $drive -ErrorAction SilentlyContinue)) {
$driveToMount = $drive
break;
}
}
#all drives are in use, then unmount the first one
if(-not $driveToMount) {
$driveToMount = $drives[0]
}
$val = Exec-Process -executablePath $vcdPath -arguments "/l=$driveToMount `"$isoPath`"" -waitForCompletion
$psdrive = $null
if($waitUntilDriveAvailable) {
$sw = new-object System.Diagnostics.Stopwatch
$sw.Start();
while(-not $psdrive -or ($psdrive -and -not (dir $psdrive.Root -erroraction silentlycontinue))) {
Write-Progress -PercentComplete -1 -Activity "Waiting for Drive $driveToMount to become available" -CurrentOperation "Waiting" -SourceId 1 -Status "Polling for drive readiness"
$psdrive = (Get-PSDrive | where { $_.Name -like "$driveToMount" })
[Threading.Thread]::Sleep(200)
if($sw.Elapsed.TotalSeconds -gt 30) {Write-Warning "Timeout (30 seconds) waiting for drive to become ready"; break; }
}
Write-Progress -PercentComplete -1 -Activity "Waiting for Drive $driveToMount to become available" -CurrentOperation "Waiting" -completed -SourceId 1 -Status "Polling for drive readiness"
}
return $psdrive
}
function VCDGet-PSDrives() {
<#
.SYNOPSIS
Gets a list of all drive letters that Virtual Clone Drive uses
.DESCRIPTION
Gets a list of all drive letters that Virtual Clone Drive uses
.EXAMPLE
PS C:\> $drives = VCDGet-PSDrives
.INPUTS
None
.OUTPUTS
char[]
.NOTES
Requires that Virtual clone drive is installed
.LINK
VCDMount-Iso
#>
#need to get the drives that VCD uses
$vcdKey = gi "Registry::HKEY_CURRENT_USER\Software\Elaborate Bytes\VirtualCloneDrive"
if( -not $vcdKey) {
throw "No Virtual Clone Drive letters are specified in HKEY_CURRENT_USER\Software\Elaborate Bytes\VirtualCloneDrive"
}
$driveMask = [int]$vcdKey.GetValue("VCDDriveMask");
$driveLetters = @();
$start = [int][char]'A';
$end = [int][char]'Z';
for($letter = $start; $letter -le $end; $letter++)
{
if(1 -band $driveMask) {
#found a letter
$driveLetters += [char]$letter
}
$driveMask = [Shift]::Right($driveMask, 1)
}
$driveLetters
}
#Use this to wait a process to complete
function Exec-Process([string]$executablePath, [string]$arguments, [switch]$waitForCompletion) {
Write-Host ("Start at: " + [DateTime]::Now.ToString())
write-host -for cyan "$executablePath ${arguments}"
$continue = $true
while($continue) {
try {
$process = [diagnostics.process]::start($executablePath, $arguments);
if($waitForCompletion) {
$process.WaitForExit();
Write-host "Exited with code: $($process.ExitCode)"
}
$continue = $false;
break;
} catch {
if($_.Exception.Message.Contains("The wrong diskette is in the drive")) {
Write-Warning $_.Exception
Write-Warning "Retrying operation..."
$continue = $true;
[Threading.Thread]::Sleep(1000);
} else {
throw
}
}
}
Write-Host ("End at: " + [DateTime]::Now.ToString())
}
@martijnburgers
Copy link

Thanks, just what I needed!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment