# Compulsory variables
$hyperVHost='HYPERV007'
$vmName='WindowsGoldenImage'
$parentDirectory='C:\ClusterStorage\Volume5'
$disk1Size='100GB'
$memoryAllocation='8GB'
$networkSwitch='PublicZone'
$vlan='1005'
$clusterName='DEV-CLUSTER05'

# Optional variables
$disk2Size=$false # false value here means no disk2 creation
$cpuCount=4
$isoDirectory='C:\ClusterStorage\Volume1\_ISOs'
$isoFile="$isoDirectory\SW_DVD9_Win_Server_STD_CORE_2019_64Bit_English_DC_STD_MLF_X21-96581.ISO"

function createNewVm{
    param(
        $hyperVHost,
        $vmName,
        $parentDirectory,        
        $disk1Size='80GB',
        $disk2Size=$false,
        $memoryAllocation='4GB',
        $cpuCount=2,
        $isoFile,
        $networkSwitch,
        $vlan=$false        
        )
    $ErrorActionPreference='Stop'
    $vmFolder="$parentDirectory\$vmName"
    $vmDisk1="$vmFolder\$vmName`_disk0.vhdx"
    $vmDisk2="$vmFolder\$vmName`_disk1.vhdx"    
    $disk1Size/=1
    $memoryAllocation/=1
    if($disk2size){$disk2Size/=1}
    #Pre-empt this error
    #New-VHD : Cannot bind parameter 'SizeBytes'. Cannot convert value GB to type "System.UInt64". Error: "Input string
    #was not in a correct format."
    #At line:1 char:35
    #+ New-VHD -Path $vmDisk1 -SizeBytes $disk1Size -Dynamic
    #+                                   ~~~~~~~~~~
    #    + CategoryInfo          : InvalidArgument: (:) [New-VHD], ParameterBindingException
    #    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Vhd.PowerShell.Cmdlets.NewVhd
    #

    function confirmation($content,$testValue="I confirm",$maxAttempts=3){
                $confirmed=$false;
                $attempts=0;        
                $content|write-host
                write-host "Please review this content for accuracy.`r`n"
                while ($attempts -le $maxAttempts){
                    if($attempts++ -ge $maxAttempts){
                        write-host "A maximum number of attempts have reached. No confirmations received!`r`n"
                        break;
                        }
                    $userInput = Read-Host -Prompt "Please type in this value => $testValue <= to confirm";
                    if ($userInput.ToLower() -ne $testValue.ToLower()){
                        cls;
                        $content|write-host
                        write-host "Attempt number $attempts of $maxAttempts`: $userInput does not match $testValue. Try again..`r`n"
                        }else{
                            $confirmed=$true;
                            write-host "Confirmed!`r`n";
                            break;
                            }
                    }
                return $confirmed;
            }    
    
    $confirm=confirmation "Please verify these variables for accuracy:`nVM Name`t: $vmName`nVM Folder`t: $vmFolder`nVM Disk1`t: $disk1Size bytes`nVM Disk2`t: $disk2Size bytes`nVM RAM`t: $memoryAllocation bytes`nVM Network`t: $networkSwitch`nVM VLAN`t: $vlan"
    if($confirm){
        try{
            write-host 'Creating VM Folder...'
            if (!(test-path $vmFolder)){mkdir $vmFolder -force}

            write-host 'Creating virtual hard disk(s)...'
            if(!(test-path $vmDisk1)){New-VHD -Path $vmDisk1 -SizeBytes $disk1Size -Dynamic}
            if($disk2Size -and !(test-path $vmDisk2)){New-VHD -Path $vmDisk2 -SizeBytes $disk2Size -Dynamic}

            write-host 'Creating VM...'
            
            New-VM -Name $vmName `
                    -MemoryStartupBytes $memoryAllocation `
                    -BootDevice VHD `
                    -VHDPath $vmDisk1 `
                    -Path $vmFolder `
                    -Generation 2 `
                    -Switch $networkSwitch
            
            write-host "Adding CPU count as $cpuCount"
            SET-VMProcessor –VMName $vmName –count $cpuCount

            write-host 'Attaching 2nd disk if necessary'
            if($disk2Size){Add-VMHardDiskDrive -VMName $vmName -path $vmDisk2}

            write-host "Mapping ISO image to $isoFile..."
            Add-VMDvdDrive -VMName $vmName -Path $isoFile

            write-host "Checking VLAN assignment $vlan"
            if($vlan){Set-VMNetworkAdapterVlan -VMName $vmName -Access -VlanId $vlan}

            write-host "Starting VM $vmName..."
            Start-VM -Name $vmName

            write-host 'Connecting to new VM...'
            if ($env:computername -eq $(.{[void]($hyperVHost -match '([\w\-]+)\.{0,1}');$matches[1]})){
                invoke-expression "VMConnect.exe $env:computername $vmName"
                }
            else{
                write-host "Please RDP into the $env:computername Hyper-V host to run this command 'VMConnect.exe `$env:computername $vmName'"
                }
            return $true
            }
        catch{
            write-warning "$($error[0])"

            return $false
            }
        }
    else{
        write-host 'Cancelled.'
        }
}

createNewVm -hyperVHost $hyperVHost -vmName $vmName -parentDirectory $parentDirectory -disk1Size $disk1Size -disk2Size $disk2Size `
            -cpuCount $cpuCount -memoryAllocation $memoryAllocation -isoFile $isoFile -networkSwitch $networkSwitch -vlan $vlan