Files
PowerShell/Horizon Tools/KISVDIDesktopResolver.ps1
T
2026-07-24 17:37:31 -07:00

210 lines
7.3 KiB
PowerShell

param (
[string]$vCenter = "",
[string]$Horizon = "",
[string]$Pool = "",
[switch]$Help = $false,
[switch]$SaveCred = $false
)
# Variables
$fileVersion = "1.1.0"
$fileDate = "2026-06-15"
$scriptName = Split-Path -Path $PSCommandPath -Leaf
$mypath = split-path -parent $MyInvocation.MyCommand.Definition
$now = (Get-Date).ToString("yyyy-MM-dd_HH:mm")
$LogFile = "$mypath\KISVDIDesktopResolver.log"
# Display Script Banner
Write-Host "--------------------------------------------------" -ForegroundColor White
Write-Host "Resolve Failed Horizon Desktops" -ForegroundColor Green
Write-Host "Version $($FileVersion) ($($FileDate))" -ForegroundColor Green
Write-Host "Written by Charlie Silverman" -ForegroundColor Green
Write-Host "--------------------------------------------------" -ForegroundColor White
function CheckModuleInstalled($moduleName, $command) {
Write-Host "Checking that package $moduleName is installed..." -NoNewLine
if (-not(get-command $command -erroraction silentlycontinue)) {
Write-Host " Missing" -ForegroundColor Red
if (-not (Get-Module -ListAvailable -Name $moduleName)) {
$response = ""
while (($response -ne "yes") -and ($response -ne "no")) {
$response = (Read-Host "ImportExcel module not instaled. Install now? (yes/no)").ToLower()
}
if ($response -eq "no") {
Write-Host "Operation Cancelled." -ForegroundColor Yellow
exit
}
Write-Host "Installing PowerShell module $moduleName..." -NoNewLine
Install-Module -Name $moduleName -Scope CurrentUser -Force
Write-Host " Success" -ForegroundColor Green
}
Write-Host "Loading PowerShell module $moduleName..." -NoNewLine
Import-Module $moduleName
Write-Host " Success" -ForegroundColor Green
} else {
Write-Host " Found" -ForegroundColor Green
}
}
# Check for ImportExcel and install if missing
CheckModuleInstalled -moduleName "VCF.PowerCLI" -command "connect-viserver"
$void = Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
import-module $mypath/KISHorizon.psm1 -DisableNameChecking
if ($Help) {
Write-Host
Write-Host "Purpose: Resolve Horizon VMs with errors."
Write-Host "Command Syntax:"
Write-Host " $scriptName (-vCenter [vcenter host name]) (-Horizon ""[cluster]"") (-Pool ""[filename]"")" -foregroundcolor green
Write-Host "Command Line Options:"
Write-Host
Write-Host -NoNewLine " -vCenter " -foregroundcolor Green
Write-Host "- The FQDN or IP address of a vCenter server."
Write-Host -NoNewLine " -Horizon " -foregroundcolor Green
Write-Host "- The FQDN or IP address of a Horizon connection broker."
Write-Host -NoNewLine " -Pool " -foregroundcolor Green
Write-Host "- A comma-delimited list of pools to check. If not specified, all pools will be checked."
Write-Host
Write-Host "If any of the information is not provided, you will be prompted with the exception of the pool list. If a credential has been"
Write-Host "previously stored, it will be used again unless the -savecred option is specified."
Write-Host
exit
}
if ($vCenter -eq "") {
$vCenter = Read-Host "Enter FQDN or IP address of vCenter Server"
}
if ($SaveCred) {
$vccred = Get-Credential -Message "Enter credentials for vCenter server $vCenter"
$vccred| Export-Clixml -path .\kistools-$vcenter.cred
Write-Host "Saving credentials."
}
if (Test-Path -path .\kistools-$vcenter.cred -PathType Leaf) {
$vccred = Import-Clixml -path .\kistools-$vcenter.cred
Write-Host "- Using stored vCenter credentials"
} else {
$vccred = Get-Credential -Message "Enter credentials for vCenter server $vCenter"
if (!$vccred) {
Write-Host "ERROR: No credentials were entered" -foregroundcolor yellow
exit
}
}
#Establish connection to vCenter
try {
Write-Host -NoNewLine "Connecting to vCenter $vcenter... "
$vcconn = Connect-VIServer -server $vcenter -Credential $vccred -ErrorAction Stop
Write-Host "Success" -ForegroundColor green
} catch {
Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine
Write-Host
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
exit
}
if ($Horizon -eq "") {
$Horizon = Read-Host "Enter FQDN or IP address of Horizon Connection Broker"
}
if ($SaveCred) {
$hzcred = Get-Credential -Message "Enter credentials for Horizon Broker $Horizon"
$hzcred | Export-Clixml -path .\kistools-$Horizon.cred
Write-Host "Saving credentials."
}
if (Test-Path -path .\kistools-$Horizon.cred -PathType Leaf) {
$hzcred = Import-Clixml -path .\kistools-$Horizon.cred
Write-Host "- Using stored Horizon credentials"
} else {
$hzcred = Get-Credential -Message "Enter credentials for Horizon server $Horizon"
if (!$hzcreds) {
Write-Host "ERROR: No credentials were entered" -foregroundcolor yellow
exit
}
}
#Establish connection to Horizon
try {
Write-Host -NoNewLine "Connecting to Horizon Connection Broker $Horizon... "
$hzconn = Connect-HorizonServer -server $Horizon -credential $hzcred
Write-Host "Success" -ForegroundColor green
} catch {
Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine
Write-Host
exit
}
if ($Pool -ne "") {
$Pools = $Pool.split(",")
$poolsvalid = @()
foreach($thisPool in $Pools) {
Write-Host -NoNewLine "Verifying existence of pool $thisPool... "
$thispool = $hzconn | Get-HorizonDesktopPool -poolname $thisPool
if ($thispool) {
Write-Host "Success" -ForegroundColor green
$poolsvalid += $thisPool
} else {
Write-Host "Failure - Skipping" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine
Write-Host
}
}
} else {
$poolsvalid = $hzconn | Get-HorizonDesktopPool
}
$totalfixed = 0
$totalerror = 0
$poolreport = ""
foreach ($thisPool in $poolsvalid) {
$unreachable = $thispool.Machines | Where-Object {$_.state -eq "AGENT_UNREACHABLE"}
if ($unreachable.length -gt 0) {
$label = "desktops"
if ($unreachable.length -eq 1) { $label = "desktop" }
Write-Host "Pool $($thispool.Name) has $($unreachable.length) $label in an Unreachable state."
}
$poolfixed = 0
foreach ($machine in $unreachable) {
$thisvm = Get-VM $machine.Name
Write-Host "- Resetting NIC for VM $($thisvm.Name) in pool $($thisPool.Name)... " -NoNewLine
$void = $thisvm | Get-NetworkAdapter | Set-NetworkAdapter -connected:$false -confirm:$false
Start-Sleep -Seconds 2
$void = $thisvm | Get-NetworkAdapter | Set-NetworkAdapter -connected:$true -confirm:$false
Write-Host "Success" -ForegroundColor Green
$poolfixed += 1
}
if ($poolfixed -gt 0) {
$totalfixed += $poolfixed
$label = "VMs"
if ($poolfixed -eq 1) { $label = "VM" }
$poolreport += "`r`n - Pool $($thispool.Name): $poolfixed $label resolved"
}
}
try {
Write-Host -NoNewLine "Disconnecting from vCenter $vcenter... "
$void = Disconnect-VIServer -server $vcenter -confirm:$false
Write-Host "Success" -ForegroundColor green
} catch {
Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine
Write-Host
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
exit
}
Write-Host "`r`nTotal Desktops fixed in this run: $totalfixed"
Write-Host $poolreport
$label = "desktops"
if ($totalfixed -eq 1) { $label = "desktop" }
Add-Content $LogFile "$Now - Total $label fixed in this run: $totalfixed"
$reportlines = $poolreport.split("`r`n")
foreach ($line in $reportlines) {
if ($line -ne "") {
Add-Content $LogFile "$Now - $line"
}
}