Functions/GenXdev.Software/EnsurePSTools.ps1
|
<############################################################################## Part of PowerShell module : GenXdev.Software Original cmdlet filename : EnsurePSTools.ps1 Original author : René Vaessen / GenXdev Version : 3.28.2026 ################################################################################ Copyright (c) 2026 René Vaessen / GenXdev Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ################################################################################> ############################################################################### <# .SYNOPSIS Ensures Sysinternals tools (PSTools) are installed and available. .DESCRIPTION Verifies if Sysinternals tools like handle.exe are installed and properly configured on the system. If not found, installs the Sysinternals Suite using WinGet, pre-accepts all End-User License Agreements (EULAs) via registry keys, and handles the complete installation process automatically. .PARAMETER Force Switch to force reinstallation of Sysinternals tools even if they are already installed. .PARAMETER PSExeName The executable name to check for verifying Sysinternals tools installation. Default is 'handle.exe'. .EXAMPLE EnsurePSTools Ensures Sysinternals tools are installed and properly configured. .EXAMPLE EnsurePSTools -Force -PSExeName 'procexp.exe' Forces reinstallation of Sysinternals tools and uses procexp.exe to verify installation. ###############################################################################> function EnsurePSTools { [CmdletBinding()] param( ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Force reinstallation of Sysinternals tools' )] [switch]$Force, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Automatically consent to Sysinternals tools and ' + 'WinGet module installation and set persistent flag.') )] [switch] $AutoConsent, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Automatically consent to third-party software ' + 'installation and set persistent flag for all packages.') )] [switch] $AutoConsentAllPackages, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Only auto consent during session') )] [switch]$SessionOnly ######################################################################## ) begin { $Extra = ";($ENV:LOCALAPPDATA)\Microsoft\WinGet\Links\"; $ENV:PATH = "$($ENV:PATH)".Replace($Extra, "") + $Extra } process { # check if we should install/reinstall based on force flag or missing executable if ($Force -or (@(Microsoft.PowerShell.Core\Get-Command procexp.exe ` -ErrorAction SilentlyContinue).Length -eq 0)) { # request consent before installing sysinternals packages $sysinternalsConsent = GenXdev\Confirm-InstallationConsent ` -ApplicationName 'Microsoft Sysinternals Suite' ` -Source 'WinGet' ` -Description ('System administration and diagnostic tools. ' + 'By consenting, you accept all End-User License ' + 'Agreements (EULAs) for all Sysinternals tools in one go.') ` -Publisher 'Microsoft' ` -AutoConsent:$AutoConsent ` -AutoConsentAllPackages:$AutoConsentAllPackages if (-not $sysinternalsConsent) { throw 'Installation consent denied for Microsoft Sysinternals Suite. Cannot proceed without system tools.' } # inform user about installation process starting Microsoft.PowerShell.Utility\Write-Host 'Installing Sysinternals packages...' # install the package with force to ensure success $null = Microsoft.WinGet.Client\Install-WinGetPackage -Id 'Microsoft.Sysinternals.Suite' -Force -MatchOption EqualsCaseInsensitive # verify installation succeeded unless force was specified if (-not $Force -and (-not (Microsoft.PowerShell.Core\Get-Command "procexp" ` -ErrorAction SilentlyContinue))) { throw "Sysinternals installation failed." } # pre-accept all Sysinternals EULAs by creating registry keys # for each tool in the installation directory Microsoft.PowerShell.Utility\Write-Verbose ( 'Accepting Sysinternals EULAs via registry keys...') $procexpSource = (Microsoft.PowerShell.Core\Get-Command ` procexp.exe -ErrorAction SilentlyContinue).Source if ($procexpSource) { $installDir = Microsoft.PowerShell.Management\Split-Path ` -Parent (Microsoft.PowerShell.Management\Get-Item ` $procexpSource).Target # get unique tools by grouping 32/64-bit variants $tools = Microsoft.PowerShell.Management\Get-ChildItem ` $installDir -Filter *.exe | Microsoft.PowerShell.Core\Where-Object { $_.BaseName -notmatch '64$' -and $_.BaseName -notmatch '-x86$' } foreach ($tool in $tools) { $productName = $tool.VersionInfo.ProductName $keyName = if ($productName) { $productName -replace '^Sysinternals\s+', '' ` -replace '^SysInternals\s+', '' } else { $tool.BaseName } if (-not $keyName) { $keyName = $tool.BaseName } $regPath = "HKCU:\SOFTWARE\Sysinternals\${keyName}" if (-not (Microsoft.PowerShell.Management\Test-Path ` $regPath)) { $null = Microsoft.PowerShell.Management\New-Item ` -Path $regPath -Force $null = Microsoft.PowerShell.Management\New-ItemProperty ` -Path $regPath ` -Name 'EulaAccepted' ` -Value 1 ` -PropertyType DWord ` -Force Microsoft.PowerShell.Utility\Write-Verbose ( " Accepted EULA for: ${keyName}") } } } } # log successful completion of the function Microsoft.PowerShell.Utility\Write-Verbose '✅ Sysinternals tools are ready.' } end { } } |