143 lines
8.1 KiB
Markdown
143 lines
8.1 KiB
Markdown
---
|
|
name: drive-map
|
|
description: "Reliably create/repoint Windows network drive maps on a remote endpoint via GuruRMM: runs in the user session (not SYSTEM), stores per-host creds with cmdkey, persistent maps, repoints stale NAS shortcuts, verifies access. Triggers: map a drive, drive mapping, repoint share."
|
|
---
|
|
|
|
# drive-map — remote drive maps & share shortcuts that actually stick
|
|
|
|
`net use` from RMM "doesn't work" for predictable reasons, and we kept re-solving
|
|
them by hand. This skill encodes the fixes so a repoint is one command.
|
|
|
|
## The four things that make mapped drives fight you (and the fix this skill bakes in)
|
|
|
|
1. **SYSTEM context is invisible to the user.** RMM runs as SYSTEM by default. A
|
|
drive mapped/shortcut written as SYSTEM lands in SYSTEM's profile, NOT the
|
|
logged-on user's — so the user sees nothing and you think it "failed."
|
|
**Fix:** every operation here runs `context: user_session`. It uses the user's
|
|
token, `[Environment]::GetFolderPath('Desktop')`, and the user's credential
|
|
vault. **Requires an active (logged-on) desktop session** — locked is usually
|
|
OK, logged-off is not. If no session, the skill reports it instead of silently
|
|
no-opping.
|
|
2. **Workgroup PC -> domain share = Access Denied** unless a credential is stored.
|
|
A machine that is not domain-joined (e.g. `DESKTOP-LPOPV30`, WORKGROUP, local
|
|
login) has no Kerberos/NTLM identity the server trusts. It must present a
|
|
**stored** credential for that exact server host.
|
|
**Fix:** `cred`/`migrate` run `cmdkey /add:<HOST> /user:<DOMAIN\user> /pass:…`
|
|
in the user session so the credential lands in the user's Credential Manager,
|
|
keyed to the server host used in the UNC. (This is precisely how Karen reaches
|
|
the NAS today: `cmdkey` target `CASCADESDS`, user `karen rossini`.)
|
|
3. **Maps vanish on logoff.** `net use` without persistence is gone next login.
|
|
**Fix:** persistent by default (`/persistent:yes`); cmdkey credential is
|
|
persistent too, so the map reconnects without a prompt.
|
|
4. **Stale NAS shortcuts/maps linger.** The old `\\cascadesds\…` shortcut and the
|
|
live connection confuse users mid-migration.
|
|
**Fix:** `--remove-old <UNC-prefix>` repoints or deletes desktop shortcuts that
|
|
target the old prefix, drops the old drive letter, and removes the old cmdkey.
|
|
|
|
## Credential handling (read this)
|
|
|
|
- The password is read from the **SOPS vault** (`--cred-vault` + `--cred-field`),
|
|
never passed as plaintext on the command line (CLAUDE.md rule).
|
|
- **Caveat — it transits RMM.** cmdkey needs the plaintext on the endpoint, so the
|
|
password appears in the dispatched command text, which RMM stores in command
|
|
history (admin-only, internal). For a sensitive account, purge that history
|
|
entry afterward or rotate. The skill never prints the password to stdout/errorlog.
|
|
- For a domain account whose password we don't have, the correct move on a DC we
|
|
control is to set it deliberately and vault it first — do that, then run `cred`.
|
|
|
|
## Usage
|
|
|
|
```
|
|
bash .claude/skills/drive-map/scripts/drive-map.sh <verb> --host <name> [opts]
|
|
```
|
|
|
|
| Verb | Does |
|
|
|------|------|
|
|
| `verify` | Test-Path the target UNC/letter from the user session; report reachable or not. Read-only. |
|
|
| `cred` | Store a per-host credential (`cmdkey /add`) so the user can reach a server. |
|
|
| `map` | Map a drive letter to `\\HOST\Share` (persistent), optionally storing the cred first. |
|
|
| `shortcut` | Drop a desktop `.lnk` to a UNC target (optionally pin to Quick Access). |
|
|
| `unmap` | Remove a drive letter and/or desktop shortcuts pointing at `--remove-old`, and the old cmdkey. |
|
|
| `migrate` | The all-in-one repoint: remove/repoint old shortcut, store new cred, map and/or shortcut the new target, verify. |
|
|
|
|
### Options
|
|
|
|
```
|
|
--host NAME RMM hostname (required; resolved to agent id, must be Windows + online)
|
|
--server '\\HOST\Share' target share for a drive map
|
|
--target '\\HOST\Share\Sub' UNC for a shortcut / verify
|
|
--letter X drive letter for map/unmap (no colon)
|
|
--name NAME shortcut filename (default: leaf of --target)
|
|
--cred-user 'DOMAIN\user' identity to store (e.g. CASCADES\karen.rossini)
|
|
--cred-vault PATH sops path holding the password (e.g. clients/cascades-tucson/...sops.yaml)
|
|
--cred-field FIELD field within the vault entry (default: credentials.password)
|
|
--remove-old '\\oldhost\share' prefix of stale shortcuts/connections to strip (migrate/unmap)
|
|
--quick-access also pin --target to Quick Access (best-effort; Shell verb)
|
|
--no-persistent non-persistent map (default is persistent)
|
|
--profile-hint NAME substring to disambiguate the user when several are logged on
|
|
--dry-run print the generated PowerShell, do not dispatch
|
|
--timeout N dispatch timeout seconds (default 90)
|
|
```
|
|
|
|
### Examples
|
|
|
|
```bash
|
|
# Karen: workgroup PC, repoint NAS ALDocs shortcut to CS-SERVER, store her domain cred
|
|
bash .claude/skills/drive-map/scripts/drive-map.sh migrate \
|
|
--host DESKTOP-LPOPV30 \
|
|
--target '\\CS-SERVER\Server\ALDocs' --name ALDocs --quick-access \
|
|
--remove-old '\\cascadesds\Server' \
|
|
--cred-user 'CASCADES\karen.rossini' \
|
|
--cred-vault clients/cascades-tucson/karen-rossini.sops.yaml
|
|
|
|
# Just check a user can reach the new share
|
|
bash .claude/skills/drive-map/scripts/drive-map.sh verify --host DESKTOP-LPOPV30 \
|
|
--target '\\CS-SERVER\Server\ALDocs'
|
|
|
|
# Map a letter for a domain-joined user (no cred needed)
|
|
bash .claude/skills/drive-map/scripts/drive-map.sh map --host SOME-PC \
|
|
--server '\\CS-SERVER\SalesDept' --letter S
|
|
```
|
|
|
|
## CRITICAL — the RMM `verify` is NOT authoritative (read this)
|
|
|
|
`verify` (and any RMM-dispatched `net use`/`net view`/`Test-Path`/`Get-SmbConnection`)
|
|
runs in an agent-injected process that does **not** share the user's real interactive
|
|
network-logon session. It **false-negatives**: it can report `error 67 (BAD_NETWORK_NAME)`
|
|
/ `RPC 1702` / "not reachable" for shares that are **actually fine**. Proven at Cascades
|
|
2026-06-26 — RMM tests failed against a user's daily-use NAS and showed "no connections"
|
|
for a client that had a live server-side session with open files; an entire "CS-SERVER SMB
|
|
outage" investigation turned out to be this artifact (the server was healthy: `Get-SmbSession`
|
|
showed 7 users / 30 open files). It is **inconsistent**, not always-wrong — it passes once a
|
|
cmdkey is freshly stored in the active session (as in the successful Karen ALDocs migrate).
|
|
|
|
**Therefore:**
|
|
- A `verify` **failure is NOT proof of a problem.** Never diagnose a "server/share outage"
|
|
from RMM client-side SMB results. Validate the SERVER with `Get-SmbSession` /
|
|
`Get-SmbOpenFile` (server truth), or do a REAL interactive test on the endpoint.
|
|
- A `verify` **success is meaningful** (reachable confirmed). Treat the cred+shortcut
|
|
operations (cmdkey, `.lnk`, Quick Access) as the real deliverable — those persist
|
|
reliably — and have a human confirm interactively when possible.
|
|
- See errorlog friction `rmm/smb-testing` and memory `project_cascades_network_segments`.
|
|
|
|
## Hard rules
|
|
|
|
- **`verify` first and last, but treat a FAILURE as inconclusive** (see CRITICAL above) —
|
|
confirm interactively before declaring either success or a server problem. A green
|
|
`net use` line is not proof of access; a red one is not proof of failure.
|
|
- **One user at a time, with a session.** If no interactive user is logged on, stop
|
|
and say so; do not "succeed" against SYSTEM's profile.
|
|
- **Additive to permissions.** This skill never touches share/NTFS ACLs. If the user
|
|
lacks rights on the target, fix that on the server side (group membership), not here.
|
|
- **Confirm before mutating a live user's desktop** during business hours unless told
|
|
to proceed — it is outward-facing (the user sees their desktop change).
|
|
- On any genuine failure the script calls `log-skill-error.sh` (per CLAUDE.md).
|
|
|
|
## Implementation
|
|
|
|
- `scripts/drive-map.sh` — bash orchestrator: RMM auth (`rmm-auth.sh`), agent
|
|
resolution, vault read for the password, generates the endpoint PowerShell,
|
|
dispatches it `context: user_session`, polls, reports. All endpoint logic runs
|
|
in the user session by design (see fix #1).
|
|
- No endpoint install; the PowerShell is generated per call and dispatched via RMM.
|