PowerShell – Enterprise-style PowerShell 5.1 GUI for browser link management.

Just another Tech site

PowerShell – Enterprise-style PowerShell 5.1 GUI for browser link management.

Something I thought that might help with link management

 

 

 

 

 

 

 

 

– Audio greetings with female voice, user, and date context.
– Extensive logging to C:\logs\PASS\<yyyyMMDD>\Pass_yyyyMMDD.log.
– Advanced try/catch error handling.
– Dark mode Windows Form with menu bar, status bar, and custom controls.
– Multi-browser support (Edge, Chrome, Firefox).
– Inline GUI layout to directly add or remove text file items dynamically.

Here is the code, still a work in progress but it does work.

<#
.SYNOPSIS
    Enterprise-style PowerShell 5.1 GUI for browser link management.
.DESCRIPTION
    - Audio greetings with female voice, user, and date context.
    - Extensive logging to C:\logs\PASS\<yyyyMMDD>\Pass_yyyyMMDD.log.
    - Advanced try/catch error handling.
    - Dark mode Windows Form with menu bar, status bar, and custom controls.
    - Multi-browser support (Edge, Chrome, Firefox).
    - Inline GUI layout to directly add or remove text file items dynamically.
.NOTES
    Requires Administrator privileges.
    Target: PowerShell 5.1 on Windows.
#>

# Ensure script runs as Administrator
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Warning "This script must be run as an Administrator."
    Exit
}

# --- Configuration & Global Variables ---
$Script:LogDir   = "C:\logs\PASS\$(Get-Date -Format 'yyyyMMDD')"
$Script:LogFile  = Join-Path $Script:LogDir "Pass_$(Get-Date -Format 'yyyyMMDD').log"
$Script:LinksDir = ".\list"
$Script:LinksFile = Join-Path $Script:LinksDir "links.txt"
$Script:LinkDictionary = [System.Collections.Generic.Dictionary[string, string]]::new()

# --- Assembly Loading ---
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Speech

# --- Logging Engine ---
Function Write-Log {
    Param (
        [Parameter(Mandatory=$true)][String]$Message,
        [Parameter(Mandatory=$false)][ValidateSet("INFO", "WARN", "ERROR")][String]$Level = "INFO"
    )
    Try {
        if (-not (Test-Path $Script:LogDir)) {
            New-Item -ItemType Directory -Path $Script:LogDir -Force | Out-Null
        }
        $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        $LogLine = "[$Timestamp] [$Level] $Message"
        Add-Content -Path $Script:LogFile -Value $LogLine -ErrorAction Stop
    }
    Catch {
        Write-Error "Failed to write to log file: $_"
    }
}

# --- Audio Engine (Configured for Female Voice) ---
Function Invoke-VoiceGreeting {
    Param ([Parameter(Mandatory=$true)][String]$Type)
    Try {
        $Synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
        
        # Explicitly search for and select an installed female voice profile
        Try {
            $Synth.SelectVoiceByHints([System.Speech.Synthesis.VoiceGender]::Female)
        }
        Catch {
            Write-Log "Requested female voice profile not found. Using system standard voice instead." "WARN"
        }

        $User = [Environment]::UserName
        $DateString = Get-Date -Format "dddd, MMMM d, yyyy"
        $TimeString = Get-Date -Format "h:mm tt"
        
        if ($Type -eq "Start") {
            $Text = "Welcome $User. Today is $DateString, and the current time is $TimeString. BAT-TECH-LINKS Starting."
        } else {
            $Text = "Goodbye $User. Session ending on $DateString at $TimeString. Updating logs and closing application."
        }
        $Synth.Speak($Text)
    }
    Catch {
        Write-Log "Voice synthesis completely failed: $_" "WARN"
    }
}

# --- UI Helper Engines ---
Function Update-Status {
    Param (
        [Parameter(Mandatory=$true)][String]$Text,
        [Parameter(Mandatory=$true)][Boolean]$IsError
    )
    $StatusTextBox.Text = $Text
    if ($IsError) {
        $StatusTextBox.ForeColor = [System.Drawing.Color]::Red
        $StatusLabel.Text = " Error occurred."
    } else {
        $StatusTextBox.ForeColor = [System.Drawing.Color]::LimeGreen
        $StatusLabel.Text = " Ready."
    }
}

