Functions/New-VirtualHardDisk.ps1
function New-VirtualHardDisk { <# .SYNOPSIS Creates a new virtual hard disk (*.vhd) and several other operations .DESCRIPTION Creates a new virtual hard disk (*.vhd), mounts it, initializes it, formats it and optionally sets the volume label and optionally creates an AutoRun.inf in the root of the new drive .PARAMETER Path The explicit path to the new VHD file .PARAMETER PartitionType The partition type. Validate set: 'MBR', 'GPT'. Default: 'MBR' .PARAMETER VhdType How the Vhd is allocated. Validate set: 'Expandable', 'Fixed'. Default: 'Expandable' .PARAMETER FileSystem The filesystem that will be formatted onto the new virtual disk. Validate set: 'FAT', 'FAT32', 'ExFAT', 'NTFS'. Default: 'FAT' .PARAMETER Size The size of the disk in bytes. Default: 1GB .PARAMETER VolumeLabel Optional string for label on the filesystem .PARAMETER AutoRunIcon Optional icon that will be copied onto root of the virtual disk and AutoRun.inf setting pointing to it .PARAMETER AutoRunLabel Optional label that will be displayed in Windows Explorer and AutoRun.inf setting for it .EXAMPLE New-VirtualHardDisk -Path c:\temp\512.vhd -Size 512MB -VhdType Expandable -FileSystem NTFS -VolumeLabel 'Temp Volume' -AutoRunLabel 'This is my temporary volume' -AutoRunIcon C:\temp\TemporaryFolder.ico Path : C:\temp\512.vhd MaxSizeMB : 512 VhdType : Expandable PartitionType : MBR FileSystem : NTFS VolumeLabel : Temp Volume AutoRunLabel : This is my temporary volume AutoRunIcon : C:\temp\TemporaryFolder.ico .NOTES Must be run from an elevated prompt. #> # todo Max volumelabel length is 32 if NTFS, 11 if others # todo Remount disk doesn't seem to work look into it [CmdletBinding()] param( [ValidateScript({ if (Test-Path -Path $_) { throw "ERROR: Path [$_] already exists. This will not overwrite the file." $false } else { $true } })] [string] $Path, [ValidateSet('MBR', 'GPT')] [string] $PartitionType = 'MBR', [ValidateSet('Expandable', 'Fixed')] [string] $VhdType = 'Expandable', [ValidateSet('FAT', 'FAT32', 'ExFAT', 'NTFS')] $FileSystem = 'FAT', [int64] $Size = 1GB, [string] $VolumeLabel, [ValidateScript({ if ((Test-Path $_) -and ($_ -match '\.ico$')) { $true } else { if (-not (Test-Path $_)) { throw "ERROR: Icon specified [$_] does not exist." } else { throw 'ERROR: Icon must have .ico extension.' } $false } })] [string] $AutoRunIcon, [ValidateScript({ if ($_.Length -gt 32) { throw 'Maximum label length is 32 characters' $false } else { $true } })] [string] $AutoRunLabel ) begin { Write-Verbose -Message "Starting [$($MyInvocation.Mycommand)]" if (-not (Test-IsAdmin)) { Write-Error 'This function must be run from an elevated prompt.' break } $Path = Resolve-PathForce -Path $Path if (-not (Test-Path -Path (Split-Path -Path $Path))) { Write-Error "The parent folder to [$Path] does not exist." break } $Messages = ([ordered] @{ FAT = New-Object -TypeName psobject -Property ([ordered] @{ MinSizeMB = 8 ; MaxSizeMB = 2048 ; MaxVolumeLabel = 11 }) FAT32 = New-Object -TypeName psobject -Property ([ordered] @{ MinSizeMB = 256 ; MaxSizeMB = 32768 ; MaxVolumeLabel = 11 }) exFAT = New-Object -TypeName psobject -Property ([ordered] @{ MinSizeMB = 2048 ; MaxSizeMB = 102400 ; MaxVolumeLabel = 11 }) NTFS = New-Object -TypeName psobject -Property ([ordered] @{ MinSizeMB = 8 ; MaxSizeMB = 102400 ; MaxVolumeLabel = 32 }) }) $VolumeBefore = Get-Volume $SizeMB = [math]::Floor($Size / 1MB) if ($SizeMB -lt $Messages.$FileSystem.MinSizeMB) { Write-Error "Minimum size for [$FileSystem] is [$($Messages.$FileSystem.MinSizeMB)] MB and you wanted [$SizeMB]" break } if ($VolumeLabel.Length -gt $Messages.$FileSystem.MaxVolumeLabel) { Write-Error "Maximum length for the volume label is [$($Messages.$FileSystem.MaxVolumeLabel)] for filesystem [$FileSystem] and yours was [$($VolumeLabel.Length)] long" break } $DiskPartScript = Join-Path -Path $env:TEMP -ChildPath 'DiskPart.script' Set-Content -Path $DiskPartScript -Value "create vdisk file=""$Path"" maximum=$SizeMB type=$VhdType" Add-Content -Path $DiskPartScript -Value "exit" #write-output "[$DiskPartScript]" } process { $null = diskpart.exe /s "$DiskPartScript" $null = Mount-DiskImage -ImagePath "$Path" Get-Disk | Where-Object { $_.Partitionstyle -eq 'Raw' } | Initialize-Disk -PartitionStyle $PartitionType -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Tee-Object -Variable NewDrive | Format-Volume -FileSystem $FileSystem -NewFileSystemLabel "$VolumeLabel" -Confirm:$false | Tee-Object -Variable Format #Write-host -ForegroundColor Cyan 'before blah' $VolumeAfter = Get-Volume $NewVolume = "$($VolumeAfter.DriveLetter | Where-Object { $_ -notin $VolumeBefore.DriveLetter}):" if ($AutoRunIcon) { Set-AutoRun.inf -Path $NewVolume -Icon "$AutoRunIcon" } if ($AutoRunLabel) { Set-AutoRun.inf -Path $NewVolume -Label "$AutoRunLabel" } $null = Dismount-DiskImage -ImagePath "$Path" $null = Mount-DiskImage -ImagePath "$Path" New-Object -TypeName psobject -Property ([ordered] @{ Path = $Path MaxSizeMB = $SizeMB VhdType = $VhdType PartitionType = $PartitionType FileSystem = $FileSystem VolumeLabel = $VolumeLabel AutoRunLabel = $AutoRunLabel AutoRunIcon = $AutoRunIcon }) } end { Remove-Item -Path $DiskPartScript Write-Verbose -Message "Ending [$($MyInvocation.Mycommand)]" } } |