Hyper-V On-The-Go – Sending Files to Your VMs (Part 3)

In a previous blog I discussed methods for sending files to the VMs in your portable lab. Those methods included the following:

  1. ISO transfer
  2. PowerShell Cmdlet transfer
  3. Direct VHD Transfer
  4. Network Transfer

I’ve covered the ISO method and discarded the Network method for practicality reasons. In THIS blog I will be covering the PowerShell Cmdlet method. It can be tricky and I have had inconsistent results using it but together we will try to work through any issues and see how it can be done.

Please note that the Hyper-V module will be required for the PowerShell bits.

Kudos to Jeff Hicks for his original work on this. He has a guest-host article on this topic located here.

“….the Script’s the thing wherein lies the conscience of the King….”

Ok, so maybe I shouldn’t wax Shakespearean, but that man just got the mindset shared by many engineers (shipbound or otherwise). There is a poetry to be read in the fine tuned system, logical essay or code snippet, a kind of beauty that many engineers/admins appreciate. PowerShell is the language of stanzas that brings consistency, stability and creativity to what can be humdrum or onerous tasks presented to administrators on a daily basis.

So lets see what kind of pretty things we can come up with for transferring files as we continue with the “Boldly Going” series.

Much Ado About Everything” or “The Devil’s in the Details”

Step 1 – Install the required modules

Install and import the Hyper-V module. No matter how your environment is configured, you will need to import this module. If it is not installed, install it then import it. This module contains the functions needed to transfer files to your VM. If you are using Hyper-V for your portable lab solution (if you’re reading this article then you are) then you should probably add the module load to your $Profile.

Step 2

desktop.

The PowerShell Engine

My script is based off of Chris Wu’s New-IsoFile function located in the PS Gallery Here.

Drag2ISO.ps1