# --- File/Data Management Engine ---
Function Load-LinksFile {
    Try {
        if (-not (Test-Path $Script:LinksDir)) {
            New-Item -ItemType Directory -Path $Script:LinksDir -Force | Out-Null
        }
        if (-not (Test-Path $Script:LinksFile)) {
            New-Item -ItemType File -Path $Script:LinksFile -Force | Out-Null
            Add-Content -Path $Script:LinksFile -Value "Google,https://google.com"
        }
        
        $Script:LinkDictionary.Clear()
        $Dropdown.Items.Clear()
        
        $Lines = Get-Content -Path $Script:LinksFile
        foreach ($Line in $Lines) {
            if ($Line -match "^([^,]+),(.+)$") {
                $Name = $Matches[1].Trim()
                $Url = $Matches[2].Trim()
                if (-not $Script:LinkDictionary.ContainsKey($Name)) {
                    $Script:LinkDictionary.Add($Name, $Url)
                    [void]$Dropdown.Items.Add($Name)
                }
            }
        }
        if ($Dropdown.Items.Count -gt 0) { 
            $Dropdown.SelectedIndex = 0 
        } else {
            $Dropdown.Text = ""
        }
        Write-Log "Successfully loaded $($Script:LinkDictionary.Count) links from flat file." "INFO"
    }
    Catch {
        Write-Log "Error processing links file: $_" "ERROR"
    }
}

Function Save-LinksFile {
    Try {
        $Lines = @()
        foreach ($Key in $Script:LinkDictionary.Keys) {
            $Lines += "$Key,$($Script:LinkDictionary[$Key])"
        }
        Set-Content -Path $Script:LinksFile -Value $Lines -ErrorAction Stop
        Write-Log "Flat database synchronized successfully." "INFO"
    }
    Catch {
        Write-Log "Failed saving data to flat file: $_" "ERROR"
        Update-Status "Failed: Database file save error." $true
    }
}

# --- Browser Launch Engine ---
Function Launch-Browser {
    Param (
        [Parameter(Mandatory=$true)][String]$BrowserExe,
        [Parameter(Mandatory=$true)][String]$BrowserName
    )
    $SelectedName = $Dropdown.SelectedItem
    if ([string]::IsNullOrEmpty($SelectedName)) {
        Update-Status "Failed: No link item selected." $true
        Return
    }
    
    Try {
        $Url = $Script:LinkDictionary[$SelectedName]
        Write-Log "Attempting to launch $BrowserName to $Url" "INFO"
        
        $Process = Start-Process $BrowserExe -ArgumentList $Url -PassThru -ErrorAction Stop
        Update-Status "Successful: Opened $SelectedName in $BrowserName." $false
        Write-Log "Successfully launched $BrowserName (PID: $($Process.Id))" "INFO"
    }
    Catch {
        $ErrorMsg = "Failed to launch $BrowserName. Verify browser installation."
        Update-Status "Failed: See log for details." $true
        Write-Log "$ErrorMsg Details: $_" "ERROR"
    }
}

# --- Initialization & Form Layout (Dark Mode) ---
Write-Log "Initializing Application GUI Framework..." "INFO"
Invoke-VoiceGreeting "Start"

$Form = New-Object System.Windows.Forms.Form
$Form.Text = "BAT-TECH Enterprise Link Hub v3.0"
$Form.Size = New-Object System.Drawing.Size(520, 560)
$Form.StartPosition = "CenterScreen"
$Form.BackColor = [System.Drawing.Color]::FromArgb(30, 30, 30)
$Form.ForeColor = [System.Drawing.Color]::White
$Form.Font = New-Object System.Drawing.Font("Segoe UI", 10)
$Form.FormBorderStyle = "FixedSingle"
$Form.MaximizeBox = $false

# Font Templates
$FontStatus = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold)

# 1. Menu Bar
$MenuStrip = New-Object System.Windows.Forms.MenuStrip
$MenuStrip.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
$MenuStrip.ForeColor = [System.Drawing.Color]::White

$FileMenu = New-Object System.Windows.Forms.ToolStripMenuItem("File")
$FileMenu.ForeColor = [System.Drawing.Color]::White
$ExitMenuItem = New-Object System.Windows.Forms.ToolStripMenuItem("Exit")
$ExitMenuItem.ForeColor = [System.Drawing.Color]::Black
$ExitMenuItem.Add_Click({ $Form.Close() })
[void]$FileMenu.DropDownItems.Add($ExitMenuItem)
[void]$MenuStrip.Items.Add($FileMenu)
$Form.MainMenuStrip = $MenuStrip
$Form.Controls.Add($MenuStrip)

