Some of you might have seen previews on the socials but for the last few months I have been working hard on a GUI based tool to deploy golden images to VMware Horizon Instant Clone Desktop Pools and RDS Farms. This because who isn’t sick and tired of having to go into each and every Pod admin interface to o a million clicks to deploy a few new golden images?
The work started mid December and as usual the first 75% was done pretty quickly so mid January I had a first working version. While I expected a first version that would only support Desktop Pools to be available mid February (Vmug Virtual EUC day someone?) this build actually already had most of the parts in place to support both Desktop Pools and RDS Farms. After this first build my regular work for ControlUp started picking up again so I had less time to fix the numerous bugs that I encountered. Well bugs? Most where logic errors on my part but most of them have been ironed out by now. All in all the version that you can use today has cost me ~80hrs in building & testing and many many more hours thinking about solutions.
Is the tool perfect? Definitely not but it works and it’s more than what we’ve had before and I will be looking into impriving it even more.
The Tool
I guess you got bored with the talking and would like to see the tool now. The content of thos blog post might get it’s own page later for documentation purposes. The tool itself can be downloaded from this GitHub repository. Make sure to grab both the xaml and ps1 files, put them in a single folder and you should be good. The tool entirely runs on Powershell and is using the WPF Framework for the GUI.
Powershell 7.3 or later (for performance reasons I used some PS 7.3 options so the tool WILL break with an older version.)
Horizon 8 2206 or later (the reason for this is that otherwise the secondary images wouldn’t be available and that’s a feature I wanted in there for sure.)
Deplying a new golden Image
For normal usage you can just start the ps1 file.
This will bring you to this tab, before the first use though you need to go to the configuration page.
Fill in one of your cconnection servers, credentials and hit the test button. If you have a cloud pod setup the other pods will be automatically detected and make sure to check the Ignore Certificate Errors checkbox in case that’s needed!
If the test was successfull you are good to go to either the Desktop Pools or RDS Farms tabs. Both are almost completely the same so I will only show desktop pools
Hit the connect button and all Instant Clone Pools or Farms from all pods will be auto populated in the first pull down menu.
The second pulldown menu allows you to select a new source VM
And the third pull down the snapshot (I guess you guessed that already, I might need to add labels but they are so ugly in WPF)
To the right you have all kinds of options that you should recognize from the regular gui including add vTPM that was added in Horizon 2206. This checkbox isn’t in the RDS Farms as we currently simply don’t have the option to have Horizon add a vTPM there. If the options are valid ( like more cores that cores/socket and if those numbers will work (can’t do 3 cores and 2 cores per socket!) the Deploy Golden Image becomes available. Hit this to start the deployment, you can check the status by hitting the refresh button. (don’t tell anyone but the functions does exactly the same as a connect)
Handling Secondary Images
By default a secondary image will not be pushed to any machines. Just select the Push As Secondary Image checkbox and hit Deploy Golden Image button.
What you can also do is select one or more of the machines and deploy the Golden Images ot those machines
Once a Secondary Image has been deployed the three other buttons come available.
From top to bottom you can either cancel the secondary image completely, apply the golden image to more desktops (selecting ones that already has it won’t break anything and will just deploy it when possible) and promote the Secondary Image to the Primary golden image for the pool. The latter will cause a rebuild of ALL machines including the ones already running on the image. In the future I will also add a button to configure a machine to run the original image.
Settings and logs location
All settings are stored in an xml file in %appdata%\HGIDTool this includes the password configured in the Settings tab as a regular Encrypted PowerShell Credentials object. If you didn’t hit save on the settings tab this will be automatically done when closing the tool.
In case you want to borrow some of my code the log files contain every API call that I do to get date, push an image or handlke secondary images. This is the same output as you’d get when running in -verbose mode so that’s only needed when you’re troubleshooting the tool.
I have just added a page that lists the Horizon 8 2209 changes in the API’s. If you’re interested in the overall release notes, please see this link.
Some of the changes that stand out are brand new calls related to Radius & SAML settings but also options to bind to a domain, setting up unauthenticated users. licenses and pre-logon settings.
As always, a complete overview of all calls can be found in the API Explorer. But this is a list of the changes.
Since several version in each VMware Horizon release notes pages there has been this mention:
This links to this page: VMware Horizon REST APIs (84155) for a while this page was updated with the latest additions to the REST api’s but I guess people didn’t want to do that anymore so that page now simply links to the API Explorer:
Since I used this changelog to decide on what I wanted to blog about I thought it was time to create a changelog myself. What I did was download all the swagger specifications and compare them. For reasons I had to do this in excel but at least I now have a nice source for this. (ping me if you would like to have the excel file). This result in a new menu item at the top of my blog with the changelog for every Horizon 8 version. Yes I know the rest api’s have been available since 7.10 but I decided to start with 8.0. Please use the menu on top of the links below to go to the changelog for the version that you would like to see.
One of the goals and hopes I had with my 100DaysOfCode (I am writing this on day 100!) was that the Horizon REST api’s to create desktop pools and RDS farms would have been available at the end. Only half of that came out and with Horizon 8 2103 we can finally create a RDS farm using those rest api’s. I have decided to add this to the Python module based on a dictionary that the user sends to the new_farm method. I could still add a fully fetched function but that would require a lot of arguments and using **kwargs is an option but than the user would still need to find out what to use.
First I will need to know what json data I actually need, let’s have a look at the api explorer page to get a grip on this
As said I send a dictionary to the method so let’s import data into a dict called data and I will print it to screen. The dictionary needs to follow this specific order of lines so that’s why a json is very useful to start with.
with open('/mnt/d/homelab/farm.json') as f:
data = json.load(f)
As you can see in both the json and the output there’s a lot of things we can change and some things that we need to change lik id’s for all the components like vCenter, base vm, base snapshot and more. First I need the access_group_id this can be retreived using the get_local_access_groups method. For all of these I will also set the variable in the dictionary that we need.
local_access_group = next(item for item in (config.get_local_access_groups()) if item["name"] == "Root")
data["access_group_id"] = local_access_group["id"]
Than it’s time for the Instant Clone Admin id
ic_domain_account = next(item for item in (config.get_ic_domain_accounts()) if item["username"] == "administrator")
data["automated_farm_settings"]["customization_settings"]["instant_clone_domain_account_id"] = ic_domain_account["id"]
For the basevm and snapshot id’s I used the same method but a bit differently as I had already used this method in another script
vcenters = monitor.virtual_centers()
vcid = vcenters[0]["id"]
dcs = external.get_datacenters(vcenter_id=vcid)
dcid = dcs[0]["id"]
base_vms = external.get_base_vms(vcenter_id=vcid,datacenter_id=dcid,filter_incompatible_vms=True)
base_vm = next(item for item in base_vms if item["name"] == "srv2019-p1-2020-10-13-08-44")
basevmid=base_vm["id"]
base_snapshots = external.get_base_snapshots(vcenter_id=vcid, base_vm_id=base_vm["id"])
base_snapshot = next(item for item in base_snapshots if item["name"] == "Created by Packer")
snapid=base_snapshot["id"]
data["automated_farm_settings"]["provisioning_settings"]["base_snapshot_id"] = snapid
data["automated_farm_settings"]["provisioning_settings"]["parent_vm_id"] = basevmid
Host or cluster id
host_or_clusters = external.get_hosts_or_clusters(vcenter_id=vcid, datacenter_id=dcid)
for i in host_or_clusters:
if (i["details"]["name"]) == "Cluster_Pod1":
host_or_cluster = i
data["automated_farm_settings"]["provisioning_settings"]["host_or_cluster_id"] = host_or_cluster["id"]
Resource Pool
resource_pools = external.get_resource_pools(vcenter_id=vcid, host_or_cluster_id=host_or_cluster["id"])
for i in resource_pools:
# print(i)
if (i["type"] == "CLUSTER"):
resource_pool = i
data["automated_farm_settings"]["provisioning_settings"]["resource_pool_id"] = resource_pool["id"]
VM folder again is a bit different as I have to get the id from one of the children objects
vm_folders = external.get_vm_folders(vcenter_id=vcid, datacenter_id=dcid)
for i in vm_folders:
children=(i["children"])
for ii in children:
# print(ii["name"])
if (ii["name"]) == "Pod1":
vm_folder = i
data["automated_farm_settings"]["provisioning_settings"]["vm_folder_id"] = vm_folder["id"]
Datacenter and vcenter id’s I already had to grab for the base vm and base snapshot so I can just add them
Datastores is a bit more funky as there can be multiple so I needed to create a list first and than populate that based on the name of the datastores I have.
datastore_list = []
datastores = external.get_datastores(vcenter_id=vcid, host_or_cluster_id=host_or_cluster["id"])
for i in datastores:
# print(i)
if (i["name"] == "VDI-500") or i["name"] == "VDI-200":
ds = {}
ds["datastore_id"] = i["id"]
datastore_list.append(ds)
data["automated_farm_settings"]["storage_settings"]["datastores"] = datastore_list
For my final script I put them in a bit different order and I decided to change a whole lot more options but if you have your json perfected this shouldn’t always be required. Also take note that for true/false in the json that I use the True/False from python.
import requests, getpass, urllib, json
import vmware_horizon
requests.packages.urllib3.disable_warnings()
url = input("URL\n")
username = input("Username\n")
domain = input("Domain\n")
pw = getpass.getpass()
hvconnectionobj = vmware_horizon.Connection(username = username,domain = domain,password = pw,url = url)
hvconnectionobj.hv_connect()
print("connected")
monitor = obj=vmware_horizon.Monitor(url=hvconnectionobj.url, access_token=hvconnectionobj.access_token)
external=vmware_horizon.External(url=hvconnectionobj.url, access_token=hvconnectionobj.access_token)
inventory=vmware_horizon.Inventory(url=hvconnectionobj.url, access_token=hvconnectionobj.access_token)
config=vmware_horizon.Config(url=hvconnectionobj.url, access_token=hvconnectionobj.access_token)
with open('/mnt/d/homelab/farm.json') as f:
data = json.load(f)
vcenters = monitor.virtual_centers()
vcid = vcenters[0]["id"]
dcs = external.get_datacenters(vcenter_id=vcid)
dcid = dcs[0]["id"]
base_vms = external.get_base_vms(vcenter_id=vcid,datacenter_id=dcid,filter_incompatible_vms=True)
base_vm = next(item for item in base_vms if item["name"] == "srv2019-p1-2020-10-13-08-44")
basevmid=base_vm["id"]
base_snapshots = external.get_base_snapshots(vcenter_id=vcid, base_vm_id=base_vm["id"])
base_snapshot = next(item for item in base_snapshots if item["name"] == "Created by Packer")
snapid=base_snapshot["id"]
host_or_clusters = external.get_hosts_or_clusters(vcenter_id=vcid, datacenter_id=dcid)
for i in host_or_clusters:
if (i["details"]["name"]) == "Cluster_Pod1":
host_or_cluster = i
resource_pools = external.get_resource_pools(vcenter_id=vcid, host_or_cluster_id=host_or_cluster["id"])
for i in resource_pools:
# print(i)
if (i["type"] == "CLUSTER"):
resource_pool = i
vm_folders = external.get_vm_folders(vcenter_id=vcid, datacenter_id=dcid)
for i in vm_folders:
children=(i["children"])
for ii in children:
# print(ii["name"])
if (ii["name"]) == "Pod1":
vm_folder = i
datastore_list = []
datastores = external.get_datastores(vcenter_id=vcid, host_or_cluster_id=host_or_cluster["id"])
for i in datastores:
# print(i)
if (i["name"] == "VDI-500") or i["name"] == "VDI-200":
ds = {}
ds["datastore_id"] = i["id"]
datastore_list.append(ds)
local_access_group = next(item for item in (config.get_local_access_groups()) if item["name"] == "Root")
ic_domain_account = next(item for item in (config.get_ic_domain_accounts()) if item["username"] == "administrator")
data["access_group_id"] = local_access_group["id"]
data["automated_farm_settings"]["customization_settings"]["ad_container_rdn"] = "OU=Pod1,OU=RDS,OU=VMware,OU=EUC"
data["automated_farm_settings"]["customization_settings"]["reuse_pre_existing_accounts"] = True
data["automated_farm_settings"]["customization_settings"]["instant_clone_domain_account_id"] = ic_domain_account["id"]
data["automated_farm_settings"]["enable_provisioning"] = False
data["automated_farm_settings"]["max_sessions"] = 50
data["automated_farm_settings"]["min_ready_vms"] = 3
data["automated_farm_settings"]["pattern_naming_settings"]["max_number_of_rds_servers"] = 4
data["automated_farm_settings"]["pattern_naming_settings"]["naming_pattern"] = "farmdemo-{n:fixed=3}"
data["automated_farm_settings"]["provisioning_settings"]["base_snapshot_id"] = snapid
data["automated_farm_settings"]["provisioning_settings"]["parent_vm_id"] = basevmid
data["automated_farm_settings"]["provisioning_settings"]["host_or_cluster_id"] = host_or_cluster["id"]
data["automated_farm_settings"]["provisioning_settings"]["resource_pool_id"] = resource_pool["id"]
data["automated_farm_settings"]["provisioning_settings"]["vm_folder_id"] = vm_folder["id"]
data["automated_farm_settings"]["provisioning_settings"]["datacenter_id"] = dcid
data["automated_farm_settings"]["stop_provisioning_on_error"] = True
data["automated_farm_settings"]["storage_settings"]["datastores"] = datastore_list
data["automated_farm_settings"]["transparent_page_sharing_scope"] = "GLOBAL"
data["automated_farm_settings"]["vcenter_id"] = vcid
data["description"] = "Python_demo_farm"
data["display_name"] = "Python_demo_farm"
data["display_protocol_settings"]["allow_users_to_choose_protocol"] = True
data["display_protocol_settings"]["default_display_protocol"] = "BLAST"
data["display_protocol_settings"]["session_collaboration_enabled"] = True
data["enabled"] = False
data["load_balancer_settings"]["cpu_threshold"] = 12
data["load_balancer_settings"]["disk_queue_length_threshold"] = 16
data["load_balancer_settings"]["disk_read_latency_threshold"] = 12
data["load_balancer_settings"]["disk_write_latency_threshold"] = 16
data["load_balancer_settings"]["include_session_count"] = True
data["load_balancer_settings"]["memory_threshold"] = 12
data["name"] = "Python_demo_farm"
data["session_settings"]["disconnected_session_timeout_minutes"] = 5
data["session_settings"]["disconnected_session_timeout_policy"] = "NEVER"
data["session_settings"]["empty_session_timeout_minutes"] = 6
data["session_settings"]["empty_session_timeout_policy"] = "AFTER"
data["session_settings"]["logoff_after_timeout"] = False
data["session_settings"]["pre_launch_session_timeout_minutes"] = 12
data["session_settings"]["pre_launch_session_timeout_policy"] = "AFTER"
data["type"] = "AUTOMATED"
inventory.new_farm(farm_data=data)
end=hvconnectionobj.hv_disconnect()
print(end)
How does this look? Actually you don’t see a lot happening but the farm will have been created
As always the script can be found on my github in the examples folder together with the json file.
With this I am closing my 100DaysOfCode challenge but I pledge to keep maintaining the python module and I will extend it when new REST api calls arrive for VMware Horizon.
A day late but never late than never, this is your monthly overview with all the latest and greatest VMware flings. The flings site received a new fresh look head out to https://flings.vmware.com to have a look yourself. I am not sure if the (are they new?) tags for updated or new flings are okay yet as one has been marked updated but it seems to be new while one new one I could find a blog post for from last month but I missed it for my overview, not sure what happened there. Overall I see four new flings and ten received an update.
Nuance PowerMics are the leading dictation device used in Healthcare today.
This handy standalone Fling will assist in determining the optimal PowerMic configuration for a specific customer environment.
To determine the configuration that works best for you, we need to know a few details about the customer environment:
Endpoint type
Endpoint vendor
Endpoint operating system
Single/nested mode
Horizon protocol
The PowerMic Configuration Wizard will then provide the specific settings for optimal PowerMic performance and accuracy in the customers environment.
[sta_anchor id=”vracsc” /]
vRealize Automation Code Stream CLI
vRealize Automation Code Stream CLI is a command line tool written in Go to interact with the vRealize Automation Code Stream APIs. This Fling is written to help automate Code Stream and provide a simple way to migrate content between Code Stream instances and projects.
Import and Export Code Stream artefacts such as Pipelines, Variables, Endpoints
Perform CRUD operations on Code Stream artefacts such as Pipelines, Variables, Endpoints
Trigger Executions of Pipelines
[sta_anchor id=”hvddv” /]
Hillview: Distributed Data Visualization
Hillview is a simple cloud-based spreadsheet program for browsing large data collections. The data manipulated is read-only. Users can sort, find, filter, transform, query, zoom-in/out, and chart data. Operations are performed using direct manipulation in the GUI. Hillview is designed to work on very large data sets (billions of rows). Hillview can import data from a variety of sources: CSV files, ORC files, Parquet files, databases, parallel databases; new connectors can be added with relatively little effort. Hillview takes advantage of all the cores of the worker machines for fast visualizations.
Hillview is a distributed system, composed of two pieces:
A distributed set of one or many workers, which should be installed close to the data (e.g., on the machines that host the data).
A front-end service that runs a web server and aggregates data from all workers.
The source code of Hillview is available as an open-source project with an Apache-2 license from Hillview’s github repository. For any questions, feature requests or bug reports please file an issue on github.
[sta_anchor id=”sddciefvcoaws” /]
SDDC Import/Export for VMware Cloud on AWS
The SDDC Import/Export for VMware Cloud on AWS tool enables you to save and restore your VMware Cloud on AWS (VMC) Software-Defined Data Center (SDDC) networking and security configuration.
There are many situations when customers want to migrate from an existing SDDC to a different one. While HCX addresses the data migration challenge, this tool offers customers the ability to copy the configuration from a source to a destination SDDC.
A few example migration scenarios are:
SDDC to SDDC migration from bare-metal (i3) to a different bare-metal type (i3en)
SDDC to SDDC migration from VMware-based org to an AWS-based org
SDDC to SDDC migration from region (i.e. London) to a different region (i.e. Dublin).
Other use cases are:
Backups – save the entire SDDC configuration
Lab purposes – customers or partners might want to deploy SDDCs with a pre-populated configuration.
DR purposes – deploy a pre-populated configuration in conjunction with VMware Site Recovery or VMware Cloud Disaster Recovery
The Workspace ONE mobileconfig Importer gives you the ability to import existing mobileconfig files directly into a Workspace ONE UEM environment as a Custom Settings profile, import app preference plist files in order to created managed preference profiles, and to create new Custom Settings profiles from scratch. When importing existing configuration profiles, the tool will attempt to separate each PayloadContent dictionary into a separate payload for the Workspace ONE profile.
Changelog
Version 1.1
Support for Big Sur
Updated icon
[sta_anchor id=”wsoneuemwmt” /]
Workspace One UEM Workload Migration Tool
Quite a few updates for this fling already!
The Workspace One UEM Workload Migration Tool allows a seamless migration of Applications and Device configurations between different Workspace One UEM environments. With the push of a button, workloads move from UAT to Production, instead of having to manually enter the information or upload files manually. Therefore, decreasing the time to move data between Dev/UAT environments to Production.
Changelog
Version 2.1.0
Fixed app upload issues for Workspace One UEM 1910+
Fixed profile search issue for Workspace One UEM 1910+
Added profile update support
Added template folder structure creation
Updated Mac app to support notarization for Catalina
Version 2.0.1
Fixed Baseline Migration issue
Fixed Profile Errors not displaying in the UI
Version 2.0.0
Baseline Migration Support
MacOS application
UI refactoring to make bulk migrations easier
Added support for script detection with Win32 applications
Version 1.0.1
Fixed issue with expired credentials.
[sta_anchor id=”vsanhclc” /]
vSAN Hardware Compatibility List Checker
The vSAN Hardware Compatibility List Checker is a tool that verifies all installed storage adapters against the vSAN supported storage controller list. The tool will verify if the model, driver and firmware version of the storage adapter are supported.
Changelog
Version 2.2
Support multi-platforms for Windows, Linux and MacOS
Bug fixed
[sta_anchor id=”vmss2core” /]
Vmss2core
Vmss2core is a tool to convert VMware checkpoint state files into formats that third party debugger tools understand. It can handle both suspend (.vmss) and snapshot (.vmsn) checkpoint state files (hereafter referred to as a ‘vmss file’) as well as both monolithic and non-monolithic (separate .vmem file) encapsulation of checkpoint state data.
Changelog
Version 1.0.1
Fixed running out of memory issues
Added support for more versions of Windows 10/Windows 2016
[sta_anchor id=”vrbt” /]
vRealize Build Tools
vRealize Build Tools provides tools to development and release teams implementing solutions based on vRealize Automation (vRA) and vRealize Orchestrator (vRO). The solution targets Virtual Infrastructure Administrators and Solution Developers working in parallel on multiple vRealize-based projects who want to use standard DevOps practices.
Changelog
Version 2.12.5 Update
[vRBT] Package installer – Add support for installation on a standalone vRO (not embedded) version 8.x with basic authentication
[vRA] Added catalog entitlements and examples to the vra-ng archetype
[vRO] Support / in Workflow name or path, by substituting it with dash (-) character.
[vRBT] Added http / socket timeouts support in the installer
[ABX] Support for ABX actions
[vRO] Support of placeholders in workflow description
[vRA] Import vRA8 custom resources before blueprints
[vROPS] Fixed policy import / export problem with vROPs 8.2, maintaining backward compatibility
[MVN] Fixed ussue with installer timeouts
[TS] vRO pkg – Adds support for slash in workflow path or name
[vRBT] Package installer – updated documentation, added checking of workflow input, writing of workflow error message to file, setting of installer exit code when executing of a workflow
[TS] Allow additional trigger events for policies trigered by the vcd mqtt plugin
[MVN] Fix Missing vRA Tenant After Successful package import
Based on the customer requests, have added few more command line options for CSV reports generation and AD LDS data cleanup.
What’s New:
Adds support to cleanup stale global local entitlement assignments from ADAM DB.
Global AD LDS Command:
adlds-analyzer.cmd –resolve-localpool-ga
Scans the cloud pod database and resolves the stale entries of local pool global assignments.
Note: This resolves deleted local pool conflicts of current pod only. If dashboard session data load error or session search fails in a different pod, a scan and resolve has to be executed in that pod.
List of new commands added to Local AD LDS:
adlds-analyzer.cmd –export-machine
All machine data exported as CSV file. Compatibility: Horizon 7.10 and above, 8.x
adlds-analyzer.cmd –export-machine -pool=”DesktopPool1,DesktopPool2″
All machine data exported as CSV file. Use -pool= to filter machines by desktop pool name. Compatibility: Horizon 7.10 and above, 8.x
Spaces are not allowed in -pool= optional argument.
adlds-analyzer.cmd –export-session
All local sessions data exported as CSV file. Compatibility: Horizon 7.10 and above, 8.x
adlds-analyzer.cmd –export-session -pool=”PoolName1,PoolName2″ -farm=”FarmName1,FarmName2″
All local session data exported as CSV file. Use -pool= to filter sessions by desktop pool name. -farm= filter sessions by RDS farm name. Compatibility: Horizon 7.10 and above, 8.x
Spaces are not allowed in -pool= and -farm= optional argument.
adlds-analyzer.cmd –check-apps-integrity
Scans and lists the stale application icons in local ADLDS instance.
adlds-analyzer.cmd –check-apps-integrity -input=”AbsoluteFilePath1″,”AbsoluteFilePath2″
Reads the list of adam LDIF files in “-input=” for parsing and exports the stale application icons data to a file.
adlds-analyzer.cmd –export-named-lic-users
Exports the utilized and un-utilized named license users list information.
[sta_anchor id=”wsoneaafm” /]
Workspace ONE App Analyzer for macOS
The Workspace ONE macOS App Analyzer will determine any Privacy Permissions, Kernel Extensions, or System Extensions needed by an installed macOS application, and can be used to automatically create profiles in Workspace ONE UEM to whitelist those same settings when deploying apps to managed devices.
Changelog
Version 1.2.1
Fixed bug that caused crash with certain System Extension configurations
[sta_anchor id=”avpu” /]
App Volumes Packaging Utility
This App Volumes Packaging Utility helps to package applications. With this fling, packagers can add the necessary metadata to MSIX app attach VHDs so they can be used alongside existing AV format packages. The MSIX format VHDs will require App Volumes 4, version 2006 or later and Windows 10, version 2004 or later.
Changelog
Version 1.2 Update
Fixed bugs found in internal testing.
[sta_anchor id=”dodstigg” /]
DoD Security Technical Implementation Guide(STIG) ESXi VIB
The DoD Security Technical Implementation Guide (‘STIG’) ESXi VIB is a Fling that provides a custom VMware-signed ESXi vSphere Installation Bundle (‘VIB’) to assist in remediating Defense Information Systems Agency STIG controls for ESXi. This VIB has been developed to help customers rapidly implement the more challenging aspects of the vSphere STIG. These include the fact that installation is time consuming and must be done manually on the ESXi hosts. In certain cases, it may require complex scripting, or even development of an in-house VIB that would not be officially digitally signed by VMware (and therefore would not be deployed as a normal patch would). The need for a VMware-signed VIB is due to the system level files that are to be replaced. These files cannot be modified at a community supported acceptance level. The use of the VMware-signed STIG VIB provides customers the following benefits:
The ability to use vSphere Update Manager (‘VUM’) to quickly deploy the VIB to ESXi hosts (you cannot do this with a customer created VIB)
The ability to use VUM to quickly check if all ESXi hosts have the STIG VIB installed and therefore are also in compliance
No need to manually replace and copy files directly on each ESXi host in your environment
No need to create complex shell scripts that run each time ESXi boots to re-apply settings
Changelog
Update March 2021
New ESXi 7.0 STIG VIB release
Updated sshd_config file to meet the ESXi 7.0 Draft STIG which is also now the default config in 7.0 U2 with the exception of permitting root user logins.
Removed /etc/vmware/welcome file from VIB since it can be configured via the UI or PowerCLI now with issue.
See the updated Overview and Installation guide included in the download.
[sta_anchor id=”osot” /]
VMware OS Optimization Tool
No comments needed, just use the OS Optimization Tool when creating your golden images!
Changelog
March 2021, b2002
Fixed issue where the theme file was being updated by a Generalize task and the previously selected optimizations including wallpaper color were being lost.
The administrator username used during Generalize was not getting passed through properly to the unattend answer file. This resulted in a mismatch when using some languages versions of Windows.
Removed legacy code GPO Policy corruption
Removed CMD.exe box that displayed at logon.
Windows Store Apps were not being removed properly on Windows 10 version 20H2. Fixed the optimizations to cope with the differences introduced in this version.
Optimizations
Changed step Block all consumer Microsoft account user authentication to be unselected by default. When disabled this was causing failures to login to Edge and Windows store.
Changed the step Turn off Thumbnail Previews in File Explorer to be unselected by default. This was causing no thumbnails to show for store apps in search results.
Windows 8 and 8.1 templates have been removed from the list of built-in templates. To optimize these versions of Windows, use the separate download for version b1130.
Removed old Windows 10 templates from the Public Templates repository:
Windows 10 1809-2004-Server 2019
Windows 10 1507-1803-Server 2016
January 2021, b2001 Bug Fixes
All optimization entries have been added back into the main user template. This allows manual tuning and selection of all optimizations.
Fixed two hardware acceleration selections were not previously controlled by the Common Option for Visual Effect to disable hardware acceleration.
Optimize
During an Optimize, the optimization selections are automatically exported to a default json file (%ProgramData%\VMware\OSOT\OptimizedTemplateData.json).
Analyze
When an Analyze is run, if the default json file exists (meaning that this image has already been optimized), this is imported and used to select the optimizations and the Common Options selections with the previous choices.
If the default selections are required, on subsequent runs of the OS Optimization Tool, delete the default json file, relaunch the tool and run Analyze.
Command Line
The OptimizedTemplateData.json file can also be used from the command line with the -applyoptimization parameter.
Optimizations
Changed entries for Hyper-V services to not be selected by default. These services are required for VMs deployed onto Azure. Windows installation sets these to manual (trigger) so these so not cause any overhead on vSphere, when left with the default setting.
Yesterday Robin Stolpe again reached out that he was having issues assigning multiple accounts to the same dedicated machine. He couldn’t get this running with the vmware.hv.helper and looking that with how it is implemented now it will probably never work. I decided to put together some of the functions I have used for ControlUp script based actions and some of my other work to put together the following script (that can be found on Github here.)
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$False,
ParameterSetName="separatecredentials",
HelpMessage='Enter a username' )]
[ValidateNotNullOrEmpty()]
[string] $Username,
[Parameter(Mandatory=$false,
ParameterSetName="separatecredentials",
HelpMessage='Domain i.e. loft.lab' )]
[string] $Domain,
[Parameter(Mandatory=$false,
ParameterSetName="separatecredentials",
HelpMessage='Password in plain text' )]
[string] $Password,
[Parameter(Mandatory=$true, HelpMessage='FQDN of the connectionserver' )]
[ValidateNotNullOrEmpty()]
[string] $ConnectionServerFQDN,
[Parameter(Mandatory=$false,
ParameterSetName="credsfile",
HelpMessage='Path to credentials xml file' )]
[ValidateNotNullOrEmpty()]
[string] $Credentialfile,
[Parameter(Mandatory=$false, HelpMessage='username of the user to logoff (domain\user i.e. loft.lab\user1')]
[ValidateNotNullOrEmpty()]
[string[]] $TargetUsers,
[Parameter(Mandatory=$false, HelpMessage='Name of the desktop pool the machine belongs to')]
[string] $TargetPool,
[Parameter(Mandatory=$false, HelpMessage='dns name of the machine the user is on i.d. lp-002.loft.lab')]
[string] $TargetMachine,
[Parameter(Mandatory=$false, HelpMessage='domain for the target users')]
[string] $TargetDomain
)
if($Credentialfile -and ((test-path $Credentialfile) -eq $true)){
try{
write-host "Using credentialsfile"
$credentials=Import-Clixml $Credentialfile
$username=($credentials.username).split("\")[1]
$domain=($credentials.username).split("\")[0]
$secpw=$credentials.password
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secpw)
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
}
catch{
write-error -Message "Error importing credentials"
break
}
}
elseif($Credentials -and ((test-path $credentials) -eq $false)){
write-error "Invalid Path to credentials file"
break
}
elseif($username -and $Domain -and $Password){
write-host "Using separate credentials"
}
function Get-HVDesktopPool {
param (
[parameter(Mandatory = $true,
HelpMessage = "Displayname of the Desktop Pool.")]
[string]$HVPoolName,
[parameter(Mandatory = $true,
HelpMessage = "The Horizon View Connection server object.")]
[VMware.VimAutomation.HorizonView.Impl.V1.ViewObjectImpl]$HVConnectionServer
)
# Try to get the Desktop pools in this pod
try {
# create the service object first
[VMware.Hv.QueryServiceService]$queryService = New-Object VMware.Hv.QueryServiceService
# Create the object with the definiton of what to query
[VMware.Hv.QueryDefinition]$defn = New-Object VMware.Hv.QueryDefinition
# entity type to query
$defn.queryEntityType = 'DesktopSummaryView'
# Filter on the correct displayname
$defn.Filter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='desktopSummaryData.displayName'; 'value' = "$HVPoolname"}
# Perform the actual query
[array]$queryResults= ($queryService.queryService_create($HVConnectionServer.extensionData, $defn)).results
# Remove the query
$queryService.QueryService_DeleteAll($HVConnectionServer.extensionData)
# Return the results
if (!$queryResults){
write-host "Can't find $HVPoolName, exiting."
exit
}
else {
return $queryResults
}
}
catch {
write-host 'There was a problem retreiving the Horizon View Desktop Pool.'
}
}
function Get-HVDesktopMachine {
param (
[parameter(Mandatory = $true,
HelpMessage = "ID of the Desktop Pool.")]
[VMware.Hv.DesktopId]$HVPoolID,
[parameter(Mandatory = $true,
HelpMessage = "Name of the Desktop machine.")]
[string]$HVMachineName,
[parameter(Mandatory = $true,
HelpMessage = "The Horizon View Connection server object.")]
[VMware.VimAutomation.HorizonView.Impl.V1.ViewObjectImpl]$HVConnectionServer
)
try {
# create the service object first
[VMware.Hv.QueryServiceService]$queryService = New-Object VMware.Hv.QueryServiceService
# Create the object with the definiton of what to query
[VMware.Hv.QueryDefinition]$defn = New-Object VMware.Hv.QueryDefinition
# entity type to query
$defn.queryEntityType = 'MachineDetailsView'
# Filter so we get the correct machine in the correct pool
$poolfilter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='desktopData.id'; 'value' = $HVPoolID}
$machinefilter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='data.name'; 'value' = "$HVMachineName"}
$filterlist = @()
$filterlist += $poolfilter
$filterlist += $machinefilter
$filterAnd = New-Object VMware.Hv.QueryFilterAnd
$filterAnd.Filters = $filterlist
$defn.Filter = $filterAnd
# Perform the actual query
[array]$queryResults= ($queryService.queryService_create($HVConnectionServer.extensionData, $defn)).results
# Remove the query
$queryService.QueryService_DeleteAll($HVConnectionServer.extensionData)
# Return the results
if (!$queryResults){
write-host "Can't find $HVPoolName, exiting."
exit
}
else{
return $queryResults
}
}
catch {
write-host 'There was a problem retreiving the Horizon View Desktop Pool.'
}
}
function Get-HVUser {
param (
[parameter(Mandatory = $true,
HelpMessage = "User loginname..")]
[string]$HVUserLoginName,
[parameter(Mandatory = $true,
HelpMessage = "Name of the Domain.")]
[string]$HVDomain,
[parameter(Mandatory = $true,
HelpMessage = "The Horizon View Connection server object.")]
[VMware.VimAutomation.HorizonView.Impl.V1.ViewObjectImpl]$HVConnectionServer
)
try {
# create the service object first
[VMware.Hv.QueryServiceService]$queryService = New-Object VMware.Hv.QueryServiceService
# Create the object with the definiton of what to query
[VMware.Hv.QueryDefinition]$defn = New-Object VMware.Hv.QueryDefinition
# entity type to query
$defn.queryEntityType = 'ADUserOrGroupSummaryView'
# Filter to get the correct user
$userloginnamefilter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='base.loginName'; 'value' = $HVUserLoginName}
$domainfilter = New-Object VMware.Hv.QueryFilterEquals -property @{'memberName'='base.domain'; 'value' = "$HVDomain"}
$filterlist = @()
$filterlist += $userloginnamefilter
$filterlist += $domainfilter
$filterAnd = New-Object VMware.Hv.QueryFilterAnd
$filterAnd.Filters = $filterlist
$defn.Filter = $filterAnd
# Perform the actual query
[array]$queryResults= ($queryService.queryService_create($HVConnectionServer.extensionData, $defn)).results
# Remove the query
$queryService.QueryService_DeleteAll($HVConnectionServer.extensionData)
# Return the results
if (!$queryResults){
write-host "Can't find user $HVUserLoginName in domain $HVDomain, exiting."
exit
}
else {
return $queryResults
}
}
catch {
write-host 'There was a problem retreiving the user.'
}
}
$hvserver1=connect-hvserver $ConnectionServerFQDN -user $username -domain $domain -password $password
$Services1= $hvServer1.ExtensionData
$desktop_pool=Get-HVDesktopPool -hvpoolname $TargetPool -HVConnectionServer $hvserver1
$poolid=$desktop_pool.id
$machine = get-hvdesktopmachine -HVConnectionServer $hvserver1 -HVMachineName $TargetMachine -HVPoolID $poolid
$machineid = $machine.id
$useridlist=@()
foreach ($targetuser in $TargetUsers){
$user = Get-HVUser -HVConnectionServer $hvserver1 -hvdomain $TargetDomain -HVUserLoginName $targetUser
$useridlist+=$user.id
}
$Services1.Machine.Machine_assignUsers($machineid, $useridlist)
So first I have 3 functions to get the Pool, the machine and users. With a foreach on the $Targetusers list I create a list of the userid’s that is required to use for the Machine_assignUsers function of the machine service.
A long time ago in a galaxy far far away I wrote this blog post to log a user off from their vdi session. Today I got an inquiry from Robin Stolpe that he was trying to make it a script with arguments instead if the menu’s but was having some issues with that. This gave me the chance to make it a bit nicer of a script with the option to user username/domain/password as credentials but also a credentialfile , optional forcefully logging off the users and with Robin’s requirements of being able to provide the exact username and the machine that user is working on.
So I started with the parameters and for that I included 2 parameter sets so you can either choose to have the separate credentials or to use a credentials file.
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$False,
ParameterSetName="separatecredentials",
HelpMessage='Enter a username' )]
[ValidateNotNullOrEmpty()]
[string] $Username,
[Parameter(Mandatory=$false,
ParameterSetName="separatecredentials",
HelpMessage='Domain i.e. loft.lab' )]
[string] $Domain,
[Parameter(Mandatory=$false,
ParameterSetName="separatecredentials",
HelpMessage='Password in plain text' )]
[string] $Password,
[Parameter(Mandatory=$true, HelpMessage='FQDN of the connectionserver' )]
[ValidateNotNullOrEmpty()]
[string] $ConnectionServerFQDN,
[Parameter(Mandatory=$false,
ParameterSetName="credsfile",
HelpMessage='Path to credentials xml file' )]
[ValidateNotNullOrEmpty()]
[string] $Credentialfile,
[Parameter(Mandatory=$false, HelpMessage='Synchronise the local site only' )]
[switch] $Force,
[Parameter(Mandatory=$false, HelpMessage='username of the user to logoff (domain\user i.e. loft.lab\user1')]
[ValidateNotNullOrEmpty()]
[string] $TargetUser,
[Parameter(Mandatory=$false, HelpMessage='dns name of the machine the user is on i.d. lp-002.loft.lab')]
[string] $TargetMachine
)
Than I check if a credential file was supplied and if I can actually import it
Or an error importing the xml (duh, what do you think what happoens when you use a json instead of xml, fool!)
Then it’s a matter of logging in, performing a query and checking if there’s really a session for this user. As you can see I am using machineOrRDSServerDNS so it should also work for RDS sessions.
And last but not least logging the user of with or without the -force option
if($Force){
write-host "Forcefully logging off $targetUser from $targetmachine"
$Services1.Session.Session_Logoffforced($session.id)
}
else{
write-host "Logging off $targetUser from $targetmachine"
try{
$Services1.Session.Session_Logoff($session.id)
}
catch{
write-error "error logging the user off, maybe the sessions was locked. Try with -force"
}
}
This session was locked
So let’s force that thing
And here’s the entire script but you can also find it on my github.
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$False,
ParameterSetName="separatecredentials",
HelpMessage='Enter a username' )]
[ValidateNotNullOrEmpty()]
[string] $Username,
[Parameter(Mandatory=$false,
ParameterSetName="separatecredentials",
HelpMessage='Domain i.e. loft.lab' )]
[string] $Domain,
[Parameter(Mandatory=$false,
ParameterSetName="separatecredentials",
HelpMessage='Password in plain text' )]
[string] $Password,
[Parameter(Mandatory=$true, HelpMessage='FQDN of the connectionserver' )]
[ValidateNotNullOrEmpty()]
[string] $ConnectionServerFQDN,
[Parameter(Mandatory=$false,
ParameterSetName="credsfile",
HelpMessage='Path to credentials xml file' )]
[ValidateNotNullOrEmpty()]
[string] $Credentialfile,
[Parameter(Mandatory=$false, HelpMessage='Synchronise the local site only' )]
[switch] $Force,
[Parameter(Mandatory=$false, HelpMessage='username of the user to logoff (domain\user i.e. loft.lab\user1')]
[ValidateNotNullOrEmpty()]
[string] $TargetUser,
[Parameter(Mandatory=$false, HelpMessage='dns name of the machine the user is on i.d. lp-002.loft.lab')]
[string] $TargetMachine
)
if($Credentialfile -and ((test-path $Credentialfile) -eq $true)){
try{
write-host "Using credentialsfile"
$credentials=Import-Clixml $Credentialfile
$username=($credentials.username).split("\")[1]
$domain=($credentials.username).split("\")[0]
$secpw=$credentials.password
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secpw)
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
}
catch{
write-error -Message "Error importing credentials"
break
}
}
elseif($Credentials -and ((test-path $credentials) -eq $false)){
write-error "Invalid Path to credentials file"
break
}
elseif($username -and $Domain -and $Password){
write-host "Using separate credentials"
}
$hvserver1=connect-hvserver $ConnectionServerFQDN -user $username -domain $domain -password $password
$Services1= $hvServer1.ExtensionData
$queryService = New-Object VMware.Hv.QueryServiceService
$sessionfilterspec = New-Object VMware.Hv.QueryDefinition
$sessionfilterspec.queryEntityType = 'SessionLocalSummaryView'
$sessionfilter1= New-Object VMware.Hv.QueryFilterEquals
$sessionfilter1.membername='namesData.userName'
$sessionfilter1.value=$TargetUser
$sessionfilter2= New-Object VMware.Hv.QueryFilterEquals
$sessionfilter2.membername='namesData.machineOrRDSServerDNS'
$sessionfilter2.value=$TargetMachine
$sessionfilter=new-object vmware.hv.QueryFilterAnd
$sessionfilter.filters=@($sessionfilter1, $sessionfilter2)
$sessionfilterspec.filter=$sessionfilter
$session=($queryService.QueryService_Create($Services1, $sessionfilterspec)).results
$queryService.QueryService_DeleteAll($services1)
if($session.count -eq 0){
write-host "No session found for $targetuser on $targetmachine"
break
}
if($Force){
write-host "Forcefully logging off $targetUser from $targetmachine"
$Services1.Session.Session_Logoffforced($session.id)
}
else{
write-host "Logging off $targetUser from $targetmachine"
try{
$Services1.Session.Session_Logoff($session.id)
}
catch{
write-error "error logging the user off, maybe the sessions was locked. Try with -force"
}
}
One of the REST api calls that where added for Horizon 8 2012 was the ability to push images to Desktop Pools (sadly not for farms yet). This week I added that functionality to the VMware Horizon Python Module. Looking at the swagger UI these are the needed arguments:
So the source can be either the streams from Horizon Cloud or a regular vm/snapshot combo. For the time you will need to use some moment in epoch. The optional items for adding the virtual tpm, stop on error I have set the default for what they are listed. As logoff policy I have chosen to set a default in WAIT_FOR_LOGOFF.
For this blog posts I have to go with the vm/snapshot combo as I don’t have streams setup at the moment. First I need to connect:
Now let’s look at what the desktop_pool_push_image method needs
First I will grab the correct desktop pool, I will use Pod02-Pool02 this time. There are several ways to get the correct pool but I have chosen to use this one.
desktop_pools=inventory.get_desktop_pools()
desktop_pool = next(item for item in desktop_pools if item["name"] == "Pod02-Pool02")
poolid=desktop_pool["id"]
To get the VM and Snapshots I first need to get the vCenter and datacenter id’s
I created a new golden image last Friday and it has this name: W10-L-2021-03-19-17-27 so I need to get the compatible base vm’s and get the id for this one
base_vms = external.get_base_vms(vcenter_id=vcid,datacenter_id=dcid,filter_incompatible_vms=True)
base_vm = next(item for item in base_vms if item["name"] == "W10-L-2021-03-19-17-27")
basevmid=base_vm["id"]
I had Packer create a snapshot and I can get that in a similar way
base_snapshots = external.get_base_snapshots(vcenter_id=vcid, base_vm_id=base_vm["id"])
base_snapshot = next(item for item in base_snapshots if item["name"] == "Created by Packer")
snapid=base_snapshot["id"]
I get the current time in epoch using the time module (google is your best friend to define a moment in the future in epoch)
current_time = time.time()
For this example I add all the arguments but if you don’t change fromt he defaults that’s not needed
and when I now look at my desktop pool it’s pushing the new image
I have created a new folder on Github for examples and the script to deploy new images is the first example. I did move a couple of the names to variables so make ie better usable. You can find it here. Or see the code below this.
It’s been a busy month on the flings front, no less than 17(!!) new releases and updated flings. This is how my browser tabs look:
If I have therm all correct there are 6 new releases and 10 updates (2 1 of which update without a changelog so a boo for that!) so this post is going to be a long one!
This Fling is a collection of ESXi Native Drivers which enables ESXi to recognize and consume various NVMe-based storage devices. These devices are not officially on the VMware HCL and have been developed to enable and support the VMware Community.
Currently, this Fling provides an emulated NVMe driver for the Apple 2018 Intel Mac Mini 8,1 and the Apple 2019 Intel Mac Pro 7,1 allowing customers to use the local NVMe SSD with ESXi. This driver is packaged up as an Offline Bundle and is only activated when it detects ESXi has been installed on either an Apple Mac Mini or Apple Mac Pro.
[sta_anchor id=”vcfp” /]
VMware Cloud Foundation Powernova
VMware Cloud Foundation Powernova is a Fling built on top of VCF that provides the users the ability to perform Power Operations (Power ON, Power OFF) seamlessly across the entire inventory. It has a sleek UI to visualize the entire VCF inventory (which is the first of its kind for VCF) across the domains of VCF.
The UI is easy to use and elucidates the current Health and Power State of each node in the VCF inventory. Powernova lets the user work on the Power Operations on the components with domain specific inter dependencies automatically resolved.
Powernova also performs valid health checks on all nodes in the VCF inventory to ensure Power Operations are performed only on healthy nodes. Powernova takes minimal input (4 user defined inputs on their VCF system) and does all the magic for the users behind the scenes.
If any infrastructure maintenance activity, VCF migration activity, or power operations need to be performed only on specific domains in VCF, then Powernova is the one stop solution for all VCF users.
[sta_anchor id=”wsoamt” /]
Workspace ONE Access Migration Tool
Workspace ONE Access Migration Tool helps ease migration of Apps from one WS1 Access tenant to another (on-premises to SaaS or SaaS to SaaS) and use cases that require mirroring one tenant to another (for setting up UAT from PROD or vice versa) by providing capabilities listed below
Features
Copying of App Categories
Migrating Weblinks (3rd party IDP), icons as is
Creating a link to federated apps and copying the icons (to maintain the same user experience)
Copying App Assignment to a Category mapping
[sta_anchor id=”sdpdovci” /]
Sample Data Platform Deployment on Virtualized Cloud Infrastructure
Data is king and your users need a sample data platform quickly.
With this Fling, you will leverage your VMware Cloud Foundation 4.0 with vRealize Automation deployment and stand a sample data platform based on vSphere Virtual Machines in less than 20-minutes comprising of Kafka, Spark, Solr, and ELK.
You can also choose whether to deploy a wavefront proxy and configure the components to send data to the wavefront proxy or use your own.
[sta_anchor id=”cndfe” /]
Community Networking Driver for ESXi
This Fling is a collection of ESXi Native Drivers which enables ESXi to recognize and consume various PCIe-based network adapters (See Requirements for details). These devices are not officially on the VMware HCL and have been developed to enable and support the VMware Community.
[sta_anchor id=”csci” /]
Code Stream Concourse Integrator
The Code Stream Concourse Integrator (CSCI) Fling provides integration between a vRealize Automation Code Stream and Concourse CI tools with which users can trigger Concourse CI pipelines from Code Stream pipelines without any additional tooling/scripting. This enables users to use the features from both the tools flexibly and seamlessly as per their needs. This solution is built using Code Stream’s extensibility feature named Custom Integration.
Updates
[sta_anchor id=”ecc” /]
ESXi Compatibility Checker
The ESXi Compatibility Checker helps the vSphere admin out in checking if their environment will work with later versions of ESXi. [non-sponsored advertisement]Also check Runecast, they can run a simulation for you as well.[/non-sponsored advertisement]
Changelog
Build 20210219
Fix for ESX / VC 7.0 U1 Versioning issues
A new logo 😉
[sta_anchor id=”vmlp” /]
VMware Machine Learning Platform
Our goal is to provide an end-to-end ML platform for Data Scientists to perform their job more effectively by running ML workloads on top of VMware infrastructure.
Save the costs by enabling efficient use of shared GPUs for ML workfloads
Reduce the risks of broken Data Science workflows by leveraging well-tested and ready-to-use demos and project templates
Faster “go-to-market” for ML models by utilizing end-to-end oriented tooling including fast and easy model deployment and serving via standardized REST API
Changelog
Version 0.4.1
Jupyter: R Kernel
Jupyter: BitFusion 2.5.0 Demo
Jupyter: MADlib/RTS4MADlib on Greenplum Demo
Multiple bug fixes
[sta_anchor id=”vhpct” /]
Virtualized High Performance Computing Toolkit
This toolkit is intended to facilitate managing the lifecycle of these special configurations by leveraging vSphere APIs. It also includes features that help vSphere administrators perform some common vSphere tasks that are related to creating such high-performing environments, such as VM cloning, setting Latency Sensitivity, and sizing vCPUs, memory, etc.
Changelog
Nope 🙁
[sta_anchor id=”hpi” /]
Horizon Peripherals Intelligence
Horizon Peripherals Intelligence is an online self-serviced diagnosis service that can help increase the satisfaction when using peripheral devices with Horizon product by both the end users and the admin user. Currently, we support diagnosis for the following device categories – USB storage devices, USB printers, USB scanners, Cameras. We will continue to cover more device categories in the future
Changelog
Version 1.0
Add support for USB Audios, Speechmics, Signaturepads, Barcode scanners
Add support for L10n of web pages in simplified Chinese, traditional Chinese and English
Add support for window 7 and windows 2012R2
Add support for 32 bits OS
Add support for cmdline installation
[sta_anchor id=”woaafm” /]
Workspace ONE App Analyzer for macOS
The Workspace ONE macOS App Analyzer will determine any Privacy Permissions, Kernel Extensions, or System Extensions needed by an installed macOS application, and can be used to automatically create profiles in Workspace ONE UEM to whitelist those same settings when deploying apps to managed devices.
Update: OSOT didn’t receive an update, someone only edited the page according to Hilko.
[sta_anchor id=”hhu” /]
Horizon Helpdesk Utility
Besides ControlUp the helpdesk fling is the best tool to help your users.
Changelog
Version 1.5.0.24
Added support for Horizon 8.1
[sta_anchor id=”hcibench” /]
HCIBench
HCIBench stands for “Hyper-converged Infrastructure Benchmark”. It’s essentially an automation wrapper around the popular and proven open source benchmark tools: Vdbench and Fio that make it easier to automate testing across a HCI cluster. HCIBench aims to simplify and accelerate customer POC performance testing in a consistent and controlled way. The tool fully automates the end-to-end process of deploying test VMs, coordinating workload runs, aggregating test results, performance analysis and collecting necessary data for troubleshooting purposes.
Changelog
Version 2.5.3
Fixed graphite permission issue which blocked vdbench/fio grafana display
Updated drop cache script to make it compatible with upcoming vSphere
Again if you’re not a ControlUp customer Reach is the next best thing to manage you’re Horizon environment.
Changelog
Version 1.3.1.2
Added support for Horizon 8.1
Bugfixes
[sta_anchor id=”wsod” /]
Workspace ONE Discovery
VMware Workspace ONE UEM is used to manage Windows 10 endpoints, whether it be Certificate Management, Application Deployment or Profile Management. The Discovery Fling enables you to view these from the device point of view and review the Workspace ONE related services, which applications have been successfully deployed, use the granular view to see exactly what has been configured with Profiles, view User & Machine certificates and see which Microsoft Windows Updates have been applied.
Changelog
February, 16, 2021 – Version 1.2
Replaced icon
New logo 🙂
[sta_anchor id=”avmu” /]
App Volumes Migration Utility
App Volumes Migration Utility allows admins to migrate AppStacks managed by VMware App Volumes 2.18, to the new application package format of App Volumes 4. The format of these packages in App Volumes 4 have evolved to improve performance and help simplify application management.
Changelog
Version 1.0.7 Update
Migration fails if their are blacklisted registry entries containing embedded NULL chars.
File system migration fails if their are directories having a trailing DOT name ( ex- Microsoft. ).
Earlier this week I added several methods to the VMware Horizon Python Module that are centered about application pools and I promised a blog post so here it is 🙂 In the module we have the following methods in the Inventory about Application Pools:
Halfway at day 50 for my #100DaysOfCode Challenge. Rolled back some name changes and added a couple new methods to the @VMwareHorizon#Python Module. A blogpost will follow on how to use new_application_pool and update_application_pool. pic.twitter.com/nJOywEzUDj
All of the connects at the bottom is so I don’t need to think to do those if I need them when testing.
I end with
end=hvconnectionobj.hv_disconnect()
print(end)
Both the connected and end prints aren’t required at all but give me feedback about the status of the connection.
[sta_anchor id=”get_application_pools” /]
get_application_pools
This is the easiest method to use as it doesn’t require anything. It does allow for setting page sizes and filtering if needed. See this article if you want to know more about filtering: https://www.retouw.nl/2021/02/14/filtering-searching-and-pagination-with-the-python-module-for-vmware-horizon/ The method will return a list of dicts, for the first example I will show only the names of the items.
ap = inventory.get_application_pools(maxpagesize=100)
for i in ap:
print(i["name"])
Or just with the entire list returned
ap = inventory.get_application_pools(maxpagesize=100)
print(ap)
[sta_anchor id=”get_application_pool” /]
get_application_pool
To get a single application pool you can use get_application_pool and it requires an application_pool_id, I will use the first one of the list of application to show it.
ap = inventory.get_application_pools(maxpagesize=100)
firstap=ap[0]
print(inventory.get_application_pool(application_pool_id=firstap["id"]))
[sta_anchor id=”delete_application_pool” /]
delete_application_pool
To delete an application pool we again only need the application_pool_id I will combine both the get methods to show all application pools before and after the deletion. (with some prints not relevant for the code so I won’t show them below)
ap = inventory.get_application_pools(maxpagesize=100)
for i in ap:
print(i["name"])
firstap=ap[0]
print(inventory.get_application_pool(application_pool_id=firstap["id"]))
inventory.delete_application_pool(application_pool_id=firstap["id"])
ap = inventory.get_application_pools(maxpagesize=100)
for i in ap:
print(i["name"])
[sta_anchor id=”new_application_pool” /]
new_application_pool
Since I just deleted my firefox pool I will need to recreate it. The new_application_pool method requires a dict with quite a lof of values. This is the standard list that the swagger-ui gives you
This does not say that all of these are required, what I have found to be an easy way to find what the minimums are is to create an application pool with a single key value pair. display_name is always required so I will use that one. Experience has learned that this might require several tries so let’s go.
It looks like we actually need some more: at least desktop_pool_id or farm_id since I am doing this against a connection server with no farms I’ll use a desktop pool.
No errors and a peak in the admin console shows me that I again have a firefox application
[sta_anchor id=”update_application_pool” /]
update_application_pool
To update the pools we need the application_pool_id and again a dict, this time the dict needs things we want to update. Experience again learned me there are a few required key value pairs while the example in the swagger-ui shows lots, so let’s find those. I am going to use my new firefox app as the source for this. What I actually am going to try to change is the display_name so I will use that as the first key value pair.
So here different key value pairs are required than when creating a new application pool, strange but there is nothing I can do about it! I will add these from the ap object I retrieve earlier in the script.
aps = inventory.get_application_pools(maxpagesize=100)
for i in aps:
print(i["display_name"])
filter = {}
filter["type"] = "And"
filter["filters"] = []
filter1={}
filter1["type"] = "Equals"
filter1["name"] = "name"
filter1["value"] = "Firefox"
filter["filters"].append(filter1)
ap = (inventory.get_application_pools(filter=filter))[0]
appid = ap["id"]
update_app = {}
update_app["display_name"] = "FF2"
update_app["executable_path"] = ap["executable_path"]
update_app["multi_session_mode"] = ap["multi_session_mode"]
update_app["enable_pre_launch"] = ap["enable_pre_launch"]
inventory.update_application_pool(application_pool_id=appid, application_pool_data=update_app)
aps = inventory.get_application_pools(maxpagesize=100)
for i in aps:
print(i["display_name"])
So with that you have the basics to retrieve, create, update and delete application pools using python
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here:
Cookie Policy