|
| 1 | +--- |
| 2 | +title: "install.ps1 is published beside install.sh, and runs on Windows PowerShell 5.1 — what a fresh Windows machine has" |
| 3 | +issue: https://github.com/NobleFactor/devlore-cli/issues/948 |
| 4 | +status: active |
| 5 | +created: 2026-09-24 |
| 6 | +updated: 2026-09-24 |
| 7 | +--- |
| 8 | + |
| 9 | +# Plan: install.ps1 is published, and runs on 5.1 |
| 10 | + |
| 11 | +Lane 1 of [#949](https://github.com/NobleFactor/devlore-cli/issues/949). Design: |
| 12 | +[#798](https://github.com/NobleFactor/devlore-cli/issues/798), ruling 1 as it stands and ruling 3 as |
| 13 | +reversed below. |
| 14 | + |
| 15 | +## Issue 948 |
| 16 | + |
| 17 | +`install.ps1` has done what `install.sh` does since #914: fetch the archive for the host, verify it, unpack it |
| 18 | +so the products sit in `bin/` beside `share/`, run each product's `self install <prefix> --unattended`. Two |
| 19 | +things stand between it and #798's acceptance: |
| 20 | + |
| 21 | +- **Nobody can reach it.** `release.yaml`'s "Sync install script to website" step copies `install.sh` to the |
| 22 | + site's `public/` and `git add`s that one path. The header's own usage line, `irm |
| 23 | + https://devlore.noblefactor.com/install.ps1 | iex`, is a 404. |
| 24 | +- **It was never written for the shell it will run in.** A fresh Windows machine has Windows PowerShell 5.1 |
| 25 | + and nothing else. The body assumes 7: `$IsWindows` under `Set-StrictMode -Version Latest` throws on 5.1, |
| 26 | + and `Invoke-WebRequest` without `-UseBasicParsing` engages 5.1's Internet Explorer parser. |
| 27 | + |
| 28 | +**Ruling 3 reversed, 2026-09-24.** #798 had the body as `#Requires -Version 7` with a 5.1 preamble that |
| 29 | +installs pwsh and re-launches. Ruled instead: the installer uses what is known to be on the box, Windows |
| 30 | +PowerShell 5.1, and installs nothing but devlore. The shell-provider rewrite makes PowerShell 7 one shell |
| 31 | +among the ones a user may pick, not a prerequisite; the installer does not pre-empt that by installing it. |
| 32 | + |
| 33 | +## Goals |
| 34 | + |
| 35 | +1. `irm https://devlore.noblefactor.com/install.ps1 | iex` works, on the next release after the merge. |
| 36 | +2. The one script runs under Windows PowerShell 5.1 and PowerShell 7 alike, on Windows, macOS and Linux, |
| 37 | + one code path. |
| 38 | +3. Nothing is installed but lore, star and writ. |
| 39 | + |
| 40 | +## Requirements |
| 41 | + |
| 42 | +### Requirement 1: The sync publishes both scripts |
| 43 | + |
| 44 | +In `.github/workflows/release.yaml`, the sync step copies `install.sh` and `install.ps1`, adds both paths, |
| 45 | +and its commit and pull-request text say "install scripts". The release summary (lines 102–107) gains the |
| 46 | +Windows one-liner beside the Unix one. Nothing else in the workflow changes. |
| 47 | + |
| 48 | +### Requirement 2: The body runs on 5.1 |
| 49 | + |
| 50 | +The floor is declared and the 5.1 incompatibilities fixed; everything else in the body stays #914's. |
| 51 | + |
| 52 | +- `#Requires -Version 5.1` as the first line after the header. |
| 53 | +- `Get-OSName`: `$IsWindows`, `$IsMacOS`, `$IsLinux` do not exist on 5.1, and under |
| 54 | + `Set-StrictMode -Version Latest` a missing variable is an error. On 5.1 the edition is `Desktop` and the |
| 55 | + platform is Windows; on 7 the automatic variables exist. The function reads `$PSVersionTable.PSEdition` |
| 56 | + first and the automatic variables only on Core. |
| 57 | +- `Invoke-WebRequest` and `Invoke-RestMethod` carry `-UseBasicParsing`: on 5.1 the default engages the |
| 58 | + Internet Explorer DOM parser, which hangs on a machine that has never opened IE. On 7 the switch is |
| 59 | + accepted and ignored. |
| 60 | +- `[Net.ServicePointManager]::SecurityProtocol` includes `Tls12` before the first request: 5.1 on a |
| 61 | + machine whose .NET default predates it cannot reach GitHub otherwise; on 7 the assignment is harmless. |
| 62 | +- Everything else the body uses is in 5.1: `Expand-Archive`, `Get-FileHash`, `Get-ChildItem -File`, |
| 63 | + `-in`/`-notin`, `[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture` (.NET Framework |
| 64 | + 4.7.1+, which Windows 10 and 11 carry). The audit is Phase 3's first box. |
| 65 | + |
| 66 | +### Requirement 3: The header says so |
| 67 | + |
| 68 | +The header's Usage states the floor: "Runs on Windows PowerShell 5.1 and PowerShell 7." The |
| 69 | +`.\install.ps1 -Prefix` form notes that a Windows client's default execution policy refuses a downloaded |
| 70 | +script, and that the `irm | iex` form is the one that needs no policy change. The `# Parameters` block is |
| 71 | +unchanged (lane 2 adds the layer flags). |
| 72 | + |
| 73 | +## Implementation Phases |
| 74 | + |
| 75 | +### Phase 1: Commit the plan |
| 76 | + |
| 77 | +- [x] This plan, before the change |
| 78 | +- [x] The reversal recorded on #798 as a comment, dated, in the owner's words |
| 79 | + |
| 80 | +### Phase 2: The change |
| 81 | + |
| 82 | +- [x] `release.yaml`: both scripts synced, both paths added, texts and summary updated (Requirement 1) |
| 83 | +- [x] `install.ps1`: the floor and the four fixes (Requirement 2) |
| 84 | +- [x] `install.ps1`: the header (Requirement 3) |
| 85 | + |
| 86 | +### Phase 3: Verify |
| 87 | + |
| 88 | +- [x] Every cmdlet, operator and .NET member the body uses is checked against 5.1's surface, listed in |
| 89 | + the pull request, and nothing outside it remains: the automatic `$Is*` variables are now read only |
| 90 | + on Core; `PSEdition` exists on 5.1; `Expand-Archive` (5.0), `Get-FileHash` (4.0), `-in` (3.0), |
| 91 | + `RuntimeInformation` (.NET Framework 4.7.1) are all inside it |
| 92 | +- [x] Under pwsh 7.x on DANOBLE-UD24-1 (linux/arm64): the body ran against a scratch prefix, |
| 93 | + `DEVLORE_TOOLS=writ`, pre-release `v0.1.0-dev.20260924074819`, checksum verified, and |
| 94 | + `<prefix>/bin/writ --version` reported build `d54626d2`; nothing outside the prefix was written |
| 95 | +- [ ] Under Windows PowerShell 5.1 on a Windows machine (DANOBLE-WD11-3), both invocation forms, against a |
| 96 | + scratch prefix: the products install and answer `--version`. This is rule 11's live-path test and it |
| 97 | + cannot run here; it is the owner's, or a Windows job's, and this box stays open until it has |
| 98 | +- [x] `release.yaml` parses as YAML; the sync step's shell block, extracted with the `${{ }}` expressions |
| 99 | + replaced, passes `bash -n`; shellcheck's one real finding is the pre-existing SC2164 on `cd website`, |
| 100 | + not this change's |
| 101 | +- [x] No gate in this repository reads `.ps1`: `star lint` has go, go-style, markdown and shell, and |
| 102 | + `ci.yaml` runs no PSScriptAnalyzer. Checked by hand with PSScriptAnalyzer 1.25.0 (CI's pin, |
| 103 | + installed to this host's CurrentUser scope that day) and the organization's settings: 33 findings, |
| 104 | + every one present on the base too (`PSAvoidUsingWriteHost` and kin), none this change's. The gap |
| 105 | + is noted for the lint-tooling schedule (noblefactor-ops#232) |
| 106 | + |
| 107 | +### Phase 4: Merge, publish, converge |
| 108 | + |
| 109 | +- [x] PR script written, shown, and handed over |
| 110 | +- [ ] After the merge: the next pre-release's sync opens the site PR carrying both scripts; when it merges, |
| 111 | + `curl -sI https://devlore.noblefactor.com/install.ps1` answers 200 and the body matches the |
| 112 | + repository's. Until a release runs, this box stays open and the plan `active` |
| 113 | + |
| 114 | +## Out of Scope |
| 115 | + |
| 116 | +- **The layer flags** — lane 2, #950. |
| 117 | +- **Installing PowerShell 7**, or any shell. Reversed above. |
| 118 | +- **What the products do under 5.1.** `self install` is each product's; if writ's PowerShell actions need |
| 119 | + pwsh on Windows, that is the shell-provider rewrite's question, not the installer's. |
| 120 | +- **A Windows CI job that runs the installer end to end.** #855's scenario jobs cover writ's journey, not |
| 121 | + the installer; a job that provisions a 5.1-only Windows is its own work. |
0 commit comments