EnhancedHyperVAO.psm1

#Region '.\Public\Add-DVDDriveToVM.ps1' -1

function Add-DVDDriveToVM {
    <#
    .SYNOPSIS
    Adds a DVD drive with the specified ISO to the VM and validates the addition.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName,

        [Parameter(Mandatory = $true)]
        [string]$InstallMediaPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting Add-DVDDriveToVM function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName; InstallMediaPath = $InstallMediaPath }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Validating if the ISO is already added to VM: $VMName" -Level "INFO"
            if (Validate-ISOAdded -VMName $VMName -InstallMediaPath $InstallMediaPath) {
                Write-EnhancedLog -Message "ISO is already added to VM: $VMName" -Level "INFO"
                return
            }

            Write-EnhancedLog -Message "Adding SCSI controller to VM: $VMName" -Level "INFO"
            Add-VMScsiController -VMName $VMName -ErrorAction Stop

            Write-EnhancedLog -Message "Adding DVD drive with ISO to VM: $VMName" -Level "INFO"
            Add-VMDvdDrive -VMName $VMName -Path $InstallMediaPath -ErrorAction Stop

            Write-EnhancedLog -Message "DVD drive with ISO added to VM: $VMName" -Level "INFO"

            Write-EnhancedLog -Message "Validating the ISO addition for VM: $VMName" -Level "INFO"
            if (-not (Validate-ISOAdded -VMName $VMName -InstallMediaPath $InstallMediaPath)) {
                Write-EnhancedLog -Message "Failed to validate the ISO addition for VM: $VMName" -Level "ERROR"
                throw "ISO validation failed."
            }
        }
        catch {
            Write-EnhancedLog -Message "An error occurred while adding DVD drive to VM: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Add-DVDDriveToVM function" -Level "INFO"
    }
}
#EndRegion '.\Public\Add-DVDDriveToVM.ps1' 52
#Region '.\Public\ConfigureVM.ps1' -1

function ConfigureVM {
    <#
    .SYNOPSIS
    Configures the specified VM with the given processor count and memory settings.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$VMName,

        [Parameter(Mandatory = $true)]
        [int]$ProcessorCount
    )

    Begin {
        Write-EnhancedLog -Message "Starting Configure-VM function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName; ProcessorCount = $ProcessorCount }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Configuring VM processor for VM: $VMName with $ProcessorCount processors" -Level "INFO"
            Set-VMProcessor -VMName $VMName -ExposeVirtualizationExtensions $true -Count $ProcessorCount

            Write-EnhancedLog -Message "Configuring memory for VM: $VMName" -Level "INFO"
            Set-VMMemory -VMName $VMName

            Write-EnhancedLog -Message "VM $VMName configured" -Level "INFO"
        } catch {
            Write-EnhancedLog -Message "An error occurred while configuring VM $VMName $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Configure-VM function" -Level "INFO"
    }
}
#EndRegion '.\Public\ConfigureVM.ps1' 39
#Region '.\Public\ConfigureVMBoot.ps1' -1

function ConfigureVMBoot {
    <#
    .SYNOPSIS
    Configures the boot order of the specified VM to boot from the specified differencing disk.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$VMName,

        [Parameter(Mandatory = $true)]
        [string]$DifferencingDiskPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting Configure-VMBoot function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName; DifferencingDiskPath = $DifferencingDiskPath }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Retrieving hard disk drive for VM: $VMName with path: $DifferencingDiskPath" -Level "INFO"
            $VHD = Get-VMHardDiskDrive -VMName $VMName | Where-Object { $_.Path -eq $DifferencingDiskPath }

            if ($null -eq $VHD) {
                Write-EnhancedLog -Message "No hard disk drive found for VM: $VMName with the specified path: $DifferencingDiskPath" -Level "ERROR"
                throw "Hard disk drive not found."
            }

            Write-EnhancedLog -Message "Setting VM firmware for VM: $VMName to boot from the specified disk" -Level "INFO"
            Set-VMFirmware -VMName $VMName -FirstBootDevice $VHD

            Write-EnhancedLog -Message "VM boot configured for $VMName" -Level "INFO"
        } catch {
            Write-EnhancedLog -Message "An error occurred while configuring VM boot for $VMName $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Configure-VMBoot function" -Level "INFO"
    }
}
#EndRegion '.\Public\ConfigureVMBoot.ps1' 44
#Region '.\Public\Connect-VMConsole.ps1' -1

