# Installation and updates

<div style="text-align: justify;">

The Print Service has no installer. The program is delivered as a git repository that contains only the released build. Updates are a `git` checkout, driven by a script that stops the service gracefully first. Configuration, token, job journal and logs live in a separate data folder and survive every update.

---

<h3 id="requirements" style="color: #203671; margin-top: 2.2em;">Requirements</h3>

<table style="width: 100%; border-collapse: collapse;">
  <tbody>
    <tr style="border-top: 1px solid #e6e8ef; border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>Operating system</strong></td>
      <td style="padding: 6px 10px;">Windows 10/11 or Windows Server 2019 or newer, x64</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>Runtime</strong></td>
      <td style="padding: 6px 10px;"><a href="https://dotnet.microsoft.com/download/dotnet/10.0">.NET 10 Desktop Runtime (x64)</a>. The build is framework-dependent, the runtime is not bundled.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>Git</strong></td>
      <td style="padding: 6px 10px;">Git for Windows and read access to the release repository</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>Network</strong></td>
      <td style="padding: 6px 10px;">HTTPS to the VeloxFactory API and WSS to the Reverb server of your instance. With receive mode <code>Polling</code> the API alone is enough.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>API token</strong></td>
      <td style="padding: 6px 10px;">Token of a user with <code>global:use-api</code>, <code>report-print-task:read</code> and <code>report-print-task:update</code>. <code>printer:read</code> is optional and enables the printer comparison. <code>:read</code> is also the right the private channel checks, a token without it never receives a WebSocket event.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>Service account</strong></td>
      <td style="padding: 6px 10px;">A dedicated Windows account for the scheduled task, see below</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><strong>Printers</strong></td>
      <td style="padding: 6px 10px;">Installed machine-wide, see <a href="/books/veloxfactory/page/printers-and-printing">Printers and printing</a></td>
    </tr>
  </tbody>
</table>

---

<h3 id="layout" style="color: #203671; margin-top: 2.2em;">Folder layout</h3>

```
C:\kiwisoftware\VeloxPrint\
  app\          clone of the release repository, program only, updated by update.ps1
    bin\        kiwisoftware.VeloxFactory.PrintService.App.exe and its libraries
    update.ps1
    README.md
  data\         created by the app, never part of git
    config.json     configuration without token
    secrets.json    API token, encrypted
    state.db        job journal, outbox, statistics, log buffer, engine status (SQLite)
    logs\           rolling log files
```

Where the data folder is:

1. `--config <path>` sets it explicitly: all files of the instance live next to that configuration file.
2. If the program runs from a folder named `app` or below it, the data folder is `data` next to that `app` folder.
3. Otherwise it is `%ProgramData%\kiwisoftware\VeloxPrint\`.

<table style="width: 100%; border-collapse: collapse;">
  <thead>
    <tr style="border-top: 1px solid #e6e8ef; border-bottom: 1px solid #e6e8ef;">
      <th style="text-align: left; padding: 6px 10px; white-space: nowrap;">File</th>
      <th style="text-align: left; padding: 6px 10px;">Permissions</th>
    </tr>
  </thead>
  <tbody>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>config.json</code></td>
      <td style="padding: 6px 10px;">Administrators and service account: modify. Users: read.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>secrets.json</code></td>
      <td style="padding: 6px 10px;">Administrators and service account: modify. Users: no access.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;"><code>state.db</code>, <code>logs\</code></td>
      <td style="padding: 6px 10px;">Service account: modify. Users: read.</td>
    </tr>
  </tbody>
</table>

The first start with administrator rights creates the data folder and sets these permissions. Setting up the scheduled task adds the service account.

<div style="border-left: 4px solid #203671; background: #f0f3fb; padding: 10px 16px; margin: 16px 0; border-radius: 0 4px 4px 0;">
⚠️ <strong>Do not copy <code>secrets.json</code> to another machine.</strong> The token is encrypted with DPAPI for this machine (scope LocalMachine), so the window of an administrator and the headless service account can both read it. On another machine it cannot be decrypted, enter the token there again.
</div>

---

<h3 id="first-installation" style="color: #203671; margin-top: 2.2em;">First installation</h3>

<h4 style="color: #203671; margin-top: 1.4em;">1. Create the service account</h4>

The scheduled task runs under its own account. It must exist before the task is set up, the Print Service does not create it. PowerShell as administrator:

```powershell
$pw = Read-Host -AsSecureString "Password"
New-LocalUser -Name "svc-veloxprint" -Password $pw -FullName "VeloxFactory Print Service" `
  -Description "Service account VeloxFactory Print Service" -PasswordNeverExpires -UserMayNotChangePassword
```

