# ============================================================================== # CONFIGURATIE & KLEUREN # ============================================================================== $baseUrl = "https://scripts.vdbrandt.net" $menuColor = "Cyan" $folderColor = "White" $scriptNameColor = "Green" $fileNameColor = "Gray" $emptyColor = "Yellow" $errorColor = "Red" # Vaste, simpele lijn-variabelen (80 tekens breed) $headerBorder = "================================================================================" $subBorder = "--------------------------------------------------------------------------------" # ============================================================================== # INITIALISATIE # ============================================================================== $rootUrl = "$baseUrl/scripts/" $currentUrl = $rootUrl $history = @() # Maak een geruisloos .NET web-object aan om de blauwe balk te voorkomen $webClient = New-Object System.Net.WebClient while ($true) { Clear-Host # Bepaal de naam voor de header if ($currentUrl -eq $rootUrl) { $menuTitle = "HOOFDMENU" } else { $decodedDirName = [System.Uri]::UnescapeDataString(($currentUrl.TrimEnd('/') -split '/')[-1]) $menuTitle = $decodedDirName.ToUpper() } # Bepaal de benodigde spaties om de titel redelijk te centreren binnen de 80 tekens $spacesNeeded = [math]::Max(0, [int]((80 - $menuTitle.Length) / 2)) $centeredTitle = (" " * $spacesNeeded) + $menuTitle Write-Host "" Write-Host $headerBorder -ForegroundColor $menuColor Write-Host $centeredTitle -ForegroundColor $menuColor Write-Host $headerBorder -ForegroundColor $menuColor Write-Host "" try { # Download de HTML-mappenlijst geruisloos via .NET $htmlContent = $webClient.DownloadString($currentUrl) # Haal alle href="..." waarden op $hrefPattern = 'href="([^"]+)"' $links = [regex]::Matches($htmlContent, $hrefPattern) | ForEach-Object { $_.Groups.Value } # Filter de links streng om hoofdmappen en server-links uit te sluiten $filteredLinks = $links | Where-Object { $_ -notmatch "\?" -and $_ -notmatch "^\.\./" -and $_ -notmatch "^http" -and $_ -ne "/" -and $_ -ne "menu.ps1" -and $_ -ne "scripts" -and $_ -notmatch "^/scripts" } } catch { Write-Host "Fout bij ophalen van webserver data: $_" -ForegroundColor $errorColor Read-Host "Druk op Enter om af te sluiten..." break } $menuItems = @() $index = 1 foreach ($href in $filteredLinks) { if ($href -match "/$") { $decodedDir = [System.Uri]::UnescapeDataString($href.TrimEnd('/')) $menuItems += [PSCustomObject]@{ Index = $index Type = "Folder" MenuName = "[$decodedDir]" ScriptName = $null ScriptInfo = @() FileName = $href } $index++ } elseif ($href -match "\.ps1$") { $decodedFileName = [System.Uri]::UnescapeDataString($href) $menuName = $decodedFileName $hasScriptName = $false $scriptInfoLines = @() try { $fileUrl = $currentUrl + $href $fileBody = $webClient.DownloadString($fileUrl) if ($fileBody) { # 1. Zoek naar #scriptname: via RegEx if ($fileBody -match '(?mi)^\s*#\s*scriptname:\s*(.*)$') { # MET KRACHT GECORRIGEERD: Index 1 staat nu gegarandeerd correct $customName = $Matches[1].Trim() if ($customName) { $menuName = $customName $hasScriptName = $true } } # 2. Zoek naar alle regels die beginnen met #scriptinfo: #$infoMatches = [regex]::Matches($fileBody, '(?mi)^\s*#\s*scriptinfo:\s*(.*)$') $infoMatches = [regex]::Matches($fileBody, '(?mi)^[ \t]*#[ \t]*scriptinfo:[ \t]*(.*)$') foreach ($match in $infoMatches) { # MET KRACHT GECORRIGEERD: Index 1 staat nu gegarandeerd correct # $cleanInfoLine = $match.Groups[1].Value.Trim() # if ($cleanInfoLine) { # $scriptInfoLines += $cleanInfoLine # } # 2. Haal de tekst achter de dubbele punt op (leeg blijft leeg) $scriptInfoLines = foreach ($match in $infoMatches) { $match.Groups[1].Value } } } } catch { # Stille fallback } $menuItems += [PSCustomObject]@{ Index = $index Type = "File" MenuName = $menuName ScriptName = if ($hasScriptName) { $menuName } else { $null } ScriptInfo = $scriptInfoLines FileName = $href } $index++ } } # Toon de menu-opties if ($menuItems.Count -eq 0) { Write-Host "(Geen bestanden of mappen gevonden)" -ForegroundColor $emptyColor } else { foreach ($item in $menuItems) { $paddedIndex = "$($item.Index).".PadRight(4) if ($item.Type -eq "Folder") { Write-Host "$paddedIndex $($item.MenuName)" -ForegroundColor $folderColor } else { if ($item.ScriptName) { Write-Host "$paddedIndex $($item.MenuName)" -ForegroundColor $scriptNameColor } else { Write-Host "$paddedIndex $($item.MenuName)" -ForegroundColor $fileNameColor } } } } # Witregel boven de dunne lijn in het hoofdmenu Write-Host "" Write-Host $subBorder -ForegroundColor $menuColor if ($currentUrl -eq $rootUrl) { Write-Host "x. Verlaat script" -ForegroundColor $menuColor } else { Write-Host "x. Terug naar bovenliggende map" -ForegroundColor $menuColor } Write-Host "" $input = Read-Host "Maak een keuze" $input = $input.Trim() if ($input -eq 'x') { if ($currentUrl -eq $rootUrl) { Clear-Host $webClient.Dispose() Write-Host "" Write-Host "Menu beeindigd." -ForegroundColor $menuColor Write-Host "" break } else { $currentUrl = $history[-1] $history = $history[0..($history.Count - 2)] continue } } # Check of de invoer begint met 'i ' of 'i' gevolgd door een getal $showInfoOnly = $false $targetIndexText = $input if ($input -match '^i\s+(.+)$' -or $input -match '^i(\d+)$') { $showInfoOnly = $true # MET KRACHT GECORRIGEERD: Index 1 staat nu gegarandeerd correct $targetIndexText = $Matches[1].Trim() } $selection = $null if ([int]::TryParse($targetIndexText, [ref]$selection)) { $chosenItem = $menuItems | Where-Object { $_.Index -eq $selection } if ($chosenItem) { if ($chosenItem.Type -eq "Folder") { if ($showInfoOnly) { Write-Host "Informatie opvragen is alleen mogelijk voor scripts, niet voor mappen." -ForegroundColor $errorColor Start-Sleep -Seconds 2 } else { $history += $currentUrl $currentUrl = $currentUrl + $chosenItem.FileName } } elseif ($chosenItem.Type -eq "File") { $targetFileUrl = $currentUrl + $chosenItem.FileName # Bepaal de displaynaam voor de balken $runningName = $chosenItem.FileName if ($chosenItem.ScriptName) { $runningName = $chosenItem.ScriptName } $forceExecuteAfterInfo = $false if ($showInfoOnly) { # --- ACTIE: TOON INFO BLOK (i 2) --- Clear-Host Write-Host "" Write-Host $headerBorder -ForegroundColor $menuColor Write-Host "INFO: " -ForegroundColor $menuColor -NoNewline Write-Host "$runningName" -ForegroundColor $scriptNameColor Write-Host $headerBorder -ForegroundColor $menuColor $pureFileName = [System.Uri]::UnescapeDataString($chosenItem.FileName) Write-Host "Script: $pureFileName" -ForegroundColor $scriptNameColor Write-Host "" if ($chosenItem.ScriptInfo.Count -gt 0) { foreach ($infoLine in $chosenItem.ScriptInfo) { Write-Host "$infoLine" -ForegroundColor $scriptNameColor } } else { Write-Host "Geen aanvullende informatie beschikbaar voor dit script." -ForegroundColor $emptyColor } Write-Host "" Write-Host $subBorder -ForegroundColor $menuColor $infoChoice = Read-Host "Druk op R om script te starten of Enter om terug te keren naar het menu" if ($infoChoice.Trim().ToUpper() -eq 'R') { $forceExecuteAfterInfo = $true } } # --- ACTIE: RUN SCRIPT --- if (-not $showInfoOnly -or $forceExecuteAfterInfo) { Clear-Host Write-Host "" Write-Host $headerBorder -ForegroundColor $scriptNameColor Write-Host "START: $runningName" -ForegroundColor $scriptNameColor Write-Host $headerBorder -ForegroundColor $scriptNameColor Write-Host "" try { Invoke-RestMethod -Uri $targetFileUrl -UseBasicParsing | Invoke-Expression } catch { Write-Host "" Write-Host "Fout opgetreden tijdens het uitvoeren van het script: $_" -ForegroundColor $errorColor } Write-Host "" Write-Host $headerBorder -ForegroundColor $scriptNameColor Write-Host "STATUS: Voltooid" -ForegroundColor $scriptNameColor Write-Host $headerBorder -ForegroundColor $scriptNameColor Write-Host "" Read-Host "Druk op Enter om terug te keren naar het menu..." } } } else { Write-Host "Ongeldige keuze, probeer het opnieuw." -ForegroundColor $errorColor Start-Sleep -Seconds 1 } } else { Write-Host "Ongeldige invoer, voer een nummer of 'x' in." -ForegroundColor $errorColor Start-Sleep -Seconds 1 } }