I often use Virtual Hard Disk (VHD or VHDX) files for different purposes then disks for virtual machines (VMs).
A few examples:
- Container for temporary data
- It is possible to use it in home environment for file backups or for differential backups using Windows Server Backup.
- I like to use VHD as data disk (D:) on my old Microsoft Surface version 1. I won Surface v1 and I still use it at home. The only problem of my Surface that it has small disk. It is not a good idea to create more partitions because more partitions means more wasted space (every partition must have enough free space). To keep application data and system on different partitions I decided to create VHD and mount it using Scheduled Task when system starts.
The only problem of VHD and PowerShell that it is not possible to use *-VHD cmdlets (New-VHD, Mount-VHD) on a devices without Hyper-V role (for example on my Microsoft Surface). The only possibility is to use PowerShell Storage module (Mount-DiskImage) or Dism module (Mount-WindowsImage) to mount VHD and diskpart to create it.
I decided it to write a new module with following cmdlets (advanced functions with module manifest):
- New-RvVirtualDisk
- Mount-RvVirtualDisk
- Dismount-RvVirtualDisk
Cmdlets (advanced functions) have a lot of possibilities how to use them:
- It is possible to run it locally or to define ComputerName to run it on remote device (server) or to set Session parameter and use already established session to remote device (server).
- New-RvVirtualDisk will not only create VHD or VHDX but it can also format it and assign defined drive letter or Mount Point.
- Mount-RvVirtualDisk will not only mount defined VHD or VHDX but it can also assign access path (drive letter or Mount Point) to existing partition on mounted disk.
- New-RvVirtualDisk and Mount-RvVirtualDisk return CimInstance (from Get-Volume) that contains DriveLetter property so it possible for example script another operations that automatically copy data to mounted disk.
Examples
Use established session; Create new disk, format it and keep it mounted
$sessionItem = New-PSSession -ComputerName cont2test0.ad1.contoso.com New-RvVirtualDisk -Path 'C:\Temp\NewDisk.vhdx' -Mount:$true ` -Session $sessionItem Disconnect-PSSession -Session $sessionItem | Remove-PSSession
Invoke commands on multiple servers; Create new disk, format it, specify drive letter (or Mount Point) and file system label and do not keep the disk mounted
New-RvVirtualDisk -Path 'C:\Temp\NewDisk2.vhdx' ` -SizeBytes 100GB ` -Dynamic:$true ` -Format:$true ` -AccessPath Z: ` -VolumeLabel 'My new storage' ` -Mount:$false ` -ComputerName cont2test0.ad1.contoso.com, cont2test1.ad1.contoso.com
Invoke commands on multiple servers; Mount disk and if partition does not have access path (drive letter or Mount Point) then assign available drive letter
Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$true ` -ComputerName cont2test0.ad1.contoso.com, cont2test1.ad1.contoso.com
Mount and add or change drive letter
Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$true ` -AccessPath Z:
Dismount piped VHDX files
Get-DiskImage -ImagePath 'C:\Temp\NewDisk.vhdx' | Dismount-RvVirtualDisk
New-RvVirtualDisk
Function New-RvVirtualDisk { <# .SYNOPSIS Create new VHD or VHDX file (virtual disk). .DESCRIPTION Developer Developer: Rudolf Vesely, http://rudolfvesely.com/ Copyright (c) Rudolf Vesely. All rights reserved License: Free for private use only "RV" are initials of the developer's name Rudolf Vesely and distingue names of Rudolf Vesely's cmdlets from the other cmdlets. Description Create new VHD or VHDX file (virtual disk). Cmdlet is functional on devices where it is not possible to use *-VHD cmdlets because the device does not have installed Hyper-V role. Requirements Developed and tested using PowerShell 4.0. .PARAMETER Path Path to the VHD or VHDX file. .PARAMETER SizeBytes Size in Bytes. .PARAMETER Dynamic Possibilities $true (default) Dynamically expanding virtual disk $false Virtual disk with fixed size. .PARAMETER Format Initialize disk (GPT), create partition, volume and format (NTFS). .PARAMETER AccessPath If specified and volume is formatted then partition will get specified access path. Possibilities Drive letter (only): X Drive letter: X: Mount Point: "D:\My disk" If not specified and volume is formatted then available drive letter will be assigned to the new partition. .PARAMETER VolumeLabel Defined file system label for the new volume. .PARAMETER Mount If $false then the new disk will not be mounted or will be dismounted after formatting. .PARAMETER Force Remove already existing file and create new. .EXAMPLE EXAMPLE: Local: Create new disk, format it and keep it mounted' New-RvVirtualDisk -Path 'C:\Temp\NewDisk.vhdx' ` -SizeBytes 100GB ` -Dynamic:$true ` -Format:$true ` -Mount:$true .EXAMPLE 'Local: Create new disk, format it, specify drive letter (or Mount Point) and volume label and keep it mounted' New-RvVirtualDisk -Path 'C:\Temp\NewDisk2.vhdx' ` -SizeBytes 100GB ` -Dynamic:$true ` -Format:$true ` -AccessPath Z: ` -VolumeLabel 'My new storage' ` -Mount:$true ` -ComputerName cont2test0.ad1.contoso.com .EXAMPLE 'Local: Create new disk, overwrite existing file, format it but do not keep it mounted' New-RvVirtualDisk -Path 'C:\Temp\NewDisk.vhdx' ` -SizeBytes 100GB ` -Dynamic:$true ` -Format:$true ` -Mount:$false ` -Force:$true .EXAMPLE 'ComputerName: Create new disk, format it and keep it mounted' New-RvVirtualDisk -Path 'C:\Temp\NewDisk.vhdx' -Mount:$true ` -ComputerName cont2test0.ad1.contoso.com, cont2test0.ad1.contoso.com .EXAMPLE 'Session: Create new disk, format it and keep it mounted' $sessionItem = New-PSSession -ComputerName cont2test0.ad1.contoso.com New-RvVirtualDisk -Path 'C:\Temp\NewDisk.vhdx' -Mount:$true ` -Session $sessionItem Disconnect-PSSession -Session $sessionItem | Remove-PSSession .INPUTS .OUTPUTS Output from Get-Volume: Microsoft.Management.Infrastructure.CimInstance .LINK https://techstronghold.com/ #> [CmdletBinding( DefaultParametersetName = 'Path', SupportsShouldProcess = $true, PositionalBinding = $false, HelpURI = 'https://techstronghold.com/', ConfirmImpact = 'Medium' )] Param ( [Parameter( Mandatory = $false, Position = 0, ParameterSetName = 'Path', ValueFromPipelineByPropertyName = $true )] [ValidateLength(1, 255)] [Alias('FullName')] [string[]]$Path, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [int64]$SizeBytes = 127GB, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [switch]$Dynamic = $true, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [switch]$Format = $true, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [string]$AccessPath, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [string]$VolumeLabel = 'Data', [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [switch]$Mount = $true, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [switch]$Force, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [AllowNull()] [ValidateLength(1, 255)] [string[]]$ComputerName, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [AllowNull()] [System.Management.Automation.Runspaces.PSSession[]]$Session ) Begin { # Configurations $ErrorActionPreference = 'Stop' if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Set-PSDebug -Strict Set-StrictMode -Version Latest #region Functions Function New-RvVirtualDiskProcess { [CmdletBinding( DefaultParametersetName = 'Disk', SupportsShouldProcess = $true, PositionalBinding = $true, HelpURI = 'https://techstronghold.com/', ConfirmImpact = 'Medium' )] Param ( [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'Disk' )] [string[]]$Path, [Parameter( Mandatory = $true, Position = 1 # ParameterSetName = '' )] [int64]$SizeBytes, [Parameter( Mandatory = $true, Position = 2 # ParameterSetName = '' )] [bool]$Dynamic, [Parameter( Mandatory = $true, Position = 3 # ParameterSetName = '' )] [bool]$Format, [Parameter( Mandatory = $true, Position = 4 # ParameterSetName = '' )] [AllowNull()] [AllowEmptyString()] [string]$AccessPath, [Parameter( Mandatory = $true, Position = 5 # ParameterSetName = '' )] [AllowNull()] [AllowEmptyString()] [string]$VolumeLabel, [Parameter( Mandatory = $true, Position = 6 # ParameterSetName = '' )] [bool]$Mount, [Parameter( Mandatory = $true, Position = 7 # ParameterSetName = '' )] [bool]$Force ) Begin { # Configurations $ErrorActionPreference = 'Stop' if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Set-PSDebug -Strict Set-StrictMode -Version Latest } Process { foreach ($pathItem in $Path) { <# Create #> # Check if already exists if (Test-Path -Path $pathItem -PathType Leaf) { if ($Force) { Write-Warning -Message ('Item will be removed: {0}' -f $pathItem) Remove-Item -Path $pathItem } else { Write-Error -Message ('Item already exists: {0}' -f $pathItem) } } # Create parent directory elseif (!(Test-Path -Path (Split-Path -Path $pathItem -Parent) -PathType Container)) { New-Item -Path (Split-Path -Path $pathItem -Parent) -ItemType directory | Out-Null } # diskpart: Command # create vdisk file= {[type=<fixed|expandable>] | [parent=] | [source=]} [maximum=] [sd=] [noerr] $diskpartCommand = 'create vdisk file="{0}"' -f $pathItem if ($Dynamic) { $diskpartCommand += ' type=expandable maximum={0}' -f [int64]($SizeBytes / 1MB) } else { $diskpartCommand += ' type=fixed' } # diskpart: Run Write-Debug -Message ('diskpart command: {0}' -f $diskpartCommand) $diskpartOutput = $diskpartCommand | diskpart if ($diskpartOutput -match 'DiskPart successfully') { Write-Debug -Message 'OK' } else { Write-Error -Message ('Error during trial to create file: {0}' -f $pathItem) } <# Mount and format #> if ($Format -or $Mount) { $vhdItem = Mount-DiskImage -ImagePath $pathItem -PassThru if ($Format) { $vhdItem | Get-DiskImage | Get-Disk | Initialize-Disk -PartitionStyle GPT -PassThru | New-Partition -UseMaximumSize -OutVariable partitionItem | Format-Volume -FileSystem NTFS -NewFileSystemLabel $VolumeLabel -Confirm:$false | Out-Null if ($AccessPath) { # Drive letter only (only single character) if ($AccessPath -match '^[a-zA-Z]$') { $accessPathItem = '{0}:' -f $AccessPath.ToUpper() } # Mount Point elseif ($AccessPath -match '^[a-zA-Z]:\\\w') { if (!(Test-Path -Path $AccessPath -PathType Container)) { New-Item -Path (Split-Path -Path $pathItem -Parent) ` -ItemType directory | Out-Null } $accessPathItem = $AccessPath } # Other, for example X: else { $accessPathItem = $AccessPath } Write-Verbose -Message ('Add access path: {0}' -f $accessPathItem) $partitionItem | Add-PartitionAccessPath -AccessPath $accessPathItem } else { Write-Verbose -Message 'Add available drive letter' $partitionItem | Add-PartitionAccessPath -AssignDriveLetter } # Return $partitionItem | Get-Volume } else { # Return $vhdItem | Get-DiskImage | Get-Disk } if (!$Mount) { $vhdItem | Dismount-DiskImage } } } } End { } } #endregion } Process { # Remote device: Session if ($Session) { foreach ($sessionItem in $Session) { Invoke-Command ` -Session $sessionItem ` -ArgumentList $Path, $SizeBytes, $Dynamic, $Format, $AccessPath, $VolumeLabel, $Mount, $Force ` -ScriptBlock ${Function:New-RvVirtualDiskProcess} } } else { foreach ($computerNameItem in $(if ($ComputerName) { $ComputerName } else { '.' } )) { # Local device if ($computerNameItem -eq '.' -or $computerNameItem -eq $env:COMPUTERNAME) { New-RvVirtualDiskProcess ` -Path $Path ` -SizeBytes $SizeBytes ` -Dynamic:$Dynamic ` -Format:$Format ` -AccessPath $AccessPath ` -VolumeLabel $VolumeLabel ` -Mount:$Mount ` -Force:$Force } # Remote device: ComputerName else # if ($ComputerName) { Invoke-Command ` -ComputerName $computerNameItem ` -ArgumentList $Path, $SizeBytes, $Dynamic, $Format, $AccessPath, $VolumeLabel, $Mount, $Force ` -ScriptBlock ${Function:New-RvVirtualDiskProcess} } } } } End { } }
Mount-RvVirtualDisk
Function Mount-RvVirtualDisk { <# .SYNOPSIS Mount VHD or VHDX file (virtual disk). .DESCRIPTION Developer Developer: Rudolf Vesely, http://rudolfvesely.com/ Copyright (c) Rudolf Vesely. All rights reserved License: Free for private use only "RV" are initials of the developer's name Rudolf Vesely and distingue names of Rudolf Vesely's cmdlets from the other cmdlets. Description Mount VHD or VHDX file (virtual disk). Cmdlet is functional on devices where it is not possible to use *-VHD cmdlets because the device does not have installed Hyper-V role. Requirements Developed and tested using PowerShell 4.0. .PARAMETER Path Path to the VHD or VHDX file. .PARAMETER DiskImage Output from Get-DiskImage (Microsoft.Management.Infrastructure.CimInstance). .PARAMETER AddAccessPath If first partition on the mounted disk does not have access path (drive letter or Mount Point) then add it. if -AccessPath parameter is not specified and the first partition does not have existing access path then add available drive letter. .PARAMETER AccessPath If specified then first partition will get specified access path. Possibilities Drive letter (only): X Drive letter: X: Mount Point: "D:\My disk" .EXAMPLE 'Local: Mount and do not try to make the partition accessible' Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$false .EXAMPLE 'Local: Mount and if partition does not have access path (drive letter or Mount Point) then assign available drive letter' Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$true .EXAMPLE 'Local: Mount and if partition does not have defined access path then assign defined drive letter or Mount Point' Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$true ` -AccessPath Z: .EXAMPLE 'ComputerName: Mount and do not try to make the partition accessible' Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$false ` -ComputerName cont2test0.ad1.contoso.com, cont2test0.ad1.contoso.com .EXAMPLE 'Session: Mount and do not try to make the partition accessible' $sessionItem = New-PSSession -ComputerName cont2test0.ad1.contoso.com Mount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -AddAccessPath:$false ` -Session $sessionItem Disconnect-PSSession -Session $sessionItem | Remove-PSSession .INPUTS Output from Get-DiskImage: Microsoft.Management.Infrastructure.CimInstance .OUTPUTS Output from Get-Volume: Microsoft.Management.Infrastructure.CimInstance .LINK https://techstronghold.com/ #> [CmdletBinding( DefaultParametersetName = 'DiskImage', SupportsShouldProcess = $true, PositionalBinding = $false, HelpURI = 'https://techstronghold.com/', ConfirmImpact = 'Medium' )] Param ( [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'Path', ValueFromPipelineByPropertyName = $true )] [ValidateLength(1, 255)] [Alias('FullName')] [string[]]$Path, [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'DiskImage', ValueFromPipeline = $true )] [Microsoft.Management.Infrastructure.CimInstance[]]$DiskImage, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [switch]$AddAccessPath = $true, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [string]$AccessPath, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [AllowNull()] [ValidateLength(1, 255)] [string[]]$ComputerName, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [AllowNull()] [System.Management.Automation.Runspaces.PSSession[]]$Session ) Begin { # Configurations $ErrorActionPreference = 'Stop' if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Set-PSDebug -Strict Set-StrictMode -Version Latest #region Functions Function Mount-RvVirtualDiskProcess { [CmdletBinding( DefaultParametersetName = 'Disk', SupportsShouldProcess = $true, PositionalBinding = $true, HelpURI = 'https://techstronghold.com/', ConfirmImpact = 'Medium' )] Param ( [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'Disk' )] [AllowNull()] [string[]]$Path, [Parameter( Mandatory = $true, Position = 1 # ParameterSetName = '' )] [AllowNull()] [Microsoft.Management.Infrastructure.CimInstance[]]$DiskImage, [Parameter( Mandatory = $true, Position = 2 # ParameterSetName = '' )] [bool]$AddAccessPath, [Parameter( Mandatory = $true, Position = 3 # ParameterSetName = '' )] [AllowNull()] [AllowEmptyString()] [string]$AccessPath ) Begin { # Configurations $ErrorActionPreference = 'Stop' if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Set-PSDebug -Strict Set-StrictMode -Version Latest } Process { <# Mount #> $diskImageItems = @() foreach ($pathItem in $Path) { $diskImageItems += Mount-DiskImage -ImagePath $pathItem -PassThru | Get-DiskImage } foreach ($diskImageItem in $DiskImage) { $diskImageItems += Mount-DiskImage -ImagePath $diskImageItem.ImagePath -PassThru | Get-DiskImage } <# Access paths #> foreach ($diskImageItem in $diskImageItems) { # Correct defind access path $mountPoint = $false if ($AccessPath) { # Drive letter only (only single character) if ($AccessPath -match '^[a-zA-Z]$') { $accessPathItem = '{0}:' -f $AccessPath.ToUpper() } # Mount Point elseif ($AccessPath -match '^[a-zA-Z]:\\\w') { $accessPathItem = $AccessPath $mountPoint = $true } # Other, for example X: else { $accessPathItem = $AccessPath } # Remove last backslash for further comparison $accessPathItem -replace '\\$', '' } else { $accessPathItem = $null } # Add access path if ($AddAccessPath) { $partitionItem = $diskImageItem | Get-Disk | Get-Partition | Where-Object -Property Type -EQ Basic | Select-Object -First 1 # Get access paths without last backslash and do not include partition GUID $partitionItemAccessPathItems = $partitionItem | Select-Object -ExpandProperty AccessPaths | Where-Object -FilterScript { $_ -notmatch '^\\\\\?' } | ForEach-Object -Process { $_ -replace '\\$', '' } # Add specific access path if ($accessPathItem) { if ($partitionItemAccessPathItems -contains $accessPathItem) { Write-Verbose -Message ('Partition has defined access path; Current access paths: {0}' -f ($partitionItemAccessPathItems -join ', ')) } else { if ($mountPoint -and !(Test-Path -Path $accessPathItem -PathType Container)) { New-Item -Path $accessPathItem -ItemType directory | Out-Null } Write-Verbose -Message ('Partition does not have defined access path; Add: {0}' -f $accessPathItem) $partitionItem | Add-PartitionAccessPath -AccessPath $accessPathItem } } # Add any access path else { if ($partitionItemAccessPathItems) { Write-Verbose -Message ('Partition has following access paths: {0}' -f ($partitionItemAccessPathItems -join ', ')) } else { Write-Verbose -Message 'No access path; Assign available drive letter' $partitionItem | Add-PartitionAccessPath -AssignDriveLetter } } # Return $partitionItem | Get-Volume } else { # Return $diskImageItem | Get-Disk | Get-Partition | Get-Volume } } } End { # Refresh Windows PowerShell Drives Get-PSDrive | Out-Null } } #endregion } Process { # Remote device: Session if ($Session) { foreach ($sessionItem in $Session) { Invoke-Command ` -Session $sessionItem ` -ArgumentList $Path, $DiskImage, $AddAccessPath, $AccessPath ` -ScriptBlock ${Function:Mount-RvVirtualDiskProcess} } } else { foreach ($computerNameItem in $(if ($ComputerName) { $ComputerName } else { '.' } )) { # Local device if ($computerNameItem -eq '.' -or $computerNameItem -eq $env:COMPUTERNAME) { Mount-RvVirtualDiskProcess ` -Path $Path ` -DiskImage $DiskImage ` -AddAccessPath:$AddAccessPath ` -AccessPath $AccessPath } # Remote device: ComputerName else # if ($ComputerName) { Invoke-Command ` -ComputerName $computerNameItem ` -ArgumentList $Path, $DiskImage, $AddAccessPath, $AccessPath ` -ScriptBlock ${Function:Mount-RvVirtualDiskProcess} } } } } End { } }
Dismount-RvVirtualDisk
Function Dismount-RvVirtualDisk { <# .SYNOPSIS Dismount VHD or VHDX file (virtual disk). .DESCRIPTION Developer Developer: Rudolf Vesely, http://rudolfvesely.com/ Copyright (c) Rudolf Vesely. All rights reserved License: Free for private use only "RV" are initials of the developer's name Rudolf Vesely and distingue names of Rudolf Vesely's cmdlets from the other cmdlets. Description Dismount VHD or VHDX file (virtual disk). Cmdlet is functional on devices where it is not possible to use *-VHD cmdlets because the device does not have installed Hyper-V role. Requirements Developed and tested using PowerShell 4.0. .PARAMETER Path Path to the VHD or VHDX file. .PARAMETER DiskImage Output from Get-DiskImage (Microsoft.Management.Infrastructure.CimInstance). .EXAMPLE 'Local: Dismount defined VHDX file' Dismount-RvVirtualDisk -Path 'C:\Temp\NewDisk.vhdx' .EXAMPLE 'Local: Dismount defined VHDX file; Pipeline' Get-ChildItem -Path 'C:\Temp' -Filter *.vhdx | Dismount-RvVirtualDisk .EXAMPLE 'Local: Dismount defined VHDX file; Pipeline' Get-DiskImage -ImagePath 'C:\Temp\NewDisk.vhdx' | Dismount-RvVirtualDisk .EXAMPLE 'ComputerName: Dismount defined VHDX file' Dismount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -ComputerName cont2test0.ad1.contoso.com, cont2test0.ad1.contoso.com .EXAMPLE 'Session: Dismount defined VHDX file' $sessionItem = New-PSSession -ComputerName cont2test0.ad1.contoso.com Dismount-RvVirtualDisk ` -Path 'C:\Temp\NewDisk.vhdx' ` -Session $sessionItem Disconnect-PSSession -Session $sessionItem | Remove-PSSession .INPUTS Output from Get-DiskImage: Microsoft.Management.Infrastructure.CimInstance .OUTPUTS .LINK https://techstronghold.com/ #> [CmdletBinding( DefaultParametersetName = 'DiskImage', SupportsShouldProcess = $true, PositionalBinding = $false, HelpURI = 'https://techstronghold.com/', ConfirmImpact = 'Medium' )] Param ( [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'Path', ValueFromPipelineByPropertyName = $true )] [ValidateLength(1, 255)] [Alias('FullName')] [string[]]$Path, [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'DiskImage', ValueFromPipeline = $true )] [Microsoft.Management.Infrastructure.CimInstance[]]$DiskImage, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [AllowNull()] [ValidateLength(1, 255)] [string[]]$ComputerName, [Parameter( Mandatory = $false # Position = , # ParameterSetName = '' )] [AllowNull()] [System.Management.Automation.Runspaces.PSSession[]]$Session ) Begin { # Configurations $ErrorActionPreference = 'Stop' if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Set-PSDebug -Strict Set-StrictMode -Version Latest } Process { if ($PSCmdlet.ParameterSetName -eq 'Path') { $pathItems = $Path } else # if ($PSCmdlet.ParameterSetName -eq 'DiskImage') { $pathItems = $DiskImage.ImagePath } # Remote device: Session if ($Session) { foreach ($sessionItem in $Session) { Invoke-Command ` -Session $sessionItem ` -ScriptBlock { Dismount-DiskImage -ImagePath $Using:pathItems } } } else { foreach ($computerNameItem in $(if ($ComputerName) { $ComputerName } else { '.' } )) { # Local device if ($computerNameItem -eq '.' -or $computerNameItem -eq $env:COMPUTERNAME) { Dismount-RvVirtualDiskProcess ` -Path $pathItems } # Remote device: ComputerName else # if ($ComputerName) { Invoke-Command ` -ComputerName $computerNameItem ` -ScriptBlock { Dismount-DiskImage -ImagePath $Using:pathItems } } } } } End { } }
One response to “PowerShell advanced function (cmdlet) to create, format, mount and dismount VHD and VHDX files on local and remote computers”
Function New-RvVirtualDisk :
$diskpartCommand += ‘ type=fixed’
should be :
$diskpartCommand += ‘ type=fixed’ maximum={0}’ -f [int64]($SizeBytes / 1MB)
?