1. Do not add the account to the Administrators group, the standard Users group is enough.
2. Use `-PasswordNeverExpires`. An expired password stops the task until it is set up again.
3. For printers on a print server in a domain, use a domain account (`DOMAIN\svc-veloxprint`) instead. Only a domain account can authenticate at the print server.
4. Do not use `SYSTEM`. It accesses print servers with the computer account, shares often refuse that.

<h4 style="color: #203671; margin-top: 1.4em;">2. Clone the release</h4>

PowerShell as administrator:

```powershell
New-Item -ItemType Directory C:\kiwisoftware\VeloxPrint
git clone https://git.fischernetz.xyz/bfischer/veloxfactory-printservice-release.git C:\kiwisoftware\VeloxPrint\app
```

<h4 style="color: #203671; margin-top: 1.4em;">3. Configure</h4>

1. Start `C:\kiwisoftware\VeloxPrint\app\bin\kiwisoftware.VeloxFactory.PrintService.App.exe` **as administrator**. The first elevated start creates `data\` and restricts its permissions.
2. **Settings → Connection:** base URL of VeloxFactory and API token. **Test connection** checks reachability, token, channel authorization, WebSocket handshake and rate limit headers.
3. **Settings → WebSocket (Reverb):** host, port, scheme and app key of your Reverb server.
4. **Settings → Receiving:** the broadcast ids of this site.
5. Save. See the [Configuration reference](/books/veloxfactory/page/configuration-reference) for every setting.

<h4 style="color: #203671; margin-top: 1.4em;">4. Set up the scheduled task</h4>

**Settings → Operation → Set up scheduled task**, enter the service account (`.\svc-veloxprint` for a local account) and its password. Alternatively on the command line (as administrator):

```powershell
& "C:\kiwisoftware\VeloxPrint\app\bin\kiwisoftware.VeloxFactory.PrintService.App.exe" --install-task --user .\svc-veloxprint
```

The setup:

1. grants the account the right *Log on as a batch job*,
2. sets the permissions of the data folder and `secrets.json` for the account,
3. registers the Windows event log source *VeloxFactory Print Service*,
4. creates or updates the task with the settings below.

<table style="width: 100%; border-collapse: collapse;">
  <thead>
    <tr style="border-top: 1px solid #e6e8ef; border-bottom: 1px solid #e6e8ef;">
      <th style="text-align: left; padding: 6px 10px; white-space: nowrap;">Task setting</th>
      <th style="text-align: left; padding: 6px 10px;">Value</th>
      <th style="text-align: left; padding: 6px 10px;">Reason</th>
    </tr>
  </thead>
  <tbody>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Name</td>
      <td style="padding: 6px 10px;"><code>VeloxFactory Print Service</code>, for an alternative configuration <code>VeloxFactory Print Service (&lt;config name&gt;)</code></td>
      <td style="padding: 6px 10px;">Root folder of the Task Scheduler library</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Run</td>
      <td style="padding: 6px 10px;">Whether the user is logged on or not, password stored</td>
      <td style="padding: 6px 10px;">No desktop needed; without stored password network printers are unreachable</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Trigger</td>
      <td style="padding: 6px 10px;">At system start, delayed 1 minute</td>
      <td style="padding: 6px 10px;">Network and spooler are ready</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Action</td>
      <td style="padding: 6px 10px;"><code>--headless</code> (plus <code>--config</code> for an alternative instance), start in the program folder</td>
      <td style="padding: 6px 10px;">The Task Scheduler would otherwise start in <code>System32</code></td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Time limit</td>
      <td style="padding: 6px 10px;">None</td>
      <td style="padding: 6px 10px;">The Windows default of 3 days would end the engine</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">On failure</td>
      <td style="padding: 6px 10px;">Restart every minute, up to 999 times</td>
      <td style="padding: 6px 10px;">Crash recovery</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Already running</td>
      <td style="padding: 6px 10px;">Do not start a new instance</td>
      <td style="padding: 6px 10px;">In addition to the instance mutex</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">Privileges</td>
      <td style="padding: 6px 10px;">Not elevated</td>
      <td style="padding: 6px 10px;">Not needed</td>
    </tr>
    <tr>
      <td style="padding: 6px 10px; white-space: nowrap;">Battery</td>
      <td style="padding: 6px 10px;">Runs on battery, starts when available</td>
      <td style="padding: 6px 10px;">Missed starts are caught up</td>
    </tr>
  </tbody>
</table>

<div style="border-left: 4px solid #203671; background: #f0f3fb; padding: 10px 16px; margin: 16px 0; border-radius: 0 4px 4px 0;">
⚠️ <strong>Do not edit the task by hand.</strong> Setting it up again from the window or with <code>--install-task</code> overwrites it with the values above. After changing the password of the service account, set the task up again, the password is stored in the task.
</div>

The window shows the task under **Settings → Operation**: state, account, last and next run, last result and the XML definition. It can start and remove the task there, too.

<h4 style="color: #203671; margin-top: 1.4em;">5. Verify</h4>

1. **Printers:** print a test page on every printer the site uses.
2. Start the task (**Settings → Operation → Start** or reboot). The window switches to monitor mode.
3. Create a print task in VeloxFactory for one of the broadcast ids and watch it on the **Dashboard**.

---

<h3 id="update" style="color: #203671; margin-top: 2.2em;">Updates and rollback</h3>

PowerShell as administrator:

```powershell
# newest release
powershell -ExecutionPolicy Bypass -File C:\kiwisoftware\VeloxPrint\app\update.ps1

