From a55d66cc4a6cde11ec95fa1de14d936207f45467 Mon Sep 17 00:00:00 2001 From: Magnetar Man <40738529+Magnetarman@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:42:56 +0200 Subject: [PATCH 1/4] Update Microsoft.PowerShell_profile.ps1 --- assets/Microsoft.PowerShell_profile.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/assets/Microsoft.PowerShell_profile.ps1 b/assets/Microsoft.PowerShell_profile.ps1 index 83d5fd46..d2b28996 100644 --- a/assets/Microsoft.PowerShell_profile.ps1 +++ b/assets/Microsoft.PowerShell_profile.ps1 @@ -37,7 +37,7 @@ # ============================================================================ -$ProfileVersion = "2.6.0.7" +$ProfileVersion = "2.6.0.8" $URL_WINTOOLKIT_STABLE = "https://raw.githubusercontent.com/Magnetarman/WinToolkit/refs/heads/main/WinToolkit.ps1" @@ -609,7 +609,10 @@ function Get-SpeedtestExecutable { if (-not $installed) { if (-not (Require-Admin -FeatureName 'Speedtest')) { return $null } Write-Host "⬇️ $packageId is not installed. Installing via WinGet..." -ForegroundColor Yellow - winget install --id $packageId --source winget --accept-source-agreements --accept-package-agreements --silent --scope machine + # Out-Host keeps the WinGet output visible on screen but prevents it from entering the + # success output stream: otherwise the function would return an array (WinGet log lines + # + path) and '& $speedtestExe' would fail on the first run right after installation. + winget install --id $packageId --source winget --accept-source-agreements --accept-package-agreements --silent --scope machine | Out-Host if ($LASTEXITCODE -ne 0) { Write-Failure "$packageId installation failed (code $LASTEXITCODE)." return $null From 3e31e9cb6682acd070acdd2e3f357cdcc3578ecc Mon Sep 17 00:00:00 2001 From: Magnetar Man <40738529+Magnetarman@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:46:05 +0200 Subject: [PATCH 2/4] Update Microsoft.PowerShell_profile.ps1 --- assets/Microsoft.PowerShell_profile.ps1 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/assets/Microsoft.PowerShell_profile.ps1 b/assets/Microsoft.PowerShell_profile.ps1 index d2b28996..5b8a4cdc 100644 --- a/assets/Microsoft.PowerShell_profile.ps1 +++ b/assets/Microsoft.PowerShell_profile.ps1 @@ -609,12 +609,14 @@ function Get-SpeedtestExecutable { if (-not $installed) { if (-not (Require-Admin -FeatureName 'Speedtest')) { return $null } Write-Host "⬇️ $packageId is not installed. Installing via WinGet..." -ForegroundColor Yellow - # Out-Host keeps the WinGet output visible on screen but prevents it from entering the - # success output stream: otherwise the function would return an array (WinGet log lines - # + path) and '& $speedtestExe' would fail on the first run right after installation. - winget install --id $packageId --source winget --accept-source-agreements --accept-package-agreements --silent --scope machine | Out-Host - if ($LASTEXITCODE -ne 0) { - Write-Failure "$packageId installation failed (code $LASTEXITCODE)." + + # Invoke-WingetPackageAction echoes the WinGet output via Write-Host and returns a + # structured result. A raw 'winget install' would leak its log lines into this + # function's return value and turn $speedtestExe into an array on the first run. + $installArgs = @('install', '--id', $packageId, '-e', '--source', 'winget', '--silent', '--scope', 'machine', '--accept-package-agreements', '--accept-source-agreements') + $result = Invoke-WingetPackageAction -Arguments $installArgs + if ($result.ExitCode -ne 0) { + Write-Failure "$packageId installation failed (code $($result.ExitCode))." return $null } # Refresh PATH so the freshly installed executable is found in the current session From 0d1ee47a858325573ecf19947d374ea150032bc5 Mon Sep 17 00:00:00 2001 From: Magnetar Man <40738529+Magnetarman@users.noreply.github.com> Date: Sat, 17 Oct 2026 13:49:33 +0200 Subject: [PATCH 3/4] Update Microsoft.PowerShell_profile.ps1 --- assets/Microsoft.PowerShell_profile.ps1 | 54 +++++++++++++++++++------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/assets/Microsoft.PowerShell_profile.ps1 b/assets/Microsoft.PowerShell_profile.ps1 index 5b8a4cdc..ca06954b 100644 --- a/assets/Microsoft.PowerShell_profile.ps1 +++ b/assets/Microsoft.PowerShell_profile.ps1 @@ -37,7 +37,7 @@ # ============================================================================ -$ProfileVersion = "2.6.0.8" +$ProfileVersion = "2.6.0.10" $URL_WINTOOLKIT_STABLE = "https://raw.githubusercontent.com/Magnetarman/WinToolkit/refs/heads/main/WinToolkit.ps1" @@ -672,10 +672,33 @@ function Speedtest { Write-Host "🚀 Starting Speedtest..." -ForegroundColor Yellow Write-Host "📝 Results saved to '$outputPath'." -ForegroundColor Yellow - # Human-readable raw output on screen + save to file (single run, no extra latency) - & $speedtestExe --accept-license --accept-gdpr -p *>&1 | Tee-Object -FilePath $outputPath + # Raw output goes to the file; the console gets a filtered view so the first-run + # EULA/GDPR banners and the transient '[error] Cannot open socket' retries stay + # out of the result flow (they remain available in the saved log). + & $speedtestExe --accept-license --accept-gdpr -p *>&1 | Out-File -FilePath $outputPath $text = Get-Content -Path $outputPath -Raw + if ([string]::IsNullOrWhiteSpace($text)) { + Write-Warn "Speedtest produced no output. Check the log: $outputPath" + return + } + + # Show only the results block: the very first run prints license banners before it + $displayText = $text + $resultsStart = $text.IndexOf('Speedtest by Ookla') + if ($resultsStart -gt 0) { $displayText = $text.Substring($resultsStart) } + + # Transient connection errors (server probing retries) stay in the file only + $errorMatches = [regex]::Matches($displayText, '(?m)^\[error\].*$') + if ($errorMatches.Count -gt 0) { + $displayText = [regex]::Replace($displayText, '(?m)^\[error\].*\r?\n?', '') + } + + Write-Host '' + Write-Host $displayText.TrimEnd() + if ($errorMatches.Count -gt 0) { + Write-Warn "$($errorMatches.Count) transient connection error(s) were retried automatically. Full log: $outputPath" + } # Helper: extract first capture group or 'n/a' (guarantees a non-empty value) function Get-Value([string]$Pattern, [string]$InputStr) { @@ -935,18 +958,13 @@ function Invoke-WingetPackageAction { [string[]]$Arguments ) + # WinGet writes UTF-8 while the console may still use an OEM codepage (e.g. CP850): + # without this temporary swap, accented output arrives mangled ("non ├¿ responsabile"). + $previousEncoding = [Console]::OutputEncoding try { + [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false) $output = @(& winget @Arguments 2>&1) $exitCode = $LASTEXITCODE - - foreach ($line in $output) { - Write-Host $line - } - - return [PSCustomObject]@{ - ExitCode = $exitCode - Output = ($output -join [Environment]::NewLine) - } } catch { return [PSCustomObject]@{ @@ -954,6 +972,18 @@ function Invoke-WingetPackageAction { Output = $_.Exception.Message } } + finally { + [Console]::OutputEncoding = $previousEncoding + } + + foreach ($line in $output) { + Write-Host $line + } + + return [PSCustomObject]@{ + ExitCode = $exitCode + Output = ($output -join [Environment]::NewLine) + } } From 66eff7ed3c644794c7e25d4a534b1ec802ab5884 Mon Sep 17 00:00:00 2001 From: Magnetar Man <40738529+Magnetarman@users.noreply.github.com> Date: Sat, 17 Oct 2026 13:53:28 +0200 Subject: [PATCH 4/4] Update PowerShell profile version to 2.6.0.8 --- assets/Microsoft.PowerShell_profile.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/Microsoft.PowerShell_profile.ps1 b/assets/Microsoft.PowerShell_profile.ps1 index ca06954b..c061cfc5 100644 --- a/assets/Microsoft.PowerShell_profile.ps1 +++ b/assets/Microsoft.PowerShell_profile.ps1 @@ -37,7 +37,7 @@ # ============================================================================ -$ProfileVersion = "2.6.0.10" +$ProfileVersion = "2.6.0.8" $URL_WINTOOLKIT_STABLE = "https://raw.githubusercontent.com/Magnetarman/WinToolkit/refs/heads/main/WinToolkit.ps1"