feat: set-token.ps1 + JF LANdata import script

- get-token.ps1: reads token from ~/.ka-note/token.txt, validates JWT expiry
- set-token.ps1: stores token (from arg or clipboard) to ~/.ka-note/token.txt with expiry display
- import-jf-landata.ps1: idempotent import for JF LANdata context (12 topics, 14 history entries)
- MSAL auto-login blocked by missing redirect URI in app registration (documented in get-token.ps1)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
beo3000 2026-02-21 22:18:18 +01:00
parent 3b6ae8c92b
commit a67dc06b30
3 changed files with 204 additions and 43 deletions

View File

@ -1,56 +1,70 @@
<#
.SYNOPSIS
Gets a Bearer token for the Ka-Note production API via MSAL.PS.
Installs MSAL.PS automatically if missing.
Uses cached tokens / refresh tokens browser login only needed on first run
or after token cache is cleared.
Gets a valid Bearer token for the Ka-Note production API.
PREFERRED (fully automatic): Add the redirect URI once in Azure Portal:
App registrations Ka-Note (1aba7af7-...) Authentication
Add platform "Mobile and desktop" URI: https://login.microsoftonline.com/common/oauth2/nativeclient
Then uncomment the MSAL section below.
CURRENT FALLBACK: reads cached token from %USERPROFILE%\.ka-note\token.txt
Store a fresh token there with: .\set-token.ps1 "eyJ..."
.OUTPUTS
Writes the access token string to stdout.
.EXAMPLE
$token = & "$PSScriptRoot\get-token.ps1"
Writes the access token string to stdout (no trailing newline).
#>
param()
$ErrorActionPreference = 'Stop'
$ClientId = '1aba7af7-eec1-4e49-b87e-9f941c0e8630'
$TenantId = '94cf90d7-e9ff-49a1-bc3b-a5b94d3cc8ca'
$Scopes = "api://$ClientId/access"
$tokenFile = Join-Path $env:USERPROFILE '.ka-note\token.txt'
# --- Ensure MSAL.PS is available ---------------------------------------------
if (-not (Get-Module -ListAvailable -Name 'MSAL.PS')) {
Write-Host " [INFO] Installing MSAL.PS module..." -ForegroundColor DarkGray
Install-Module -Name 'MSAL.PS' -Scope CurrentUser -Force -AllowClobber
}
Import-Module MSAL.PS -ErrorAction Stop
# ── Option A: MSAL.PS (uncomment after adding redirect URI in Azure Portal) ───
# Requires one-time Azure Portal step:
# App registrations → 1aba7af7-eec1-4e49-b87e-9f941c0e8630 → Authentication
# → Add platform "Mobile and desktop applications"
# → Redirect URI: https://login.microsoftonline.com/common/oauth2/nativeclient
# → Save
#
# if (-not (Get-Module -ListAvailable MSAL.PS)) {
# Install-Module -Name MSAL.PS -Scope CurrentUser -Force -AllowClobber
# }
# Import-Module MSAL.PS
# $p = @{
# ClientId = '1aba7af7-eec1-4e49-b87e-9f941c0e8630'
# TenantId = '94cf90d7-e9ff-49a1-bc3b-a5b94d3cc8ca'
# Scopes = 'api://1aba7af7-eec1-4e49-b87e-9f941c0e8630/access'
# }
# try { $r = Get-MsalToken @p -Silent 2>$null }
# catch { $r = Get-MsalToken @p -Interactive }
# Write-Output $r.AccessToken
# return
# --- Acquire token -----------------------------------------------------------
$params = @{
ClientId = $ClientId
TenantId = $TenantId
Scopes = $Scopes
}
$result = $null
# 1. Try silent first (uses cached access token or refresh token)
try {
$result = Get-MsalToken @params -Silent 2>$null
} catch {
# No cached token or refresh failed — fall back to interactive
}
# 2. Interactive browser login
if (-not $result) {
Write-Host " [AUTH] Opening browser for login..." -ForegroundColor Yellow
$result = Get-MsalToken @params -Interactive
}
if (-not $result -or -not $result.AccessToken) {
Write-Error "Failed to acquire token."
# ── Option B: cached token file (current default) ────────────────────────────
if (-not (Test-Path $tokenFile)) {
Write-Error "No cached token found. Run: .\set-token.ps1 `"eyJ...`""
exit 1
}
# Output only the token (callers capture via $token = & .\get-token.ps1)
Write-Output $result.AccessToken
$token = (Get-Content $tokenFile -Raw -Encoding UTF8).Trim()
# Check JWT expiry (payload is base64url, second segment)
try {
$parts = $token.Split('.')
$payload = $parts[1]
# Pad base64url to multiple of 4
$pad = 4 - ($payload.Length % 4); if ($pad -ne 4) { $payload += '=' * $pad }
$payload = $payload.Replace('-', '+').Replace('_', '/')
$claims = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payload)) | ConvertFrom-Json
$expUtc = [System.DateTimeOffset]::FromUnixTimeSeconds($claims.exp).UtcDateTime
$remaining = ($expUtc - [System.DateTime]::UtcNow).TotalMinutes
if ($remaining -lt 2) {
Write-Warning "Token expired $(if ($remaining -lt 0) { [math]::Round(-$remaining) + ' min ago' } else { 'in < 2 min' }). Run: .\set-token.ps1 `"eyJ...`""
exit 1
}
Write-Host " Token valid for $([math]::Round($remaining)) min." -ForegroundColor DarkGray
} catch {
Write-Warning "Could not parse token expiry - using as-is."
}
Write-Output $token

