aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-08-23 00:37:31 +0300
committerGitHub <noreply@github.com>2026-08-23 00:37:31 +0300
commitc9601b9396532a552679328c8f0804d52909bc84 (patch)
tree407359aad803b3dd4fc7491f0b47656ebfb448a2
parentdb6f301f1301d85ca7a4271363760836f53ac0d0 (diff)
fix(windows): add local cmd installer bootstrap (#3133)
* fix(windows): add local cmd installer bootstrap refs #2751 * fix(windows): bound installer downloads refs #2751
-rw-r--r--README.md2
-rw-r--r--README.zh-CN.md2
-rw-r--r--docs/next/CHANGELOG.md1
-rw-r--r--docs/next/README.md2
-rw-r--r--docs/next/README.zh-CN.md2
-rw-r--r--docs/next/website/src/content/docs/install.mdx6
-rw-r--r--docs/next/website/src/content/docs/ja/install.mdx6
-rw-r--r--docs/next/website/src/content/docs/ja/windows-beta.mdx6
-rw-r--r--docs/next/website/src/content/docs/windows-beta.mdx6
-rw-r--r--docs/next/website/src/content/docs/zh-cn/install.mdx6
-rw-r--r--docs/next/website/src/content/docs/zh-cn/windows-beta.mdx6
-rw-r--r--docs/versions/0.8.2/website/src/content/docs/install.mdx6
-rw-r--r--docs/versions/0.8.2/website/src/content/docs/ja/install.mdx6
-rw-r--r--docs/versions/0.8.2/website/src/content/docs/ja/windows-beta.mdx6
-rw-r--r--docs/versions/0.8.2/website/src/content/docs/windows-beta.mdx6
-rw-r--r--docs/versions/0.8.2/website/src/content/docs/zh-cn/install.mdx6
-rw-r--r--docs/versions/0.8.2/website/src/content/docs/zh-cn/windows-beta.mdx6
-rw-r--r--scripts/windows_install_conpty_package_test.ps133
-rw-r--r--website/_headers8
-rw-r--r--website/agent-guide.md9
-rw-r--r--website/index.html2
-rw-r--r--website/install.cmd21
-rw-r--r--website/install.ps162
-rw-r--r--website/scripts/prepare-docs.mjs1
24 files changed, 207 insertions, 10 deletions
diff --git a/README.md b/README.md
index 2f8bc7ed..d731bf03 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ https://github.com/user-attachments/assets/043ec09f-4bdd-41d5-aee0-8fda6b83e267
curl -fsSL https://herdr.dev/install.sh | sh
```
-or `brew install herdr` · `mise use -g herdr` · windows: `powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [binaries](https://github.com/herdrdev/herdr/releases)
+or `brew install herdr` · `mise use -g herdr` · windows: `powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [endpoint-protected Windows](https://herdr.dev/docs/windows-beta/) · [binaries](https://github.com/herdrdev/herdr/releases)
then start it where the work lives:
diff --git a/README.zh-CN.md b/README.zh-CN.md
index a762bc86..1fc88d49 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -42,7 +42,7 @@ https://github.com/user-attachments/assets/043ec09f-4bdd-41d5-aee0-8fda6b83e267
curl -fsSL https://herdr.dev/install.sh | sh
```
-或者 `brew install herdr` · `mise use -g herdr` · Windows:`powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [二进制文件](https://github.com/herdrdev/herdr/releases)
+或者 `brew install herdr` · `mise use -g herdr` · Windows:`powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [受端点保护的 Windows](https://herdr.dev/zh-cn/docs/windows-beta/) · [二进制文件](https://github.com/herdrdev/herdr/releases)
然后在工作所在的目录启动它:
diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md
index cad470a9..ff465e65 100644
--- a/docs/next/CHANGELOG.md
+++ b/docs/next/CHANGELOG.md
@@ -6,6 +6,7 @@
- Custom themes can now define separate light and dark color overrides when automatic theme switching is enabled. (#837, thanks @aneym)
### Fixed
+- Windows users whose endpoint security blocks the fileless PowerShell install command can now use a local `install.cmd` bootstrap; installer downloads use `curl.exe` while preserving package checksum verification. (#2751)
- Retained mouse selections now copy when Ctrl+C or Cmd+C arrives before a delayed mouse release instead of forwarding the copy shortcut to the pane. (#3100, thanks @moret)
- Removing a background worktree workspace no longer changes focus to its parent workspace. (#3098)
- Prefix bindings such as `prefix+|` now recognize characters produced by macOS Option and custom keyboard layouts, while exact chords such as `prefix+alt+w` keep priority. (#3079, thanks @vlcinsky)
diff --git a/docs/next/README.md b/docs/next/README.md
index 2f8bc7ed..d731bf03 100644
--- a/docs/next/README.md
+++ b/docs/next/README.md
@@ -44,7 +44,7 @@ https://github.com/user-attachments/assets/043ec09f-4bdd-41d5-aee0-8fda6b83e267
curl -fsSL https://herdr.dev/install.sh | sh
```
-or `brew install herdr` · `mise use -g herdr` · windows: `powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [binaries](https://github.com/herdrdev/herdr/releases)
+or `brew install herdr` · `mise use -g herdr` · windows: `powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [endpoint-protected Windows](https://herdr.dev/docs/windows-beta/) · [binaries](https://github.com/herdrdev/herdr/releases)
then start it where the work lives:
diff --git a/docs/next/README.zh-CN.md b/docs/next/README.zh-CN.md
index a762bc86..1fc88d49 100644
--- a/docs/next/README.zh-CN.md
+++ b/docs/next/README.zh-CN.md
@@ -42,7 +42,7 @@ https://github.com/user-attachments/assets/043ec09f-4bdd-41d5-aee0-8fda6b83e267
curl -fsSL https://herdr.dev/install.sh | sh
```
-或者 `brew install herdr` · `mise use -g herdr` · Windows:`powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [二进制文件](https://github.com/herdrdev/herdr/releases)
+或者 `brew install herdr` · `mise use -g herdr` · Windows:`powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"` · [受端点保护的 Windows](https://herdr.dev/zh-cn/docs/windows-beta/) · [二进制文件](https://github.com/herdrdev/herdr/releases)
然后在工作所在的目录启动它:
diff --git a/docs/next/website/src/content/docs/install.mdx b/docs/next/website/src/content/docs/install.mdx
index c69cdd7a..a14a1d5b 100644
--- a/docs/next/website/src/content/docs/install.mdx
+++ b/docs/next/website/src/content/docs/install.mdx
@@ -19,6 +19,12 @@ On Windows, run:
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+If endpoint security blocks that fileless PowerShell command, open Command Prompt and run:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
The installer downloads the release binary for your platform and places it on your PATH. New direct installs use the stable update channel. Existing Windows preview installs stay on preview until you switch them with `herdr channel set stable`. The Windows installer uses versioned install folders and updates a `current` junction, so updates do not need to overwrite a running `herdr.exe`.
## Install with Homebrew
diff --git a/docs/next/website/src/content/docs/ja/install.mdx b/docs/next/website/src/content/docs/ja/install.mdx
index 3fe29f40..72d591c8 100644
--- a/docs/next/website/src/content/docs/ja/install.mdx
+++ b/docs/next/website/src/content/docs/ja/install.mdx
@@ -19,6 +19,12 @@ Windows では次を実行します:
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+エンドポイントセキュリティによってこのファイルレス PowerShell コマンドがブロックされる場合は、コマンドプロンプトを開いて次を実行します:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
インストーラーはプラットフォームに合ったリリースバイナリをダウンロードして PATH 上に配置します。新しい直接インストールは安定版アップデートチャンネルを使います。既存の Windows プレビューインストールは、`herdr channel set stable` で切り替えるまでプレビューに残ります。Windows インストーラーはバージョン付きインストールフォルダーを使い、`current` ジャンクションを更新します。そのため、アップデート時に実行中の `herdr.exe` を上書きする必要がありません。
## Homebrew でインストール
diff --git a/docs/next/website/src/content/docs/ja/windows-beta.mdx b/docs/next/website/src/content/docs/ja/windows-beta.mdx
index 89baaa43..96c8e12f 100644
--- a/docs/next/website/src/content/docs/ja/windows-beta.mdx
+++ b/docs/next/website/src/content/docs/ja/windows-beta.mdx
@@ -13,6 +13,12 @@ Windows に Herdr をネイティブインストールするには PowerShell ã‚
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+エンドポイントセキュリティによってこのファイルレス PowerShell コマンドがブロックされる場合は、コマンドプロンプトを開いて次を実行します:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
Windows ビルドは安定版とプレビューの両方のアップデートチャンネルで提供されます。新規インストールはデフォルトで安定版を使い、通常の利用には安定版を推奨します。既存のプレビューインストールは、`herdr channel set stable` を実行するまでプレビューに残ります。古いプレビュービルドでこのコマンドが拒否される場合は、プレビューのまま一度 `herdr update` を実行してから再試行してください。プレビューでは `master` からの新しく検証の少ない修正を受け取れますが、リグレッションが起きる可能性があります。そのトレードオフを望む場合に限り、`herdr channel set preview` でオプトインしてください。
インストーラーはリリースを `%USERPROFILE%\.herdr\packages\standalone\releases` に保存し、`%LOCALAPPDATA%\Programs\Herdr\bin` を現在のリリースに向け、実行中のプロセスがアップデートを妨げないよう少数の古いリリースを保持します。
diff --git a/docs/next/website/src/content/docs/windows-beta.mdx b/docs/next/website/src/content/docs/windows-beta.mdx
index c5839639..ed21feeb 100644
--- a/docs/next/website/src/content/docs/windows-beta.mdx
+++ b/docs/next/website/src/content/docs/windows-beta.mdx
@@ -13,6 +13,12 @@ Install Herdr natively on Windows with PowerShell:
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+If endpoint security blocks that fileless PowerShell command, open Command Prompt and run:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
Windows builds are available through both stable and preview update channels. New installs use stable by default, and stable is recommended for normal use. Existing preview installs stay on preview until you run `herdr channel set stable`. If an older preview build rejects that command, run `herdr update` once on preview and retry. Preview provides newer, less-tested fixes from `master` and may regress; opt in with `herdr channel set preview` only when you want that tradeoff.
The installer stores releases under `%USERPROFILE%\.herdr\packages\standalone\releases`, points `%LOCALAPPDATA%\Programs\Herdr\bin` at the current release, and keeps a small number of older releases so running processes do not block updates.
diff --git a/docs/next/website/src/content/docs/zh-cn/install.mdx b/docs/next/website/src/content/docs/zh-cn/install.mdx
index 9f8ef5a5..0324d60b 100644
--- a/docs/next/website/src/content/docs/zh-cn/install.mdx
+++ b/docs/next/website/src/content/docs/zh-cn/install.mdx
@@ -19,6 +19,12 @@ curl -fsSL https://herdr.dev/install.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+如果端点安全软件阻止该无文件 PowerShell 命令,请打开命令提示符并运行:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
安装器会下载适合你平台的发布二进制文件并放到 PATH 上。新的直接安装默认使用稳定更新通道。现有的 Windows 预览安装会继续留在预览通道,直到你运行 `herdr channel set stable`。Windows 安装器使用带版本号的安装文件夹,并更新一个 `current` 联接点,因此更新时不需要覆盖正在运行的 `herdr.exe`。
## 用 Homebrew 安装
diff --git a/docs/next/website/src/content/docs/zh-cn/windows-beta.mdx b/docs/next/website/src/content/docs/zh-cn/windows-beta.mdx
index 2b25552a..a22058ae 100644
--- a/docs/next/website/src/content/docs/zh-cn/windows-beta.mdx
+++ b/docs/next/website/src/content/docs/zh-cn/windows-beta.mdx
@@ -13,6 +13,12 @@ Windows 上的 Herdr 使用 ConPTY 和 Windows 的进程/运行时行为,而不æ
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+如果端点安全软件阻止该无文件 PowerShell 命令,请打开命令提示符并运行:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
Windows 构建同时通过稳定版和预览版更新通道提供。新安装默认使用稳定版,常规使用也建议选择稳定版。现有预览安装会继续留在预览通道,直到你运行 `herdr channel set stable`。如果旧预览构建拒绝该命令,请先在预览通道运行一次 `herdr update`,再重试。预览版会提供来自 `master` 的更新、测试较少的修复,也可能出现回归;只有在接受这一取舍时,才应通过 `herdr channel set preview` 主动启用。
安装器将发布版本保存在 `%USERPROFILE%\.herdr\packages\standalone\releases` 下,让 `%LOCALAPPDATA%\Programs\Herdr\bin` 指向当前版本,并保留少量旧版本,以免运行中的进程阻塞更新。
diff --git a/docs/versions/0.8.2/website/src/content/docs/install.mdx b/docs/versions/0.8.2/website/src/content/docs/install.mdx
index c69cdd7a..a14a1d5b 100644
--- a/docs/versions/0.8.2/website/src/content/docs/install.mdx
+++ b/docs/versions/0.8.2/website/src/content/docs/install.mdx
@@ -19,6 +19,12 @@ On Windows, run:
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+If endpoint security blocks that fileless PowerShell command, open Command Prompt and run:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
The installer downloads the release binary for your platform and places it on your PATH. New direct installs use the stable update channel. Existing Windows preview installs stay on preview until you switch them with `herdr channel set stable`. The Windows installer uses versioned install folders and updates a `current` junction, so updates do not need to overwrite a running `herdr.exe`.
## Install with Homebrew
diff --git a/docs/versions/0.8.2/website/src/content/docs/ja/install.mdx b/docs/versions/0.8.2/website/src/content/docs/ja/install.mdx
index 3fe29f40..72d591c8 100644
--- a/docs/versions/0.8.2/website/src/content/docs/ja/install.mdx
+++ b/docs/versions/0.8.2/website/src/content/docs/ja/install.mdx
@@ -19,6 +19,12 @@ Windows では次を実行します:
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+エンドポイントセキュリティによってこのファイルレス PowerShell コマンドがブロックされる場合は、コマンドプロンプトを開いて次を実行します:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
インストーラーはプラットフォームに合ったリリースバイナリをダウンロードして PATH 上に配置します。新しい直接インストールは安定版アップデートチャンネルを使います。既存の Windows プレビューインストールは、`herdr channel set stable` で切り替えるまでプレビューに残ります。Windows インストーラーはバージョン付きインストールフォルダーを使い、`current` ジャンクションを更新します。そのため、アップデート時に実行中の `herdr.exe` を上書きする必要がありません。
## Homebrew でインストール
diff --git a/docs/versions/0.8.2/website/src/content/docs/ja/windows-beta.mdx b/docs/versions/0.8.2/website/src/content/docs/ja/windows-beta.mdx
index 89baaa43..96c8e12f 100644
--- a/docs/versions/0.8.2/website/src/content/docs/ja/windows-beta.mdx
+++ b/docs/versions/0.8.2/website/src/content/docs/ja/windows-beta.mdx
@@ -13,6 +13,12 @@ Windows に Herdr をネイティブインストールするには PowerShell ã‚
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+エンドポイントセキュリティによってこのファイルレス PowerShell コマンドがブロックされる場合は、コマンドプロンプトを開いて次を実行します:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
Windows ビルドは安定版とプレビューの両方のアップデートチャンネルで提供されます。新規インストールはデフォルトで安定版を使い、通常の利用には安定版を推奨します。既存のプレビューインストールは、`herdr channel set stable` を実行するまでプレビューに残ります。古いプレビュービルドでこのコマンドが拒否される場合は、プレビューのまま一度 `herdr update` を実行してから再試行してください。プレビューでは `master` からの新しく検証の少ない修正を受け取れますが、リグレッションが起きる可能性があります。そのトレードオフを望む場合に限り、`herdr channel set preview` でオプトインしてください。
インストーラーはリリースを `%USERPROFILE%\.herdr\packages\standalone\releases` に保存し、`%LOCALAPPDATA%\Programs\Herdr\bin` を現在のリリースに向け、実行中のプロセスがアップデートを妨げないよう少数の古いリリースを保持します。
diff --git a/docs/versions/0.8.2/website/src/content/docs/windows-beta.mdx b/docs/versions/0.8.2/website/src/content/docs/windows-beta.mdx
index c5839639..ed21feeb 100644
--- a/docs/versions/0.8.2/website/src/content/docs/windows-beta.mdx
+++ b/docs/versions/0.8.2/website/src/content/docs/windows-beta.mdx
@@ -13,6 +13,12 @@ Install Herdr natively on Windows with PowerShell:
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+If endpoint security blocks that fileless PowerShell command, open Command Prompt and run:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
Windows builds are available through both stable and preview update channels. New installs use stable by default, and stable is recommended for normal use. Existing preview installs stay on preview until you run `herdr channel set stable`. If an older preview build rejects that command, run `herdr update` once on preview and retry. Preview provides newer, less-tested fixes from `master` and may regress; opt in with `herdr channel set preview` only when you want that tradeoff.
The installer stores releases under `%USERPROFILE%\.herdr\packages\standalone\releases`, points `%LOCALAPPDATA%\Programs\Herdr\bin` at the current release, and keeps a small number of older releases so running processes do not block updates.
diff --git a/docs/versions/0.8.2/website/src/content/docs/zh-cn/install.mdx b/docs/versions/0.8.2/website/src/content/docs/zh-cn/install.mdx
index 9f8ef5a5..0324d60b 100644
--- a/docs/versions/0.8.2/website/src/content/docs/zh-cn/install.mdx
+++ b/docs/versions/0.8.2/website/src/content/docs/zh-cn/install.mdx
@@ -19,6 +19,12 @@ curl -fsSL https://herdr.dev/install.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+如果端点安全软件阻止该无文件 PowerShell 命令,请打开命令提示符并运行:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
安装器会下载适合你平台的发布二进制文件并放到 PATH 上。新的直接安装默认使用稳定更新通道。现有的 Windows 预览安装会继续留在预览通道,直到你运行 `herdr channel set stable`。Windows 安装器使用带版本号的安装文件夹,并更新一个 `current` 联接点,因此更新时不需要覆盖正在运行的 `herdr.exe`。
## 用 Homebrew 安装
diff --git a/docs/versions/0.8.2/website/src/content/docs/zh-cn/windows-beta.mdx b/docs/versions/0.8.2/website/src/content/docs/zh-cn/windows-beta.mdx
index 2b25552a..a22058ae 100644
--- a/docs/versions/0.8.2/website/src/content/docs/zh-cn/windows-beta.mdx
+++ b/docs/versions/0.8.2/website/src/content/docs/zh-cn/windows-beta.mdx
@@ -13,6 +13,12 @@ Windows 上的 Herdr 使用 ConPTY 和 Windows 的进程/运行时行为,而不æ
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```
+如果端点安全软件阻止该无文件 PowerShell 命令,请打开命令提示符并运行:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+```
+
Windows 构建同时通过稳定版和预览版更新通道提供。新安装默认使用稳定版,常规使用也建议选择稳定版。现有预览安装会继续留在预览通道,直到你运行 `herdr channel set stable`。如果旧预览构建拒绝该命令,请先在预览通道运行一次 `herdr update`,再重试。预览版会提供来自 `master` 的更新、测试较少的修复,也可能出现回归;只有在接受这一取舍时,才应通过 `herdr channel set preview` 主动启用。
安装器将发布版本保存在 `%USERPROFILE%\.herdr\packages\standalone\releases` 下,让 `%LOCALAPPDATA%\Programs\Herdr\bin` 指向当前版本,并保留少量旧版本,以免运行中的进程阻塞更新。
diff --git a/scripts/windows_install_conpty_package_test.ps1 b/scripts/windows_install_conpty_package_test.ps1
index f4c4fc60..264fafe2 100644
--- a/scripts/windows_install_conpty_package_test.ps1
+++ b/scripts/windows_install_conpty_package_test.ps1
@@ -7,6 +7,16 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$installerPath = (Resolve-Path -LiteralPath "$PSScriptRoot\..\website\install.ps1").Path
+$bootstrapPath = (Resolve-Path -LiteralPath "$PSScriptRoot\..\website\install.cmd").Path
+$bootstrapContent = Get-Content -LiteralPath $bootstrapPath -Raw
+foreach ($forbiddenCommand in @("Invoke-RestMethod", "Invoke-WebRequest", "Invoke-Expression", "iex")) {
+ if ($bootstrapContent -match "(?i)\b$forbiddenCommand\b") {
+ throw "CMD bootstrap uses forbidden PowerShell network execution: $forbiddenCommand"
+ }
+}
+if ($bootstrapContent -notmatch "(?i)\bcurl\.exe\b") {
+ throw "CMD bootstrap does not download through curl.exe"
+}
$parseErrors = $null
$tokens = $null
$installerAst = [System.Management.Automation.Language.Parser]::ParseFile(
@@ -17,6 +27,19 @@ $installerAst = [System.Management.Automation.Language.Parser]::ParseFile(
if ($parseErrors.Count -ne 0) {
throw ($parseErrors | Out-String)
}
+$forbiddenPowerShellCommands = @(
+ $installerAst.FindAll(
+ { param($node) $node -is [System.Management.Automation.Language.CommandAst] },
+ $true
+ ) |
+ ForEach-Object { $_.GetCommandName() } |
+ Where-Object {
+ $_ -in @("Invoke-RestMethod", "Invoke-WebRequest", "Invoke-Expression", "irm", "iwr", "iex")
+ }
+)
+if ($forbiddenPowerShellCommands.Count -ne 0) {
+ throw "installer uses forbidden PowerShell network execution: $($forbiddenPowerShellCommands -join ', ')"
+}
foreach ($functionName in @("Prepend-PathEntry", "Update-PathRegistryEntry")) {
$definition = $installerAst.FindAll(
{
@@ -76,6 +99,7 @@ $herdrHome = Join-Path $root "home"
$installDir = Join-Path $root "bin"
New-Item -ItemType Directory -Force -Path $webRoot | Out-Null
Copy-Item -LiteralPath $archive -Destination (Join-Path $webRoot "herdr-windows-x86_64.zip")
+Copy-Item -LiteralPath $installerPath -Destination (Join-Path $webRoot "install.ps1")
$hash = (Get-FileHash -Algorithm SHA256 $archive).Hash.ToLowerInvariant()
$listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0)
@@ -114,6 +138,7 @@ $legacyStableManifest | Out-File -LiteralPath $stableManifestPath -Encoding utf8
$server = $null
$oldHerdrHome = $env:HERDR_HOME
+$oldInstallerUrl = $env:HERDR_INSTALLER_URL
$oldProcessPath = $env:Path
try {
$server = Start-Process python -ArgumentList @("-m", "http.server", "$port", "--bind", "127.0.0.1", "--directory", $webRoot) -PassThru -WindowStyle Hidden
@@ -134,10 +159,15 @@ try {
$freshStableBin = Join-Path $root "fresh-stable-bin"
$stableManifest | Out-File -LiteralPath $stableManifestPath -Encoding utf8
$env:HERDR_HOME = $freshStableHome
+ $env:HERDR_INSTALLER_URL = "http://127.0.0.1:$port/install.ps1"
$env:Path = $oldProcessPath
- & $installerPath `
+ & $bootstrapPath `
-ManifestUrl $stableManifestUrl `
-InstallDir $freshStableBin
+ if ($LASTEXITCODE -ne 0) {
+ throw "CMD bootstrap failed with exit code $LASTEXITCODE"
+ }
+ $env:HERDR_INSTALLER_URL = $oldInstallerUrl
$freshStableRelease = Get-ChildItem -LiteralPath (Join-Path $freshStableHome "packages\standalone\releases") -Directory |
Where-Object { $_.Name.StartsWith("0.0.1-") } |
Select-Object -First 1
@@ -458,6 +488,7 @@ exit /b 1
}
} finally {
$env:HERDR_HOME = $oldHerdrHome
+ $env:HERDR_INSTALLER_URL = $oldInstallerUrl
$env:Path = $oldProcessPath
if ($null -ne $server -and -not $server.HasExited) {
Stop-Process -Id $server.Id -Force -ErrorAction SilentlyContinue
diff --git a/website/_headers b/website/_headers
index da99d1b0..6422cca9 100644
--- a/website/_headers
+++ b/website/_headers
@@ -14,6 +14,14 @@
Content-Type: text/plain
Content-Disposition: inline
+/install.ps1
+ Content-Type: text/plain
+ Content-Disposition: inline
+
+/install.cmd
+ Content-Type: text/plain
+ Content-Disposition: inline
+
/latest.json
Content-Type: application/json
Cache-Control: public, max-age=300
diff --git a/website/agent-guide.md b/website/agent-guide.md
index 71392817..b542dd94 100644
--- a/website/agent-guide.md
+++ b/website/agent-guide.md
@@ -32,13 +32,20 @@ curl -fsSL https://herdr.dev/install.sh | sh
herdr
```
-Windows:
+Windows PowerShell:
```powershell
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
herdr
```
+If endpoint security blocks that fileless PowerShell command, use Command Prompt:
+
+```cmd
+curl.exe -fsSLo install.cmd https://herdr.dev/install.cmd && install.cmd && del install.cmd
+herdr
+```
+
Homebrew, mise, and Nix installs, verification, and manual downloads: https://herdr.dev/docs/install/. Direct installs use the stable channel by default and update with `herdr update`; preview is opt-in. Package-manager installs update through that package manager. Check the version with `herdr --version`.
## First-run walkthrough
diff --git a/website/index.html b/website/index.html
index 06750444..4186792e 100644
--- a/website/index.html
+++ b/website/index.html
@@ -475,7 +475,7 @@
<button type="button" id="copy-btn-2" aria-label="Copy install command">copy</button>
</div>
</div>
- <div class="meta">Windows: <code>irm https://herdr.dev/install.ps1 | iex</code> &nbsp;—&nbsp; <a href="/docs/">all install methods →</a></div>
+ <div class="meta">Windows: <code>irm https://herdr.dev/install.ps1 | iex</code> &nbsp;—&nbsp; <a href="/docs/windows-beta/">endpoint-protected install</a> · <a href="/docs/">all install methods →</a></div>
</div>
</section>
diff --git a/website/install.cmd b/website/install.cmd
new file mode 100644
index 00000000..325e3b38
--- /dev/null
+++ b/website/install.cmd
@@ -0,0 +1,21 @@
+@echo off
+setlocal
+
+set "INSTALLER_URL=https://herdr.dev/install.ps1"
+set "CURL_PROTOCOL=--proto =https --tlsv1.2"
+if defined HERDR_INSTALLER_URL (
+ set "INSTALLER_URL=%HERDR_INSTALLER_URL%"
+ set "CURL_PROTOCOL=--proto =http,https"
+)
+set "INSTALLER_PATH=%TEMP%\herdr-install-%RANDOM%-%RANDOM%.ps1"
+
+curl.exe --fail --silent --show-error --location --connect-timeout 30 --speed-limit 1024 --speed-time 30 %CURL_PROTOCOL% --output "%INSTALLER_PATH%" -- "%INSTALLER_URL%"
+if errorlevel 1 (
+ del /f /q "%INSTALLER_PATH%" >nul 2>&1
+ exit /b 1
+)
+
+powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%INSTALLER_PATH%" %*
+set "INSTALLER_EXIT=%ERRORLEVEL%"
+del /f /q "%INSTALLER_PATH%" >nul 2>&1
+exit /b %INSTALLER_EXIT%
diff --git a/website/install.ps1 b/website/install.ps1
index 9dacfaa9..94a57314 100644
--- a/website/install.ps1
+++ b/website/install.ps1
@@ -216,6 +216,50 @@ function Get-ManifestAsset {
}
}
+function Invoke-CurlDownload {
+ param(
+ [string]$Uri,
+ [string]$Destination
+ )
+
+ $parsedUri = $null
+ if (-not [System.Uri]::TryCreate($Uri, [System.UriKind]::Absolute, [ref]$parsedUri) -or
+ $parsedUri.Scheme -notin @("http", "https")) {
+ throw "Herdr download URL must use HTTP or HTTPS: $Uri"
+ }
+
+ $curl = Get-Command curl.exe -CommandType Application -ErrorAction SilentlyContinue |
+ Select-Object -First 1
+ if ($null -eq $curl) {
+ throw "Herdr installation requires curl.exe, which is included with supported Windows versions."
+ }
+
+ $arguments = @(
+ "--fail",
+ "--silent",
+ "--show-error",
+ "--location",
+ "--connect-timeout", "30",
+ "--speed-limit", "1024",
+ "--speed-time", "30"
+ )
+ if ($parsedUri.Scheme -eq "https") {
+ $arguments += @("--proto", "=https", "--tlsv1.2")
+ }
+ $arguments += @("--output", $Destination, "--", $Uri)
+
+ $curlOutput = & $curl.Source @arguments 2>&1
+ $curlExitCode = $LASTEXITCODE
+ if ($curlExitCode -ne 0) {
+ $detail = ($curlOutput | ForEach-Object { $_.ToString() }) -join [Environment]::NewLine
+ $message = "Failed to download $Uri (curl exit code $curlExitCode)."
+ if (-not [string]::IsNullOrWhiteSpace($detail)) {
+ $message += " $detail"
+ }
+ throw $message
+ }
+}
+
function ConvertTo-ManifestObject {
param([object]$Manifest)
@@ -232,6 +276,18 @@ function ConvertTo-ManifestObject {
return $json | ConvertFrom-Json
}
+function Get-RemoteManifest {
+ param([string]$Uri)
+
+ $manifestPath = Join-Path ([System.IO.Path]::GetTempPath()) ("herdr-manifest-" + [System.Guid]::NewGuid().ToString("N") + ".json")
+ try {
+ Invoke-CurlDownload -Uri $Uri -Destination $manifestPath
+ return ConvertTo-ManifestObject -Manifest ([System.IO.File]::ReadAllText($manifestPath))
+ } finally {
+ Remove-Item -LiteralPath $manifestPath -Force -ErrorAction SilentlyContinue
+ }
+}
+
function Test-FileDigest {
param(
[string]$Path,
@@ -685,7 +741,7 @@ if ($useLocalPackage) {
}
Write-Step "Fetching Herdr $Channel manifest"
- $manifest = ConvertTo-ManifestObject -Manifest (Invoke-RestMethod -Uri $ManifestUrl)
+ $manifest = Get-RemoteManifest -Uri $ManifestUrl
$manifestChannelProperty = $manifest.PSObject.Properties["channel"]
if (-not $channelWasExplicit -and $null -ne $manifestChannelProperty -and [string]$manifestChannelProperty.Value -eq "preview") {
$Channel = "preview"
@@ -704,7 +760,7 @@ if ($useLocalPackage) {
$Channel = "preview"
$ManifestUrl = $ManifestUrl.Substring(0, $ManifestUrl.Length - "latest.json".Length) + "preview.json"
Write-Step "Fetching Herdr preview manifest"
- $manifest = ConvertTo-ManifestObject -Manifest (Invoke-RestMethod -Uri $ManifestUrl)
+ $manifest = Get-RemoteManifest -Uri $ManifestUrl
}
$asset = Get-ManifestAsset -Manifest $manifest -Target $target
if (-not [string]::IsNullOrWhiteSpace($ExpectedBuildId) -and [string]$manifest.build_id -ne $ExpectedBuildId) {
@@ -733,7 +789,7 @@ try {
$stagingDir = Join-Path $releasesDir ".staging.$releaseName.$PID"
if (-not $useLocalPackage) {
Write-Step "Downloading Herdr"
- Invoke-WebRequest -Uri $asset.Url -OutFile $downloadPath
+ Invoke-CurlDownload -Uri $asset.Url -Destination $downloadPath
}
Test-FileDigest -Path $downloadPath -ExpectedDigest $asset.Sha256
diff --git a/website/scripts/prepare-docs.mjs b/website/scripts/prepare-docs.mjs
index 14d62abc..e8278851 100644
--- a/website/scripts/prepare-docs.mjs
+++ b/website/scripts/prepare-docs.mjs
@@ -68,6 +68,7 @@ async function preparePublicAssets() {
for (const file of [
'install.sh',
'install.ps1',
+ 'install.cmd',
'agent-guide.md',
'latest.json',
'preview.json',