param( [string]$HorizonServer = "", [string]$OutFile = "", [string]$InputXML = "", [switch]$SaveCred = $false, [switch]$debug = $false, [switch]$help = $false ) # Variables $fileVersion = "1.1.0" $fileDate = "2026-06-24" $scriptName = Split-Path -Path $PSCommandPath -Leaf $mypath = split-path -parent $MyInvocation.MyCommand.Definition $now = (Get-Date).ToString("yyyy-MM-dd_HH:mm") $userfolder = $env:USERPROFILE # Display Script Banner Write-Host "--------------------------------------------------" -ForegroundColor White Write-Host "Export Pool Settings to Excel File" -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 "$moduleName module not instaled. Install now? (yes/no)").ToLower() } if ($response -eq "no") { Write-Host "Operation aborted." -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" CheckModuleInstalled -moduleName "ImportExcel" -command "Open-ExcelPackage" Import-Module $mypath\KISHorizon.psm1 $abyss = Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Scope Session -Confirm:$false if ($Help) { Write-Host Write-Host "Purpose: Resolve Horizon VMs with errors." Write-Host "Command Syntax:" Write-Host " $scriptName (-Horizon ""[cluster]"") (-SaveCred)" -ForegroundColor Green Write-Host "Command Line Options:" Write-Host Write-Host -NoNewLine " -Horizon " -ForegroundColor Green Write-Host "- The FQDN or IP address of a Horizon connection broker." Write-Host -NoNewLine " -SaveCred " -ForegroundColor Green Write-Host "- Ask for credentials and save them to current user's profile directory." Write-Host Write-Host "The Horizon server will be queried for all vCenter servers it is configured for and credentials will be required for each." Write-Host "Any information not provided will be prompted for during script execution." exit } if ($OutFile -eq "") { $OutFile = "KISHorizonExport-$($HorizonServer).xlsx" } if (Test-Path -path $Outfile -PathType Leaf) { Remove-Item -Path $Outfile } if ($inputXML -eq "") { if ($HorizonServer -eq "") { $HorizonServer = Read-Host "Enter FQDN or IP address of Horizon Connection Broker" } if ($SaveCred) { $hzcred = Get-Credential -Message "Enter credentials for Horizon server $HorizonServer in the format DOMAIN\USERNAME" $hzcred | Export-Clixml -path $userfolder\kistools-$HorizonServer.cred Write-Host "Saving credentials." } if (Test-Path -path $userfolder\kistools-$HorizonServer.cred -PathType Leaf) { $hzcred = Import-Clixml -path $userfolder\kistools-$HorizonServer.cred Write-Host "- Using stored Horizon credentials" } else { $hzcred = Get-Credential -Message "Enter credentials for Horizon server $HorizonServer in the format DOMAIN\USERNAME" 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 $HorizonServer... " $hzconn = Connect-HorizonServer -server $HorizonServer -credential $hzcred Write-Host "Success" -ForegroundColor green } catch { Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine Write-Host exit } # Establish connection to all vCenter servers configured on this Horizon system $vcenterlist = $hzconn | Get-HorizonvCenter foreach ($thisvc in $vcenterlist) { $vcname = $thisvc.server_name if ($SaveCred) { $vccred = Get-Credential -Message "Enter credentials for vCenter server $vcname" $vccred| Export-Clixml -path $userfolder\kistools-$vcname.cred Write-Host "Saving credentials." } if (Test-Path -path $userfolder\kistools-$vcname.cred -PathType Leaf) { $vccred = Import-Clixml -path $userfolder\kistools-$vcname.cred Write-Host "- Using stored vCenter credentials" } else { $vccred = Get-Credential -Message "Enter credentials for vCenter server $vcname" if (!$vccred) { Write-Host "ERROR: No credentials were entered" -foregroundcolor yellow exit } } #Establish connection to vCenter try { Write-Host -NoNewLine "Connecting to vCenter $vcname... " $vcconn = Connect-VIServer -server $vcname -Credential $vccred -Force -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 } } $pools = $hzconn | Get-HorizonDesktopPool } else { $pools = Import-CliXml -path $inputXML } foreach ($thisvc in $vcenterlist) { Write-Host -NoNewLine "Disconnecting from vCenter $vcname... " try { $abyss = Disconnect-ViServer $thisvc.server_name -confirm:$false Write-Host "Success" -ForegroundColor green } catch { Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine Write-Host } } Write-Host -NoNewLine "Generating Excel File $OutFile... " $workbook = Open-ExcelPackage -Path $OutFile -Create #Create Initial Data Worksheet $thissheet = Add-Worksheet -ExcelPackage $workbook -WorksheetName "General Horizon Data" Set-ExcelRange -worksheet $thissheet -Range "A:A" -VerticalAlignment Top Set-Format -Address $thissheet.Cells["B:B"] -WrapText $thissheet.column(1).Width = 40 $thissheet.column(2).Width = 40 $thissheet.column(3).Width = 40 Set-ExcelRange -Worksheet $thissheet -Range "A1:E1" -Merge:$true $domains = Get-HorizonADDomains -Horizon $hzconn $vcenterservers = Get-HorizonvCenter -Horizon $hzconn $goldimages = $pools.provisioning_settings.base_vm_name | Select-Object -Unique $row = 1 $thissheet.cells["A1"].value = "General data for Horizon server $HorizonServer" Set-Format -Address $thissheet.Cells["A1"] -Bold Set-ExcelRange -Worksheet $thissheet -Range "A1" -FontSize 20 $row += 2 $thissheet.cells["A" + $row].value = "vCenter Servers" Set-Format -Address $thissheet.Cells["A" + $row] -Bold Set-ExcelRange -Worksheet $thissheet -Range "A$row" -FontSize 16 $row += 1 $vctabletop = $row $thissheet.cells["A" + $row].value = "vCenter Server" $thissheet.cells["B" + $row].value = "Version" $thissheet.cells["C" + $row].value = "User Account" $row += 1 foreach ($vc in $vcenterlist) { $thissheet.cells["A" + $row].value = $vc.server_name $thissheet.cells["B" + $row].value = $vc.version $thissheet.cells["C" + $row].value = $vc.user_name $row += 1 } $vcTableRange = $thissheet.Cells[$vctabletop, 1, ($row-1), 3] $vcTable = $thissheet.Tables.Add($vcTableRange, "vCenterList") $vcTable.StyleName = "TableStyleMedium15" $row += 1 $thissheet.cells["A" + $row].value = "Active Directory Domains" Set-Format -Address $thissheet.Cells["A" + $row] -Bold Set-ExcelRange -Worksheet $thissheet -Range "A$row" -FontSize 16 $row += 1 $adtabletop = $row $thissheet.cells["A" + $row].value = "DNS Name" $thissheet.cells["B" + $row].value = "NetBIOS Name" $row += 1 foreach ($add in $domains) { $thissheet.cells["A" + $row].value = $add.dns_name $thissheet.cells["B" + $row].value = $add.netbios_name $row += 1 } $adTableRange = $thissheet.Cells[$adtabletop, 1, ($row-1), 2] $adTable = $thissheet.Tables.Add($adTableRange, "ADDomains") $adTable.StyleName = "TableStyleMedium15" $row += 1 $thissheet.cells["A" + $row].value = "Published Gold Images" Set-Format -Address $thissheet.Cells["A" + $row] -Bold Set-ExcelRange -Worksheet $thissheet -Range "A$row" -FontSize 16 $row += 1 $adtabletop = $row $thissheet.cells["A" + $row].value = "Gold Image VMs" $thissheet.cells["B" + $row].value = "Pools" $row += 1 foreach ($image in $goldimages) { $thissheet.cells["A" + $row].value = $image $thissheet.cells["B" + $row].value = (($pools | Where-Object {$_.provisioning_settings.base_vm_name -eq $image}).Name -Join "`r`n") $row += 1 } $giTableRange = $thissheet.Cells[$adtabletop, 1, ($row-1), 2] $giTable = $thissheet.Tables.Add($giTableRange, "GoldImages") $giTable.StyleName = "TableStyleMedium15" foreach ($pool in $pools) { $thissheet = Add-Worksheet -ExcelPackage $workbook -WorksheetName $pool.name $entitlements = $pool.entitlements | ForEach-Object { $_.Domain + "\" + $_.SamAccountName } $data = @( [pscustomobject]@{Name = "Pool ID";Value=$pool.name} [pscustomobject]@{Name = "Display Name";Value=$pool.display_name} [pscustomobject]@{Name = "Description";Value=$pool.description} [pscustomobject]@{Name = "Type";Value=$pool.session_type} [pscustomobject]@{Name = "User Assignment";Value=$pool.user_assignment} [pscustomobject]@{Name = "vCenter Server";Value=$pool.vcenter} [pscustomobject]@{Name = "Naming Pattern";Value=$pool.pattern_naming_settings.naming_pattern} [pscustomobject]@{Name = "Max Machines";Value=$pool.pattern_naming_settings.max_number_of_machines} [pscustomobject]@{Name = "Spare Machines";Value=$pool.pattern_naming_settings.number_of_spare_machines} [pscustomobject]@{Name = "Min Machines";Value=$pool.pattern_naming_settings.min_number_of_machines} [pscustomobject]@{Name = "Datacenter";Value=$pool.provisioning_settings.datacenter_name} [pscustomobject]@{Name = "Resource Pool";Value=$pool.provisioning_settings.resource_pool_name} [pscustomobject]@{Name = "Parent VM";Value=$pool.provisioning_settings.base_vm_name} [pscustomobject]@{Name = "Snapshot Path";Value=$pool.provisioning_settings.snapshot_path} [pscustomobject]@{Name = "VM Folder Path";Value=$pool.provisioning_settings.base_folder_path} [pscustomobject]@{Name = "Cluster";Value=$pool.cluster} [pscustomobject]@{Name = "Resource Pool";Value=$pool.provisioning_settings.resource_pool_name} [pscustomobject]@{Name = "Datacenter";Value=$pool.provisioning_settings.datacenter_name} [pscustomobject]@{Name = "Datastores";Value=$pool.storage_settings.datastores.name -join "`r`n"} [pscustomobject]@{Name = "Network";Value=($pool.machines.managed_machine_data.network_labels.network_label_name | Select-Object -Unique | Sort-Object) -join "`r`n"} [pscustomobject]@{Name = "Use vSAN";Value=$pool.storage_settings.use_vsan} [pscustomobject]@{Name = "Add Virtual TPM";Value=$pool.provisioning_settings.add_virtual_tpm} [pscustomobject]@{Name = "vGPU Enabled";Value=$pool.GpuEnabled} [pscustomobject]@{Name = "Customization Type";Value=$pool.customization_settings.customization_type} [pscustomobject]@{Name = "Ad Container";Value=$pool.customization_settings.ad_container_rdn} [pscustomobject]@{Name = "Reuse Existing AD Object";Value=$pool.customization_settings.reuse_pre_existing_accounts} [pscustomobject]@{Name = "Cloneprep Script Settings";Value=$pool.customization_settings.cloneprep_script_settings} [pscustomobject]@{Name = "Power Off Script Name";Value=$pool.customization_settings.cloneprep_customization_settings.power_off_script_name} [pscustomobject]@{Name = "Power Off Script Parameters";Value=$pool.customization_settings.cloneprep_customization_settings.power_off_script_parameters} [pscustomobject]@{Name = "Post Sync Script Name";Value=$pool.customization_settings.cloneprep_customization_settings.post_synchronization_script_name} [pscustomobject]@{Name = "Post Sync Script Parameters";Value=$pool.customization_settings.cloneprep_customization_settings.post_synchronization_script_parameters} [pscustomobject]@{Name = "Automatic Logoff Policy";Value=$pool.session_settings.disconnected_session_timeout_policy} [pscustomobject]@{Name = "Automatic Logoff Minutes";Value=$pool.session_settings.disconnected_session_timeout_minutes} [pscustomobject]@{Name = "Allow Users to Reset Machines";Value=$pool.session_settings.allow_users_to_reset_machines} [pscustomobject]@{Name = "Allow Multiple Sessions Per User";Value=$pool.session_settings.allow_multiple_sessions_per_user} [pscustomobject]@{Name = "Used VM Policy";Value=$pool.session_settings.delete_or_refresh_machine_after_logoff} [pscustomobject]@{Name = "Logoff After Timeout";Value=$pool.session_settings.disconnected_session_timeout_policy} [pscustomobject]@{Name = "Supported Display Protocols";Value=$pool.display_protocol_settings.display_protocols -join "`r`n"} [pscustomobject]@{Name = "Default Display Protocol";Value=$pool.display_protocol_settings.default_display_protocol} [pscustomobject]@{Name = "Allow Users to Choose Protocol";Value=$pool.display_protocol_settings.allow_users_to_choose_protocol} [pscustomobject]@{Name = "External HTML Access";Value=$pool.display_protocol_settings.html_access_enabled} [pscustomobject]@{Name = "Enable Collaboration";Value=$pool.display_protocol_settings.session_collaboration_enabled} [pscustomobject]@{Name = "Entitlements";Value=$entitlements} ) $rowcount = 1 foreach ($datum in $data) { $thissheet.cells["A" + $rowcount].Value = $datum.name $thissheet.cells["B" + $rowcount].Value = $datum.value $rowcount += 1 } $thissheet.Column(1).Style.HorizontalAlignment = "Right" $thissheet.Column(1).Width = 40 $thissheet.Column(2).Width = 200 Set-Column -ExcelPackage $workbook -WorksheetName $pool.Name -Column 2 -WrapText Set-Column -ExcelPackage $workbook -WorksheetName $pool.Name -Column 2 -HorizontalAlignment Left Set-Column -ExcelPackage $workbook -WorksheetName $pool.Name -Column 1 -VerticalAlignment Top Set-ExcelRange -Worksheet $thissheet -Range "A:B" -FontSize 14 $thissheet.cells["A:A"].Style.Indent = 2 Set-ExcelRange -Worksheet $thissheet -Range "B:B" -Bold } Close-ExcelPackage $workbook Write-Host "Success" -ForegroundColor green