210 lines
7.3 KiB
PowerShell
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"
|
|
}
|
|
} |