# getAllVms.ps1

$clusterName='*'

function includeRSAT{
    $ErrorActionPreference='stop'
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    #$rsatWindows7x32='https://download.microsoft.com/download/4/F/7/4F71806A-1C56-4EF2-9B4F-9870C4CFD2EE/Windows6.1-KB958830-x86-RefreshPkg.msu'
    $rsatWindows7x64='https://download.microsoft.com/download/4/F/7/4F71806A-1C56-4EF2-9B4F-9870C4CFD2EE/Windows6.1-KB958830-x64-RefreshPkg.msu'
    $rsatWindows81='https://download.microsoft.com/download/1/8/E/18EA4843-C596-4542-9236-DE46F780806E/Windows8.1-KB2693643-x64.msu'
    $rsat1709 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS_1709-x64.msu"
    $rsat1803 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS_1803-x64.msu"
    $rsatWs2016 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS2016-x64.msu"
  
    # This command does not work on Windows 2012R2
    #$releaseId=(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId
    #Get-ItemProperty : Property ReleaseId does not exist at path HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
    #NT\CurrentVersion.
    #At line:1 char:2
    #+ (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Na ...
    #+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #    + CategoryInfo          : InvalidArgument: (ReleaseId:String) [Get-ItemProperty], PSArgumentException
    #    + FullyQualifiedErrorId : System.Management.Automation.PSArgumentException,Microsoft.PowerShell.Commands.GetItemPropertyCommand
  
    $releaseId=(Get-Item "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue('ReleaseID')
    $osVersion=[System.Environment]::OSVersion.Version
    [double]$osVersionMajorMinor="$($osVersion.Major).$($osVersion.Minor)"  
    $osName=(Get-WmiObject Win32_OperatingSystem).Name
    #$osType=switch ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType){
    #    1 {'client'}
    #    2 {'domaincontroller'}
    #    3 {'memberserver'}
    #    }
  
    $windowsVersion=(Get-CimInstance Win32_OperatingSystem).Version
  
    switch ($releaseId){
        1607{write-host 'Windows Server 2016 Release 1607 detected';$link=$rsatWs2016;break}
        1709{write-host 'Windows Server 2016 Release 1709 detected';$link=$rsat1709;break}
        1803{write-host 'Windows Server 2016 Release 1803 detected';$link=$rsat1803}
    }
      
    switch ($osVersionMajorMinor){
        {$_ -eq 6.0}{write-host 'Windows Server 2008 or Windows Vista detected';$link=$rsat1709;break}
        {$_ -eq 6.1}{write-host 'Windows Server 2008 R2 or Windows 7 detected';$link=$rsatWindows7x64;break}
        {$_ -eq 6.2}{write-host 'Windows Server 2012 or Windows 8.1 detected';$link=$rsatWindows81;break}
        {$_ -eq 6.3}{write-host 'Windows Server 2012 R2 detected';$link=$rsatWindows81}
    }
 
    if (!(Get-Module -ListAvailable -Name ActiveDirectory -EA SilentlyContinue)){
        Write-host "Prerequisite checks: module ActiveDirectory NOT currently available on this system. Please wait while the program adds that plugin..."
        try{
            # If OS is Windows Server, then install RSAT using a different method
            if ($osName -match "^Microsoft Windows Server") {
                # This sequence has confirmed to be valid on Windows Server 2008 R2 and above
                Write-Verbose "Importing Windows Feature: RSAT-AD-PowerShell"
                Import-Module ServerManager
                Add-WindowsFeature RSAT-AD-PowerShell
                }
            else{
                Write-Verbose "This sequence targets Windows Client versions"
                $destinationFile= ($ENV:USERPROFILE) + "\Downloads\" + (split-path $link -leaf)
                Write-Host "Downloading RSAT from $link..."
                Start-BitsTransfer -Source $link -Destination $destinationFile
                $fileCheck=Get-AuthenticodeSignature $destinationFile
                if($fileCheck.status -ne "valid") {write-host "$destinationFile is not valid. Please try again...";break}
                $wusaCommand = $destinationFile + " /quiet"
                Write-host "Installing RSAT - please wait..."
                Start-Process -FilePath "C:\Windows\System32\wusa.exe" -ArgumentList $wusaCommand -Wait
                }
            return $true
            }
        catch{
            write-warning "$($error[0].Exception)"
            return $false
            }
    }else{
        Write-host "Prerequisite checks: module ActiveDirectory IS currently available on this system." -ForegroundColor Green
        return $true
        }
}

function getAllVms([string[]]$clusterName,$verbose=$true){
    
    if(!$clusterName -or $clusterName -eq '*'){
        $result=@()
        $domains=(Get-ADForest).Name|%{(Get-ADForest -Identity $_).Name}        
        foreach ($domain in $domains){
            write-host "Collecting all Hyper-V Clusters in $domain. This may take a while, depending on cluster sizes."
            $allClusters=(get-cluster -domain $domain).Name
            if($verbose){
                $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
                write-host "Minutes elapsed $elapsed`: cluster names collected"
                }
            $nodes=$allClusters|%{try{Get-ClusterGroup -Cluster $_ -ea SilentlyContinue|?{$_.GroupType -eq 'VirtualMachine'}}catch{}}
            if($verbose){
                $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
                write-host "Minutes elapsed $elapsed`: Node and VM names collected for $domain"
                }
            $result+=$nodes
            }
        return $result
    }else{
        $nodes=$clusterName|%{Get-ClusterGroup -Cluster $_ -ea SilentlyContinue}|?{$_.GroupType -eq 'VirtualMachine'}
        if($verbose){
            $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
            write-host "Minutes elapsed $elapsed`: Node and VM names collected for $domain"
            }
        return $nodes
        }
    
}

getAllVms $clusterName