View File

@ -0,0 +1,99 @@
<#
.SYNOPSIS
Imports / re-imports "JF: LANdata" into Ka-Note. Idempotent.
.EXAMPLE
.\import-jf-landata.ps1 -Prod
#>
param([switch]$Prod, [switch]$Force)
$ErrorActionPreference = 'Stop'
. "$PSScriptRoot\import-helpers.ps1"
$scripts = $PSScriptRoot
$RepoRoot = Resolve-Path "$PSScriptRoot\..\.."
$workDir = Join-Path $RepoRoot "work"
# ── 1. Download ───────────────────────────────────────────────────────────────
Write-Host "`n[1] Downloading bundle..." -ForegroundColor Cyan
$dlArgs = @('-File', "$scripts\download.ps1", '-Force')
if ($Prod) { $dlArgs += '-Prod' }
& powershell @dlArgs
if ($LASTEXITCODE -ne 0) { throw "Download failed" }
Initialize-BundleSession -WorkDir $workDir
$ctxPath = "$workDir\contexts.json"
$topsPath = "$workDir\topics.json"
$ctxId = 'jf-landata'
# ── 2. Context ────────────────────────────────────────────────────────────────
Write-Host "`n[2] Context..." -ForegroundColor Cyan
Upsert-Context -CtxPath $ctxPath -Id $ctxId -Name 'JF: LANdata' -SortOrder 30
# ── 3. Cleanup + Topics ───────────────────────────────────────────────────────
Write-Host "`n[3] Cleanup + Topics..." -ForegroundColor Cyan
Remove-ContextTopics -TopicsPath $topsPath -ContextId $ctxId
$journalId = Add-Topic $topsPath $ctxId 'Sitzungsprotokoll' `
'Meeting-Notizen chronologisch.' 5 $true
Add-Topic $topsPath $ctxId 'Access-Manager' `
"- VM vorbereitet, warten auf Stefan`n- SQL-Server benoetigt`n- Banf kann freigegeben werden`n- Angebot mit AM (nur Drolshagen)`n- Jo triggert Thema an" 10 | Out-Null
Add-Topic $topsPath $ctxId 'Teams-Probleme HKR / BZ-WLAN' `
"- LANdata startet Aufzeichnung, Log-Probleme`n- Ball bei Steffen (Kabel neu ziehen, Kabel Telekom-Sophos tauschen)`n- Zaehler resettet, Fehler weniger geworden`n- Steffen: zweiten Rechner mit PfSense Gateway`n- PRTG Leitung HKR ueberwachen`n- Ticket BZ-WLAN: #481057 DNS Verschluesselung" 20 | Out-Null
Add-Topic $topsPath $ctxId 'PRTG und Sophos / STAS' `
"- Fromm / Abdul an PRTG-Sophos Protokollierung WAN-Port`n- Jo braucht PRTG-Daten fuer Analyse`n- STAS-Problem: Sophos Heartbeat`n- Sophos Ticket bei Marvin, Citrix-Endpoint-Problem`n- Auth-Service geaendert (geloest)" 30 | Out-Null
Add-Topic $topsPath $ctxId '5G Router / Netzwerk HKR' `
"- Problem Standard-Gateway → asynchrone Routen`n- Reverse-Problem: Default-GW ist Switch → Routing-Problem`n- Test Fr./Sa. Abend: max. 2h Internet-Downtime`n- Philip: Test nach Karneval`n- diverse Netzwerkfehler HKR, hohe Verluste am Switch (Zaehler)" 40 | Out-Null
Add-Topic $topsPath $ctxId 'Citrix / NetScaler / MFA' `
"- Passwortproblem: Zeichensatz auf NS anders als MPS`n- Stefan: Termin SVA-Citrix + LANdata-MPS`n- MFA fuer Citrix: Gruppen mit IP-Adressen kombinieren (erledigt)`n- Citrix Bleed Sicherheitsluecke`n- Sophos Endpoint auf Citrix Terminalserver (Marvin)" 50 | Out-Null
Add-Topic $topsPath $ctxId 'Microsoft Lizenzen' `
"- Open Value Verlaengerung: 60:40 Jahres-/Monatslizenzen`n- E3 ohne Teams (EU-Gesetz): 2 EUR guenstiger, mit Teams 6 EUR teurer`n- Win11 OEM: open key ca. 69 EUR Upgrade`n- KYC fuer Teams Phone Porting (Jo)`n- Lizenzen WITEC: MS Server, Sophos FW, Hornet offboarding automatisch" 60 | Out-Null
Add-Topic $topsPath $ctxId 'Azure Berechtigungskonzept' `
"- Matrix: Welche Rollen fuer welche Aufgaben`n- Azubi war Voll-Admin der Azure-Cloud (Ticket #13969)`n- Mitglieder durch Gruppen (Willy liefert noch)`n- Zuordnung Org-Einheiten in Azure`n- Rollenbeschreibungen`n- unzulaessige Azure-Lizenzierung wg. MFA-Pflicht: P1 erforderlich" 70 | Out-Null
Add-Topic $topsPath $ctxId 'SAN / Backup / File-Server' `
"- SAN Latenzen (nicht freier Speicher, Willy sucht Support)`n- Diskrepanz: SAN 7 TB frei, VM 2 TB frei`n- Notfallhandbuch SAN erweitern`n- SAP-Ausfall: HA-Cluster hat nicht funktioniert (WAN-Port kein Trigger)`n- File-Server Ausfall: Ticket #257534" 80 | Out-Null
Add-Topic $topsPath $ctxId 'Firewall / Heartbeat / Luedensch.' `
"- Heartbeat Authentifizierung (CSOC Thema)`n- Slave als neuen Master neu konfigurieren`n- Luedenscheid: Betriebsmodus RED, Routen passen nicht zur Sophos-Konfig`n- HKR-Regel MS wegen Updates: Natting-Problem? NAT-Regeln fehlen?`n- Backup-FW update PhiLos" 90 | Out-Null
Add-Topic $topsPath $ctxId 'China / Internationale Vernetzung' `
"- AFT/staatliche Regulierungen`n- SD-WAN Empfehlung: lokale Anbieter, keinen Europaeischen`n- Artikel 9 Data Security Policy China`n- Logfiles 6 Monate vorhalten`n- MS 365: Popup-Funktion nicht verfuegbar (chinesische Regulierung)`n- FW China: Jo hat noch keine Antwort" 100 | Out-Null
Add-Topic $topsPath $ctxId 'DNS Verschluesselung' `
"- DNS Traffic aktuell nicht verschluesselt`n- DNS Protection Sophos verschluesselt auch nicht`n- Ticket #481057`n- nicht kritisch aber auf der Liste" 110 | Out-Null
# ── 4. History entries ────────────────────────────────────────────────────────
Write-Host "`n[4] History entries..." -ForegroundColor Cyan
Add-HistoryEntry $journalId '2026-02-18' "## Next`n`n- Access Manager`n- Sophos Ticket zum Thema STAS: bitte neues Ticket bei Sophos" | Out-Null
Add-HistoryEntry $journalId '2026-02-18' "## 2026-02-18`n`n- 5G Router: erst WLAN-Test`n- diverse Replikationsfehler DC bei RES geloest`n- PRTG und Sophos: Jo macht Wissensuebergabe (Problem geloest)`n- HKR-Regel MS wegen Updates: LANdata im Austausch mit Anbieter, Kuriosite festgestellt, hakt nach`n- Idee Philip/ChrKl: Jo prueft Natting-Problem (NAT-Regeln ev. fehlend)" | Out-Null
Add-HistoryEntry $journalId '2026-02-11' "## 2026-02-11`n`n- Backup und Firewall: Stefan beschreibt Grund fuer neuen ESX-Server`n- Termin Willi + Christopher wg. Domaenen-Anmeldung: Fehler behoben (falsch konfig. DCs), weitere Tests`n- Angebot DL fuer AM: ChrKl banft`n- TISAX: Status Sophos Heartbeat`n- Teams HKR: Zaehler resettet, Fehler weniger, auch mit neuen Kabeln. Steffen: zweiten Rechner mit PfSense. Warten auf Steffen`n- PRTG und Sophos: Jo braucht PRTG-Daten, dann tiefere Analyse`n- HKR-Regel MS: LANdata hakt nach" | Out-Null
Add-HistoryEntry $journalId '2026-02-03' "## 2026-02-03`n`n- Neues Format LANdata: kostenloser IT-Strategie-Termin 2h, Ziel Roadmap`n- Info Server VLAN verteilt`n- PRTG und Sophos: Abdul/Fromm in Arbeit, finale Rueckmeldung ausstehend`n- Teams HKR: Ball bei Steffen (Kabel, PfSense)`n- 5G Router: Standard-Gateway Problem → asynchrone Routen, Philip verschiebt Test nach Karneval" | Out-Null
Add-HistoryEntry $journalId '2026-01-28' "## 2026-01-28`n`n- PRTG und Sophos: Protokollierung WAN-Port, Philip prueft nochmal`n- Citrix NetScaler Passwortproblem: Zeichensatz NS != MPS, Stefan organisiert Termin`n- Austausch NHV KW23: Koordination (wer faehrt, wer schaltet, was wird getestet)`n- Teams HKR: LANdata startet Aufzeichnung" | Out-Null
Add-HistoryEntry $journalId '2026-01-21' "## 2026-01-21`n`n- Windows Hello tut nicht → Eray uebernimmt`n- File-Server Problem: klingt nach DC-Problem`n- China: staatliche Regulierungen, SD-WAN Empfehlung lokale Anbieter, Artikel 9 Data Security Policy, Logfiles 6 Monate, MS 365 einschraenkungen`n- Empfehlung: Vernetzung China aus China beauftragen" | Out-Null
Add-HistoryEntry $journalId '2026-01-14' "## 2026-01-14`n`n- HKR: Jo mit Telekom gesprochen (Leitung nicht stark ausgelastet), hohe Verluste am Switch (Zaehler), Termin Fr. 8:15`n- MacMon Angebot: genauer Plan Switche benoetigt, Philip legt Projekt in Plane an`n- FW HKR-Regel MS: Christian F. auf TODO`n- 5G Router: Problem Standard-Gateway, Test nach Karneval`n- PRTG und Sophos: Fromm in Arbeit`n- Edge-Problem: seit Sa. behoben" | Out-Null
Add-HistoryEntry $journalId '2026-01-07' "## 2026-01-07`n`n- 5G Router: Standard-Gateway Problem (asynchrone Routen), reverse-Problem (Default-GW ist Switch), Sa./Fr. Test, max. 2h Downtime`n- PRTG mit Jo: Fromm bei Sophos dran, Ziel Internetbandbreite HKR ueberwachen`n- Citrix NetScaler: Zeichensatz-Problem, Stefan organisiert Termin`n- FW HKR-Regel MS: Teams bricht ab wenn Regel aktiv" | Out-Null
Add-HistoryEntry $journalId '2025-12-10' "## 2025-12-10`n`n- SAN Probleme: nicht freier Speicher, Latenz unterirdisch, Willy sucht Unterstuetzung" | Out-Null
Add-HistoryEntry $journalId '2025-12-03' "## 2025-12-03`n`n- KYC fuer Teams Phone Porting: Jo klaert`n- Teilen mit Malaysia: LANdata prueft, ob zusaetzliche Richtlinie gebaut werden kann`n- 5G Router: grundsaetzlich funktioniert er" | Out-Null
Add-HistoryEntry $journalId '2025-11-26' "## 2025-11-26`n`n- Status Access-Manager: Jo triggert an`n- BitSight HKR untergliedern?`n- Citrix: Sonderzeichen-Problem in komplexen Passwoertern → NetScaler (nicht Radius)`n- Sophos AP Support kuendigen?`n- HKR sperren Sky: Auffaelligkeiten zusammenstellen, Steffen: XP + lokale Admin-Rechte entziehen" | Out-Null
Add-HistoryEntry $journalId '2025-11-19' "## 2025-11-19`n`n- AM Termin passt`n- Sophos und Citrix: Marvin war krank, Ticket wieder eroeffnet`n- FW China: Jo hat noch keine Antwort`n- Teilen mit Malaysia: LANdata prueft`n- Makros Hornet durch SMTP-Regel durchlassen`n- Jo: Telekom HKR: 100% ausgelastet 6-18 Uhr, Downloads koennen Teams-Problem verursachen, Jo + Philip schauen sich das an" | Out-Null
Add-HistoryEntry $journalId '2025-11-12' "## 2025-11-12`n`n- Entscheidung Lizenz Visio fuer viflow: open vs. e3`n- FW WITEC nach China: internationale Leitung auf China-Seite benoetigt`n- AM: Feedback von Willi benoetigt`n- Bestellung MS Open erledigt`n- SAN: Diskrepanz 7TB / 2TB, hohe Latenzen, Jo meldet sich" | Out-Null
Add-HistoryEntry $journalId '2025-11-05' "## 2025-11-05`n`n- Lizenz AM: Jo schickt Lizenz`n- Sophos auf Citrix: Marvin krank, Ticket bei Sophos aufgemacht, laesst sich nicht installieren" | Out-Null
# ── 5. Upload ─────────────────────────────────────────────────────────────────
Write-Host "`n[5] Uploading..." -ForegroundColor Cyan
$ulArgs = @('-File', "$scripts\upload.ps1")
if ($Prod) { $ulArgs += '-Prod' }
if ($Force) { $ulArgs += '-Force' }
& powershell @ulArgs
if ($LASTEXITCODE -ne 0) { throw "Upload failed" }
Write-Host "`n[DONE] JF LANdata import complete." -ForegroundColor Green

View File

@ -0,0 +1,48 @@
<#
.SYNOPSIS
Stores a Bearer token for Ka-Note prod in %USERPROFILE%\.ka-note\token.txt.
Run this after copying a fresh token from the Ka-Note browser app.
.PARAMETER Token
The JWT token string. If omitted, reads from clipboard.
.EXAMPLE
.\set-token.ps1 "eyJ..."
.\set-token.ps1 # reads from clipboard
#>
param([string]$Token)
$ErrorActionPreference = 'Stop'
if (-not $Token) {
$Token = Get-Clipboard
if (-not $Token) { Write-Error "No token provided and clipboard is empty."; exit 1 }
Write-Host " Read token from clipboard." -ForegroundColor DarkGray
}
$Token = $Token.Trim()
if (-not $Token.StartsWith('eyJ')) {
Write-Error "Does not look like a JWT token (expected 'eyJ...')."
exit 1
}
# Parse expiry
try {
$parts = $Token.Split('.')
$payload = $parts[1]
$pad = 4 - ($payload.Length % 4); if ($pad -ne 4) { $payload += '=' * $pad }
$payload = $payload.Replace('-', '+').Replace('_', '/')
$claims = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payload)) | ConvertFrom-Json
$expUtc = [System.DateTimeOffset]::FromUnixTimeSeconds($claims.exp).UtcDateTime
$local = $expUtc.ToLocalTime()
$remaining = [math]::Round(($expUtc - [System.DateTime]::UtcNow).TotalMinutes)
Write-Host " Token expires: $($local.ToString('HH:mm')) ($remaining min remaining)" -ForegroundColor $(if ($remaining -lt 10) { 'Yellow' } else { 'Green' })
} catch {
Write-Host " Token stored (could not parse expiry)." -ForegroundColor DarkGray
}
# Save
$dir = Join-Path $env:USERPROFILE '.ka-note'
if (-not (Test-Path $dir)) { New-Item -ItemType Directory $dir | Out-Null }
$file = Join-Path $dir 'token.txt'
$Token | Set-Content $file -Encoding UTF8 -NoNewline
Write-Host " Saved to: $file" -ForegroundColor Green