# 2. Main Label
$DropdownLabel = New-Object System.Windows.Forms.Label
$DropdownLabel.Text = "Select Target Asset URL:"
$DropdownLabel.Location = New-Object System.Drawing.Point(25, 50)
$DropdownLabel.Size = New-Object System.Drawing.Size(200, 25)
$Form.Controls.Add($DropdownLabel)

# 3. Dropdown Box
$Dropdown = New-Object System.Windows.Forms.ComboBox
$Dropdown.Location = New-Object System.Drawing.Point(25, 80)
$Dropdown.Size = New-Object System.Drawing.Size(450, 30)
$Dropdown.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList
$Dropdown.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
$Dropdown.ForeColor = [System.Drawing.Color]::White
$Form.Controls.Add($Dropdown)

# 4. Action Buttons (Browser Launchers)
$BtnEdge = New-Object System.Windows.Forms.Button
$BtnEdge.Text = "Open in Edge"
$BtnEdge.Location = New-Object System.Drawing.Point(25, 130)
$BtnEdge.Size = New-Object System.Drawing.Size(140, 35)
$BtnEdge.BackColor = [System.Drawing.Color]::FromArgb(0, 122, 204)
$BtnEdge.FlatStyle = "Flat"
$BtnEdge.Add_Click({ Launch-Browser "msedge.exe" "Microsoft Edge" })
$Form.Controls.Add($BtnEdge)

$BtnChrome = New-Object System.Windows.Forms.Button
$BtnChrome.Text = "Open in Chrome"
$BtnChrome.Location = New-Object System.Drawing.Point(180, 130)
$BtnChrome.Size = New-Object System.Drawing.Size(140, 35)
$BtnChrome.BackColor = [System.Drawing.Color]::FromArgb(60, 60, 60)
$BtnChrome.FlatStyle = "Flat"
$BtnChrome.Add_Click({ Launch-Browser "chrome.exe" "Google Chrome" })
$Form.Controls.Add($BtnChrome)

$BtnFirefox = New-Object System.Windows.Forms.Button
$BtnFirefox.Text = "Open in Firefox"
$BtnFirefox.Location = New-Object System.Drawing.Point(335, 130)
$BtnFirefox.Size = New-Object System.Drawing.Size(140, 35)
$BtnFirefox.BackColor = [System.Drawing.Color]::FromArgb(60, 60, 60)
$BtnFirefox.FlatStyle = "Flat"
$BtnFirefox.Add_Click({ Launch-Browser "firefox.exe" "Mozilla Firefox" })
$Form.Controls.Add($BtnFirefox)

# Divider Line
$Divider = New-Object System.Windows.Forms.Label
$Divider.Location = New-Object System.Drawing.Point(25, 185)
$Divider.Size = New-Object System.Drawing.Size(450, 2)
$Divider.BorderStyle = "Fixed3D"
$Form.Controls.Add($Divider)

# 5. File Management Actions (Inline UI Controls)
$TxtNameLabel = New-Object System.Windows.Forms.Label
$TxtNameLabel.Text = "Link Name:"
$TxtNameLabel.Location = New-Object System.Drawing.Point(25, 200)
$TxtNameLabel.Size = New-Object System.Drawing.Size(100, 20)
$Form.Controls.Add($TxtNameLabel)

$TxtName = New-Object System.Windows.Forms.TextBox
$TxtName.Location = New-Object System.Drawing.Point(25, 225)
$TxtName.Size = New-Object System.Drawing.Size(130, 25)
$TxtName.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
$TxtName.ForeColor = [System.Drawing.Color]::White
$Form.Controls.Add($TxtName)

$TxtUrlLabel = New-Object System.Windows.Forms.Label
$TxtUrlLabel.Text = "URL Address:"
$TxtUrlLabel.Location = New-Object System.Drawing.Point(170, 200)
$TxtUrlLabel.Size = New-Object System.Drawing.Size(100, 20)
$Form.Controls.Add($TxtUrlLabel)

$TxtUrl = New-Object System.Windows.Forms.TextBox
$TxtUrl.Location = New-Object System.Drawing.Point(170, 225)
$TxtUrl.Size = New-Object System.Drawing.Size(305, 25)
$TxtUrl.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
$TxtUrl.ForeColor = [System.Drawing.Color]::White
$Form.Controls.Add($TxtUrl)

