aboutsummaryrefslogtreecommitdiff
path: root/website
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 /website
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
Diffstat (limited to 'website')
-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
6 files changed, 98 insertions, 5 deletions
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',