diff --git a/lxs.ps1 b/lxs.ps1 index 254df0b..3699f52 100644 --- a/lxs.ps1 +++ b/lxs.ps1 @@ -1,6 +1,12 @@ <# LXS - platform dispatcher (Windows side) + NOTE: this file must stay BOM-less and pure ASCII. It is the one script + fetched with `irm ... | iex`, and Invoke-Expression fails on a leading + U+FEFF. Being ASCII keeps it parseable when Windows PowerShell 5.1 falls + back to the ANSI codepage for a BOM-less file. Everything under windows\ + carries a UTF-8 BOM instead, because 5.1 reads those from disk. + Thin shim kept at the repo root so the documented one-liner stays short and stable while the real implementation lives in windows\lxs.ps1: @@ -40,7 +46,7 @@ if ($LxsSelfDir) { } } -# No files on disk — we were piped from irm. Fetch the platform entrypoint. +# No files on disk - we were piped from irm. Fetch the platform entrypoint. $temp = Join-Path $env:TEMP ("lxs.entrypoint.{0}.ps1" -f [guid]::NewGuid().ToString('N').Substring(0, 8)) try { Invoke-WebRequest -Uri "$LxsRawBase/$LxsPlatformDir/lxs.ps1" -OutFile $temp ` diff --git a/windows/apps/browsers-media.ps1 b/windows/apps/browsers-media.ps1 index 2118ea0..9b27eaa 100644 --- a/windows/apps/browsers-media.ps1 +++ b/windows/apps/browsers-media.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Browsers and media (Windows) Description: Browsers and media players installed through winget. Repo: https://git.hyko.cx/hykocx/lxs @@ -19,7 +19,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_browsers.log' diff --git a/windows/apps/claude-code.ps1 b/windows/apps/claude-code.ps1 index b63b1bc..3d1eb12 100644 --- a/windows/apps/claude-code.ps1 +++ b/windows/apps/claude-code.ps1 @@ -1,10 +1,10 @@ -<# +<# LXS - Claude Code (Windows) Description: Install and check the Claude Code CLI. Two supported install methods, both official: - - winget (Anthropic.ClaudeCode) — does not auto-update - - the native installer from claude.ai — updates itself in the background + - winget (Anthropic.ClaudeCode) - does not auto-update + - the native installer from claude.ai - updates itself in the background Repo: https://git.hyko.cx/hykocx/lxs #> @@ -24,7 +24,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_claude_code.log' @@ -67,7 +70,7 @@ function Install-LxsClaudeWinget { Write-Host '' Write-Host 'Installs the Anthropic.ClaudeCode package.' Write-Host '' - Write-Host "$($script:Gray)winget installs do not update themselves — run option 5, or$($script:NC)" + Write-Host "$($script:Gray)winget installs do not update themselves - run option 5, or$($script:NC)" Write-Host "$($script:Gray)$('winget upgrade Anthropic.ClaudeCode'), to get new versions.$($script:NC)" Write-Host '' if (-not (Confirm-LxsAction -Question 'Install Claude Code with winget?' -DefaultYes)) { diff --git a/windows/apps/containers.ps1 b/windows/apps/containers.ps1 index b61b770..8ccfa22 100644 --- a/windows/apps/containers.ps1 +++ b/windows/apps/containers.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Containers and virtualization (Windows) Description: WSL 2, Hyper-V, Docker Desktop and VirtualBox. Repo: https://git.hyko.cx/hykocx/lxs @@ -19,7 +19,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_containers.log' @@ -86,7 +89,7 @@ function Install-LxsWsl { Write-Host '' & wsl.exe --install if ($LASTEXITCODE -eq 0) { - Write-LxsOk 'WSL install started — reboot to finish' + Write-LxsOk 'WSL install started - reboot to finish' } else { Write-LxsWarn "wsl --install exited with code $LASTEXITCODE" } @@ -110,7 +113,7 @@ function Enable-LxsHyperV { Write-Host '' try { Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All -All -NoRestart -ErrorAction Stop | Out-Null - Write-LxsOk 'Hyper-V enabled — reboot to finish' + Write-LxsOk 'Hyper-V enabled - reboot to finish' } catch { Write-LxsErr "Could not enable Hyper-V: $($_.Exception.Message)" } diff --git a/windows/apps/dev-pack.ps1 b/windows/apps/dev-pack.ps1 index f806b59..558cbca 100644 --- a/windows/apps/dev-pack.ps1 +++ b/windows/apps/dev-pack.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Dev Pack (Windows) Description: The usual development toolchain, installed through winget. Repo: https://git.hyko.cx/hykocx/lxs @@ -19,7 +19,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_dev_pack.log' diff --git a/windows/apps/index.ps1 b/windows/apps/index.ps1 index 5596227..5614900 100644 --- a/windows/apps/index.ps1 +++ b/windows/apps/index.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Apps index (Windows) Description: Interactive menu listing the installers in windows\apps Repo: https://git.hyko.cx/hykocx/lxs @@ -19,7 +19,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } function Show-LxsAppsMenu { diff --git a/windows/apps/utilities.ps1 b/windows/apps/utilities.ps1 index f52820a..eefd746 100644 --- a/windows/apps/utilities.ps1 +++ b/windows/apps/utilities.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Utilities (Windows) Description: Everyday utilities installed through winget. Repo: https://git.hyko.cx/hykocx/lxs @@ -19,7 +19,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_utilities.log' diff --git a/windows/lib/common.ps1 b/windows/lib/common.ps1 index 9907155..c1d4f00 100644 --- a/windows/lib/common.ps1 +++ b/windows/lib/common.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Common library (Windows) Sourced by windows\lxs.ps1 and every sub-script. Mirrors linux/lib/common.sh: @@ -11,7 +11,7 @@ #> # ═══════════════════════════════════════════════════════════════════════════ -# Console setup — UTF-8 output (box drawing chars) and VT sequences (colors). +# Console setup - UTF-8 output (box drawing chars) and VT sequences (colors). # Both are best-effort: a console that refuses either falls back to plain text. # ═══════════════════════════════════════════════════════════════════════════ @@ -26,7 +26,7 @@ function Initialize-LxsConsole { [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false $script:LxsUnicodeEnabled = $true } catch { - # Redirected output or a locked-down host — fall back to ASCII rules. + # Redirected output or a locked-down host - fall back to ASCII rules. $script:LxsUnicodeEnabled = $false } @@ -77,14 +77,14 @@ public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); Initialize-LxsConsole # ═══════════════════════════════════════════════════════════════════════════ -# UI helpers — title + horizontal rule, no closed box. Mirrors common.sh. +# UI helpers - title + horizontal rule, no closed box. Mirrors common.sh. # -# Show-LxsBoxTop "TITLE" "RIGHT" → TITLE [ RIGHT ] -# ────────────────────────────────── -# Show-LxsBoxMid "SECTION" → ─ SECTION ──────────────────────── -# Show-LxsBoxBottom → ────────────────────────────────── -# Show-LxsMenuItem "01" "LABEL" "desc" → [01] LABEL // desc -# Show-LxsPrompt → > +# Show-LxsBoxTop "TITLE" "RIGHT" -> TITLE [ RIGHT ] +# ---------------------------------- +# Show-LxsBoxMid "SECTION" -> - SECTION ------------------------ +# Show-LxsBoxBottom -> ---------------------------------- +# Show-LxsMenuItem "01" "LABEL" "desc" -> [01] LABEL // desc +# Show-LxsPrompt -> > # ═══════════════════════════════════════════════════════════════════════════ function Get-LxsTermWidth { @@ -193,7 +193,7 @@ function Write-LxsErr { param([string]$Message) Write-Host "$($script:Red)[KO]$ # Sub-scripts read $args by hand, exactly like the bash `for arg in "$@"` loop. # A param([switch]) block cannot be used: LXS invokes sub-scripts with a # splatted string[] (& $script @Arguments), and PowerShell binds every element -# of a splatted array positionally — '-Yes' would land in $args as a value and +# of a splatted array positionally - '-Yes' would land in $args as a value and # the switch would silently stay $false. # # $opts = Read-LxsFlags -Arguments $args -Known @('-Yes', '-y', '-Help') @@ -255,9 +255,9 @@ function Confirm-LxsAction { # ═══════════════════════════════════════════════════════════════════════════ # Progress helpers # -# Invoke-LxsSpinner — external command, output captured to a log file, +# Invoke-LxsSpinner - external command, output captured to a log file, # animated spinner (mirrors run_spinner in common.sh). -# Invoke-LxsStep — inline PowerShell work; prints [..] then [OK]/[KO]. +# Invoke-LxsStep - inline PowerShell work; prints [..] then [OK]/[KO]. # # Both return $true on success. Log file: $env:LXS_LOG_FILE or %TEMP%\lxs.log # ═══════════════════════════════════════════════════════════════════════════ @@ -419,7 +419,7 @@ function Assert-LxsWindows { Write-LxsWarn "Windows build $build is older than the supported floor ($MinimumBuild). Some tools may fail." } } catch { - # Not fatal — CIM can be unavailable in stripped-down images. + # Not fatal - CIM can be unavailable in stripped-down images. } return $true } @@ -435,7 +435,8 @@ function Test-LxsDiskSpace { $seen = @{} foreach ($path in $Paths) { if ([string]::IsNullOrWhiteSpace($path)) { continue } - $root = try { [System.IO.Path]::GetPathRoot((Resolve-Path $path -ErrorAction Stop).Path) } catch { $null } + $root = $null + try { $root = [System.IO.Path]::GetPathRoot((Resolve-Path $path -ErrorAction Stop).Path) } catch { $root = $null } if (-not $root) { $root = [System.IO.Path]::GetPathRoot($path) } if (-not $root) { Write-LxsErr "Cannot read disk usage for $path" @@ -478,7 +479,7 @@ function Assert-LxsWinget { } # `winget list` is slow (a second or more per call), and a package menu asks -# about a dozen ids at once — so the full listing is fetched once and reused. +# about a dozen ids at once - so the full listing is fetched once and reused. $script:LxsWingetListCache = $null function Get-LxsWingetListText { @@ -535,7 +536,7 @@ function Install-LxsWingetPackage { Clear-LxsWingetListCache if (-not $installed) { - Write-Host "$($script:Gray) Package id: $Id — check it with: winget search --id $Id$($script:NC)" + Write-Host "$($script:Gray) Package id: $Id - check it with: winget search --id $Id$($script:NC)" } return $installed } @@ -717,7 +718,7 @@ function Add-LxsUserPath { $current = [Environment]::GetEnvironmentVariable('Path', 'User') if ($null -eq $current) { $current = '' } # Windows paths are case-insensitive and a trailing backslash is - # meaningless, so compare normalized — otherwise every run appends a + # meaningless, so compare normalized - otherwise every run appends a # near-duplicate entry. $normalized = $Directory.TrimEnd('\') foreach ($entry in ($current -split ';')) { diff --git a/windows/lxs.ps1 b/windows/lxs.ps1 index 363327d..b67b3e0 100644 --- a/windows/lxs.ps1 +++ b/windows/lxs.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Windows multi-tool Description: Centralized workstation management and deployment toolkit Repo: https://git.hyko.cx/hykocx/lxs @@ -73,7 +73,10 @@ if ($libPath -and (Test-Path $libPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($libSource)) + # Strip the UTF-8 BOM: it is required in the file (Windows PowerShell 5.1 + # reads a BOM-less .ps1 with the ANSI codepage) but arrives as a leading + # U+FEFF character when fetched over HTTP, which the parser rejects. + . ([scriptblock]::Create(($libSource -replace '^\uFEFF', ''))) } # ═══════════════════════════════════════════════════════════════════════════ @@ -113,7 +116,7 @@ function Test-LxsRemoteVersion { } if ($age -ge $LxsVersionTtl) { - # Refresh inline but on a short leash — a slow repo must not stall the menu. + # Refresh inline but on a short leash - a slow repo must not stall the menu. try { $remote = Invoke-RestMethod -Uri "$LxsRawBase/VERSION" -TimeoutSec 3 ` -Headers @{ 'Cache-Control' = 'no-cache' } -UseBasicParsing -ErrorAction Stop @@ -162,7 +165,7 @@ function Show-LxsHeader { $totalMem = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1) $usedMem = [math]::Round(($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / 1MB, 1) } catch { - # CIM unavailable — the header degrades but the menu still works. + # CIM unavailable - the header degrades but the menu still works. } $cores = $env:NUMBER_OF_PROCESSORS @@ -318,7 +321,7 @@ function Invoke-LxsCmdTool { } # ═══════════════════════════════════════════════════════════════════════════ -# setup / update — download the repo zip and mirror it into $LxsInstallDir. +# setup / update - download the repo zip and mirror it into $LxsInstallDir. # Everything lands under %LOCALAPPDATA%, so no elevation is needed here; # individual tools elevate themselves when they touch the machine. # ═══════════════════════════════════════════════════════════════════════════ diff --git a/windows/tools/cleanup.ps1 b/windows/tools/cleanup.ps1 index 85c8f34..6ec086e 100644 --- a/windows/tools/cleanup.ps1 +++ b/windows/tools/cleanup.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Disk Cleanup (Windows) Description: Reclaim disk space (temp files, Windows Update cache, recycle bin, Prefetch, error reports, WinSxS component store). @@ -23,7 +23,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_cleanup.log' @@ -80,14 +83,14 @@ function Get-LxsFolderSize { } # Delete the *contents* of a folder, never the folder itself. Files locked by a -# running process are skipped silently — that is expected on a live system. +# running process are skipped silently - that is expected on a live system. function Clear-LxsFolderContents { param( [Parameter(Mandatory = $true)][string]$Path, [Parameter(Mandatory = $true)][string]$Label ) if (-not (Test-Path $Path)) { - Write-Host "$($script:Gray) $Label — not present, skipped$($script:NC)" + Write-Host "$($script:Gray) $Label - not present, skipped$($script:NC)" return 0 } $before = Get-LxsFolderSize -Path $Path @@ -102,7 +105,7 @@ function Clear-LxsFolderContents { $after = Get-LxsFolderSize -Path $Path $freed = [math]::Max(0, $before - $after) $suffix = if ($skipped -gt 0) { " ($skipped item(s) in use, skipped)" } else { '' } - Write-LxsOk "$Label — $(Format-LxsSize $freed) reclaimed$suffix" + Write-LxsOk "$Label - $(Format-LxsSize $freed) reclaimed$suffix" return $freed } @@ -170,7 +173,7 @@ if (-not $NoRecycleBin) { Write-LxsOk 'Recycle bin emptied' } catch { # Clear-RecycleBin throws when the bin is already empty. - Write-Host "$($script:Gray) Recycle bin — already empty or not accessible$($script:NC)" + Write-Host "$($script:Gray) Recycle bin - already empty or not accessible$($script:NC)" } } @@ -187,14 +190,14 @@ if ($doUpdateCache) { $stopped += $svc } } catch { - Write-LxsWarn "Could not stop $svc — the update cache may be partially locked." + Write-LxsWarn "Could not stop $svc - the update cache may be partially locked." } } try { Clear-LxsFolderContents -Path (Join-Path $env:SystemRoot 'SoftwareDistribution\Download') -Label 'Windows Update cache' | Out-Null } finally { foreach ($svc in $stopped) { - try { Start-Service -Name $svc -ErrorAction Stop } catch { Write-LxsWarn "Failed to restart $svc — start it manually." } + try { Start-Service -Name $svc -ErrorAction Stop } catch { Write-LxsWarn "Failed to restart $svc - start it manually." } } } } diff --git a/windows/tools/debloat.ps1 b/windows/tools/debloat.ps1 index b0b4649..4a6eb00 100644 --- a/windows/tools/debloat.ps1 +++ b/windows/tools/debloat.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Debloat and privacy (Windows) Description: Remove preinstalled apps you pick, and turn off telemetry, Cortana, ads, tracking tasks, Copilot and Recall. @@ -27,7 +27,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_debloat.log' @@ -57,9 +60,9 @@ function Assert-LxsCheckpoint { # ═══════════════════════════════════════════════════════════════════════════ # Preinstalled apps # -# Only packages on this list are ever offered. Anything not listed here — +# Only packages on this list are ever offered. Anything not listed here - # including the Store, App Installer (winget), Terminal, Defender UI, the -# VCLibs/.NET runtime frameworks and every driver package — is left alone, +# VCLibs/.NET runtime frameworks and every driver package - is left alone, # because removing those breaks Windows or LXS itself. # ═══════════════════════════════════════════════════════════════════════════ @@ -152,13 +155,13 @@ function Remove-LxsSelectedApps { Write-Host '' Write-Host "$($script:Gray)Enter the numbers to remove, separated by commas (e.g. 1,4,7),$($script:NC)" - Write-Host "$($script:Gray)or 'all' for every entry above. Empty cancels — nothing is removed$($script:NC)" + Write-Host "$($script:Gray)or 'all' for every entry above. Empty cancels - nothing is removed$($script:NC)" Write-Host "$($script:Gray)unless you name it here.$($script:NC)" Write-Host '' $selection = Read-Host -Prompt 'Selection' if ([string]::IsNullOrWhiteSpace($selection)) { - Write-LxsInfo 'Cancelled — nothing removed.' + Write-LxsInfo 'Cancelled - nothing removed.' return } @@ -347,7 +350,7 @@ function Invoke-LxsTweakGroup { Disable-ScheduledTask -TaskName $leaf -TaskPath $parent -ErrorAction Stop | Out-Null $disabled++ } catch { - # Absent on this edition/build — nothing to disable. + # Absent on this edition/build - nothing to disable. } } Write-LxsOk "$disabled tracking scheduled task(s) disabled" @@ -360,7 +363,7 @@ function Restore-LxsTweaks { Write-Host 'This restores every registry value, service and scheduled task that' Write-Host 'this script changes, back to the Windows default.' Write-Host '' - Write-Host "$($script:Gray)Apps you removed are NOT restored — reinstall them from the Store.$($script:NC)" + Write-Host "$($script:Gray)Apps you removed are NOT restored - reinstall them from the Store.$($script:NC)" Write-Host '' if (-not (Confirm-LxsAction -Question 'Revert the privacy tweaks?')) { Write-LxsInfo 'Cancelled.' @@ -374,13 +377,13 @@ function Restore-LxsTweaks { if (Test-Path $e.Path) { Remove-ItemProperty -Path $e.Path -Name $e.Name -ErrorAction Stop } - Write-LxsOk "$($e.Label) — policy removed" + Write-LxsOk "$($e.Label) - policy removed" } catch { # Already absent: that is the default state we wanted. } } else { if (Set-LxsRegistryValue -Path $e.Path -Name $e.Name -Value $e.Default) { - Write-LxsOk "$($e.Label) — restored to default" + Write-LxsOk "$($e.Label) - restored to default" } } } diff --git a/windows/tools/harden.ps1 b/windows/tools/harden.ps1 index c23d1e2..380efb8 100644 --- a/windows/tools/harden.ps1 +++ b/windows/tools/harden.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Harden Windows Description: Apply a baseline security posture (firewall, SMBv1, UAC, Defender, LLMNR/NetBIOS) and audit local accounts. @@ -24,7 +24,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_harden.log' @@ -266,7 +269,7 @@ if ($DoNameResolution) { } # ═══════════════════════════════════════════════════════════════════════════ -# Account audit — reports only, changes nothing. +# Account audit - reports only, changes nothing. # ═══════════════════════════════════════════════════════════════════════════ Write-Host '' @@ -279,7 +282,7 @@ try { foreach ($a in $admins) { Write-Host " - $($a.Name) $($script:Gray)($($a.ObjectClass), $($a.PrincipalSource))$($script:NC)" } if ($admins.Count -gt 2) { Write-Host '' - Write-LxsWarn "$($admins.Count) accounts have administrator rights — review whether they all need it." + Write-LxsWarn "$($admins.Count) accounts have administrator rights - review whether they all need it." } } catch { Write-LxsWarn "Could not enumerate the Administrators group: $($_.Exception.Message)" @@ -301,7 +304,7 @@ try { Write-Host "$($script:Gray) Password never expires: $($enabledNoExpiry.Name -join ', ')$($script:NC)" } if ($guest -and $guest.Enabled) { - Write-LxsWarn 'The Guest account is ENABLED — disable it unless you rely on it.' + Write-LxsWarn 'The Guest account is ENABLED - disable it unless you rely on it.' } else { Write-LxsOk 'Guest account is disabled' } @@ -318,7 +321,7 @@ Show-LxsSeparator Write-Host '' Write-LxsOk "$changes hardening change(s) applied" if ($problems -gt 0) { - Write-LxsWarn "$problems change(s) failed — see the messages above." + Write-LxsWarn "$problems change(s) failed - see the messages above." } if ($DoSmb) { Write-LxsWarn 'Reboot to finish removing the SMBv1 client feature.' diff --git a/windows/tools/index.ps1 b/windows/tools/index.ps1 index bc73b41..d6c6fc1 100644 --- a/windows/tools/index.ps1 +++ b/windows/tools/index.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Tools index (Windows) Description: Interactive menu listing the scripts in windows\tools Repo: https://git.hyko.cx/hykocx/lxs @@ -19,7 +19,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } function Show-LxsToolsMenu { @@ -66,7 +69,7 @@ function Show-LxsToolsMenu { $code = Invoke-LxsSibling -RelativePath $script -SelfDirectory $PSScriptRoot # Exit code 75 from a child means it already paused on its own - # (its own "Back" or end-of-run prompt) — skip the redundant prompt. + # (its own "Back" or end-of-run prompt) - skip the redundant prompt. if ($code -ne 75) { Read-LxsEnter } } } diff --git a/windows/tools/net-diag.ps1 b/windows/tools/net-diag.ps1 index e671178..de1760f 100644 --- a/windows/tools/net-diag.ps1 +++ b/windows/tools/net-diag.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Network Diagnostics (Windows) Description: Inspect and repair the network stack. Everything is read-only except option 8 (stack reset). @@ -20,7 +20,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_net_diag.log' @@ -51,7 +54,8 @@ function Show-LxsListeningPorts { Write-Host '' try { $rows = Get-NetTCPConnection -State Listen -ErrorAction Stop | ForEach-Object { - $procName = try { (Get-Process -Id $_.OwningProcess -ErrorAction Stop).ProcessName } catch { 'unknown' } + $procName = 'unknown' + try { $procName = (Get-Process -Id $_.OwningProcess -ErrorAction Stop).ProcessName } catch { $procName = 'unknown' } [pscustomobject]@{ Local = "$($_.LocalAddress):$($_.LocalPort)" Port = $_.LocalPort diff --git a/windows/tools/remote-access.ps1 b/windows/tools/remote-access.ps1 index 2b86901..4cb3e23 100644 --- a/windows/tools/remote-access.ps1 +++ b/windows/tools/remote-access.ps1 @@ -1,6 +1,6 @@ -<# +<# LXS - Remote Access (Windows) - Description: Remote Desktop and the OpenSSH server — status, enable, + Description: Remote Desktop and the OpenSSH server - status, enable, disable. The Windows counterpart of root-ssh-login.sh. Repo: https://git.hyko.cx/hykocx/lxs #> @@ -20,7 +20,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_remote_access.log' @@ -60,7 +63,7 @@ function Show-LxsRemoteStatus { if (Get-LxsNlaState) { Write-LxsOk 'Network Level Authentication is on' } else { - Write-LxsWarn 'Network Level Authentication is OFF — turn it on (option 2).' + Write-LxsWarn 'Network Level Authentication is OFF - turn it on (option 2).' } try { $port = (Get-ItemProperty -Path $LxsRdpTcpKey -Name 'PortNumber' -ErrorAction Stop).PortNumber @@ -123,7 +126,7 @@ function Enable-LxsRdp { Write-LxsWarn "Could not enable the firewall rules: $($_.Exception.Message)" } Write-Host '' - Write-LxsWarn 'Only expose RDP to the internet behind a VPN — it is a constant brute-force target.' + Write-LxsWarn 'Only expose RDP to the internet behind a VPN - it is a constant brute-force target.' } function Disable-LxsRdp { @@ -255,7 +258,7 @@ function Set-LxsSshDefaultShell { default { $null } } if (-not $shell) { - if ($choice -eq '2') { Write-LxsErr 'pwsh.exe was not found — install PowerShell 7 first.' } + if ($choice -eq '2') { Write-LxsErr 'pwsh.exe was not found - install PowerShell 7 first.' } else { Write-LxsInfo 'Cancelled.' } return } diff --git a/windows/tools/repair.ps1 b/windows/tools/repair.ps1 index 144b4c7..0304f35 100644 --- a/windows/tools/repair.ps1 +++ b/windows/tools/repair.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - System Repair (Windows) Description: Integrity repair for the component store and system files (SFC, DISM, chkdsk). Requires administrator rights. @@ -20,7 +20,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_repair.log' diff --git a/windows/tools/restore-point.ps1 b/windows/tools/restore-point.ps1 index b38f045..52082b7 100644 --- a/windows/tools/restore-point.ps1 +++ b/windows/tools/restore-point.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - System Restore Point (Windows) Description: Enable System Protection, create checkpoints, list them and roll back. The safety net for harden.ps1 and debloat.ps1. @@ -20,7 +20,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_restore_point.log' @@ -70,7 +73,7 @@ function Show-LxsProtectionStatus { Write-Host " Shadow storage: $usedGB GB used of $maxGB GB allocated" } } else { - Write-LxsWarn "System Protection looks OFF for $drive — no restore points can be created." + Write-LxsWarn "System Protection looks OFF for $drive - no restore points can be created." } } catch { Write-LxsWarn 'Could not read the shadow storage configuration.' diff --git a/windows/tools/system-info.ps1 b/windows/tools/system-info.ps1 index 211b9b0..4aca982 100644 --- a/windows/tools/system-info.ps1 +++ b/windows/tools/system-info.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - System Infos (Windows) Description: Essential system monitoring and diagnostic views. Read-only: nothing here changes the machine. @@ -20,7 +20,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_system_infos.log' @@ -63,7 +66,7 @@ function Show-LxsSystemInformation { ForEach-Object { "$($_.Name) (driver $($_.DriverVersion))" }) if ($gpu.Count -gt 0) { Write-LxsField 'GPU' $gpu } } catch { - # Headless or restricted WMI — not worth failing the whole view. + # Headless or restricted WMI - not worth failing the whole view. } # Activation status. LicenseStatus 1 = licensed. @@ -81,7 +84,7 @@ function Show-LxsSystemInformation { 6 { 'Extended grace' } default { 'Unknown' } } - Write-LxsField 'Activation' "$state — $($lic[0].Name)" + Write-LxsField 'Activation' "$state - $($lic[0].Name)" } } catch { # SoftwareLicensingProduct is unavailable on some SKUs. @@ -172,7 +175,7 @@ function Show-LxsEventLogs { Show-LxsBoxTop -Title 'SYSTEM LOGS' -Right 'LAST 50' Write-Host '' foreach ($logName in @('System', 'Application')) { - Write-Host "$($script:Cyan)$($script:Bold)$logName — errors and warnings$($script:NC)" + Write-Host "$($script:Cyan)$($script:Bold)$logName - errors and warnings$($script:NC)" try { $events = Get-WinEvent -FilterHashtable @{ LogName = $logName; Level = 1, 2, 3 } -MaxEvents 25 -ErrorAction Stop $events | Format-Table -AutoSize -Wrap ` diff --git a/windows/tools/update-windows.ps1 b/windows/tools/update-windows.ps1 index 52363db..ca06429 100644 --- a/windows/tools/update-windows.ps1 +++ b/windows/tools/update-windows.ps1 @@ -1,4 +1,4 @@ -<# +<# LXS - Update Windows Description: Install pending Windows updates and upgrade every winget package. Mirror of linux/tools/update-server.sh. @@ -22,7 +22,10 @@ if ($LxsLibPath -and (Test-Path $LxsLibPath)) { Write-Error 'Failed to fetch lib/common.ps1' exit 1 } - . ([scriptblock]::Create($LxsLibSource)) + # The library ships with a UTF-8 BOM (Windows PowerShell 5.1 needs it to + # read the file as UTF-8); over HTTP that BOM arrives as a leading U+FEFF + # character, which the parser will not accept. + . ([scriptblock]::Create(($LxsLibSource -replace '^\uFEFF', ''))) } $env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_update_windows.log'