private/Test-IsVM.ps1

function Test-IsVM {
    <#
    .SYNOPSIS
        Tests whether the operating system is running in a recognized virtual machine
 
    .DESCRIPTION
        Queries Win32_ComputerSystem and Win32_BIOS through CIM. Detects
        Hyper-V, VMware, VirtualBox, and QEMU or KVM guests from manufacturer,
        model, or BIOS version markers. Returns $false when computer-system CIM
        data is unavailable or no recognized marker is found.
 
    .EXAMPLE
        PS> Test-IsVM
 
        Tests CIM system and BIOS data for a recognized virtual machine.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Boolean. Returns $true when a recognized virtual machine marker
        is found; otherwise, returns $false.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Detection is limited to the manufacturer, model, and BIOS strings
        explicitly recognized by this function.
    #>

    [OutputType([bool])]
    param ()

    $cs   = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction SilentlyContinue
    $bios = Get-CimInstance -ClassName Win32_BIOS           -ErrorAction SilentlyContinue

    if (-not $cs) { return $false }

    # Hyper-V guest
    if ($cs.Manufacturer -eq 'Microsoft Corporation' -and $cs.Model -eq 'Virtual Machine') {
        return $true
    }

    # VMware
    if ($cs.Manufacturer -like 'VMware*') {
        return $true
    }

    # Oracle VirtualBox
    if ($cs.Manufacturer -eq 'innotek GmbH' -or $cs.Model -eq 'VirtualBox') {
        return $true
    }

    # QEMU / KVM
    if ($cs.Manufacturer -like 'QEMU*') {
        return $true
    }

    # BIOS version strings (covers edge cases and some cloud VMs)
    if ($bios) {
        $biosVersion = [string]$bios.SMBIOSBIOSVersion
        foreach ($marker in @('VRTUAL', 'VMWARE', 'VBOX', 'BOCHS', 'QEMU')) {
            if ($biosVersion -like "*$marker*") {
                return $true
            }
        }
    }

    return $false
}