Last active
January 23, 2025 18:46
-
-
Save mavaddat/f021e09f8c2d492e19959a9978b42544 to your computer and use it in GitHub Desktop.
Download and install xmllint for Windows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Modules PSParseHTML | |
function Install-XmlLint { | |
[CmdletBinding(SupportsShouldProcess)] | |
param ( | |
[Parameter(ValueFromPipelineByPropertyName)] | |
[string] | |
$InstallPath = (Join-Path -Path "$env:LOCALAPPDATA\Programs" -ChildPath xmllint), | |
[switch] | |
$Force | |
) | |
Write-Verbose 'Starting Install-XmlLint' | |
$baseUrl = 'http://xmlsoft.org/sources/win32' | |
if ([System.Environment]::Is64BitOperatingSystem) { | |
$baseUrl += '/64bit' | |
$fileSuffix = '_64' | |
} | |
Write-Verbose "Base URL: $baseUrl" | |
Write-Verbose "File Suffix: $fileSuffix" | |
$sort += '?C=M;O=D' # Order by date, descending | |
$libs = 'iconv', 'libxml2', 'libxml', 'xmlsec', 'zlib' | |
$httpClient = [System.Net.Http.HttpClient]::new() | |
$xmllintSite = Invoke-RestMethod -Method Get -Uri ($baseUrl + $sort) | ConvertFrom-HTML -Engine AngleSharp | |
$downloadLinks = $xmllintSite.QuerySelectorAll('body > table > tbody > tr > td > a') | |
Write-Verbose "Found $($downloadLinks.Text -match "($($libs -join '|')).*$fileSuffix") of $($libs.Count) download links" | |
@' | |
Microsoft.Bcl.AsyncInterfaces (>= 8.0.0) | |
System.Buffers (>= 4.6.0) | |
System.Memory (>= 4.6.0) | |
System.Text.Encoding.CodePages (>= 8.0.0) | |
ZstdSharp.Port (>= 0.8.4) | |
SharpCompress (>= 0.1) | |
'@ | Select-String -Pattern '\S+(?= \(.*\))' -AllMatches | Select-Object -ExpandProperty Matches | ForEach-Object { | |
(Get-Item (Join-Path (Split-Path (Get-Package $_.Value).Source) lib/netstandard*) | | |
Sort-Object { [version] ($_.Name -replace '^netstandard') })[-1] | | |
Get-ChildItem -Filter *.dll -Recurse | | |
ForEach-Object { | |
Write-Verbose "Adding '$($_.Name)' assembly into PowerShell session" | |
Add-Type -LiteralPath $_.FullName } | |
} | |
$extractOptions = [SharpCompress.Common.ExtractionOptions]::new() | |
$extractOptions.ExtractFullPath = $true | |
$extractOptions.Overwrite = $true | |
if (Test-Path -Path $InstallPath -PathType Container) { | |
Push-Location -Path $InstallPath | |
} | |
else { | |
New-Item -Path $InstallPath -ItemType Directory | Push-Location | |
} | |
foreach ($lib in $libs) { | |
$downloadLink = $downloadLinks | Where-Object -FilterScript { $_.Text -imatch "${lib}.*${fileSuffix}" } | Select-Object -First 1 -ExpandProperty PathName | |
Write-Verbose -Message "Downloading '$downloadLink'" | |
$downloadLink = $baseUrl + $downloadLink | |
# Use HttpClient to download the file | |
$httpClient = [System.Net.Http.HttpClient]::new() | |
$response = $httpClient.GetAsync($downloadLink).Result | |
$response.EnsureSuccessStatusCode() | Format-Table -AutoSize -Wrap | Out-String | Write-Debug | |
$bytes = $response.Content.ReadAsByteArrayAsync().Result | |
Write-Verbose "Downloaded $($bytes.Length) bytes" | |
# Use SharpCompress to extract the 7z files | |
$readerOptions = [SharpCompress.Readers.ReaderOptions]::new() | |
$readerOptions.ArchiveEncoding = [SharpCompress.Common.ArchiveEncoding]::new() | |
$readerOptions.ArchiveEncoding.Default = [System.Text.Encoding]::GetEncoding('utf-8') | |
try { | |
$sevenZipStream = [System.IO.MemoryStream]::new($bytes) | |
$archive = [SharpCompress.Archives.SevenZip.SevenZipArchive]::Open($sevenZipStream, $readerOptions) | |
foreach ($entry in $archive.Entries) { | |
if ($entry.IsDirectory -or -not $entry.Key.StartsWith('bin/')) { | |
Write-Debug "Skipping entry: $($entry.Key)" | |
continue | |
} | |
Write-Verbose "Extracting entry: $($entry.Key)" | |
try { | |
$entryStream = $entry.OpenEntryStream() | |
} | |
catch { | |
Write-Verbose "Skipping entry without a stream: $($entry.Key)" | |
continue | |
} | |
$outputPath = [System.IO.Path]::Combine("$env:TEMP\${lib}", $entry.Key) | |
$outputDir = [System.IO.Path]::GetDirectoryName($outputPath) | |
if (-not (Test-Path -Path $outputDir)) { | |
New-Item -Path $outputDir -ItemType Directory | Out-Null | |
} | |
$fileStream = [System.IO.File]::Create($outputPath) | |
try { | |
$entryStream.CopyTo($fileStream) | |
} | |
finally { | |
$fileStream.Close() | |
$entryStream.Close() | |
} | |
} | |
} | |
catch { | |
Write-Error -Message "Failed to open the 7z archive for '${lib}': $($_.Exception)" | |
} | |
# Copy all the files in the bin folder of each downloaded library to the xmllint folder | |
Get-ChildItem -Path "$env:TEMP\${lib}\bin" | Move-Item -Destination $InstallPath -Force:$Force | |
Write-Verbose "Copied files for $lib to $InstallPath" | |
} | |
$xmlLintExe = Get-Item -Path .\xmllint.exe | |
Write-Verbose "Completed Install-XmlLint: '$($xmlLintExe.FullName)'" | |
Pop-Location | |
} | |
if ($MyInvocation.InvocationName -eq '.') { | |
# Install the required packages, if they're not already installed | |
@' | |
Microsoft.Bcl.AsyncInterfaces (>= 8.0.0) | |
System.Buffers (>= 4.6.0) | |
System.Memory (>= 4.6.0) | |
System.Text.Encoding.CodePages (>= 8.0.0) | |
ZstdSharp.Port (>= 0.8.4) | |
SharpCompress (>= 0.1) | |
'@ | Select-String -Pattern '\S+(?= \(.*\))' -AllMatches | Select-Object -ExpandProperty Matches | ForEach-Object { | |
$packageName = $_.Value | |
if (-not(Get-Package -Name $packageName -Scope CurrentUser)) { | |
Write-Verbose -Message "Installing '$packageName'" -Verbose | |
Install-Package -Name $packageName -Scope CurrentUser -Source NuGet | |
} | |
} | |
# Install xmllint into the default location | |
Install-XmlLint -Force -Verbose -Confirm:$false | |
} |
not straight forward. missing the installation steps
I need to replace the SevenZipExtractor
package as a dependency, since it does not work.
Actually, the problem was the Invoke-WebRequest
somehow corrupting the downloaded bytes.
@rinilnath , I have updated the code and tested it. You can either download the cmdlet and import it as a module
<# Get xmllint installer #> (New-Object -TypeName System.Net.WebClient).DownloadString('https://gist.githubusercontent.com/mavaddat/f021e09f8c2d492e19959a9978b42544/raw/22512df43b3e11c72c2849dcae33e248a09f6cbe/xmllistInstaller.ps1') | Out-File -FilePath $env:TEMP\xmllistInstaller.ps1 -Verbose
Import-Module -FullyQualifiedName $env:TEMP\xmllistInstaller.ps1 -Verbose -Cmdlet Install-XmlLint
# Install xmllint into the default location
Install-XmlLint -Force -Verbose -Confirm:$false
Or, use the Invoke-Expression
on the remote string to run the script:
<# Install xmllint #> iex (New-Object -TypeName System.Net.WebClient).DownloadString('https://gist.githubusercontent.com/mavaddat/f021e09f8c2d492e19959a9978b42544/raw/a121f0879efbb4ccb2c942605b3432531ce16cb9/xmllistInstaller.ps1')
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
not straight forward. missing the installation steps