$BtnAdd = New-Object System.Windows.Forms.Button
$BtnAdd.Text = "Add / Update Link"
$BtnAdd.Location = New-Object System.Drawing.Point(25, 265)
$BtnAdd.Size = New-Object System.Drawing.Size(215, 35)
$BtnAdd.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
$BtnAdd.FlatStyle = "Flat"
$BtnAdd.Add_Click({
    $Name = $TxtName.Text.Trim()
    $Url = $TxtUrl.Text.Trim()
    
    if ([string]::IsNullOrEmpty($Name) -or [string]::IsNullOrEmpty($Url)) {
        Update-Status "Failed: Name and URL fields cannot be empty." $true
        Return
    }
    
    if ($Name -like "*,*" -or $Url -like "*,*") {
        Update-Status "Failed: Commas are not allowed in fields." $true
        Return
    }

    Try {
        if ($Script:LinkDictionary.ContainsKey($Name)) {
            $Script:LinkDictionary[$Name] = $Url
            Write-Log "Updated existing link element: $Name -> $Url" "INFO"
        } else {
            $Script:LinkDictionary.Add($Name, $Url)
            Write-Log "Added new link element: $Name -> $Url" "INFO"
        }
        
        Save-LinksFile
        Load-LinksFile
        
        $Dropdown.SelectedItem = $Name
        $TxtName.Clear()
        $TxtUrl.Clear()
        Update-Status "Successful: Link synced and dropdown updated." $false
    }
    Catch {
        Update-Status "Failed to dynamically add asset link entry." $true
        Write-Log "Runtime dictionary sync operation crashed: $_" "ERROR"
    }
})
$Form.Controls.Add($BtnAdd)

$BtnRemove = New-Object System.Windows.Forms.Button
$BtnRemove.Text = "Remove Selected Link"
$BtnRemove.Location = New-Object System.Drawing.Point(260, 265)
$BtnRemove.Size = New-Object System.Drawing.Size(215, 35)
$BtnRemove.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
$BtnRemove.FlatStyle = "Flat"
$BtnRemove.Add_Click({
    $SelectedName = $Dropdown.SelectedItem
    if ([string]::IsNullOrEmpty($SelectedName)) {
        Update-Status "Failed: No valid drop-down asset entry selected." $true
        Return
    }
    
    Try {
        [void]$Script:LinkDictionary.Remove($SelectedName)
        Write-Log "Purged item '$SelectedName' from database registry." "INFO"
        
        Save-LinksFile
        Load-LinksFile
        
        Update-Status "Successful: Item removed and database synced." $false
    }
    Catch {
        Update-Status "Failed to clean registry reference." $true
        Write-Log "Remove operation target failure: $_" "ERROR"
    }
})
$Form.Controls.Add($BtnRemove)

# Divider Line 2
$Divider2 = New-Object System.Windows.Forms.Label
$Divider2.Location = New-Object System.Drawing.Point(25, 320)
$Divider2.Size = New-Object System.Drawing.Size(450, 2)
$Divider2.BorderStyle = "Fixed3D"
$Form.Controls.Add($Divider2)

# 6. Status Readout Elements
$StatusPanelLabel = New-Object System.Windows.Forms.Label
$StatusPanelLabel.Text = "Operational Status Output Log Window:"
$StatusPanelLabel.Location = New-Object System.Drawing.Point(25, 335)
$StatusPanelLabel.Size = New-Object System.Drawing.Size(300, 25)
$Form.Controls.Add($StatusPanelLabel)

$StatusTextBox = New-Object System.Windows.Forms.TextBox
$StatusTextBox.Location = New-Object System.Drawing.Point(25, 365)
$StatusTextBox.Size = New-Object System.Drawing.Size(450, 30)
$StatusTextBox.ReadOnly = $true
$StatusTextBox.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 20)
$StatusTextBox.Font = $FontStatus
$Form.Controls.Add($StatusTextBox)

# 7. Status Bar Footer
$StatusBar = New-Object System.Windows.Forms.StatusBar
$StatusLabel = New-Object System.Windows.Forms.StatusBarPanel
$StatusLabel.Text = " Initialized safely."
$StatusLabel.Width = 500
$StatusBar.ShowPanels = $true
$StatusBar.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 48)
[void]$StatusBar.Panels.Add($StatusLabel)
$Form.Controls.Add($StatusBar)

# --- Post Layout Runtime Initialization ---
Load-LinksFile
Update-Status "Successful: System loaded. Welcome." $false

# --- Form Shutdown Lifecycle Hook ---
$Form.Add_FormClosing({
    Write-Log "Initiating application graceful teardown routine." "INFO"
    Invoke-VoiceGreeting "End"
    Write-Log "Application session terminated successfully." "INFO"
})

# Launch GUI Environment
[System.Windows.Forms.Application]::Run($Form)

 

 

Tags: , , ,