docs: how another site points these tools at its own ShopDB
The asset reporter and EventSaver are both already built to be repointed - the server URL, the API key and the targeting are parameters, an ini file and manifest targeting, not code. Nothing said so, so the question "can another shop use this" had no answer that did not involve reading PowerShell. Worked examples for all three deployment paths, because sites have different management planes and the choice is not ours to make: Intune (a remediation for the reporter, a Win32 app for the screensaver, plus a Machine Configuration/DSC form for estates already governed that way), a GE-Enforce manifest entry, and manual installation for a pilot or a single bay. The two traps are written down rather than left to be discovered. EventSaver falls back to a path compiled into the binary when its ini is missing, and that path belongs to the reference site - a missing ini is not a neutral default. And a config enforced by hash reverts a hand edit on the next cycle, which is the feature working correctly and reads exactly like a bug. Also notes the reporter's -ApiUrl default still points at the reference site, so every example passes it explicitly until that is fixed.
This commit is contained in:
@@ -83,6 +83,14 @@ ADR-007 and ADR-002.
|
|||||||
returning nothing and leaving the caller to guess.
|
returning nothing and leaving the caller to guess.
|
||||||
- The display client module updates itself through the manifest, so a client
|
- The display client module updates itself through the manifest, so a client
|
||||||
change no longer means hands on every kiosk.
|
change no longer means hands on every kiosk.
|
||||||
|
- `docs/ADOPTING-AT-ANOTHER-SITE.md`: how another site repoints the asset
|
||||||
|
reporter and the EventSaver screensaver at its own ShopDB, with worked
|
||||||
|
examples for Intune (including Machine Configuration/DSC), a GE-Enforce
|
||||||
|
manifest entry, and manual installation. Both tools were already built to be
|
||||||
|
repointed - the URL, the key and the targeting are inputs - but nothing said
|
||||||
|
so, and the two things that catch people out are written down: EventSaver's
|
||||||
|
compiled-in fallback path is not neutral, and a config enforced by hash
|
||||||
|
reverts a hand edit by design.
|
||||||
- `docs/PROJECT-MAP.md`, generated by `scripts/gen_project_map.py`: versions,
|
- `docs/PROJECT-MAP.md`, generated by `scripts/gen_project_map.py`: versions,
|
||||||
the plugin inventory, every Alembic chain head, the ADR index and the size of
|
the plugin inventory, every Alembic chain head, the ADR index and the size of
|
||||||
the codebase, derived from the code. The hand-written equivalents in CLAUDE.md
|
the codebase, derived from the code. The hand-written equivalents in CLAUDE.md
|
||||||
|
|||||||
366
docs/ADOPTING-AT-ANOTHER-SITE.md
Normal file
366
docs/ADOPTING-AT-ANOTHER-SITE.md
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
# Adopting the fleet tools at another site
|
||||||
|
|
||||||
|
Two tools run on shop-floor PCs and talk to a ShopDB instance: the **asset
|
||||||
|
reporter**, which posts what a PC is to the collector API, and **EventSaver**,
|
||||||
|
a screensaver that shows a slideshow served by ShopDB. Both are designed to be
|
||||||
|
repointed at another site's server. This page is how.
|
||||||
|
|
||||||
|
Neither tool is site-specific by design. What is site-specific is the URL, the
|
||||||
|
API key, and which PCs it runs on - and all three are inputs, not code.
|
||||||
|
|
||||||
|
> **Prerequisite.** The reporter's `-ApiUrl` parameter still carries a default
|
||||||
|
> pointing at the reference site's server. Adopt it with an explicit `-ApiUrl`
|
||||||
|
> (every example below does) until that default is removed. See
|
||||||
|
> [ADR-015](adr/ADR-015-site-specific-configuration.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part 1: the asset reporter
|
||||||
|
|
||||||
|
### What it does
|
||||||
|
|
||||||
|
Runs as SYSTEM, collects hostname, BIOS serial, PC type, logged-in user, IP
|
||||||
|
addresses and the machine number where one is configured, and POSTs them to:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST https://<your-shopdb>/api/collector/computers
|
||||||
|
X-API-Key: <collector token>
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
The payload contract is [COLLECTOR-INTEGRATION.md](COLLECTOR-INTEGRATION.md) and
|
||||||
|
[ADR-006](adr/ADR-006-collector-contract.md). A field your site does not collect
|
||||||
|
is simply absent; the server upserts on `hostname` and leaves the rest alone.
|
||||||
|
|
||||||
|
### What you must provide
|
||||||
|
|
||||||
|
| Input | Where it comes from |
|
||||||
|
|---|---|
|
||||||
|
| Server URL | `-ApiUrl https://<your-shopdb>/api/collector/computers` |
|
||||||
|
| API key | `-ApiKey`, or `HKLM:\SOFTWARE\GE\ShopDB` value `CollectorKey` |
|
||||||
|
|
||||||
|
### Minting the key on your ShopDB
|
||||||
|
|
||||||
|
Create a **managed personal access token scoped to `collector.ingest` and
|
||||||
|
nothing else**, and use it as the `X-API-Key` value. That scope authorises the
|
||||||
|
collector ingest API and no normal route, so a token recovered off a shop-floor
|
||||||
|
PC cannot read your asset register. A shared `COLLECTOR_API_KEY` environment
|
||||||
|
variable also works and is simpler for a pilot, but it cannot be rotated per
|
||||||
|
fleet or revoked individually.
|
||||||
|
|
||||||
|
### Deploying it
|
||||||
|
|
||||||
|
The three paths below are alternatives - pick one. All of them end with the same
|
||||||
|
two facts on the PC: the script exists somewhere it can run from, and the key is
|
||||||
|
in the registry.
|
||||||
|
|
||||||
|
#### Option A: Microsoft Intune
|
||||||
|
|
||||||
|
**A1. The key, as a platform script.** Devices > Scripts and remediations >
|
||||||
|
Platform scripts > Add > Windows 10 and later. Run as SYSTEM, do not run in the
|
||||||
|
64-bit context only.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Set-ShopdbCollectorKey.ps1 (Intune platform script, runs once per device)
|
||||||
|
$RegPath = 'HKLM:\SOFTWARE\GE\ShopDB'
|
||||||
|
$Key = 'shopdb_pat_REPLACE_WITH_YOUR_TOKEN'
|
||||||
|
if (-not (Test-Path $RegPath)) { New-Item -Path $RegPath -Force | Out-Null }
|
||||||
|
$current = (Get-ItemProperty -Path $RegPath -Name CollectorKey -ErrorAction SilentlyContinue).CollectorKey
|
||||||
|
if ($current -ne $Key) { Set-ItemProperty -Path $RegPath -Name CollectorKey -Value $Key }
|
||||||
|
exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Putting a token in an Intune script body means anyone who can read the Intune
|
||||||
|
configuration can read the token. That is an argument for the `collector.ingest`
|
||||||
|
scope, not against Intune: the blast radius of that token is one API.
|
||||||
|
|
||||||
|
**A2. The reporter, as a remediation on a schedule.** Devices > Scripts and
|
||||||
|
remediations > Remediations. A remediation is the natural fit because it re-runs
|
||||||
|
on a schedule, which is exactly what reporting is.
|
||||||
|
|
||||||
|
*Detection script* - forces the remediation to run every cycle:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Always "not compliant": reporting is not a state to converge on, it is an
|
||||||
|
# event that should happen on every schedule tick.
|
||||||
|
exit 1
|
||||||
|
```
|
||||||
|
|
||||||
|
*Remediation script* - the reporter itself, with your URL:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
& "$PSScriptRoot\Report-AssetToShopDB.ps1" `
|
||||||
|
-ApiUrl 'https://shopdb.example.net/api/collector/computers'
|
||||||
|
exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Assign it with a daily schedule. Run as SYSTEM, 64-bit.
|
||||||
|
|
||||||
|
**A3. Intune with DSC (Machine Configuration).** If your estate is already
|
||||||
|
governed by Azure Machine Configuration, express the *key* as configuration and
|
||||||
|
leave the *reporting* to a scheduled task, because a report is an event and DSC
|
||||||
|
converges state:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Configuration ShopdbCollector
|
||||||
|
{
|
||||||
|
Import-DscResource -ModuleName PSDesiredStateConfiguration
|
||||||
|
|
||||||
|
Node localhost
|
||||||
|
{
|
||||||
|
Registry CollectorKey
|
||||||
|
{
|
||||||
|
Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\GE\ShopDB'
|
||||||
|
ValueName = 'CollectorKey'
|
||||||
|
ValueData = 'shopdb_pat_REPLACE_WITH_YOUR_TOKEN'
|
||||||
|
ValueType = 'String'
|
||||||
|
Ensure = 'Present'
|
||||||
|
}
|
||||||
|
|
||||||
|
Registry CollectorUrl
|
||||||
|
{
|
||||||
|
Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\GE\ShopDB'
|
||||||
|
ValueName = 'BaseUrl'
|
||||||
|
ValueData = 'https://shopdb.example.net'
|
||||||
|
ValueType = 'String'
|
||||||
|
Ensure = 'Present'
|
||||||
|
}
|
||||||
|
|
||||||
|
Script ReportingTask
|
||||||
|
{
|
||||||
|
GetScript = { @{ Result = (Get-ScheduledTask -TaskName 'ShopDB asset report' -ErrorAction SilentlyContinue) } }
|
||||||
|
TestScript = { [bool](Get-ScheduledTask -TaskName 'ShopDB asset report' -ErrorAction SilentlyContinue) }
|
||||||
|
SetScript = {
|
||||||
|
$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
|
||||||
|
-Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\ProgramData\ShopDB\Report-AssetToShopDB.ps1" -ApiUrl "https://shopdb.example.net/api/collector/computers"'
|
||||||
|
$trigger = New-ScheduledTaskTrigger -Daily -At 7am
|
||||||
|
Register-ScheduledTask -TaskName 'ShopDB asset report' -Action $action `
|
||||||
|
-Trigger $trigger -User 'SYSTEM' -RunLevel Highest -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: GE-Enforce
|
||||||
|
|
||||||
|
If you already run the GE-Enforce client, this is one manifest entry, and it is
|
||||||
|
how the reference site does it. `Type: PS1` with `DetectionMethod: Always` runs
|
||||||
|
the script from the share every cycle with no local copy and no hash to bump
|
||||||
|
when the script changes.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"_comment": "Reports host, BIOS serial, pc-type, logged-in user, IPs and machine number to ShopDB every cycle, as SYSTEM, straight off the share.",
|
||||||
|
"Name": "Report asset to ShopDB",
|
||||||
|
"Type": "PS1",
|
||||||
|
"Script": "apps/Report-AssetToShopDB.ps1",
|
||||||
|
"Args": "-ApiUrl https://shopdb.example.net/api/collector/computers",
|
||||||
|
"DetectionMethod": "Always"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Provision the key with a second entry, ordered **before** it, so the key is
|
||||||
|
present the same cycle the first report fires:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"_comment": "Writes the collector key from an ACL'd share file. The token is NOT in this manifest - manifests sync broadly. Rotate by replacing configs/collector-key.txt on the share; every PC picks it up next cycle.",
|
||||||
|
"Name": "Provision the ShopDB collector key",
|
||||||
|
"Type": "PS1",
|
||||||
|
"Script": "scripts/Set-CollectorKey.ps1",
|
||||||
|
"DetectionMethod": "Always"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep the token in `configs/collector-key.txt` on your share, locked to SYSTEM
|
||||||
|
and administrators - not in the manifest JSON.
|
||||||
|
|
||||||
|
#### Option C: manual
|
||||||
|
|
||||||
|
For a pilot, a single bay, or an estate with no management plane:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# As administrator, once per PC.
|
||||||
|
New-Item -Path 'C:\ProgramData\ShopDB' -ItemType Directory -Force | Out-Null
|
||||||
|
Copy-Item .\Report-AssetToShopDB.ps1 'C:\ProgramData\ShopDB\'
|
||||||
|
|
||||||
|
New-Item -Path 'HKLM:\SOFTWARE\GE\ShopDB' -Force | Out-Null
|
||||||
|
Set-ItemProperty -Path 'HKLM:\SOFTWARE\GE\ShopDB' -Name CollectorKey `
|
||||||
|
-Value 'shopdb_pat_REPLACE_WITH_YOUR_TOKEN'
|
||||||
|
|
||||||
|
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument @'
|
||||||
|
-NoProfile -ExecutionPolicy Bypass -File "C:\ProgramData\ShopDB\Report-AssetToShopDB.ps1" -ApiUrl "https://shopdb.example.net/api/collector/computers"
|
||||||
|
'@
|
||||||
|
$trigger = New-ScheduledTaskTrigger -Daily -At 7am
|
||||||
|
Register-ScheduledTask -TaskName 'ShopDB asset report' -Action $action -Trigger $trigger `
|
||||||
|
-User 'SYSTEM' -RunLevel Highest -Force
|
||||||
|
|
||||||
|
Start-ScheduledTask -TaskName 'ShopDB asset report'
|
||||||
|
```
|
||||||
|
|
||||||
|
Lock down `C:\ProgramData\ShopDB` if you put it there: a script a user can edit,
|
||||||
|
run by SYSTEM on a schedule, is a local privilege escalation. Break inheritance
|
||||||
|
and grant Administrators and SYSTEM only.
|
||||||
|
|
||||||
|
### Verifying
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-RestMethod -Uri 'https://shopdb.example.net/api/computers/by-hostname/<HOSTNAME>'
|
||||||
|
```
|
||||||
|
|
||||||
|
The PC should exist with its serial, type and last-reported timestamp. The
|
||||||
|
script also logs to `C:\Logs\Shopfloor`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part 2: EventSaver
|
||||||
|
|
||||||
|
### What it does
|
||||||
|
|
||||||
|
A Windows screensaver (`EventSaver.scr`) that shows a slideshow. It reads
|
||||||
|
`EventSaver.ini` from the directory it lives in, **on every launch**, so
|
||||||
|
retargeting it needs no recompile:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# HTTP mode (recommended): pull slides from ShopDB, cache locally. No share.
|
||||||
|
url=https://shopdb.example.net/api/slides/feed?surface=shopfloor
|
||||||
|
|
||||||
|
# Folder mode (fallback): used only when url is blank. SMB or local path.
|
||||||
|
# folder=\\fileserver\shopfloor\tv
|
||||||
|
|
||||||
|
interval=10 # seconds per image, when a slide carries no time of its own
|
||||||
|
shuffle=0 # 1 = random, 0 = ordered
|
||||||
|
fadems=600 # crossfade length, reserved
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP mode is the one to adopt: slides are managed in ShopDB (Slides), and the
|
||||||
|
screensaver caches them locally, so a PC that cannot reach the server keeps
|
||||||
|
showing the last set instead of going black.
|
||||||
|
|
||||||
|
### The two things that catch people out
|
||||||
|
|
||||||
|
**The compiled-in fallback is not yours.** If `EventSaver.ini` is missing or
|
||||||
|
both `url` and `folder` are blank, the binary falls back to a folder path
|
||||||
|
compiled into `EventSaver.cs`, which is the reference site's file server. Ship
|
||||||
|
the ini. A missing ini is not a neutral default.
|
||||||
|
|
||||||
|
**If you enforce the ini by hash, your own edits revert.** The reference
|
||||||
|
manifest pins `EventSaver.ini` with `DetectionMethod: Hash`, which is what makes
|
||||||
|
a retune propagate to the fleet automatically - and equally means a hand edit on
|
||||||
|
one PC is undone next cycle. That is the feature working. Edit the copy on
|
||||||
|
**your** share and update `DetectionValue` to its new SHA-256:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
(Get-FileHash .\configs\EventSaver.ini -Algorithm SHA256).Hash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploying it
|
||||||
|
|
||||||
|
#### Option A: Intune
|
||||||
|
|
||||||
|
Package the three files as a Win32 app (`EventSaver.scr`, `EventSaver.ini`, and
|
||||||
|
the enable script) with this install command:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# install.ps1 for the Win32 app
|
||||||
|
Copy-Item .\EventSaver.scr 'C:\Windows\System32\EventSaver.scr' -Force
|
||||||
|
Copy-Item .\EventSaver.ini 'C:\Windows\System32\EventSaver.ini' -Force
|
||||||
|
exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Detection rule: file `C:\Windows\System32\EventSaver.scr` exists **and** matches
|
||||||
|
the expected SHA-256, so a changed binary reinstalls.
|
||||||
|
|
||||||
|
The screensaver itself is per-user, so set it with a configuration profile
|
||||||
|
(Settings catalog > Screen saver) or a user-context script:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Set-ItemProperty 'HKCU:\Control Panel\Desktop' -Name SCRNSAVE.EXE -Value 'C:\Windows\System32\EventSaver.scr'
|
||||||
|
Set-ItemProperty 'HKCU:\Control Panel\Desktop' -Name ScreenSaveActive -Value '1'
|
||||||
|
Set-ItemProperty 'HKCU:\Control Panel\Desktop' -Name ScreenSaveTimeOut -Value '480'
|
||||||
|
```
|
||||||
|
|
||||||
|
With Machine Configuration/DSC, express the two files with `File` resources and
|
||||||
|
the screensaver with a `Registry` resource in the user hive - noting that DSC
|
||||||
|
runs as SYSTEM, so a per-user setting needs the logged-on user's hive or a
|
||||||
|
default-user template, which is usually more trouble than a login script.
|
||||||
|
|
||||||
|
#### Option B: GE-Enforce
|
||||||
|
|
||||||
|
Three entries, which is exactly how the reference fleet does it. Note the
|
||||||
|
per-PC-type targeting: a kiosk showing a live dashboard must **not** get a
|
||||||
|
screensaver over the top of it.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Name": "EventSaver screensaver (binary)",
|
||||||
|
"Type": "File",
|
||||||
|
"Source": "apps/EventSaver.scr",
|
||||||
|
"Destination": "C:\\Windows\\System32\\EventSaver.scr",
|
||||||
|
"DetectionMethod": "Hash",
|
||||||
|
"DetectionPath": "C:\\Windows\\System32\\EventSaver.scr",
|
||||||
|
"DetectionValue": "<sha256 of your staged .scr>",
|
||||||
|
"PCTypes": ["gea-shopfloor-common"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "EventSaver screensaver (config)",
|
||||||
|
"Type": "File",
|
||||||
|
"Source": "configs/EventSaver.ini",
|
||||||
|
"Destination": "C:\\Windows\\System32\\EventSaver.ini",
|
||||||
|
"DetectionMethod": "Hash",
|
||||||
|
"DetectionPath": "C:\\Windows\\System32\\EventSaver.ini",
|
||||||
|
"DetectionValue": "<sha256 of YOUR .ini, pointing at YOUR shopdb>",
|
||||||
|
"PCTypes": ["gea-shopfloor-common"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "EventSaver enable (per-user screensaver)",
|
||||||
|
"Type": "PS1",
|
||||||
|
"Script": "scripts/Set-EventSaverScreensaver.ps1",
|
||||||
|
"Args": "-TimeoutSeconds 480",
|
||||||
|
"DetectionMethod": "Always",
|
||||||
|
"PCTypes": ["gea-shopfloor-common"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option C: manual
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Copy-Item .\EventSaver.scr 'C:\Windows\System32\' -Force
|
||||||
|
Copy-Item .\EventSaver.ini 'C:\Windows\System32\' -Force # with YOUR url=
|
||||||
|
|
||||||
|
# Per user, in the user's own session:
|
||||||
|
Set-ItemProperty 'HKCU:\Control Panel\Desktop' -Name SCRNSAVE.EXE -Value 'C:\Windows\System32\EventSaver.scr'
|
||||||
|
Set-ItemProperty 'HKCU:\Control Panel\Desktop' -Name ScreenSaveActive -Value '1'
|
||||||
|
Set-ItemProperty 'HKCU:\Control Panel\Desktop' -Name ScreenSaveTimeOut -Value '480'
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `EventSaver.scr /c` to see which source it resolved and where it is caching.
|
||||||
|
|
||||||
|
### Verifying
|
||||||
|
|
||||||
|
Open the feed in a browser from the PC itself:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://shopdb.example.net/api/slides/feed?surface=shopfloor
|
||||||
|
```
|
||||||
|
|
||||||
|
It is a public endpoint - the screensaver has no credentials - and returns the
|
||||||
|
playlist with per-slide durations. An empty `slides` array means slides have not
|
||||||
|
been uploaded for that surface, not that the PC is misconfigured.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Which path to choose
|
||||||
|
|
||||||
|
| You have | Use |
|
||||||
|
|---|---|
|
||||||
|
| Intune, no GE-Enforce | Option A. A remediation for the reporter, a Win32 app for EventSaver. |
|
||||||
|
| GE-Enforce | Option B. One manifest entry each, and the fleet converges on its own cycle. |
|
||||||
|
| Neither, or a pilot of a few bays | Option C, then move to A or B once it earns its place. |
|
||||||
|
|
||||||
|
GE-Enforce and Intune are not exclusive. The reference site uses Intune for
|
||||||
|
enrolment and imaging and GE-Enforce for shop-floor configuration state, because
|
||||||
|
Intune is not on the shop floor network path in the same way. If you have both,
|
||||||
|
the deciding question is which one you would look at first to answer "why is
|
||||||
|
this bay wrong".
|
||||||
@@ -12,6 +12,13 @@ specialists, and they ask assistants for help. Two documents are authoritative:
|
|||||||
- `docs/OPERATE-WINDOWS.md` - restart, logs, backups, upgrades, troubleshooting.
|
- `docs/OPERATE-WINDOWS.md` - restart, logs, backups, upgrades, troubleshooting.
|
||||||
Both ship in `docs/` inside the install directory on every installed server.
|
Both ship in `docs/` inside the install directory on every installed server.
|
||||||
|
|
||||||
|
Another site adopting the shop-floor tools - the asset reporter that feeds the
|
||||||
|
collector API, and the EventSaver screensaver - should read
|
||||||
|
`docs/ADOPTING-AT-ANOTHER-SITE.md`. It has worked deployment examples for Intune
|
||||||
|
(including Machine Configuration/DSC), GE-Enforce and manual installation.
|
||||||
|
Neither tool is site-specific: the server URL, the API key and the targeting are
|
||||||
|
inputs, not code.
|
||||||
|
|
||||||
Do NOT walk someone through `docs/INSTALL-WINDOWS-IIS.md` or
|
Do NOT walk someone through `docs/INSTALL-WINDOWS-IIS.md` or
|
||||||
`docs/DEPLOY-WINDOWS-IIS.md` for a new site. Those are the MANUAL procedure, kept
|
`docs/DEPLOY-WINDOWS-IIS.md` for a new site. Those are the MANUAL procedure, kept
|
||||||
only for hand-built servers that predate the installer; following them produces a
|
only for hand-built servers that predate the installer; following them produces a
|
||||||
|
|||||||
Reference in New Issue
Block a user