# a specific release, also the way back to an older one
powershell -ExecutionPolicy Bypass -File C:\kiwisoftware\VeloxPrint\app\update.ps1 -Version 2.0.1
```

<table style="width: 100%; border-collapse: collapse;">
  <thead>
    <tr style="border-top: 1px solid #e6e8ef; border-bottom: 1px solid #e6e8ef;">
      <th style="text-align: left; padding: 6px 10px; white-space: nowrap;">Step</th>
      <th style="text-align: left; padding: 6px 10px;">What <code>update.ps1</code> does</th>
    </tr>
  </thead>
  <tbody>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">1. Check</td>
      <td style="padding: 6px 10px;">Refuses to run without administrator rights or if <code>app\</code> contains local changes</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">2. Fetch</td>
      <td style="padding: 6px 10px;"><code>git fetch</code> before anything is stopped. If the server is unreachable, the service keeps running. Already on the target: nothing to do.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">3. Stop</td>
      <td style="padding: 6px 10px;">Calls <code>--stop</code> for every scheduled task that runs from this folder (with its <code>--config</code>). Running print jobs finish, the outbox is flushed. Waits up to 90 s until no process runs from <code>app\bin</code>.</td>
    </tr>
    <tr style="border-bottom: 1px solid #e6e8ef;">
      <td style="padding: 6px 10px; white-space: nowrap;">4. Switch</td>
      <td style="padding: 6px 10px;">Checks out the newest release (<code>origin/main</code>) or the tag <code>v&lt;Version&gt;</code></td>
    </tr>
    <tr>
      <td style="padding: 6px 10px; white-space: nowrap;">5. Start</td>
      <td style="padding: 6px 10px;">Starts the scheduled tasks again that were running before</td>
    </tr>
  </tbody>
</table>

1. Releases are git tags (`v2.0.1`). `git -C C:\kiwisoftware\VeloxPrint\app log --oneline` shows the source commit of every release.
2. New settings are added to `config.json` with their defaults on the next start.
3. Never change files inside `app\`. The script refuses to update a modified folder. Settings belong into `data\`.

---

<h3 id="multiple" style="color: #203671; margin-top: 2.2em;">Several instances on one machine</h3>

Each instance needs its own configuration file. Its name becomes the prefix of all files of the instance, so several instances can share one data folder:

```
data\config.json               default instance
data\lager-nord.json           second instance
data\lager-nord.secrets.json
data\lager-nord.state.db
data\logs\lager-nord\
```

```powershell
$exe = "C:\kiwisoftware\VeloxPrint\app\bin\kiwisoftware.VeloxFactory.PrintService.App.exe"
& $exe --config C:\kiwisoftware\VeloxPrint\data\lager-nord.json                                   # window of this instance
& $exe --config C:\kiwisoftware\VeloxPrint\data\lager-nord.json --install-task --user .\svc-veloxprint
```

The task of that instance is called `VeloxFactory Print Service (lager-nord)`. Give every instance its own broadcast ids.

</div>