function Connect-VMConsole {
    <#
    .SYNOPSIS
    Connects to the console of the specified VM.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName,

        [Parameter(Mandatory = $false)]
        [string]$ServerName = "localhost",

        [Parameter(Mandatory = $false)]
        [int]$Count = 1
    )

    Begin {
        Write-EnhancedLog -Message "Starting Connect-VMConsole function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName; ServerName = $ServerName; Count = $Count }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Validating if VM $VMName exists" -Level "INFO"
            if (-not (Validate-VMExists -VMName $VMName)) {
                Write-EnhancedLog -Message "VM $VMName does not exist. Exiting function." -Level "ERROR"
                return
            }

            Write-EnhancedLog -Message "Checking if VM $VMName is running" -Level "INFO"
            if (-not (Validate-VMStarted -VMName $VMName)) {
                Write-EnhancedLog -Message "VM $VMName is not running. Cannot connect to console." -Level "ERROR"
                return
            }

            $vmConnectArgs = "$ServerName `"$VMName`""
            if ($Count -gt 1) {
                $vmConnectArgs += " -C $Count"
            }

            Write-EnhancedLog -Message "VMConnect arguments: $vmConnectArgs" -Level "DEBUG"
            Start-Process -FilePath "vmconnect.exe" -ArgumentList $vmConnectArgs -ErrorAction Stop
            Write-EnhancedLog -Message "VMConnect launched for VM $VMName on $ServerName with count $Count." -Level "INFO"
        } catch {
            Write-EnhancedLog -Message "An error occurred while launching VMConnect for VM $VMName. $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Connect-VMConsole function" -Level "INFO"
    }
}
#EndRegion '.\Public\Connect-VMConsole.ps1' 55
#Region '.\Public\CreateVMFolder.ps1' -1

function CreateVMFolder {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$VMPath,
        
        [Parameter(Mandatory = $true)]
        [string]$VMName
    )

    Begin {
        Write-EnhancedLog -Message "Starting CreateVMFolder function" -Level "INFO"
        Log-Params -Params @{ VMPath = $VMPath; VMName = $VMName }
    }

    Process {
        try {
            $VMFullPath = Join-Path -Path $VMPath -ChildPath $VMName
            Write-EnhancedLog -Message "Creating VM folder at path: $VMFullPath" -Level "INFO"
            New-Item -ItemType Directory -Force -Path $VMFullPath | Out-Null
            Write-EnhancedLog -Message "VM folder created at $VMFullPath" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            return $VMFullPath
        } catch {
            Write-EnhancedLog -Message "An error occurred while creating the VM folder: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Create-VMFolder function" -Level "INFO"
    }
}
#EndRegion '.\Public\CreateVMFolder.ps1' 33
#Region '.\Public\Dismount-VHDX.ps1' -1

function Dismount-VHDX {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VHDXPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting Dismount-VHDX function" -Level "INFO"
        Log-Params -Params @{ VHDXPath = $VHDXPath }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Validating if the VHDX is mounted: $VHDXPath" -Level "INFO"
            $isMounted = Validate-VHDMount -VHDXPath $VHDXPath
            Write-EnhancedLog -Message "Validation result: VHDX is mounted = $isMounted" -Level "INFO"

            if ($isMounted) {
                Write-EnhancedLog -Message "Checking for dependent VMs using the VHDX: $VHDXPath" -Level "INFO"
                $dependentVMs = Get-DependentVMs -VHDXPath $VHDXPath
                $runningVMs = $dependentVMs | Where-Object { $_.State -eq 'Running' }
                
                if ($runningVMs.Count -gt 0) {
                    Write-EnhancedLog -Message "Found running VMs using the VHDX. Skipping dismount." -Level "WARNING"
                    foreach ($vm in $runningVMs) {
                        Write-EnhancedLog -Message "Running dependent VM: $($vm.Name)" -Level "WARNING"
                    }
                    return
                }

                Write-EnhancedLog -Message "No running VMs found using the VHDX. Proceeding with dismount." -Level "INFO"
                Dismount-VHD -Path $VHDXPath -ErrorAction Stop
                Write-EnhancedLog -Message "VHDX dismounted successfully." -Level "INFO"
            } else {
                Write-EnhancedLog -Message "$VHDXPath is already dismounted or not mounted." -Level "INFO"
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while dismounting the VHDX: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Dismount-VHDX function" -Level "INFO"
    }
}
#EndRegion '.\Public\Dismount-VHDX.ps1' 48
#Region '.\Public\EnableVMTPM.ps1' -1

function EnableVMTPM {
    <#
    .SYNOPSIS
    Enables TPM for the specified VM.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName
    )

    Begin {
        Write-EnhancedLog -Message "Starting Enable-VMTPM function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Retrieving HGS Guardian" -Level "INFO"
            $owner = Get-HgsGuardian -Name "UntrustedGuardian"

            Write-EnhancedLog -Message "Creating new HGS Key Protector" -Level "INFO"
            $kp = New-HgsKeyProtector -Owner $owner -AllowUntrustedRoot

            Write-EnhancedLog -Message "Setting VM Key Protector for VM: $VMName" -Level "INFO"
            Set-VMKeyProtector -VMName $VMName -KeyProtector $kp.RawData

            Write-EnhancedLog -Message "Enabling TPM for VM: $VMName" -Level "INFO"
            Enable-VMTPM -VMName $VMName

            Write-EnhancedLog -Message "TPM enabled for $VMName" -Level "INFO"
        } catch {
            Write-EnhancedLog -Message "An error occurred while enabling TPM for VM $VMName $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Enable-VMTPM function" -Level "INFO"
    }
}
#EndRegion '.\Public\EnableVMTPM.ps1' 42
#Region '.\Public\EnsureUntrustedGuardianExists.ps1' -1

function EnsureUntrustedGuardianExists {
    <#
    .SYNOPSIS
    Ensures that an untrusted guardian exists. If not, creates one.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]$GuardianName = 'UntrustedGuardian'
    )

    Begin {
        Write-EnhancedLog -Message "Starting Ensure-UntrustedGuardianExists function" -Level "INFO"
        Log-Params -Params @{ GuardianName = $GuardianName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking for the existence of the guardian: $GuardianName" -Level "INFO"
            $guardian = Get-HgsGuardian -Name $GuardianName -ErrorAction SilentlyContinue

            if ($null -eq $guardian) {
                Write-EnhancedLog -Message "Guardian $GuardianName not found. Creating..." -Level "WARNING"
                New-HgsGuardian -Name $GuardianName -GenerateCertificates
                Write-EnhancedLog -Message "Guardian $GuardianName created successfully" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            } else {
                Write-EnhancedLog -Message "Guardian $GuardianName already exists" -Level "INFO"
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while checking or creating the guardian: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Ensure-UntrustedGuardianExists function" -Level "INFO"
    }
}
#EndRegion '.\Public\EnsureUntrustedGuardianExists.ps1' 39
#Region '.\Public\Get-DependentVMs.ps1' -1

function Get-DependentVMs {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VHDXPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting Get-DependentVMs function" -Level "INFO"
        Log-Params -Params @{ VHDXPath = $VHDXPath }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Retrieving all VMs" -Level "INFO"
            $allVMs = Get-VM
            Write-EnhancedLog -Message "Total VMs found: $($allVMs.Count)" -Level "INFO"

            $dependentVMs = [System.Collections.Generic.List[PSObject]]::new()

            foreach ($vm in $allVMs) {
                $hardDrives = $vm.HardDrives
                foreach ($hd in $hardDrives) {
                    $parentPath = (Get-VHD -Path $hd.Path).ParentPath
                    if ($parentPath -eq $VHDXPath) {
                        $dependentVMs.Add($vm)
                        Write-EnhancedLog -Message "Dependent VM: $($vm.Name)" -Level "INFO"
                        break
                    }
                }
            }

            Write-EnhancedLog -Message "Total dependent VMs using VHDX $VHDXPath $($dependentVMs.Count)" -Level "INFO"
            return $dependentVMs
        } catch {
            Write-EnhancedLog -Message "An error occurred while retrieving dependent VMs: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            return [System.Collections.Generic.List[PSObject]]::new()
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Get-DependentVMs function" -Level "INFO"
    }
}
#EndRegion '.\Public\Get-DependentVMs.ps1' 46
#Region '.\Public\Get-NextVMNamePrefix.ps1' -1

function Get-NextVMNamePrefix {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [PSCustomObject]$Config
    )

    Begin {
        Write-EnhancedLog -Message "Starting Get-NextVMNamePrefix function" -Level "INFO"
    }

    Process {
        try {
            Write-EnhancedLog -Message "Retrieving the most recent VM" -Level "INFO"
            $mostRecentVM = Get-VM | Sort-Object -Property CreationTime -Descending | Select-Object -First 1
            $prefixNumber = 0

            if ($null -ne $mostRecentVM) {
                Write-EnhancedLog -Message "Most recent VM found: $($mostRecentVM.Name)" -Level "INFO"
                if ($mostRecentVM.Name -match '^\d+') {
                    $prefixNumber = [int]$matches[0]
                    Write-EnhancedLog -Message "Extracted prefix number: $prefixNumber" -Level "INFO"
                } else {
                    Write-EnhancedLog -Message "Most recent VM name does not start with a number" -Level "INFO"
                }
            } else {
                Write-EnhancedLog -Message "No existing VMs found" -Level "INFO"
            }

            $nextPrefixNumber = $prefixNumber + 1
            $newVMNamePrefix = $Config.VMNamePrefixFormat -f $nextPrefixNumber
            Write-EnhancedLog -Message "Generated new VM name prefix: $newVMNamePrefix" -Level "INFO"

            return $newVMNamePrefix
        } catch {
            Write-EnhancedLog -Message "An error occurred in Get-NextVMNamePrefix: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Get-NextVMNamePrefix function completed" -Level "INFO"
    }
}
#EndRegion '.\Public\Get-NextVMNamePrefix.ps1' 45
#Region '.\Public\Initialize-HyperVServices.ps1' -1

function Initialize-HyperVServices {
    [CmdletBinding()]
    param ()

    Begin {
        Write-EnhancedLog -Message "Starting Initialize-HyperVServices function" -Level "INFO"
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking for Hyper-V services" -Level "INFO"
            if (Get-Service -DisplayName *hyper*) {
                Write-EnhancedLog -Message "Starting Hyper-V services: vmcompute and vmms" -Level "INFO"
                Start-Service -Name vmcompute -ErrorAction SilentlyContinue
                Start-Service -Name vmms -ErrorAction SilentlyContinue
                Write-EnhancedLog -Message "Hyper-V services started" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            } else {
                Write-EnhancedLog -Message "No Hyper-V services found" -Level "WARNING"
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while starting Hyper-V services: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Initialize-HyperVServices function" -Level "INFO"
    }
}
#EndRegion '.\Public\Initialize-HyperVServices.ps1' 30
#Region '.\Public\New-CustomVMWithDifferencingDisk.ps1' -1

function New-CustomVMWithDifferencingDisk {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$VMName,

        [Parameter(Mandatory = $true)]
        [string]$VMFullPath,

        [Parameter(Mandatory = $true)]
        [string]$ParentVHDPath,

        [Parameter(Mandatory = $true)]
        [string]$DifferencingDiskPath,

        [Parameter(Mandatory = $true)]
        [string]$SwitchName,

        [Parameter(Mandatory = $true)]
        [int64]$MemoryStartupBytes,

        [Parameter(Mandatory = $true)]
        [int64]$MemoryMinimumBytes,

        [Parameter(Mandatory = $true)]
        [int64]$MemoryMaximumBytes,

        [Parameter(Mandatory = $true)]
        [int]$Generation
    )

    Begin {
        Write-EnhancedLog -Message "Starting New-CustomVMWithDifferencingDisk function" -Level "INFO"
        Log-Params -Params @{
            VMName               = $VMName
            VMFullPath           = $VMFullPath
            ParentVHDPath        = $ParentVHDPath
            DifferencingDiskPath = $DifferencingDiskPath
            SwitchName           = $SwitchName
            MemoryStartupBytes   = $MemoryStartupBytes
            MemoryMinimumBytes   = $MemoryMinimumBytes
            MemoryMaximumBytes   = $MemoryMaximumBytes
            Generation           = $Generation
        }
    }

    Process {
        try {
            $NewVMSplat = @{
                Generation         = $Generation
                Path               = $VMFullPath
                Name               = $VMName
                MemoryStartupBytes = $MemoryStartupBytes
                SwitchName         = $SwitchName
                NoVHD              = $true
            }
            New-VM @NewVMSplat
            Write-EnhancedLog -Message "VM $VMName created with specified parameters" -Level "INFO"

            Set-VMMemory -VMName $VMName -DynamicMemoryEnabled $true -MinimumBytes $MemoryMinimumBytes -MaximumBytes $MemoryMaximumBytes -StartupBytes $MemoryStartupBytes
            Write-EnhancedLog -Message "Dynamic memory set for VM $VMName" -Level "INFO"

            New-VHD -Path $DifferencingDiskPath -ParentPath $ParentVHDPath -Differencing
            Write-EnhancedLog -Message "Differencing disk created at $DifferencingDiskPath based on $ParentVHDPath" -Level "INFO"

            Add-VMHardDiskDrive -VMName $VMName -Path $DifferencingDiskPath
            Write-EnhancedLog -Message "Differencing disk added to VM $VMName" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
        } catch {
            Write-EnhancedLog -Message "An error occurred while creating the VM or its components: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting New-CustomVMWithDifferencingDisk function" -Level "INFO"
    }
}
#EndRegion '.\Public\New-CustomVMWithDifferencingDisk.ps1' 78
#Region '.\Public\Parse-Size.ps1' -1

function Parse-Size {
    <#
    .SYNOPSIS
    Parses a size string and converts it to bytes.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Size
    )

    Begin {
        Write-EnhancedLog -Message "Starting Parse-Size function" -Level "INFO"
        Log-Params -Params @{ Size = $Size }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Parsing size string: $Size" -Level "INFO"
            switch -regex ($Size) {
                '^(\d+)\s*KB$' {
                    $result = [int64]$matches[1] * 1KB
                    Write-EnhancedLog -Message "Parsed size: $Size to $result bytes" -Level "INFO"
                    return $result
                }
                '^(\d+)\s*MB$' {
                    $result = [int64]$matches[1] * 1MB
                    Write-EnhancedLog -Message "Parsed size: $Size to $result bytes" -Level "INFO"
                    return $result
                }
                '^(\d+)\s*GB$' {
                    $result = [int64]$matches[1] * 1GB
                    Write-EnhancedLog -Message "Parsed size: $Size to $result bytes" -Level "INFO"
                    return $result
                }
                '^(\d+)\s*TB$' {
                    $result = [int64]$matches[1] * 1TB
                    Write-EnhancedLog -Message "Parsed size: $Size to $result bytes" -Level "INFO"
                    return $result
                }
                default {
                    Write-EnhancedLog -Message "Invalid size format: $Size" -Level "ERROR"
                    throw "Invalid size format: $Size"
                }
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while parsing size: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Parse-Size function" -Level "INFO"
    }
}
#EndRegion '.\Public\Parse-Size.ps1' 56
#Region '.\Public\Shutdown-DependentVMs.ps1' -1

# function Shutdown-DependentVMs {
# [CmdletBinding()]
# param (
# [Parameter(Mandatory = $true)]
# [string]$VHDXPath
# )

# Process {
# try {
# $dependentVMs = Get-DependentVMs -VHDXPath $VHDXPath
# foreach ($vm in $dependentVMs) {
# Write-EnhancedLog -Message "Shutting down VM: $($vm.Name)" -Level "INFO"
# Stop-VM -Name $vm.Name -Force -ErrorAction Stop
# }
# } catch {
# Write-EnhancedLog -Message "An error occurred while shutting down dependent VMs: $($_.Exception.Message)" -Level "ERROR"
# Handle-Error -ErrorRecord $_
# }
# }
# }
#EndRegion '.\Public\Shutdown-DependentVMs.ps1' 21
#Region '.\Public\Start-VMEnhanced.ps1' -1

function Start-VMEnhanced {
    <#
    .SYNOPSIS
    Starts the specified VM if it exists and is not already running.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName
    )

    Begin {
        Write-EnhancedLog -Message "Starting Start-VMEnhanced function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Validating if VM $VMName exists" -Level "INFO"
            if (-not (Validate-VMExists -VMName $VMName)) {
                Write-EnhancedLog -Message "VM $VMName does not exist. Exiting function." -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
                return
            }

            Write-EnhancedLog -Message "Checking if VM $VMName is already running" -Level "INFO"
            if (Validate-VMStarted -VMName $VMName) {
                Write-EnhancedLog -Message "VM $VMName is already running." -Level "INFO" -ForegroundColor ([ConsoleColor]::Yellow)
            } else {
                Write-EnhancedLog -Message "Starting VM $VMName" -Level "INFO"
                Start-VM -Name $VMName -ErrorAction Stop
                Write-EnhancedLog -Message "VM $VMName has been started successfully." -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while starting the VM $VMName. $($_.Exception.Message)" -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Start-VMEnhanced function" -Level "INFO"
    }
}
#EndRegion '.\Public\Start-VMEnhanced.ps1' 43
#Region '.\Public\Validate-ISOAdded.ps1' -1

function Validate-ISOAdded {
    <#
    .SYNOPSIS
    Validates if the specified ISO file is added to the VM.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName,

        [Parameter(Mandatory = $true)]
        [string]$InstallMediaPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting Validate-ISOAdded function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName; InstallMediaPath = $InstallMediaPath }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Retrieving DVD drive information for VM: $VMName" -Level "INFO"
            $dvdDrive = Get-VMDvdDrive -VMName $VMName -ErrorAction SilentlyContinue

            if ($dvdDrive -and ($dvdDrive.Path -eq $InstallMediaPath)) {
                Write-EnhancedLog -Message "ISO is correctly added to VM: $VMName" -Level "INFO" -ForegroundColor Green
                return $true
            } else {
                Write-EnhancedLog -Message "ISO is not added to VM: $VMName" -Level "WARNING" -ForegroundColor Red
                return $false
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while validating ISO addition: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            return $false
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Validate-ISOAdded function" -Level "INFO"
    }
}
#EndRegion '.\Public\Validate-ISOAdded.ps1' 43
#Region '.\Public\Validate-VHDMount.ps1' -1

function Validate-VHDMount {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VHDXPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting Validate-VHDMount function" -Level "INFO"
        Log-Params -Params @{ VHDXPath = $VHDXPath }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking if the VHDX is mounted: $VHDXPath" -Level "INFO"
            $vhd = Get-VHD -Path $VHDXPath -ErrorAction SilentlyContinue
            
            if ($null -eq $vhd) {
                Write-EnhancedLog -Message "Get-VHD did not return any information for the path: $VHDXPath" -Level "INFO" -ForegroundColor Red
                return $false
            }

            Write-EnhancedLog -Message "Get-VHD output: $($vhd | Format-List | Out-String)" -Level "DEBUG"

            if ($vhd.Attached) {
                Write-EnhancedLog -Message "VHDX is mounted: $VHDXPath" -Level "INFO" -ForegroundColor Green
                return $true
            } else {
                Write-EnhancedLog -Message "VHDX is not mounted: $VHDXPath" -Level "INFO" -ForegroundColor Red
                return $false
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while validating VHD mount status: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            return $false
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Validate-VHDMount function" -Level "INFO"
    }
}
#EndRegion '.\Public\Validate-VHDMount.ps1' 43
#Region '.\Public\Validate-VMExists.ps1' -1

function Validate-VMExists {
    <#
    .SYNOPSIS
    Validates if a VM with the specified name exists.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName
    )

    Begin {
        Write-EnhancedLog -Message "Starting Validate-VMExists function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking existence of VM: $VMName" -Level "INFO"
            $vm = Get-VM -Name $VMName -ErrorAction Stop
            Write-EnhancedLog -Message "VM $VMName exists." -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            return $true
        } catch {
            Write-EnhancedLog -Message "VM $VMName does not exist. $($_.Exception.Message)" -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
            Handle-Error -ErrorRecord $_
            return $false
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Validate-VMExists function" -Level "INFO"
    }
}
#EndRegion '.\Public\Validate-VMExists.ps1' 34
#Region '.\Public\Validate-VMStarted.ps1' -1

function Validate-VMStarted {
    <#
    .SYNOPSIS
    Validates if the specified VM is started (running).
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$VMName
    )

    Begin {
        Write-EnhancedLog -Message "Starting Validate-VMStarted function" -Level "INFO"
        Log-Params -Params @{ VMName = $VMName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking state of VM: $VMName" -Level "INFO"
            $vm = Get-VM -Name $VMName -ErrorAction Stop

            if ($vm.State -eq 'Running') {
                Write-EnhancedLog -Message "VM $VMName is running." -Level "INFO"
                return $true
            }
            else {
                Write-EnhancedLog -Message "VM $VMName is not running." -Level "WARNING"
                return $false
            }
        }
        catch {
            Write-EnhancedLog -Message "Failed to check the state of VM $VMName. $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Validate-VMStarted function" -Level "INFO"
    }
}
#EndRegion '.\Public\Validate-VMStarted.ps1' 42