private/Get-WinPEDriverPackageVMware.ps1
|
#Requires -PSEdition Core function Get-WinPEDriverPackageVMware { <# .SYNOPSIS Gets VMware Tools ISO package metadata .DESCRIPTION Reads the VMware UpdateUri from the global WinPE driver configuration, downloads its package directory listing, and locates Windows VMware Tools ISOs for amd64 and arm64. File names provide version and package identifiers; Get-VMwareListingRow parses each row's release date and file size. Missing architecture entries, request failures, and parsing failures produce a warning and no objects. .EXAMPLE PS> Get-WinPEDriverPackageVMware Returns amd64 and arm64 VMware Tools ISO metadata from the configured package index. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject. Returns two objects ordered amd64 then arm64, each with Architecture, ReadmeUri, PackageId, Version, ReleaseDate, FileName, FileSizeMB, DownloadUri, and Checksums properties, or no objects on failure. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-08-28 Dependencies: Module Functions: Get-VMwareListingRow Network Resources: Configured VMware UpdateUri DotNet Classes: System.Management.Automation.PSCustomObject #> [CmdletBinding()] [OutputType([PSCustomObject[]])] param () try { $searchUri = $global:OSDeployModule.WinPEDrivers.'vmware'.UpdateUri if ([string]::IsNullOrWhiteSpace($searchUri)) { throw "vmware UpdateUri is not defined in winpedrivers.json." } Write-Verbose "[$($MyInvocation.MyCommand.Name)] Fetching VMware packages directory listing" $response = Invoke-WebRequest -Uri $searchUri -UseBasicParsing -ErrorAction Stop $html = $response.Content # Parse both ISO entries from an Apache autoindex table # amd64: VMware-tools-windows-13.0.10-25056151.iso # arm64: VMware-tools-windows-arm-13.0.10-25056151.iso $amd64Match = [regex]::Match($html, '(VMware-tools-windows-(\d+\.\d+\.\d+)-(\d+)\.iso)') $arm64Match = [regex]::Match($html, '(VMware-tools-windows-arm-(\d+\.\d+\.\d+)-(\d+)\.iso)') if (-not $amd64Match.Success) { Write-Warning "[$(Get-Date -Format s)] Could not find amd64 ISO filename on '$searchUri'. Page format may have changed." return } if (-not $arm64Match.Success) { Write-Warning "[$(Get-Date -Format s)] Could not find arm64 ISO filename on '$searchUri'. Page format may have changed." return } $amd64File = $amd64Match.Groups[1].Value $amd64Version = $amd64Match.Groups[2].Value $amd64Id = $amd64Match.Groups[3].Value $arm64File = $arm64Match.Groups[1].Value $arm64Version = $arm64Match.Groups[2].Value $arm64Id = $arm64Match.Groups[3].Value Write-Verbose "[$($MyInvocation.MyCommand.Name)] amd64='$amd64File' arm64='$arm64File'" # Parse Last-Modified and Size from the directory listing row for each file # Apache autoindex rows: <td align="right">2026-01-20 10:30 </td><td align="right"> 113M</td> $amd64Meta = Get-VMwareListingRow -Html $html -FileName $amd64File $arm64Meta = Get-VMwareListingRow -Html $html -FileName $arm64File $baseUri = $searchUri.TrimEnd('/') @( [PSCustomObject]@{ Architecture = 'amd64' ReadmeUri = $searchUri PackageId = $amd64Id Version = $amd64Version ReleaseDate = $amd64Meta.ReleaseDate FileName = $amd64File FileSizeMB = $amd64Meta.FileSizeMB DownloadUri = "$baseUri/$amd64File" Checksums = [PSCustomObject]@{} }, [PSCustomObject]@{ Architecture = 'arm64' ReadmeUri = $searchUri PackageId = $arm64Id Version = $arm64Version ReleaseDate = $arm64Meta.ReleaseDate FileName = $arm64File FileSizeMB = $arm64Meta.FileSizeMB DownloadUri = "$baseUri/$arm64File" Checksums = [PSCustomObject]@{} } ) } catch { Write-Warning "[$(Get-Date -Format s)] $($_.Exception.Message)" } } function Get-VMwareListingRow { <# .SYNOPSIS Gets metadata from a VMware package listing row .DESCRIPTION Matches an exact VMware ISO file name in an Apache-style HTML table row and parses its date and size. Sizes expressed in gigabytes, megabytes, kilobytes, or bytes are converted to megabytes. When no exact row matches, ReleaseDate is an empty string and FileSizeMB is null. .PARAMETER Html Specifies the HTML package listing to search. .PARAMETER FileName Specifies the exact linked file name whose table row is parsed. The value is escaped before it is included in the regular expression. .EXAMPLE PS> Get-VMwareListingRow -Html $response.Content -FileName 'VMware-tools-windows-13.0.10-25056151.iso' Returns the release date and size in megabytes parsed from the matching ISO row. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject. Returns one object with ReleaseDate and FileSizeMB properties. ReleaseDate is empty and FileSizeMB is null when no row matches. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-08-28 Dependencies: DotNet Classes: System.Management.Automation.PSCustomObject #> param ([string]$Html, [string]$FileName) $releaseDate = '' $fileSizeMB = $null # Match the exact ISO row in the autoindex table; avoid adjacent .sha and .sig rows. $rowPattern = '(?is)<tr[^>]*>\s*<td[^>]*>.*?<a href="' + [regex]::Escape($FileName) + '">' + [regex]::Escape($FileName) + '</a></td>\s*<td[^>]*>\s*(?<Date>\d{4}-\d{2}-\d{2})(?:\s+\d{2}:\d{2}Z?)?\s*</td>\s*<td[^>]*>\s*(?<Size>\d+(?:\.\d+)?)\s*(?<Unit>[MGK]B?|B)?\s*</td>' $rowMatch = [regex]::Match($Html, $rowPattern) if ($rowMatch.Success) { $releaseDate = $rowMatch.Groups['Date'].Value $rawSize = [double]$rowMatch.Groups['Size'].Value $unit = $rowMatch.Groups['Unit'].Value.ToUpperInvariant() $fileSizeMB = switch ($unit) { 'GB' { [math]::Round($rawSize * 1024, 2) } 'G' { [math]::Round($rawSize * 1024, 2) } 'MB' { [math]::Round($rawSize, 2) } 'M' { [math]::Round($rawSize, 2) } 'KB' { [math]::Round($rawSize / 1024, 2) } 'K' { [math]::Round($rawSize / 1024, 2) } 'B' { [math]::Round($rawSize / 1MB, 2) } default { [math]::Round($rawSize, 2) } } } [PSCustomObject]@{ ReleaseDate = $releaseDate FileSizeMB = $fileSizeMB } } |