VBAF.Center.GPSInspector.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS VBAF-Center GPS Inspector .DESCRIPTION Connects to any GPS fleet management system and automatically configures VBAF signals from live fleet data. Supported GPS systems: 1. Webfleet (TomTom WEBFLEET.connect) 2. Geotab 3. Trackunit 4. Keatech 5. Generic REST API (any other system) Functions: Start-VBAFCenterGPSInspector — guided GPS connection wizard #> # ============================================================ # GPS SYSTEM DEFINITIONS # ============================================================ $script:GPSSystems = @( @{ ID = "Webfleet" Name = "Webfleet (TomTom)" Danish = "Webfleet — mest brugte internationalt" AuthFields = @("Account","Username","Password","APIKey") BuildURL = { param($auth, $action) "https://csv.webfleet.com/extern?account=$($auth.Account)&username=$($auth.Username)&password=$($auth.Password)&apikey=$($auth.APIKey)&lang=en&outputformat=json&action=$action" } Signals = @( @{ Name="Tom kørsel %"; Action="showVehicleReportExtern"; Field="totalstandbytime_h"; Calc="EmptyPct"; RawMin=0; RawMax=100; Unit="%" } @{ Name="Til tiden %"; Action="showOrderReportExtern"; Field="ontime_pct"; Calc="Direct"; RawMin=0; RawMax=100; Unit="%" } @{ Name="Afstand i dag (km)"; Action="showVehicleReportExtern"; Field="totaldistance_km"; Calc="Direct"; RawMin=0; RawMax=1000; Unit="km" } @{ Name="Chauffør score"; Action="showDriverReportExtern"; Field="drivingscore"; Calc="Direct"; RawMin=0; RawMax=100; Unit="%" } @{ Name="Brændstof forbrug"; Action="showVehicleReportExtern"; Field="totalfuelconsumption_l";Calc="Direct"; RawMin=0; RawMax=500; Unit="L" } ) } @{ ID = "Geotab" Name = "Geotab" Danish = "Geotab — stor international løsning" AuthFields = @("Server","Database","Username","Password") BuildURL = { param($auth, $action) "https://$($auth.Server)/apiv1" } Signals = @( @{ Name="Tom kørsel %"; Action="Get/Device"; Field="engineHours"; Calc="EmptyPct"; RawMin=0; RawMax=100; Unit="%" } @{ Name="Afstand i dag (km)"; Action="Get/Device"; Field="odometer"; Calc="Direct"; RawMin=0; RawMax=1000; Unit="km" } @{ Name="Chauffør score"; Action="Get/Device"; Field="driverScore"; Calc="Direct"; RawMin=0; RawMax=100; Unit="%" } ) } @{ ID = "Trackunit" Name = "Trackunit" Danish = "Trackunit — populær i Danmark" AuthFields = @("APIKey") BuildURL = { param($auth, $action) "https://api.trackunit.com/public/$action" } Signals = @( @{ Name="Aktive enheder"; Action="asset"; Field="count"; Calc="Direct"; RawMin=0; RawMax=100; Unit="stk" } @{ Name="Afstand i dag (km)"; Action="asset"; Field="totalKm"; Calc="Direct"; RawMin=0; RawMax=1000; Unit="km" } ) } @{ ID = "Keatech" Name = "Keatech" Danish = "Keatech — dansk løsning, 1000+ kunder" AuthFields = @("APIKey") BuildURL = { param($auth, $action) "https://api.keatech.com/v1/$action" } Signals = @( @{ Name="Flåde position"; Action="vehicles"; Field="count"; Calc="Direct"; RawMin=0; RawMax=100; Unit="stk" } @{ Name="Afstand i dag (km)"; Action="trips"; Field="totalDistance"; Calc="Direct"; RawMin=0; RawMax=1000; Unit="km" } ) } @{ ID = "Generic" Name = "Anden GPS/REST løsning" Danish = "Anden løsning — enhver REST API" AuthFields = @("URL","APIKey") BuildURL = { param($auth, $action) $url = $auth.URL if ($auth.APIKey -ne "") { $url += "?apikey=$($auth.APIKey)" } $url } Signals = @() } ) # ============================================================ # HELPER — READ NESTED VALUE # ============================================================ function Get-NestedValue { param($obj, [string]$path) $parts = $path -split "\." $value = $obj foreach ($part in $parts) { if ($null -eq $value) { return $null } $value = $value.$part } return $value } # ============================================================ # HELPER — FLATTEN JSON FOR GENERIC MODE # ============================================================ function Get-GPSFlattenedFields { param($obj, [string]$prefix = "") $results = @() if ($null -eq $obj) { return $results } $properties = $obj | Get-Member -MemberType NoteProperty -ErrorAction SilentlyContinue foreach ($prop in $properties) { $name = $prop.Name $value = $obj.$name $path = if ($prefix -ne "") { "$prefix.$name" } else { $name } if ($null -eq $value) { continue } $type = $value.GetType().Name if ($type -in @("PSCustomObject")) { $results += Get-GPSFlattenedFields -obj $value -prefix $path } elseif ($type -in @("Double","Single","Int32","Int64","Decimal")) { $results += @{ Path=$path; Value=$value } } } return $results } # ============================================================ # HELPER — PRINT BANNER # ============================================================ function Write-GPSBanner { Write-Host "" Write-Host " +----------------------------------------------------------+" -ForegroundColor Cyan Write-Host " | VBAF-Center GPS Inspector |" -ForegroundColor Cyan Write-Host " | Tilslut dit GPS-system automatisk |" -ForegroundColor Cyan Write-Host " +----------------------------------------------------------+" -ForegroundColor Cyan Write-Host "" } # ============================================================ # HELPER — TEST GPS CONNECTION # ============================================================ function Test-GPSConnection { param([string]$URL, [hashtable]$Headers = @{}) try { $response = Invoke-RestMethod -Uri $URL -Method GET -Headers $Headers -ErrorAction Stop return @{ Success=$true; Response=$response } } catch { return @{ Success=$false; Error=$_.Exception.Message } } } # ============================================================ # START-VBAFCENTERGPSINSPECTOR # ============================================================ function Start-VBAFCenterGPSInspector { param( [Parameter(Mandatory)] [string] $CustomerID ) Write-GPSBanner # Check customer exists $profPath = Join-Path $env:USERPROFILE "VBAFCenter\customers\$CustomerID.json" if (-not (Test-Path $profPath)) { Write-Host (" Kunde ikke fundet: {0}" -f $CustomerID) -ForegroundColor Red Write-Host " Kør Start-VBAFCenterOnboarding først!" -ForegroundColor Yellow return } $profile = Get-Content $profPath -Raw | ConvertFrom-Json Write-Host (" Kunde : {0}" -f $profile.CompanyName) -ForegroundColor White Write-Host (" CustomerID : {0}" -f $CustomerID) -ForegroundColor White Write-Host "" # ── STEP 1 — CHOOSE GPS SYSTEM ───────────────────────── Write-Host " TRIN 1/4 — Hvilket GPS-system bruger virksomheden?" -ForegroundColor Yellow Write-Host "" $i = 1 foreach ($sys in $script:GPSSystems) { Write-Host (" {0}. {1}" -f $i, $sys.Danish) -ForegroundColor White $i++ } Write-Host "" Write-Host " Vælg nummer: " -NoNewline -ForegroundColor Yellow $sysChoice = [int](Read-Host) $selectedSystem = $script:GPSSystems[$sysChoice - 1] if (-not $selectedSystem) { Write-Host " Ugyldigt valg." -ForegroundColor Red return } Write-Host "" Write-Host (" Valgt: {0}" -f $selectedSystem.Name) -ForegroundColor Green Write-Host "" # ── STEP 2 — COLLECT CREDENTIALS ─────────────────────── Write-Host " TRIN 2/4 — Indtast API-adgang fra jeres GPS-leverandør" -ForegroundColor Yellow Write-Host " (Disse oplysninger får du fra GPS-leverandørens support)" -ForegroundColor DarkGray Write-Host "" $auth = @{} foreach ($field in $selectedSystem.AuthFields) { Write-Host (" {0}: " -f $field) -NoNewline -ForegroundColor White $auth[$field] = Read-Host } Write-Host "" # ── STEP 3 — TEST CONNECTION ──────────────────────────── Write-Host " TRIN 3/4 — Tester forbindelsen til GPS-systemet..." -ForegroundColor Yellow Write-Host "" $headers = @{} if ($auth.ContainsKey("APIKey") -and $auth.APIKey -ne "") { $headers["Authorization"] = "Bearer $($auth.APIKey)" $headers["X-API-Key"] = $auth.APIKey } # For generic system — use URL directly if ($selectedSystem.ID -eq "Generic") { $testURL = $auth.URL if ($auth.ContainsKey("APIKey") -and $auth.APIKey -ne "") { if ($testURL -like "*?*") { $testURL += "&apikey=$($auth.APIKey)" } else { $testURL += "?apikey=$($auth.APIKey)" } } Write-Host (" URL: {0}" -f $testURL) -ForegroundColor DarkGray $test = Test-GPSConnection -URL $testURL -Headers $headers if (-not $test.Success) { Write-Host (" Forbindelse fejlede: {0}" -f $test.Error) -ForegroundColor Red Write-Host " Tjek URL og API-nøgle og prøv igen." -ForegroundColor Yellow return } Write-Host " Forbindelse OK!" -ForegroundColor Green Write-Host "" # Show all numeric fields Write-Host " TRIN 4/4 — Vælg signaler fra GPS-systemet" -ForegroundColor Yellow Write-Host "" $fields = Get-GPSFlattenedFields -obj $test.Response if ($fields.Count -eq 0) { Write-Host " Ingen numeriske felter fundet i svaret." -ForegroundColor Red Write-Host " Prøv API Inspector i stedet: Invoke-VBAFCenterAPIInspector" -ForegroundColor Yellow return } Write-Host (" {0,-4} {1,-40} {2,10}" -f "#", "Felt (JSONPath)", "Værdi") -ForegroundColor Yellow Write-Host (" {0}" -f ("-" * 60)) -ForegroundColor DarkGray $displayMap = @{} $idx = 1 foreach ($f in $fields) { Write-Host (" {0,-4} {1,-40} {2,10}" -f $idx, $f.Path, $f.Value) -ForegroundColor White $displayMap[$idx] = $f $idx++ } Write-Host "" Write-Host " Konfigurer VBAF-signaler fra disse felter." -ForegroundColor Cyan Write-Host " Tryk Enter for at afslutte eller vælg felt:" -ForegroundColor DarkGray Write-Host "" $signalIdx = 1 while ($signalIdx -le 4) { Write-Host (" Signal{0} — Felt nummer (eller Enter for at springe over): " -f $signalIdx) -NoNewline -ForegroundColor Yellow $pick = Read-Host if ($pick -eq "") { break } $picked = $displayMap[[int]$pick] if (-not $picked) { continue } Write-Host (" Navn på signal [{0}]: " -f $picked.Path) -NoNewline -ForegroundColor Yellow $sigName = Read-Host if ($sigName -eq "") { $sigName = $picked.Path } $rawMax = [Math]::Max(100, [Math]::Round($picked.Value * 3)) New-VBAFCenterSignalConfig ` -CustomerID $CustomerID ` -SignalName $sigName ` -SignalIndex "Signal$signalIdx" ` -SourceType "REST" ` -SourceURL $testURL ` -JSONPath $picked.Path ` -RawMin 0 ` -RawMax $rawMax $signalIdx++ } } else { # Known GPS system — use pre-built connector $firstAction = $selectedSystem.Signals[0].Action $builtURL = & $selectedSystem.BuildURL $auth $firstAction Write-Host (" URL: {0}" -f $builtURL) -ForegroundColor DarkGray $test = Test-GPSConnection -URL $builtURL -Headers $headers if (-not $test.Success) { Write-Host (" Forbindelse fejlede: {0}" -f $test.Error) -ForegroundColor Red Write-Host "" Write-Host " Mulige årsager:" -ForegroundColor Yellow Write-Host " - Forkert API-nøgle eller password" -ForegroundColor White Write-Host " - API-adgang ikke aktiveret af leverandøren endnu" -ForegroundColor White Write-Host " - Kontakt $($selectedSystem.Name) support" -ForegroundColor White return } Write-Host " Forbindelse OK!" -ForegroundColor Green Write-Host "" # ── STEP 4 — CONFIGURE SIGNALS ───────────────────── Write-Host " TRIN 4/4 — Vælg signaler der skal overvåges" -ForegroundColor Yellow Write-Host "" Write-Host (" {0,-4} {1,-35} {2,-15} {3}" -f "#", "Signal", "Enhed", "Beskrivelse") -ForegroundColor Yellow Write-Host (" {0}" -f ("-" * 70)) -ForegroundColor DarkGray $i = 1 foreach ($sig in $selectedSystem.Signals) { Write-Host (" {0,-4} {1,-35} {2,-15} {3}" -f $i, $sig.Name, $sig.Unit, $sig.Action) -ForegroundColor White $i++ } Write-Host "" Write-Host " Vælg op til 4 signaler (kommasepareret, f.eks. 1,2,3): " -NoNewline -ForegroundColor Yellow $picks = (Read-Host) -split "," | ForEach-Object { $_.Trim() } $signalIdx = 1 foreach ($pick in $picks) { if ($signalIdx -gt 4) { break } $sig = $selectedSystem.Signals[[int]$pick - 1] if (-not $sig) { continue } $sigURL = & $selectedSystem.BuildURL $auth $sig.Action New-VBAFCenterSignalConfig ` -CustomerID $CustomerID ` -SignalName $sig.Name ` -SignalIndex "Signal$signalIdx" ` -SourceType "REST" ` -SourceURL $sigURL ` -JSONPath $sig.Field ` -RawMin $sig.RawMin ` -RawMax $sig.RawMax $signalIdx++ } } # ── SUMMARY ──────────────────────────────────────────── Write-Host "" Write-Host " +----------------------------------------------------------+" -ForegroundColor Green Write-Host " | GPS-forbindelse konfigureret! |" -ForegroundColor Green Write-Host " +----------------------------------------------------------+" -ForegroundColor Green Write-Host "" Write-Host (" Kunde : {0}" -f $profile.CompanyName) -ForegroundColor White Write-Host (" GPS-system: {0}" -f $selectedSystem.Name) -ForegroundColor White Write-Host "" Write-Host " Test forbindelsen:" -ForegroundColor Yellow Write-Host (" Invoke-VBAFCenterRun -CustomerID ""{0}""" -f $CustomerID) -ForegroundColor Green Write-Host "" Write-Host " Start 24/7 overvågning:" -ForegroundColor Yellow Write-Host (" Start-VBAFCenterSchedule -CustomerID ""{0}""" -f $CustomerID) -ForegroundColor Green Write-Host "" Write-Host " Se resultater i portalen:" -ForegroundColor Yellow Get-VBAFCenterPortalURLs Write-Host "" } # ============================================================ # LOAD MESSAGE # ============================================================ Write-Host "" Write-Host " +------------------------------------------+" -ForegroundColor Cyan Write-Host " | VBAF-Center GPS Inspector |" -ForegroundColor Cyan Write-Host " | Tilslut GPS-system i 4 trin |" -ForegroundColor Cyan Write-Host " +------------------------------------------+" -ForegroundColor Cyan Write-Host "" Write-Host " Start-VBAFCenterGPSInspector — start GPS-forbindelsesguide" -ForegroundColor White Write-Host "" Write-Host " Understøttede GPS-systemer:" -ForegroundColor DarkGray Write-Host " Webfleet · Geotab · Trackunit · Keatech · Andre REST APIs" -ForegroundColor DarkGray Write-Host "" Write-Host " Forudsætning:" -ForegroundColor Yellow Write-Host " Kunden skal have bedt GPS-leverandøren om API-adgang" -ForegroundColor White Write-Host "" Write-Host " Quick start:" -ForegroundColor Yellow Write-Host " Start-VBAFCenterGPSInspector -CustomerID 'TruckCompanyDK'" -ForegroundColor Green Write-Host "" |