Files
vault/Career/Microlise/ESS ESP/Remote-Session Script.md
Zaine 129ce1442b
Some checks failed
Build Quartz Notes / build (push) Failing after 20s
13
2026-07-13 09:16:09 +01:00

225 lines
7.0 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
note type:
- ess
- note
date: 2026-06-11
done:
---
## Reference script (TMC `Session.ps1`)
### 1. What is the pool key?
The **server name** string (`$serverName`).
```mermaid
flowchart LR
serverName["serverName: APP01"]
pool["remoteSessionPool hashtable"]
session["PSSession object"]
serverName -->|"used as key"| pool
pool --> session
```
Same server name → same pool entry. Different server → different entry.
**Caveat for your task:** if the same server could be reached with **different credentials**, keying only on server name can return the wrong session. For a first version, matching the reference (key = server name) is fine if credentials are consistent per server.
---
### 2. What happens on the second call for the same server?
```mermaid
sequenceDiagram
participant Caller
participant GetRemoteSession as Get-RemoteSession
participant Pool
participant NewPSSession as New-PSSession
Caller->>GetRemoteSession: serverName = APP01
GetRemoteSession->>Pool: lookup APP01
Pool-->>GetRemoteSession: session found
GetRemoteSession-->>Caller: existing session
Note over NewPSSession: not called
```
- Pool lookup hits.
- Logs something like “Using existing remote session”.
- Returns the cached session.
- **`New-PSSession` is not called** — thats the whole point of the pool.
---
### 3. When is `New-PSSession` called vs skipped?
| Condition | Action |
|-----------|--------|
| Pool has an entry for `$serverName` | Skip `New-PSSession`, return cached session |
| Pool has **no** entry for `$serverName` | Call `New-PSSession`, store result in pool, return it |
```mermaid
flowchart TD
start[Get-RemoteSession called]
lookup{Pool contains serverName?}
reuse[Log: using existing session]
create[Log: creating session]
newPs[New-PSSession]
store[Store in pool]
return[Return session]
start --> lookup
lookup -->|yes| reuse --> return
lookup -->|no| create --> newPs --> store --> return
```
**Important:** `Get-RemoteSession` creates/reuses the session. **`Invoke-Command -Session $session`** is a separate step the caller does afterward (e.g. `Test-Path` on the remote box).
---
### 4. What happens when session creation fails? Does that fit ESS?
**In the reference:** if `$session` is falsy after `New-PSSession`, it logs an error and runs **`exit`** (ends the whole PowerShell process).
**In ESS capabilities:** that does **not** fit. Look at [`Remove-Folder.psm1`](deploy/scripts/modules/capabilities/Remove-Folder.psm1) — failures use **`throw`**, not `exit`.
| | TMC reference | ESS pattern |
|---|---------------|-------------|
| Failure | `exit` | `throw "message"` |
| Why | Script runner stops everything | Pester, pipelines, and orchestrators can catch/handle it |
For your module: log with `Write-Log -Level ERROR`, then **throw** so deployment fails cleanly and tests can use `Should -Throw`.
---
## Design decisions (for your implementation)
### Parameters
Match the reference, adapted to ESS style:
- **`ServerName`** (mandatory) — pool key and `New-PSSession` target.
- **`Credential`** (optional) — pass through when present; omit when using default/current-user auth.
Do **not** put remote script logic (e.g. `Test-Path`) inside `Get-RemoteSession`. Callers get a session, then run `Invoke-Command` themselves.
---
### Pool scope — where does the hashtable live?
**At module scope** in the `.psm1`, **above** the function — not inside the function body.
```mermaid
flowchart TB
subgraph psm1 [Get-RemoteSession.psm1]
poolVar["script-scoped pool hashtable"]
func[Get-RemoteSession function]
poolVar --> func
end
call1[First call] --> func
call2[Second call] --> func
func --> poolVar
```
If the pool is **inside** the function, it is recreated every call and caching never works.
Use **`$script:`** scope so the pool belongs to the module instance, not the global session (unless you deliberately want global — you dont for this task).
---
### Naming: `Get-RemoteSession` vs `New-RemoteSession`
| Verb | Meaning here |
|------|----------------|
| `New-*` | Always creates something new |
| `Get-*` | Retrieves existing **or** obtains one if needed |
Your function is “get from pool, or create and cache” → **`Get-RemoteSession`** is the right approved verb.
---
### Logging
Use **`Write-Log`** (from [`Core.Logging.psm1`](deploy/scripts/modules/core/Core.Logging.psm1)), not TMCs `Logging`.
Worth logging:
- **INFO** — “Using existing…” vs “Creating…”
- **INFO** — elapsed time for **creation only** (optional but matches the reference and helps debug slow WinRM)
- **ERROR** — before you throw on failure
---
### Failure behavior
```mermaid
flowchart LR
fail[New-PSSession fails or returns nothing]
log[Write-Log ERROR]
throwNode[throw with clear message]
fail --> log --> throwNode
```
No `exit`. Callers and Pester expect exceptions, not process termination.
---
### Pool key edge case (same server, different credentials)
Reference keys **only on server name**. Implication:
```mermaid
flowchart TD
callA["Call: APP01 + CredA"] --> pool1[Pool stores APP01 → sessionA]
callB["Call: APP01 + CredB"] --> pool2[Pool returns sessionA]
pool2 --> wrong[Wrong cred — sessionA reused]
```
For learning / v1: **same as reference** is OK if each server always uses one credential set. If thats not true later, the key would need to include something credential-related — out of scope unless your manifests require it.
---
## How this connects to `Invoke-Command`
```mermaid
sequenceDiagram
participant Step as Deployment step
participant Get as Get-RemoteSession
participant IC as Invoke-Command
Step->>Get: ServerName, Credential
Get-->>Step: $session
Step->>IC: -Session $session -ScriptBlock { Test-Path ... }
IC-->>Step: $fileExists
```
`Get-RemoteSession` = connection management.
`Invoke-Command` = run code on the remote machine.
---
## Testing note (relevant to your attached snippet)
For “fails when session cannot be created”, assert like other capabilities:
- **`{ Get-RemoteSession ... } | Should -Throw`** — proves the function throws.
- Optionally assert **`Write-Log`** was called with `-Level ERROR`.
`Should -Invoke Throw` is **not** valid Pester — `throw` is a language statement, not a mockable cmdlet. Same idea as [`Remove-Folder.Tests.ps1`](deploy/tests/modules/capabilities/Remove-Folder.Tests.ps1): use `Should -Throw` on the script block, and `Should -Invoke Write-Log` for the error log line.
For pool behavior tests: mock **`New-PSSession`**, call the function twice with the same server, expect **`New-PSSession` invoked once**.
---
## One-line summary
| Question | Answer |
|----------|--------|
| Pool key | Server name |
| Second call | Return cached session; no `New-PSSession` |
| When to create | Only when key missing from pool |
| On failure | Reference: `exit`**you:** `Write-Log` + `throw` |
| Pool location | Module-level `$script:` hashtable, not inside the function |