# listHyperVHostsInForests.ps1
# Version: 0.03

function listHyperVHostsInForests{
  # Ensure that AD management module is available for PS Session
  if (!(get-module -name "ActiveDirectory") ){
      Add-WindowsFeature RSAT-AD-PowerShell | out-null;
      import-module -name "ActiveDirectory" -DisableNameChecking | out-null;
      }

  function ListHyperVHosts {            
    [cmdletbinding()]            
    param(
      [string]$forest
    )            
    try {            
     Import-Module ActiveDirectory -ErrorAction Stop            
    } catch {            
     Write-Warning "Failed to import Active Directory module. Cannot continue. Aborting..."           
     break;
    }            

    $domains=(Get-ADForest -Identity $forest).Domains 
    foreach ($domain in $domains){
    #"$domain`: `n"
    [string]$dc=(get-addomaincontroller -DomainName $domain -Discover -NextClosestSite).HostName
    try {             
     $hyperVs = Get-ADObject -Server $dc -Filter 'ObjectClass -eq "serviceConnectionPoint" -and Name -eq "Microsoft Hyper-V"' -ErrorAction Stop;
    } catch {            
     "Failed to query $dc of $domain";         
    }            
    foreach($hyperV in $hyperVs) {            
       $x = $hyperV.DistinguishedName.split(",")            
       $HypervDN = $x[1..$x.Count] -join ","     
       if ( !($HypervDN -match "CN=LostAndFound")) {     
        $computer=Get-ADComputer -Id $HypervDN -Prop *
        $vmCount=.{
          $x=try{invoke-command -computername $computer.Name {(get-vm).count} -EA Stop}catch{-1}
          if($x -ne -1){
            return $x
          }else{
            return "Unable to probe"
          }
        }
        $thisObject=New-Object PSObject -Prop (@{
                hostname=$computer.Name
                operatingSystem=$computer.operatingSystem
                vmCount=$vmCount
                })
            $thisObject
          }           
      }
     }
  }

  function listForests{
      $GLOBAL:forests=Get-ADForest | select Name;
      if ($forests.length -gt 1){
          #for ($i=0;$i -lt $forests.length;$i++){$forests[$i].Name;}
          $forests | %{$_.Name;}
      }else{
          $forests.Name;
      }
  }
  listForests|%{ListHyperVHosts $_}
}

listHyperVHostsInForests

Sample Output

PS C:\Windows\system32> listHyperVHostsInForests

vmCount         hostname   operatingSystem
-------         --------   ---------------
Unable to probe HV01     Windows Server 2012 R2 Datacenter
Unable to probe HV02     Windows Server 2012 R2 Datacenter
Unable to probe TESTHV01   Windows Server 2019 Standard
Unable to probe TESTHV02   Windows Server 2019 Standard
9               LAX-HV01  Windows Server 2019 Datacenter
9               LAX-HV02  Windows Server 2019 Datacenter
21              LAX-HV03  Windows Server 2019 Datacenter
8               LAX-HV04  Windows Server 2019 Datacenter
14              LAX-HV05  Windows Server 2019 Datacenter
23              LAX-HV06  Windows Server 2019 Datacenter
21              LAX-HV07  Windows Server 2019 Datacenter
12              LAX-HV08   Windows Server 2019 Datacenter
16              LAX-HV09   Windows Server 2019 Datacenter
110             LAX-HV10   Windows Server 2019 Datacenter
97              LAX-HV11   Windows Server 2019 Datacenter
7               LAX-HV12  Windows Server 2019 Datacenter
32              LAX-HV13  Windows Server 2019 Datacenter
1               LAX-HV14   Windows Server 2019 Datacenter