# mtuReportAllHyperVHosts.ps1
# Ensure that AD management module is available for PS Session
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 "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 "Module ActiveDirectory IS currently available on this system." -ForegroundColor Green
return $true
}
}
function ListHyperVHosts {
[cmdletbinding()]
param(
[string]$forest
)
try {
Import-Module ActiveDirectory -ErrorAction Stop
} catch {
Write-Warning "Failed to import Active Directory module. Exiting program..."
break;
}
$domains=(Get-ADForest -Identity $forest).Domains
foreach ($domain in $domains){
[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{
write-warning "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 *
$thisObject = New-Object PSObject -Prop (
@{
hostname = $computer.Name
operatingSystem = $($computer.operatingSystem)
})
$thisObject
}
}
}
}
function listForests{
$GLOBAL:forests=Get-ADForest | select Name;
if ($forests.length -gt 1){
return $forests | %{$_.Name;}
}else{
return $forests.Name;
}
}
function mtuReport($computernames){
write-host "Please wait while we scan $($computernames.count) nodes."
$report=$computernames|%{
write-host "Scanning $_..."
try{
$result=invoke-command -computername $_ -ScriptBlock{
$adapters=Get-NetAdapter
return $adapters|select name,mtusize
}|select @{name='computerName';e={$_.PSComputerName}},@{name='adapterName';e={$_.Name}},MtuSize
}catch{
write-warning $error[0].Exception.Message
continue;
}finally{
if($result){$result}
}
}
$highLights=@{
$true='White'
$false='Yellow'
}
$mtuReport=$report|select-object computerName,adapterName,MtuSize,@{Name='highlight';e={$highLights[$_.MtuSize -eq 1500]}}
$mtuReport|%{write-host $($_|select-object -Property * -ExcludeProperty highlight) -ForegroundColor $_.highlight}
return $report
}
function sortArrayStringAsNumbers([string[]]$names){
$hashTable=@{}
foreach ($name in $names){
[int]$x=.{[void]($name -match '(?:.(\d+))+$');$matches[1]}
$hashTable.Add($name,$x)
}
$sorted=foreach($item in $hashTable.GetEnumerator() | Sort Value,Name){$item.Name}
return $sorted
}
includeRSAT;
$hyperVHosts=listForests|%{ListHyperVHosts $_}
$hyperVHostNames=sortArrayStringAsNumbers $hyperVHosts.hostname
$mtuReport=mtuReport $hyperVHostNames
# Bonus round: get all clusters in the domain - this takes a long time for a large network
$clustersInDomain=Get-Cluster -domain $env:USERDNSDOMAIN|Get-ClusterGroup
# Filter down to VirtualMachine groups
$clustersInDomain|?{$_.GroupType -eq 'VirtualMachine'}
$vmClustersInDomain=$clustersInDomain|Group-Object Cluster|Select-Object Name
$vmClustersInDomain
Categories: