Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 50 additions & 15 deletions assets/Microsoft.PowerShell_profile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -609,9 +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
winget install --id $packageId --source winget --accept-source-agreements --accept-package-agreements --silent --scope machine
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
Expand Down Expand Up @@ -667,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) {
Expand Down Expand Up @@ -930,25 +958,32 @@ 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]@{
ExitCode = $null
Output = $_.Exception.Message
}
}
finally {
[Console]::OutputEncoding = $previousEncoding
}

foreach ($line in $output) {
Write-Host $line
}

return [PSCustomObject]@{
ExitCode = $exitCode
Output = ($output -join [Environment]::NewLine)
}
}


Expand Down
Loading