HVTools.psm1

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,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [switch]
        $AutomaticCheckPoints,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [int]
        $VlanId
    )
    begin {}
    process {
        $xml = Get-XMLConfig
        if (!($Switchname)) {
            $Switchname = $xml.config.Switchname
        }
        if (!($HDPath)) {
            $HDPath = $xml.config.Diskpaths.Diskpath[0]
        }
        $ProgressValue = 20
        Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
        New-VM -Name $MachineName -Generation 2 -MemoryStartupBytes $RAM -SwitchName $Switchname -ComputerName $HVServer | Out-Null
        $ProgressValue = 40
        Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
        Set-VMProcessor -VMName $MachineName -Count $NumCPU -ComputerName $HVServer
        if ($NotDynamicRam) {
            Set-VM -VMName $MachineName -DynamicMemory -ComputerName $HVServer
        }
        $ProgressValue = 60
        Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
        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
        $ProgressValue = 80
        Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
        Add-VMHardDiskDrive -Path $VHD -VMName $MachineName -ComputerName $HVServer
        $ProgressValue = 95
        Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
        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 Get-HVMachineInfo {
    Param(
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName = '',
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    begin{}

    process {
        if (!($HVServers)) {
            $xml = Get-XMLConfig
            $HVServers = $xml.config.Servers.Server
        }
        [int]$ProgressValue = 0
        [int]$ProgressPerHVServer = 100 / $HVServers.Count
        $MachineInfo = New-Object 'System.Collections.Generic.List[HVMachineInfo]'
        foreach ($HVServer in $HVServers) {
            $AllHV = get-vm -ComputerName $HVServer | Where-Object {$_.VMName -match $MachineName}
            [int]$AllHVCount = $AllHV.count
            if ($AllHVCount -ne 0) {
                [int]$ProgressPerHV =$ProgressPerHVServer / $AllHVCount
                foreach ($HVName in ($AllHV).Name) {
                    Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue

                    $Mac = (get-vmnetworkAdapter -VMname $HVName -ComputerName $HVServer).MacAddress -replace '(.{2})(?!$)', '$1:'
                    $HVMachineInfo = get-vm -Name $HVName -ComputerName $HVServer | Select-Object Name, State, CPUUsage, ProcessorCount, MemoryAssigned, Uptime, Status, Version, Generation
                    $HVHostInfo = get-vmhost -ComputerName $HVServer | Select-Object ComputerName, LogicalProcessorCount, MemoryCapacity
                    $Gen = $HVMachineInfo.Generation
                    switch ($Gen) {
                        "1" {
                            $BootOrder = (Get-VMBios -VMName 'corp router-1' -ComputerName l22a888).StartupOrder
                        }
                        "2" {
                            $BootOrder = (get-vmfirmware -VMName $HVName -ComputerName $HVServer).bootorder.BootType
                        }
                    }
                    $HardDisk = (get-vmhardDiskDrive -VMName $HVName -ComputerName $HVServer).Path
                    [bool]$HasCheckPoint = $false
                    foreach ($EachHardDisk in $HardDisk) {
                        if ((Get-VHD -Path $EachHardDisk -ComputerName $HVServer).ParentPath) {
                            $HasCheckPoint = $true
                        }
                    }
                    $Machine = [HVMachineInfo]::new(
                        $HVMachineInfo.Name,
                        $HVMachineInfo.State,
                        $HVMachineInfo.CPUUsage,
                        $HVMachineInfo.ProcessorCount,
                        $HVMachineInfo.MemoryAssigned,
                        $Mac,
                        $HardDisk,
                        $HasCheckPoint,
                        $BootOrder,
                        $HVMachineInfo.Uptime,
                        $HVMachineInfo.Status,
                        $HVMachineInfo.Version,
                        $gen,
                        $HVHostInfo.ComputerName,
                        $HVHostInfo.LogicalProcessorCount,
                        $HVHostInfo.MemoryCapacity
                    )
                    $MachineInfo.Add($Machine)
                    $ProgressValue += $ProgressPerHV
                }
            }
       }
        return $MachineInfo
    }
    end {}
}
function Set-HVMachineBootDevice {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HVServer,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers,
        [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,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true,
        ParameterSetName = 'Floppy')]
        [switch]
        $Floppy
    )
    begin{}

    process{
        $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers
        foreach ($HVServer in $HVServers) {
            foreach ($Machine in (get-vm -ComputerName $HVServer | Where-Object {$_.Name -eq $MachineName})) {
                $FoundMachineName = $Machine.VMName
                switch ($machine.generation) {
                    "1" {
                        $StartupOrder = ''
                        if ($nic) {
                            $StartupOrder = @("LegacyNetworkAdapter", "Floppy", "CD", "IDE")
                        }
                        if ($dvd) {
                            $StartupOrder = @("CD", "LegacyNetworkAdapter", "Floppy", "IDE")
                        }
                        if ($File) {
                            $StartupOrder = @("IDE","LegacyNetworkAdapter", "Floppy", "CD")
                        }
                        if ($Floppy) {
                            $StartupOrder = @("Floppy", "LegacyNetworkAdapter", "CD", "IDE")
                        }
                        Set-VMBios -VMName $FoundMachineName -ComputerName $HVServer -StartupOrder $StartupOrder
                        Get-VMBios -VMName $FoundMachineName -ComputerName $HVServer
                    }
                    "2"{
                        if ($nic) {
                            $BootDevice = Get-VMNetworkAdapter -VMName $FoundMachineName -ComputerName $HVServer
                        }
                        if ($dvd) {
                            $BootDevice = Get-VMDvdDrive -VMName $FoundMachineName -ComputerName $HVServer
                        }
                        if ($File) {
                            $BootDevice = (get-vmfirmware -VMName $FoundMachineName -ComputerName $HVServer).BootOrder | Where-Object {$_.BootType -eq 'File'}
                        }
                        Set-VMFirmware -VMName $FoundMachineName -FirstBootDevice ($BootDevice) -ComputerName $HVServer
                        get-vmfirmware -VMName $FoundMachineName -ComputerName $HVServer | Select-Object -ExpandProperty BootOrder
                    }
                }
            }
        }
    }
    end {}
}
function Remove-HVMachine {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HVServer,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    begin{}

    process {
        $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers
        [int]$ProgressValue = 0
        Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue # not yet in use!
        foreach ($HVServer in $HVServers) {
            Stop-VM -Name  $MachineName -ComputerName $HVServer -ErrorAction Ignore -WarningAction SilentlyContinue -Force | Out-Null
            $Disks = Get-VMHardDiskDrive -VMName $MachineName -ComputerName $HVServer
            $DisksToRemove = @()
            foreach ($disk in $disks.path) {
                $DisksToRemove += $disk
                $vhd = (Get-VHD -Path $disk -ComputerName $HVServer).ParentPath
                    if ($vhd) {
                        $DisksToRemove += $vhd
                        do {
                            $vhd = (Get-VHD -Path $vhd -ComputerName $HVServer).ParentPath
                            if ($vhd) {
                                $DisksToRemove += $vhd
                            }
                    } while ($vhd)
                }
            }
            foreach ($disk in $DisksToRemove) {
                $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 = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $DiskDrivePath,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    begin{}

    process {
        $xml = Get-XMLConfig
        if (!($HVServers)) {
            $HVServers = $xml.config.Servers.Server
        }
        if (!($DiskDrivePath)) {
            $DiskDrivePaths = $xml.config.Diskpaths.Diskpath
        }
        [int]$ProgressValue = 0
        [int]$ProgressPerHVServer = 100 / $HVServers.Count
        $DiskInfo = New-Object 'System.Collections.Generic.List[DiskInfo]'
        foreach ($HVServer in $HVServers) {
            [int]$DiskDriveCount = 0
            foreach ($DiskDrivePath in $DiskDrivePaths) {
                $DiskSplit = $DiskDrivePath.split(':')
                $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])"
                if (Test-Path -Path $UNCPath) {
                    $DiskDriveCount += 1
                }
            }
            if ($DiskDriveCount -gt 0) {
                foreach ($DiskDrivePath in $DiskDrivePaths) {
                    $DiskSplit = $DiskDrivePath.split(':')
                    $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])"
                    if (Test-Path -Path $UNCPath) {
                        $HardDrives = (get-childitem -Path $UNCPath).FullName
                        $AllHV = get-vm -ComputerName $HVServer
                        [int]$AllDiskCount = $HardDrives.count
                        [int]$ProgressPerDisk = $ProgressPerHVServer / $AllDiskCount / $DiskDriveCount
                        foreach ($HardDrive in $HardDrives) {
                            Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
                            $UNCDiskSplit = $HardDrive.split('$')
                            $LocalDiskPath = "$($UNCDiskSplit[0][-1]):$($UNCDiskSplit[1])"
                            $Outcome = "Not Assigned"
                            [bool]$Match = $false
                            foreach ($vm in $AllHV) {
                                foreach ($VMDisk in (Get-VMHardDiskDrive -VMName $vm.name -ComputerName $HVServer).Path) {
                                    if ($VMDisk -eq $LocalDiskPath -and !($Match)) {
                                        $Outcome = $vm.Name
                                        $Match = $true
                                    }
                                }
                            }
                            $ProgressValue += $ProgressPerDisk
                            $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)
}

function Get-HVServers {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $HVServer,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [array]
        $HVServers
    )
    if ($HVServer) {
        $HVServers = $HVServer
    }
    if (!($HVServers)) {
        $HVServers  = Find-HVServers -MachineName $MachineName -ExactMatch
    }
    return $HVServers
}
Function Find-HVServers {
    Param(
        [Parameter(Mandatory = $true,
        ValueFromPipelineByPropertyName = $true)]
        [string]
        $MachineName,
        [Parameter(Mandatory = $false,
        ValueFromPipelineByPropertyName = $true)]
        [switch]
        $ExactMatch
    )
    $xml = Get-XMLConfig
    $HVServers = $xml.config.Servers.Server
    $ReturnHVServers = @()
    [int]$ProgressValue = 0
    [int]$ProgressPerHV = 100 / $HVServers.count
    [bool]$FoundMachine = $false
    foreach ($HVServer in $HVServers) {
        Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue
        if ($ExactMatch) {
            $FoundMachine = get-vm -ComputerName $HVServer | Where-Object {$_.Name -eq $MachineName}
        } else {
            $FoundMachine = get-vm -ComputerName $HVServer | Where-Object {$_.Name -match $MachineName}
        }
        if ($FoundMachine) {
            $ReturnHVServers += $HVServer
        }
        $ProgressValue += $ProgressPerHV
    }
    return $ReturnHVServers
}