Zum Hauptinhalt springen

Windows update server

Getting the script

To obtain the files needed on the update server, we provide a PowerShell script. You can download it in your browser or from a terminal:

(New-Object System.Net.WebClient).DownloadFile("https://repos.passwork.pro/repository/powershell/get_desktops.ps1",  "$pwd\get_desktops.ps1")

Benefits

  • Downloads only the required version from our repository — the one that matches your backend. The remote repository is used as the file source, not the version source: it hosts all desktop application versions. Which XXYY to download is determined by the script from the API or a local file.
  • Supports proxy (HTTP_PROXY), which is important in air-gapped networks that reach the internet via a proxy.
  • Can be run on a schedule (cron / Task Scheduler) so the update server stays in sync with your backend.

Where the version (which XXYY to download) comes from:

  1. Backend API — if PASSWORK_DOMAIN is set, the script requests the available desktop version via your Passwork server API and downloads the corresponding XXYY.
  2. Local file — the LOCAL_VERSIONS_FILE file contains a line with the version.

No other version sources are used: the file repository is used only for downloading, not for determining the version.

Each run downloads one XXYY version. If the backend switches to a new version — on the next run the script will get the new XXYY (from the API or updated file) and download the update files.

Variables

VariableDescription
REPO_BASE_URLURL of the repository with built desktop installers (file source).
OUTPUT_DIRDirectory for saved files (update server root or a copy).
PASSWORK_DOMAINBackend URL for version request via API (recommended if accessible).
LOCAL_VERSIONS_FILEPath to the versions file when API is not used.
HTTP_PROXYProxy for outbound requests (e.g. http://proxy:3128).
LOG_FILEPath to the log file (optional).
STATUS_FILEPath to the status file for monitoring (optional, see “Monitoring”).
KEEP_RELEASESHow many old XXYY directories to keep in OUTPUT_DIR (default 2).
LOCK_FILELock file to prevent concurrent runs (Task Scheduler); empty string to disable.

Dry run

.\get_desktop.ps1 --dry-run

Running

# Once or on a schedule (Task Scheduler)
$env:PASSWORK_DOMAIN = "https://your-backend.example.com"
$env:OUTPUT_DIR = "C:\inetpub\wwwroot\passwork\updates"
$env:HTTP_PROXY = "http://proxy.example.com:3128" # if needed
.\get_desktop.ps1

The script checks disk space, creates a lock if needed to avoid two instances running at once (e.g. from Task Scheduler), compares manifests with already downloaded files, and downloads only when something changed.

Monitoring

To verify that synchronization ran and content is up to date:

  1. Script exit code

    • 0 — success; no update needed or update completed, or --dry-run.
    • 1 — error (network, repository, disk space, etc.).
      Monitoring systems (Task Scheduler + check script, Zabbix, Prometheus, etc.) can use the script exit code.
  2. Status file (STATUS_FILE)
    If STATUS_FILE is set, the script overwrites this file after each run with lines in key=value format:

    • statusok or error;
    • version — current XXYY version (or empty if error before version was determined);
    • timestamp — time in UTC (ISO);
    • message — short message (e.g. “Update complete for version 0002” or “All latest YAML unchanged”).

    Example content after a successful run:

status=ok
version=0002
timestamp=2025-02-17T12:00:00Z
message=Update complete for version 0002

On error (including before version is determined), the script writes status=error and optionally message=exit N. For monitoring: read STATUS_FILE, ensure status=ok, and optionally check freshness via timestamp or presence of OUTPUT_DIR\<version>\latest.yml.

  1. Log (LOG_FILE)
    If LOG_FILE is set, all script messages are written there. You can scan the log for errors or lines like “Update complete” / “Repository unreachable”.

Example check for monitoring (PowerShell):

$env:STATUS_FILE = "C:\inetpub\wwwroot\passwork\updates\.sync_status"
.\get_desktop.ps1

# Check after run (or from another scheduled script):
$status = (Get-Content $env:STATUS_FILE | Where-Object { $_ -match '^status=' }) -replace '^status=', ''
if ($status -eq 'ok') { Write-Host "Sync OK" } else { Write-Host "Sync FAIL" }

# or by freshness (e.g. not older than 25 hours):
$tsLine = Get-Content $env:STATUS_FILE | Where-Object { $_ -match '^timestamp=' }
$tsStr = ($tsLine -split '=', 2)[1]
$syncTime = [DateTime]::ParseExact($tsStr.Trim(), "yyyy-MM-ddTHH:mm:ss'Z'", [Globalization.CultureInfo]::InvariantCulture, [Globalization.DateTimeStyles]::AssumeUniversal)
$hoursOld = (Get-Date).ToUniversalTime().Subtract($syncTime).TotalHours
if ($hoursOld -le 25) { Write-Host "Sync recent" } else { Write-Host "Sync may be stale" }