Param ($srcDir)
Function New-IsoFile
{
     
    Param
    ( 
        [parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]$Source,
        [parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)][Alias('Path')]
        [String] $trgPath = "$($env:userprofile)\Desktop\$((Get-Date).ToString("yyyyMMdd-HHmmss.ffff")).iso", 
        [string] $BootFile = $null, 
        [string] $Media = "Disk", 
        [string] $Title = (Get-Date).ToString("yyyyMMdd-HHmmss.ffff"), 
        [switch] $Force 
    )
    Begin
    {
        # Decode here string for ISO public class definition
        Function Dec64($a){$b = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($a));Return $b} #
        ($cp = new-object System.CodeDom.Compiler.CompilerParameters).CompilerOptions = "/unsafe" 
        If (!("ISOFile" -as [type]))
        { 
            $Type = (Dec64 "cHVibGljIGNsYXNzIElTT0ZpbGUNCnsNCiAgICBwdWJsaWMg
                dW5zYWZlIHN0YXRpYyB2b2lkIENyZWF0ZShzdHJpbmcgUGF0aCwgb2JqZWN
                0IFN0cmVhbSwgaW50IEJsb2NrU2l6ZSwgaW50IFRvdGFsQmxvY2tzKQ0KIC
                AgIHsNCiAgICAgICAgaW50IGJ5dGVzID0gMDsNCiAgICAgICAgYnl0ZVtdI
                GJ1ZiA9IG5ldyBieXRlW0Jsb2NrU2l6ZV07DQogICAgICAgIFN5c3RlbS5J
                bnRQdHIgcHRyID0gKFN5c3RlbS5JbnRQdHIpKCZieXRlcyk7DQogICAgICA
                gIFN5c3RlbS5JTy5GaWxlU3RyZWFtIG8gPSBTeXN0ZW0uSU8uRmlsZS5PcG
                VuV3JpdGUoUGF0aCk7DQogICAgICAgIFN5c3RlbS5SdW50aW1lLkludGVyb
                3BTZXJ2aWNlcy5Db21UeXBlcy5JU3RyZWFtIGkgPSBTdHJlYW0gYXMgU3lz
                dGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkNvbVR5cGVzLklTdHJlYW0
                7DQoNCiAgICAgICAgaWYgKG8gPT0gbnVsbCkgeyByZXR1cm47IH0NCiAgIC
                AgICAgd2hpbGUgKFRvdGFsQmxvY2tzLS0gPiAwKSB7DQogICAgICAgICAgI
                CBpLlJlYWQoYnVmLCBCbG9ja1NpemUsIHB0cik7IG8uV3JpdGUoYnVmLCAw
                LCBieXRlcyk7DQogICAgICAgIH0NCiAgICAgICAgby5GbHVzaCgpOyBvLkN
                sb3NlKCk7DQogICAgfQ0KfQ==")
            Add-Type -CompilerParameters $cp -TypeDefinition $Type #-IgnoreWarnings
        } #If
        If ($BootFile -and (Test-Path $BootFile))
        { 
            ($Stream = New-Object -ComObject ADODB.Stream).Open() 
            $Stream.Type = 1  # adFileTypeBinary 
            $Stream.LoadFromFile((Get-Item $BootFile).Fullname) 
            ($Boot = New-Object -ComObject IMAPI2FS.BootOptions).AssignBootImage($Stream) 
        } #If 
        $MediaType = [Ordered]@{BDR=18; BDRE=19;CDR=2; CDRW=3;DISK=12;
                        DVDDASHR=9;DVDDASHRW=10;DVDDASHR_DUALLAYER=11;
                        DVDPLUSR=6; DVDPLUSRW=7;DVDPLUSR_DUALLAYER=8;
                        DVDPLUSRW_DUALLAYER=13;DVDRAM=5;} #MediaType
        If ($MediaType[$Media] -eq $null)
        {
            write-debug "Unsupported Media Type: $Media";
            write-debug ("Choose one from: " + $MediaType.Keys);
            Break
        } #If
        ($Image = new-object -com IMAPI2FS.MsftFileSystemImage `
            -Property @{VolumeName=$Title}).ChooseImageDefaultsForMediaType($MediaType[$Media]) 
        If ((Test-Path $trgPath) -and (!$Force))
        {
            "File Exists $trgPath"
            Break
        } 
        If (!($Target = New-Item -Path $trgPath -ItemType File -Force))
        {
            "Cannot create file $trgPath"
            Break
        } 
    } #Begin
    Process { 
        Switch ($Source)
        { 
            { $_ -is [string] }
                    {
                        $Image.Root.AddTree((Get-Item $_).FullName, $true)
                        continue
                    } 
            { $_ -is [IO.FileInfo] }
                    {
                        $Image.Root.AddTree($_.FullName, $true)
                        continue
                    } 
            { $_ -is [IO.DirectoryInfo] }
                    {
                        $Image.Root.AddTree($_.FullName, $true)
                        continue
                    } 
        }#Switch 
    } #Process 
    End
    { 
        If ($Boot)
        {
            $Image.BootImageOptions=$Boot
        } 
        $Result = $Image.CreateResultImage() 
        [ISOFile]::Create($Target.FullName,$Result.ImageStream,$Result.BlockSize,$Result.TotalBlocks) 
        $Target 
    } #End 

}
If ((Test-Path $srcDir) -eq $False){}
# IyBJRVggIkZ1bmN0aW9uIE5ldy1Jc29GaWxlIHtgbiROZXdJU09gbmB0fSAjTmV3LUlzb0ZpbGUi
$writeDate = Get-Date -f yyyyMMdd
GCI $srcDir |
    New-ISOFile -Path "$srcDir.iso" `
                -Title "$($srcDir.Replace(' ','_').Split('\')[-1])-$writeDate)" `
                -Force

The Command line Engine

The batch file portion passes the dragged folder info to the Powershell script which then copies to files into an ISO file.

2Burn.cmd

@Title=Creating ISO Image from [%1]
@If []==[%1] Exit
@Set pthPS=%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
@Set pthScript=%OneDriveConsumer%\Drag2ISO.ps1
@"%pthPS%" -NoProfile -ExecutionPolicy Bypass -File "%pthScript%" -srcDir %1
@Timeout /T 10

The Override Button on your Desktop

Place both files in a directory of your choice but be sure the batch file points to the correct folder for the PS1 file (4th line). I settled on the root folder of my personal OneDrive so that it would be available across most of my machines.

Because we are trying to create a Drag-&-Drop process we need to add a link to the batch file onto our desktop. Create the shortcut, rename it to your pleasure and, if you want, give it a new icon. I do this to make it easier to find it on my desktop when I need it. I have included screen-shots fo r changing the icons below:

Right-Click on the link you created and open the properties. Change
the icon and select OK to open the default icon file.
Choose the Icon you want to use and click OK to apply it
Note the Icon has changed
Click OK to save your changes  
Now we’re ready to collect the files!

Building the image to fix the ship

This process will ISO-wrap either a single file OR multiple files in a single folder (and any sub-folders). In either case, the ISO file will be created in the same folder as the original.

Now we’re ready to create the ISO. In Windows Explorer, navigate to the folder where you downloaded/copied the file needed on the VM and select it (if you’re copying multiple files, move up one folder level and select the folder containing the files).

Now drag the file/folder to the link on your desktop and drop it. The ISO should be created immediately or after several seconds (depending on the size of your file(s)). The command window will indicate when the file has been created and will close automatically after 10 seconds.

The ISO has been created.

Now all that’s left is to connect the ISO to your VM and copy the files to its HDD (or run them from the ISO).

Warping along on a wing and a prayer

Once the scripts and links are in place, I have found this to be the quickest method for getting files onto your VMs. But different situations demand different solutions to a problem and I will be covering the other two solutions in other blogs. Until then “Lab long and prosper!“.

More Blogs in the ‘Boldly Going” Series

  1. Hardware Considerations for Portable Labs
  2. Enabling the Hyper-V Engine
  3. Reclaiming Drivespace
  4. Sending Files to Your VMs (Part 1)
  5. Sending Files to Your VMs (Part 2)
  6. Sending Files to Your VMs (Part 3)
  7. Changing the Lab VM State
  8. Lab Maintenance (pending)

Author