This commit is contained in:
224
Career/Microlise/ESS ESP/Remote-Session Script.md
Executable file
224
Career/Microlise/ESS ESP/Remote-Session Script.md
Executable file
@@ -0,0 +1,224 @@
|
||||
---
|
||||
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** — that’s 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 don’t 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 TMC’s `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 that’s 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 |
|
||||
|
||||
Reference in New Issue
Block a user