HVTools.psm1

# Import-Module "C:\repos\Posh-HVTools\HVTools"

Function New-HVMachine {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HVServer,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $RAM = [System.Int64]4GB,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $Switchname,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [int]
        $NumCPU = 2,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [switch]
        $NotDynamicRam,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [int]
        $MemoryMinimum = 1468006400,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HDSize = [System.UInt64]32GB,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HDPath = 'C:\Hyper-V\vhd\',
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [switch]
        $AutomaticCheckPoints,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [int]
        $VlanId
    )
    begin {}
    process {
        if (!($Switchname)) {
            $xml = Get-XMLConfig
            $Switchname = $xml.config.Switchname
        }
        New-VM -Name $MachineName -Generation 2 -MemoryStartupBytes $RAM -SwitchName $Switchname -ComputerName $HVServer | Out-Null
        Set-VMProcessor -VMName $MachineName -Count $NumCPU -ComputerName $HVServer
        if ($NotDynamicRam) {
            Set-VM -VMName $MachineName -DynamicMemory -ComputerName $HVServer
        }
        set-vm -VMName $MachineName -MemoryMinimumBytes $MemoryMinimum -ComputerName $HVServer

        $VHD = Join-Path -Path $HDPath -ChildPath "$MachineName.vhdx"
        New-VHD -Path $VHD -SizeBytes $HDSize -Dynamic -ComputerName $HVServer | Out-Null
        Add-VMHardDiskDrive -Path $VHD -VMName $MachineName -ComputerName $HVServer
        if (!($AutomaticCheckPoints)) {
            set-vm -VMName $MachineName -AutomaticCheckpointsEnabled:$false -ComputerName $HVServer
        }
        if ($VlanId) {
            get-vmnetworkAdapter -VMname $MachineName -ComputerName $HVServer | set-VMNetworkAdapterVlan -Access -VlanId $VlanId
        }
        Start-VM -VMName $MachineName -ComputerName $hvserver
        Start-Sleep -Seconds 2
        stop-VM -VMName $MachineName -ComputerName $hvserver -Force

        Get-HVMachineInfo -MachineName $MachineName -HVServer $HVServer
    }
    end {}
}
Function Find-HVMachine {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName
    )
    $xml = Get-XMLConfig
    $HVServers = $xml.config.Servers.Server
    foreach ($HVServer in $HVServers) {
        $Machine = get-vm -ComputerName $HVServer | Where-Object {$_.Name -eq $MachineName}
        if ($Machine) {
            return Get-HVMachineInfo -MachineName $Machine.Name -HVServer $HVServer
        }
    }
    return ""
}
function Test-HVMachine {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $Machinename,
        [Parameter(Mandatory = $true)]
        [string]
        $HVServer
    )
    if (get-vm -ComputerName $HVServer | Where-Object {$_.Name -eq $Machinename}) {
        return $true
    } else {
        return $false
    }
}
function Get-HVMachineInfo {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    begin{}

    process {
        if (!($HVServers)) {
            $xml = Get-XMLConfig
            $HVServers = $xml.config.Servers.Server
        }
        $MachineInfo = New-Object 'System.Collections.Generic.List[HVMachineInfo]'
        foreach ($HVServer in $HVServers) {
            if (Test-HVMachine -MachineName $MachineName -HVServer $HVServer) {
                $Mac = (get-vmnetworkAdapter -VMname $MachineName -ComputerName $HVServer).MacAddress -replace '(.{2})(?!$)', '$1:'
                $HVMachineInfo = get-vm -Name $MachineName -ComputerName $HVServer | Select-Object Name, State, CPUUsage,MemoryAssigned, Uptime, Status, Version, Generation
                $HVHostInfo = get-vmhost -ComputerName $HVServer | Select-Object ComputerName, LogicalProcessorCount, MemoryCapacity
                
                $Machine = [HVMachineInfo]::new(
                    $HVMachineInfo.Name,
                    $HVMachineInfo.State,
                    $HVMachineInfo.CPUUsage,
                    $HVMachineInfo.MemoryAssigned,
                    $Mac,
                    $HVMachineInfo.Uptime,
                    $HVMachineInfo.Status,
                    $HVMachineInfo.Version,
                    $HVMachineInfo.Generation,
                    $HVHostInfo.ComputerName,
                    $HVHostInfo.LogicalProcessorCount,
                    $HVHostInfo.MemoryCapacity,
                    (get-vmhardDiskDrive -VMName $MachineName -ComputerName $HVServer).Path,
                    (get-vmfirmware -VMName psd01 -ComputerName l21a888).bootorder.BootType
                )
                $MachineInfo.Add($Machine)
            }
       }
        return $MachineInfo
    }

    end {}
}
function Set-HVMachineBootDevice {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HVServer,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true,
        ParameterSetName = 'NIC')]
        [switch]
        $nic,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true,
        ParameterSetName = 'DVD')]
        [switch]
        $dvd,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true,
        ParameterSetName = 'File')]
        [switch]
        $File
    )
    begin{}

    process{
        if ($nic) {
            $BootDevice = Get-VMNetworkAdapter -VMName $MachineName -ComputerName $HVServer
        }
        if ($dvd) {
            $BootDevice = Get-VMDvdDrive -VMName $MachineName -ComputerName $HVServer
        }
        if ($File) {
            $BootDevice = (get-vmfirmware -VMName psd01 -ComputerName l21a888).BootOrder | Where-Object {$_.BootType -eq 'File'}   
        }
        Set-VMFirmware -VMName $MachineName -FirstBootDevice ($BootDevice) -ComputerName $HVServer
        get-vmfirmware -VMName $MachineName -ComputerName $HVServer | Select-Object -ExpandProperty BootOrder
    }

    end {}
}
function Remove-HVMachine {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    begin{}

    process {
        if (!($HVServers)) {
            $HVServers  = (Find-HVMachine -MachineName $MachineName).HVServer
        }
        foreach ($HVServer in $HVServers) {
            Stop-VM -Name  $MachineName -ComputerName $HVServer -ErrorAction Ignore -WarningAction SilentlyContinue -Force | Out-Null

            $Disks = Get-VMHardDiskDrive -VMName $MachineName -ComputerName $HVServer
            foreach ($Disk in $Disks.Path) {
                $DiskSplit = $disk.split(':')
                $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])"
                Remove-Item -Path $UNCPath -Force
            }
            remove-vm -Name $MachineName -ComputerName $HVServer -Force
        }
    }

    end {}
}
function Get-HVUnassignedDiskDrive {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $DiskDrivePath,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    begin{}

    process {

        if (!($HVServers)) {
            $xml = Get-XMLConfig
            $HVServers = $xml.config.Servers.Server
        }
        $DiskInfo = New-Object 'System.Collections.Generic.List[DiskInfo]'

        foreach ($HVServer in $HVServers) {
            $DiskSplit = $DiskDrivePath.split(':')
            $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])"
            $HardDrives = (get-childitem -Path $UNCPath).FullName
            foreach ($HardDrive in $HardDrives) {
                $DiskSplit = $HardDrive.split('$')
                $LocalDiskPath = "$($DiskSplit[0][-1]):$($DiskSplit[1])"
                $Outcome = "Not Assigned"
                [bool]$Match = $false
                foreach ($vm in get-vm -ComputerName $HVServer) {
                    foreach ($VMDisk in (Get-VMHardDiskDrive -VMName $vm.name -ComputerName $HVServer).Path) {
                        if ($VMDisk -eq $LocalDiskPath -and !($Match)) {
                            $Outcome = $vm.Name
                            $Match = $true
                        }
                    }
                }
                $Disk = [DiskInfo]::new(
                    $HVServer,
                    $LocalDiskPath,
                    $Outcome
                )
                $DiskInfo.add($Disk)
            }
        }
        Return $DiskInfo
    }

    end {}

}
function Get-XMLConfig {
    $xmlFilePath = Join-Path -Path $PSScriptRoot -ChildPath "HVparam.xml"
    Return [xml](Get-Content -Path $xmlFilePath)
}