Internals/VM.ps1

#Requires -RunAsAdministrator
#Requires -Modules Hyper-V


$ErrorActionPreference = "Stop"


$vmms = gwmi -namespace root\virtualization\v2 Msvm_VirtualSystemManagementService
$vmmsSettings = gwmi -namespace root\virtualization\v2 Msvm_VirtualSystemManagementServiceSettingData
$VirtualDrivePath = $vmmsSettings.DefaultVirtualHardDiskPath


$GUID_EFI_SYSTEM_PARTITION = '{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}'


function New-WindowsZerobootVirtualDisk
{
    [CmdletBinding()]
    Param
    (
    [System.IO.FileInfo]
    [parameter(Mandatory = $true)]
    [ValidateScript(
         {
         if( -Not ($_ | Test-Path) )
         {
             throw "File or folder does not exist: $_"
         }
         return $true
         })]
    $imagePath,

    [string]
    $vhdName = [System.IO.Path]::GetFileNameWithoutExtension($imagePath) + "-zeroboot.vhdx",

    [string]
    $vhdPath = (Join-Path $VirtualDrivePath $vhdName)
    )


    $img = (get-windowsImage -imagePath $imagePath | out-gridview -passthru)
    $img | Out-String


    $vhd = New-VHD -Path $vhdPath -SizeBytes 127GB -Dynamic -BlockSizeBytes 1MB
    $disk = $vhd | Mount-VHD -Passthru
    $vol_esp = $disk `
    | Initialize-Disk -PartitionStyle GPT -Passthru `
    | New-Partition -AssignDriveLetter -GptType $GUID_EFI_SYSTEM_PARTITION -Size 200MB `
    | Format-Volume -FileSystem FAT32 -NewFileSystemLabel ESP -confirm:$false
    $vol_sys = $disk `
    | New-Partition -AssignDriveLetter -UseMaximumSize `
    | Format-Volume -FileSystem NTFS -NewFileSystemLabel WINNT -confirm:$false


    Expand-WindowsImage -ImagePath $imagePath -Index $img.imageIndex -ApplyPath (-join($vol_sys.DriveLetter,":"))
    bcdboot (-join($vol_sys.DriveLetter,":\Windows")) /s (-join($vol_esp.DriveLetter,":")) /l ko-kr /f UEFI /v
    Dismount-VHD -Path $vhdPath


    Write-Host $vhdPath
    return $vhd
}


function New-WindowsVMFromZeroboot
{
    [CmdletBinding()]
    Param
    (
    [System.IO.FileInfo]
    [parameter(Mandatory = $true)]
    [ValidateScript(
         {
         if( -Not ($_ | Test-Path) )
         {
             throw "File or folder does not exist: $_"
         }
         return $true
         })]
    $ParentPath,

    [string]
    $templateName = "",

    [string]
    [ValidateNotNullOrEmpty()]
    $VMName = ($(if (!([string]::IsNullOrEmpty($templateName))) { "${templateName}-" }) + (Get-ChronoVersionString)),

    [Switch]
    [parameter(Mandatory = $false)]
    $PassThru
    )


    try
    {
    $SystemVHDPath = (Join-Path $VirtualDrivePath "${VMName}-system.vhdx")
    $VolumeVHDPath = (Join-Path $VirtualDrivePath "${VMName}-volume.vhdx")


    $SystemVHD = New-VHD -Differencing -ParentPath $ParentPath -Path $SystemVHDPath
    $VolumeVHD = New-VHDForWindowsVMDataVolume -vhdPath $VolumeVHDPath


    $NewVMParam = @{
        Name = $VMName
        Generation = 2
        SwitchName = (Get-VMSwitch -SwitchType External)[0].Name
    }
    $VM = New-VM @NewVMParam


    $vmScsiController0 = $VM | Get-VMScsiController -ControllerNumber 0
    $vmScsiController0 | Add-VMHardDiskDrive -Path $SystemVHDPath
    $vmScsiController0 | Add-VMHardDiskDrive -Path $VolumeVHDPath


    # default configuration
    $VM | Set-VMProcessor -count 2 -maximum 98


    $VMFirmwareParam = @{
        VM = $VM
        EnableSecureBoot = 1
        BootOrder = @((Get-VMHardDiskDrive $VM)[0], (Get-VMNetworkAdapter $VM)[0])
    }
    Set-VMFirmware @VMFirmwareParam


    # Get-VMIntegrationService -VM $VM -Name "Guest Service Interface" | Enable-VMIntegrationService
    $VM | Get-VMIntegrationService | Where-Object {$_.Enabled -eq $false } | ForEach-Object -Process { Enable-VMIntegrationService $_ }


    return $VM
    }
    catch
    {
    Write-Error $_.Exception.Message
    }
}


function New-LinuxVMFromZeroboot
{
    [CmdletBinding()]
    Param
    (
    [System.IO.FileInfo]
    [parameter(Mandatory = $true)]
    [ValidateScript(
         {
         if( -Not ($_ | Test-Path) )
         {
             throw "File or folder does not exist: $_"
         }
         return $true
         })]
    $ParentPath,


    [string]
    $templateName = "linux",

    [string]
    [ValidateNotNullOrEmpty()]
    $VMName = ($(if (!([string]::IsNullOrEmpty($templateName))) { "${templateName}-" }) + (Get-ChronoVersionString))
    )


    try
    {
    $SystemVHDPath = (Join-Path $VirtualDrivePath "${VMName}-system.vhdx")
    $SystemVHD = New-VHD -Differencing -ParentPath $ParentPath -Path $SystemVHDPath


    $NewVMParam = @{
        Name = $VMName
        Generation = 2
        SwitchName = (Get-VMSwitch -SwitchType External)[0].Name
    }
    $VM = New-VM @NewVMParam


    $vmScsiController0 = $VM | Get-VMScsiController -ControllerNumber 0
    $vmScsiController0 | Add-VMHardDiskDrive -Path $SystemVHDPath


    # default configuration
    $VM | Set-VMProcessor -count 2 -maximum 98


    $VMFirmwareParam = @{
        VM = $VM
        BootOrder = @((Get-VMHardDiskDrive $VM)[0], (Get-VMNetworkAdapter $VM)[0])
        EnableSecureBoot = 1
        SecureBootTemplate = "MicrosoftUEFICertificateAuthority"
    }
    Set-VMFirmware @VMFirmwareParam


    # Get-VMIntegrationService -VM $VM -Name "Guest Service Interface" | Enable-VMIntegrationService
    $VM | Get-VMIntegrationService | Where-Object {$_.Enabled -eq $false } | ForEach-Object -Process { Enable-VMIntegrationService $_ }


    return $VM
    }
    catch
    {
    Write-Error $_.Exception.Message
    }
}


# Deprecated
function New-Ubuntu2004VMFromZeroboot
{
    Param
    (
    [System.IO.FileInfo]
    [parameter(Mandatory = $true)]
    $ParentPath,

    [string]
    $templateName = "ubuntu2004",

    [string]
    [ValidateNotNullOrEmpty()]
    $VMName = ($(if (!([string]::IsNullOrEmpty($templateName))) { "${templateName}-" }) + (Get-ChronoVersionString)),

    [Switch]
    [parameter(Mandatory = $False)]
    $PassThru
    )
    return New-LinuxVMFromZeroboot -ParentPath $ParentPath -VMName $VMName
}