Skip to content

Instantly share code, notes, and snippets.

@Reiner030
Created January 16, 2026 14:37
Show Gist options
  • Select an option

  • Save Reiner030/3261f12a9cc008518ac8c530715c883e to your computer and use it in GitHub Desktop.

Select an option

Save Reiner030/3261f12a9cc008518ac8c530715c883e to your computer and use it in GitHub Desktop.
# FlipControl-GUI.ps1 - All-in-one Samsung Flip control GUI
# Requirements:
# - Windows 10/11 with PowerShell 5.1 or newer
# - A WSL distribution (e.g. Debian 12 "Trixie" or Ubuntu) installed and configured
# - Inside WSL, the package "python3-samsung-mdc" must be installed and the command "samsung-mdc" callable
# Example (Debian/Ubuntu in WSL): sudo apt-get update && sudo apt-get install -y python3-samsung-mdc
# - Network connectivity from WSL to the Samsung Flip displays (TCP port 1515)
# Device configuration (per Samsung Flip):
# - On the Flip: Settings => System => Advanced System => Remote Management:
# * Remote Management : Active
# * Display ID : 0 (must match the "0@" prefix in the target)
# * Connection : RJ45 / Ethernet (instead of RS232) for IP-based MDC
# * TLS : On for secure MDC + PIN (default is Off)
# - Default PIN on Samsung Flip is usually 000000; change it on the device if needed.
# - If TLS is Off and no PIN is configured, set "pin" to "none" or "" in the profile to call samsung-mdc without --pin.
#
# Optional convenience:
# - Save this script as, e.g., C:\Tools\FlipControl-GUI.ps1
# - Create a shortcut with target:
# powershell.exe -NoProfile -NoLogo -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Tools\FlipControl-GUI.ps1"
# - Set "Start in" in the shortcut properties to:
# C:\Tools
# - Choose an icon from the standard Windows icon libraries, for example:
# %SystemRoot%\System32\shell32.dll
# %SystemRoot%\System32\imageres.dll
# (open the shortcut properties -> Change Icon... -> paste one of the paths above)
#
# - The selected icon is internally stored as "path, index", e.g.:
# %SystemRoot%\System32\imageres.dll, 146
# but the GUI normally only shows the path; the index is managed by Windows.
# - Place the shortcut on the Desktop or in the Start menu.
#
# PS 5.1 one-liner for current user's desktop:
# $ws=New-Object -ComObject WScript.Shell;$sc=$ws.CreateShortcut([IO.Path]::Combine([Environment]::GetFolderPath('Desktop'),'FlipControl-GUI.lnk'));$sc.TargetPath='powershell.exe';$sc.Arguments='-NoProfile -NoLogo -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Tools\FlipControl-GUI.ps1"';$sc.WorkingDirectory='C:\Tools';$sc.IconLocation="$env:SystemRoot\System32\imageres.dll,146";$sc.Save()
#
# PS 5.1 one-liner for all users' desktops (admin rights needed):
# $ws=New-Object -ComObject WScript.Shell;$sc=$ws.CreateShortcut("$env:Public\Desktop\FlipControl-GUI.lnk");$sc.TargetPath='powershell.exe';$sc.Arguments='-NoProfile -NoLogo -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Tools\FlipControl-GUI.ps1"';$sc.WorkingDirectory='C:\Tools';$sc.IconLocation="$env:SystemRoot\System32\imageres.dll,146";$sc.Save()
# FlipControl-GUI.ps1 - ASCII-only, PS5.1-safe WinForms GUI
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# Embedded profile, notifications about setup in notes bottom of json
$cfgJson = @'
{
"pin": "000000",
"timeout": 5,
"wslDistro": "",
"targets": [
{ "label": "Flip #1 - Room 1", "target": "0@192.168.178.11:1515" },
{ "label": "Flip #2 - Room 2", "target": "0@192.168.178.12:1515" },
{ "label": "Flip #3 - Room 3", "target": "0@192.168.178.13:1515" }
],
"capabilities": {
"power": {
"get": true,
"set": [
"ON",
"OFF"
]
},
"input": {
"get": true,
"set": [
"IWB",
"HDMI1",
"HDMI2",
"DISPLAY_PORT_1",
"WIDI_SCREEN_MIRRORING",
"WEB_BROWSER",
"REMOTE_WORKSPACE"
]
},
"volume": {
"get": true,
"setRange": [
0,
100
]
},
"mute": {
"get": true,
"set": [
"ON",
"OFF"
]
}
},
"notes": [
"wslDistro can be set for multiple WSL instances else default is used",
"input_source/volume/mute only valid when POWER_STATE.ON",
"Display ID must match device configuration",
"TLS/PIN is used when pin is not 'none' or empty; otherwise samsung-mdc is called without --pin",
"Port 1515/TCP must allow bidirectional traffic"
]
}
'@
$cfg = $cfgJson | ConvertFrom-Json
# Embedded helpers from MdcHelpers.ps1
# MdcHelpers.ps1 - ASCII-only, PS5.1-safe helpers for samsung-mdc via WSL
function Invoke-Mdc {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string] $Target, # "ID@HOST:PORT"
[string] $Pin = "000000",
[int] $Timeout = 8,
[string] $Distro = "",
[Parameter(Mandatory=$true)][string] $Command, # power / input_source / volume / mute
[string[]] $Args,
[int] $Retry = 1
)
$usePin = -not [string]::IsNullOrWhiteSpace($Pin) -and $Pin -ne "none"
$base = @("--","samsung-mdc","-t",$Timeout.ToString())
if ($usePin) {
$base += @("--pin",$Pin)
}
$base += @($Target,$Command)
if ($Args) {
$base += $Args
}
if ([string]::IsNullOrWhiteSpace($Distro)) {
$psi = $base
} else {
$psi = @("-d",$Distro) + $base
}
$output = & wsl $psi 2>&1
# SSLError / UNEXPECTED_MESSAGE / MDCReadTimeoutError -> short retry
if ($Retry -gt 0 -and ($output -match "SSLError" -or $output -match "UNEXPECTED_MESSAGE" -or $output -match "MDCReadTimeoutError")) {
Start-Sleep -Milliseconds 600
$output = & wsl $psi 2>&1
}
return $output
}
function Get-MdcStatus {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string] $Target,
[string] $Pin = "000000",
[int] $Timeout = 8,
[string] $Distro = ""
)
$power = Invoke-Mdc -Target $Target -Pin $Pin -Timeout $Timeout -Distro $Distro -Command power
$pstate = "UNKNOWN"
if ($power -match "POWER_STATE\.(\w+):\d+") { $pstate = $Matches[1] }
$input = $null; $vol = $null; $mute = $null
if ($pstate -eq "ON") {
$input = Invoke-Mdc -Target $Target -Pin $Pin -Timeout $Timeout -Distro $Distro -Command input_source
if ($input -match "INPUT_SOURCE_STATE\.(\w+):\d+") { $input = $Matches[1] }
$vol = Invoke-Mdc -Target $Target -Pin $Pin -Timeout $Timeout -Distro $Distro -Command volume
if ($vol -match "(\d+)\s*$") { $vol = $Matches[1] } else { $vol = $null }
$mute = Invoke-Mdc -Target $Target -Pin $Pin -Timeout $Timeout -Distro $Distro -Command mute
if ($mute -match "MUTE_STATE\.(\w+):\d+") { $mute = $Matches[1] }
}
[pscustomobject]@{
Target = $Target
Power = $pstate
Input = $input
Volume = $vol
Mute = $mute
}
}
# Form windows
$form = New-Object System.Windows.Forms.Form
$form.Text = "Samsung Whiteboard Flip Control"
$form.Size = New-Object System.Drawing.Size(540,520) # Width, Height
$form.StartPosition = "CenterScreen"
# Controls
# target input_sources selection
$lblTarget = New-Object System.Windows.Forms.Label
$lblTarget.Text = "Target"
$lblTarget.Location = New-Object System.Drawing.Point(10,15)
$form.Controls.Add($lblTarget)
$cboTarget = New-Object System.Windows.Forms.ComboBox
$cboTarget.Location = New-Object System.Drawing.Point(120,10)
$cboTarget.Width = 380
$cboTarget.DropDownStyle = "DropDownList"
# build from JSON (Label, Target, Display)
$items = New-Object System.Collections.ArrayList
foreach ($t in $cfg.targets) {
$null = $items.Add([pscustomobject]@{
Label = $t.label
Target = $t.target
Display = ("{0} - {1}" -f $t.label, $t.target)
})
}
$cboTarget.DisplayMember = "Display" # UI labeling
$cboTarget.ValueMember = "Target" # value usage
$cboTarget.DataSource = $items
$form.Controls.Add($cboTarget)
# Power status/update
$lblPower = New-Object System.Windows.Forms.Label
$lblPower.Text = "Power"
$lblPower.Location = New-Object System.Drawing.Point(10,50)
$form.Controls.Add($lblPower)
$cboPower = New-Object System.Windows.Forms.ComboBox
$cboPower.Location = New-Object System.Drawing.Point(120,45)
$cboPower.Width = 60
$cboPower.DropDownStyle = "DropDownList"
$cboPower.Items.AddRange(@("ON","OFF"))
$form.Controls.Add($cboPower)
# Status label for last Refresh/Apply result
$lblStatus = New-Object System.Windows.Forms.Label
$lblStatus.Text = "Status: -"
$lblStatus.Location = New-Object System.Drawing.Point(210,50)
$lblStatus.AutoSize = $true
$lblStatus.ForeColor = [System.Drawing.Color]::Gray
$form.Controls.Add($lblStatus)
# Input status/update
$lblInput = New-Object System.Windows.Forms.Label
$lblInput.Text = "Input"
$lblInput.Location = New-Object System.Drawing.Point(10,85)
$form.Controls.Add($lblInput)
$cboInput = New-Object System.Windows.Forms.ComboBox
$cboInput.Location = New-Object System.Drawing.Point(120,80)
$cboInput.Width = 175
$cboInput.DropDownStyle = "DropDownList"
$cboInput.Items.AddRange($cfg.capabilities.input.set)
$form.Controls.Add($cboInput)
# Volume status/update with value and slider
$lblVol = New-Object System.Windows.Forms.Label
$lblVol.Text = "Volume"
$lblVol.Location = New-Object System.Drawing.Point(10,120)
$form.Controls.Add($lblVol)
$txtVol = New-Object System.Windows.Forms.TextBox
$txtVol.Location = New-Object System.Drawing.Point(120,115)
$txtVol.Width = 60
$form.Controls.Add($txtVol)
$trkVol = New-Object System.Windows.Forms.TrackBar
$trkVol.Location = New-Object System.Drawing.Point(200,110)
$trkVol.Width = 300
$trkVol.Height = 30
$trkVol.Minimum = [int]$cfg.capabilities.volume.setRange[0]
$trkVol.Maximum = [int]$cfg.capabilities.volume.setRange[1]
$trkVol.TickFrequency = 10 # markers all 10
$trkVol.SmallChange = 1 # Cursor-Keys for small hops
$trkVol.LargeChange = 10 # PageUp/Down for big hops
$form.Controls.Add($trkVol)
# Mute status/update
$lblMute = New-Object System.Windows.Forms.Label
$lblMute.Text = "Mute"
$lblMute.Location = New-Object System.Drawing.Point(10,155)
$form.Controls.Add($lblMute)
$cboMute = New-Object System.Windows.Forms.ComboBox
$cboMute.Location = New-Object System.Drawing.Point(120,150)
$cboMute.Width = 60
$cboMute.DropDownStyle = "DropDownList"
$cboMute.Items.AddRange(@("ON","OFF"))
$form.Controls.Add($cboMute)
# Refresh Button for Status Update
$btnRefresh = New-Object System.Windows.Forms.Button
$btnRefresh.Text = "Refresh"
$btnRefresh.Location = New-Object System.Drawing.Point(50,200)
$form.Controls.Add($btnRefresh)
# Apply-Button to push changes
$btnApply = New-Object System.Windows.Forms.Button
$btnApply.Text = "Apply"
$btnApply.Location = New-Object System.Drawing.Point(160,200)
$form.Controls.Add($btnApply)
# Ping-Button for test network reachability
$btnPing = New-Object System.Windows.Forms.Button
$btnPing.Text = "Ping"
$btnPing.Location = New-Object System.Drawing.Point(270,200)
$form.Controls.Add($btnPing)
# Exit-Button
$btnExit = New-Object System.Windows.Forms.Button
$btnExit.Text = "Exit"
$btnExit.Location = New-Object System.Drawing.Point(380,200)
$btnExit.Add_Click({ $form.Close() })
$form.Controls.Add($btnExit)
# Log-Textbox
$txtLog = New-Object System.Windows.Forms.TextBox
# Use monospace font for better log alignment
$txtLog.Font = New-Object System.Drawing.Font("Consolas", 8, [System.Drawing.FontStyle]::Regular)
$txtLog.Multiline = $true
$txtLog.ReadOnly = $true
$txtLog.ScrollBars = "Both" # Vertical, Horizontal
$txtLog.WordWrap = $false # important for horizontal ScrollBars
$txtLog.Location = New-Object System.Drawing.Point(10,235)
$txtLog.Width = 490
$txtLog.Height = 220 # deutlich größer
# unten breit andocken
$txtLog.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom `
-bor [System.Windows.Forms.AnchorStyles]::Left `
-bor [System.Windows.Forms.AnchorStyles]::Right
$form.Controls.Add($txtLog)
function Add-LogLine([string]$msg) {
# Leerzeile ohne Timestamp
if ([string]::IsNullOrWhiteSpace($msg)) {
$txtLog.AppendText("`r`n")
}
else {
# Normale Zeile mit Timestamp
$ts = (Get-Date).ToString("HH:mm:ss")
$txtLog.AppendText("[${ts}] $msg`r`n")
}
# Gemeinsamer Scroll/Auto-Scroll
$txtLog.SelectionStart = $txtLog.Text.Length
$txtLog.ScrollToCaret()
}
function LogCmd([string]$cmdLine) { Add-LogLine("CMD : " + $cmdLine) }
function LogOut([string]$m) { Add-LogLine("RESP: " + $m) }
function Log([string]$m) { Add-LogLine($m) }
function Set-UiStatus {
param(
[string] $Text,
[string] $State # "ok", "warn", "error", "none"
)
if (-not $lblStatus) { return }
if ([string]::IsNullOrWhiteSpace($Text)) {
$lblStatus.Text = "Status: -"
} else {
$lblStatus.Text = "Status: " + $Text
}
switch ($State) {
"ok" { $lblStatus.ForeColor = [System.Drawing.Color]::Green }
"warn" { $lblStatus.ForeColor = [System.Drawing.Color]::Goldenrod }
"error" { $lblStatus.ForeColor = [System.Drawing.Color]::Red }
default { $lblStatus.ForeColor = [System.Drawing.Color]::Gray }
}
}
function Format-MdcCmdString {
param(
[string] $Target,
[string] $Pin,
[string] $Command,
[string[]] $Args
)
$usePin = -not [string]::IsNullOrWhiteSpace($Pin) -and $Pin -ne "none"
$pinPart = ""
if ($usePin) {
$pinPart = " --pin *****"
}
$argText = ""
if ($Args -and $Args.Count -gt 0) {
$argText = " " + ($Args -join " ")
}
return "wsl -- samsung-mdc" + $pinPart + " " + $Target + " " + $Command + $argText
}
function Get-MdcErrorFromOutput {
param(
[object] $Output
)
if ($null -eq $Output) { return $null }
$flat = ""
if ($Output -is [System.Array]) {
$flat = ($Output -join " ")
} else {
$flat = [string]$Output
}
if ([string]::IsNullOrWhiteSpace($flat)) {
return $null
}
if ($flat -match "MDCTLSAuthFailed") {
return "PIN error (MDCTLSAuthFailed)"
}
elseif ($flat -match "MDCTLSRequired") {
return "TLS/PIN required (MDCTLSRequired)"
}
elseif ($flat -match "MDCSTART<<TLS>>") {
return "TLS handshake required (MDCSTART<<TLS>>)"
}
return $null
}
function Get-SelectedTarget {
if ($cboTarget.SelectedItem -and $cboTarget.SelectedItem.Target) {
return $cboTarget.SelectedItem.Target
}
return $null
}
function Set-Busy([bool]$busy) {
$form.UseWaitCursor = $busy
if ($busy) { [System.Windows.Forms.Cursor]::Current = [System.Windows.Forms.Cursors]::WaitCursor }
else { [System.Windows.Forms.Cursor]::Current = [System.Windows.Forms.Cursors]::Default }
$cboTarget.Enabled = -not $busy
$cboPower.Enabled = -not $busy
$cboInput.Enabled = (-not $busy) -and $cboInput.Enabled
$txtVol.Enabled = (-not $busy) -and $txtVol.Enabled
$trkVol.Enabled = (-not $busy) -and $trkVol.Enabled
$cboMute.Enabled = (-not $busy) -and $cboMute.Enabled
$btnRefresh.Enabled = -not $busy
$btnApply.Enabled = -not $busy
if ($btnExit) { $btnExit.Enabled = -not $busy }
$form.Refresh()
}
$updateUI = {
$t = Get-SelectedTarget
if (-not $t) { return }
Add-LogLine "" # leere Zeile als Trennung zwischen Aktionen
try {
Set-Busy $true
$hadError = $false
$lastError = $null
# POWER
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "power"
LogCmd $cmd
$powerOut = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command power
LogOut ($powerOut -join " ")
$pstate = "UNKNOWN"
if ($powerOut -match "POWER_STATE\.(\w+):\d+") { $pstate = $Matches[1] }
$cboPower.SelectedItem = $pstate
$err = Get-MdcErrorFromOutput $powerOut
if ($err) {
$hadError = $true
$lastError = $err
}
$input = $null
$vol = $null
$mute = $null
if ($pstate -eq "ON") {
# INPUT_SOURCE
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "input_source"
LogCmd $cmd
$inOut = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command input_source
LogOut ($inOut -join " ")
if ($inOut -match "INPUT_SOURCE_STATE\.(\w+):\d+") { $input = $Matches[1] }
$err = Get-MdcErrorFromOutput $inOut
if ($err) {
$hadError = $true
$lastError = $err
}
# VOLUME
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "volume"
LogCmd $cmd
$volOut = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command volume
LogOut ($volOut -join " ")
if ($volOut -match "(\d+)\s*$") { $vol = $Matches[1] }
$err = Get-MdcErrorFromOutput $inOut
if ($err) {
$hadError = $true
$lastError = $err
}
# MUTE
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "mute"
LogCmd $cmd
$muteOut = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command mute
LogOut ($muteOut -join " ")
if ($muteOut -match "MUTE_STATE\.(\w+):\d+") { $mute = $Matches[1] }
$err = Get-MdcErrorFromOutput $inOut
if ($err) {
$hadError = $true
$lastError = $err
}
$cboInput.Enabled = $true
$txtVol.Enabled = $true
$trkVol.Enabled = $true
$cboMute.Enabled = $true
} else {
$cboInput.Enabled = $false
$txtVol.Enabled = $false
$trkVol.Enabled = $false
$cboMute.Enabled = $false
}
if ($input) {
$cboInput.SelectedItem = $input
}
if ($vol) {
$txtVol.Text = [string]$vol
$v = 0
if ([int]::TryParse([string]$vol, [ref]$v) -and $v -ge $trkVol.Minimum -and $v -le $trkVol.Maximum) {
$trkVol.Value = $v
}
}
if ($mute) {
$cboMute.SelectedItem = $mute
}
if ($hadError -and $lastError) {
Log ("WARN: " + $lastError)
Set-UiStatus $lastError "error"
}
else {
Log "OK: status updated"
Set-UiStatus "OK (Refresh)" "ok"
}
}
catch {
LogOut ("ERROR: " + $_.Exception.Message)
Set-UiStatus "Error (Refresh)" "error"
}
finally {
Set-Busy $false
}
}
$cboTarget.Add_SelectedIndexChanged({ & $updateUI })
$btnRefresh.Add_Click({ & $updateUI })
$trkVol.Add_Scroll({ $txtVol.Text = $trkVol.Value.ToString() })
$btnApply.Add_Click({
$t = Get-SelectedTarget
if (-not $t) { return }
Add-LogLine "" # leere Zeile als Trennung zwischen Aktionen
try {
Set-Busy $true
$hadError = $false
$lastError = $null
# Power zuerst
$wantPower = $cboPower.SelectedItem
if ($wantPower) {
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "power" -Args @($wantPower.ToLower())
LogCmd $cmd
$res = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command power -Args @($wantPower.ToLower())
LogOut ($res -join " ")
$err = Get-MdcErrorFromOutput $res
if ($err) {
$hadError = $true
$lastError = $err
}
Start-Sleep -Seconds 1
}
# Neu lesen, damit wir wissen ob jetzt ON
$s = Get-MdcStatus -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro
if ($s.Power -eq "ON") {
if ($cboInput.SelectedItem) {
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "input_source" -Args @($cboInput.SelectedItem)
LogCmd $cmd
$res = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command input_source -Args @($cboInput.SelectedItem)
LogOut ($res -join " ")
$err = Get-MdcErrorFromOutput $res
if ($err) {
$hadError = $true
$lastError = $err
}
}
if ($txtVol.Text -match "^\d+$") {
$v = [int]$txtVol.Text
if ($v -lt $trkVol.Minimum) { $v = $trkVol.Minimum }
if ($v -gt $trkVol.Maximum) { $v = $trkVol.Maximum }
$trkVol.Value = $v
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "volume" -Args @($v.ToString())
LogCmd $cmd
$res = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command volume -Args @($v.ToString())
LogOut ($res -join " ")
$err = Get-MdcErrorFromOutput $res
if ($err) {
$hadError = $true
$lastError = $err
}
}
if ($cboMute.SelectedItem) {
$cmd = Format-MdcCmdString -Target $t -Pin $cfg.pin -Command "mute" -Args @($cboMute.SelectedItem.ToLower())
LogCmd $cmd
$res = Invoke-Mdc -Target $t -Pin $cfg.pin -Timeout $cfg.timeout -Distro $cfg.wslDistro -Command mute -Args @($cboMute.SelectedItem.ToLower())
LogOut ($res -join " ")
$err = Get-MdcErrorFromOutput $res
if ($err) {
$hadError = $true
$lastError = $err
}
}
}
# Auto-Refresh am Ende
& $updateUI
if ($hadError -and $lastError) {
Set-UiStatus $lastError "error"
}
else {
Set-UiStatus "OK (Apply)" "ok"
}
}
catch {
LogOut ("ERROR (Apply): " + $_.Exception.Message)
Set-UiStatus "Error (Apply)" "error"
}
finally {
Set-Busy $false
}
})
$btnPing.Add_Click({
$t = Get-SelectedTarget
if (-not $t) { return }
Add-LogLine ""
# Host aus DISPLAYID@HOST:PORT extrahieren
$flipHost = $null
$atIdx = $t.IndexOf("@")
if ($atIdx -ge 0) {
$rest = $t.Substring($atIdx + 1)
} else {
$rest = $t
}
$colonIdx = $rest.IndexOf(":")
if ($colonIdx -ge 0) {
$flipHost = $rest.Substring(0, $colonIdx)
} else {
$flipHost = $rest
}
Add-LogLine ("Ping test for " + $flipHost)
# Windows Ping
$winOk = $false
try {
$winOk = [bool](Test-Connection -ComputerName $flipHost -Count 1 -Quiet -ErrorAction Stop)
} catch {
$winOk = $false
}
if ($winOk) {
Add-LogLine "Ping (Windows): OK"
} else {
Add-LogLine "Ping (Windows): FAILED"
}
# WSL Ping
try {
$wslPing = & wsl ping -c 1 $flipHost 2>&1
if ($wslPing -is [System.Array]) { $wslPing = $wslPing -join " " }
if ($wslPing -match "1 received" -or $wslPing -match ", 0% packet loss") {
Add-LogLine "Ping (WSL): OK"
} else {
Add-LogLine ("Ping (WSL): FAILED - " + $wslPing)
}
} catch {
Add-LogLine ("Ping (WSL): ERROR - " + $_.Exception.Message)
}
})
# --- Startup WSL diagnostics ---
try {
Add-LogLine ""
$distId = ""
$pretty = ""
# ID=... (z.B. debian, ubuntu)
try {
$distIdRaw = & wsl -- sed -ne 's/^ID=//p' /etc/os-release 2>&1
if ($distIdRaw -is [System.Array]) { $distIdRaw = $distIdRaw -join " " }
$distId = ($distIdRaw | Out-String).Trim()
}
catch {
# ignore
}
# PRETTY_NAME=... (z.B. "Debian GNU/Linux 13 (trixie)")
try {
$prettyRaw = & wsl -- sed -ne 's/^PRETTY_NAME=//p' /etc/os-release 2>&1
if ($prettyRaw -is [System.Array]) { $prettyRaw = $prettyRaw -join " " }
$pretty = ($prettyRaw | Out-String).Trim()
}
catch {
# ignore
}
# Label bauen: bevorzugt PRETTY_NAME, sonst ID, sonst Config-Fallback
$label = $null
if (-not [string]::IsNullOrWhiteSpace($pretty)) {
if (-not [string]::IsNullOrWhiteSpace($distId)) {
$label = $pretty + " (" + $distId + ")"
} else {
$label = $pretty
}
}
elseif (-not [string]::IsNullOrWhiteSpace($distId)) {
$label = $distId
}
elseif ($cfg -and -not [string]::IsNullOrWhiteSpace($cfg.wslDistro)) {
# Fallback auf Config-Wert, z.B. "Debian"
$label = $cfg.wslDistro
}
if ($label) {
Add-LogLine ("WSL default distro: " + $label)
} else {
Add-LogLine "WSL default distro: (could not detect)"
}
Add-LogLine ""
# samsung-mdc Version wie gewohnt loggen
LogCmd "wsl -- samsung-mdc --version"
$ver = & wsl -- samsung-mdc --version 2>&1
if ($ver -is [System.Array]) { $ver = $ver -join " " }
LogOut ($ver)
}
catch {
LogOut ("ERROR (WSL/samsung-mdc): " + $_.Exception.Message)
}
# Erstes Display vorauswählen + initialen Status holen, sobald das Formular angezeigt wird
$form.Add_Shown({
try {
if ($cboTarget.Items.Count -gt 0) {
$cboTarget.SelectedIndex = 0
& $updateUI
}
}
catch {
LogOut ("ERROR (initial updateUI): " + $_.Exception.Message)
}
})
Set-UiStatus "" "none"
[void]$form.ShowDialog()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment