PSModulePath-Manager.ps1

## PSModulePath Manager - GUI Tool
<#
.SYNOPSIS
    Manage PSModulePath environment variable with GUI
.DESCRIPTION
    Add, remove, and view PSModulePath entries (User-level and System-level)
.NOTES
    Author: Joe Dwumfour
    Version: 1.0.0
    GitHub: https://github.com/dwumfour-io/PowerShell
    License: MIT
#>


[CmdletBinding()]
param()

$script:Version = "1.0.2"
$script:GitHubRepo = "https://github.com/dwumfour-io/PSModulePathManager"
$script:BackupFolder = "$env:LOCALAPPDATA\PSModulePathManager\Backups"

Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase, System.Windows.Forms

# Create backup folder if it doesn't exist
if (-not (Test-Path $script:BackupFolder)) {
    New-Item -ItemType Directory -Path $script:BackupFolder -Force | Out-Null
}

# Auto-backup function
function Backup-PSModulePath {
    try {
        $timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
        $backupFile = Join-Path $script:BackupFolder "PSModulePath_$timestamp.txt"
        
        $userPath = [Environment]::GetEnvironmentVariable("PSModulePath", "User")
        $machinePath = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
        
        $content = @"
# PSModulePath Backup
# Created: $(Get-Date)
 
[USER]
$($userPath -replace ';', "`n")
 
[SYSTEM]
$($machinePath -replace ';', "`n")
"@

        $content | Out-File -FilePath $backupFile -Encoding UTF8
        
        # Keep only last 10 backups
        Get-ChildItem $script:BackupFolder -Filter "PSModulePath_*.txt" | 
            Sort-Object LastWriteTime -Descending | 
            Select-Object -Skip 10 | 
            Remove-Item -Force
        
        return $backupFile
    } catch {
        return $null
    }
}

# Check admin and STA
$isAdmin = [Security.Principal.WindowsPrincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
$needsSta = [System.Threading.Thread]::CurrentThread.ApartmentState -ne 'STA'

if (-not $isAdmin -or $needsSta) {
    $psExe = (Get-Process -Id $PID).Path
    $args = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-WindowStyle', 'Hidden')
    if ($needsSta) { $args += '-STA' }
    $args += '-File', "`"$PSCommandPath`""
    
    $startInfo = New-Object System.Diagnostics.ProcessStartInfo
    $startInfo.FileName = $psExe
    $startInfo.Arguments = $args -join ' '
    $startInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
    $startInfo.CreateNoWindow = $true
    
    if (-not $isAdmin) {
        $startInfo.Verb = 'RunAs'
        $startInfo.UseShellExecute = $true
    } else {
        $startInfo.UseShellExecute = $false
    }
    
    [System.Diagnostics.Process]::Start($startInfo) | Out-Null
    exit
}

try {
# Build UI
$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PSModulePath Manager v$($script:Version)" Width="850" Height="750"
        WindowStartupLocation="CenterScreen" Background="#F0F0F0">
    <Grid Margin="15">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
         
        <Grid Grid.Row="0" Margin="0,0,0,15">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="PSModulePath Manager" FontSize="22" FontWeight="Bold"/>
            <Button Grid.Column="1" x:Name="HelpBtn" Content="Help" Width="80" Height="28"
                    ToolTip="Keyboard shortcuts and help (F1)"/>
        </Grid>
         
        <!-- Stats and Actions Row -->
        <Grid Grid.Row="1" Margin="0,0,0,10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" x:Name="StatsText" FontSize="12" Foreground="#666" VerticalAlignment="Center"/>
            <Button Grid.Column="1" x:Name="RefreshBtn" Content="Refresh" Width="80" Height="28" Margin="0,0,8,0"/>
            <Button Grid.Column="2" x:Name="ExportBtn" Content="Export..." Width="80" Height="28" Margin="0,0,8,0"/>
            <Button Grid.Column="3" x:Name="ImportBtn" Content="Import..." Width="80" Height="28"/>
        </Grid>
         
        <Border Grid.Row="2" BorderBrush="#999" BorderThickness="1" Background="White" Margin="0,0,0,12">
            <ListBox x:Name="PathList" FontFamily="Consolas" FontSize="11" BorderThickness="0"/>
        </Border>
         
        <TextBlock Grid.Row="4" Text="Add/Remove Paths" FontSize="14" FontWeight="SemiBold" Margin="0,5,0,8"/>
         
        <Grid Grid.Row="5" Margin="0,0,0,12">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBox x:Name="PathInput" Grid.Column="0" Height="32" Padding="6"
                     VerticalContentAlignment="Center" Margin="0,0,8,0"/>
            <Button x:Name="BrowseBtn" Grid.Column="1" Content="Browse..." Width="80" Height="32" Margin="0,0,8,0"/>
            <ComboBox x:Name="ScopeCombo" Grid.Column="2" Width="90" Height="32" Margin="0,0,8,0" SelectedIndex="0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
                <ComboBoxItem Content="USER" HorizontalContentAlignment="Center"/>
                <ComboBoxItem Content="SYSTEM" HorizontalContentAlignment="Center"/>
            </ComboBox>
            <Button x:Name="AddBtn" Grid.Column="3" Content="+ Add" Width="90" Height="32"
                    Background="#107C10" Foreground="White" Margin="0,0,8,0" BorderThickness="0"/>
            <Button x:Name="RemoveBtn" Grid.Column="4" Content="- Remove" Width="90" Height="32"
                    Background="#D13438" Foreground="White" BorderThickness="0"/>
        </Grid>
         
        <Grid Grid.Row="6">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="StatusMsg" Grid.Column="0" FontSize="12" VerticalAlignment="Center"/>
            <Button x:Name="CloseBtn" Grid.Column="1" Content="Close" Width="90" Height="32"/>
        </Grid>
    </Grid>
</Window>
"@


$win = [Windows.Markup.XamlReader]::Parse($xaml)
$list = $win.FindName('PathList')
$pathInput = $win.FindName('PathInput')
$status = $win.FindName('StatusMsg')
$statsText = $win.FindName('StatsText')
$scopeCombo = $win.FindName('ScopeCombo')
$addBtn = $win.FindName('AddBtn')
$removeBtn = $win.FindName('RemoveBtn')
$browseBtn = $win.FindName('BrowseBtn')
$refreshBtn = $win.FindName('RefreshBtn')
$exportBtn = $win.FindName('ExportBtn')
$importBtn = $win.FindName('ImportBtn')
$closeBtn = $win.FindName('CloseBtn')
$helpBtn = $win.FindName('HelpBtn')

# Keyboard shortcuts
$win.Add_KeyDown({
    param($sender, $e)
    
    # F1 - Help
    if ($e.Key -eq 'F1') {
        $helpBtn.RaiseEvent((New-Object System.Windows.RoutedEventArgs([System.Windows.Controls.Primitives.ButtonBase]::ClickEvent)))
        $e.Handled = $true
    }
    # F5 - Refresh
    elseif ($e.Key -eq 'F5') {
        $refreshBtn.RaiseEvent((New-Object System.Windows.RoutedEventArgs([System.Windows.Controls.Primitives.ButtonBase]::ClickEvent)))
        $e.Handled = $true
    }
    # Delete - Remove selected
    elseif ($e.Key -eq 'Delete' -and $list.SelectedItem) {
        $selected = $list.SelectedItem.Content.ToString()
        if ($selected -match '^\[(USER|SYSTEM)\]\s*(.+)$') {
            $pathInput.Text = $matches[2]
            $removeBtn.RaiseEvent((New-Object System.Windows.RoutedEventArgs([System.Windows.Controls.Primitives.ButtonBase]::ClickEvent)))
        }
        $e.Handled = $true
    }
    # Ctrl+C - Copy selected path
    elseif ($e.Key -eq 'C' -and $e.KeyboardDevice.Modifiers -eq 'Control' -and $list.SelectedItem) {
        $selected = $list.SelectedItem.Content.ToString()
        if ($selected -match '^\[(USER|SYSTEM)\]\s*(.+)$') {
            [System.Windows.Clipboard]::SetText($matches[2])
            $status.Text = "Path copied to clipboard"
            $status.Foreground = "Green"
        }
        $e.Handled = $true
    }
    # Escape - Close
    elseif ($e.Key -eq 'Escape') {
        $win.Close()
        $e.Handled = $true
    }
})

function RefreshList {
    $userPath = [Environment]::GetEnvironmentVariable("PSModulePath", "User")
    $machinePath = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
    $currentSession = $env:PSModulePath
    
    $userPaths = if($userPath) { $userPath.Split(';') | Where-Object {$_} } else { @() }
    $machinePaths = if($machinePath) { $machinePath.Split(';') | Where-Object {$_} } else { @() }
    $sessionPaths = if($currentSession) { $currentSession.Split(';') | Where-Object {$_} } else { @() }
    
    # Find session-only paths (paths in current session but not in User or Machine)
    $persistentPaths = $userPaths + $machinePaths
    $sessionOnlyPaths = $sessionPaths | Where-Object { $_ -notin $persistentPaths }
    
    $list.Items.Clear()
    
    # Add user paths
    foreach ($p in $userPaths) {
        $item = New-Object System.Windows.Controls.ListBoxItem
        $item.Content = "[USER] $p"
        $item.Background = [System.Windows.Media.Brushes]::LightGreen
        $list.Items.Add($item) | Out-Null
    }
    
    # Add machine paths
    foreach ($p in $machinePaths) {
        $item = New-Object System.Windows.Controls.ListBoxItem
        $item.Content = "[SYSTEM] $p"
        $item.Background = [System.Windows.Media.Brushes]::LightGoldenrodYellow
        $list.Items.Add($item) | Out-Null
    }
    
    # Add session-only paths (temporary, not persistent)
    foreach ($p in $sessionOnlyPaths) {
        $item = New-Object System.Windows.Controls.ListBoxItem
        $item.Content = "[SESSION] $p"
        $item.Background = [System.Windows.Media.Brushes]::LightSkyBlue
        $item.Foreground = [System.Windows.Media.Brushes]::DarkBlue
        $list.Items.Add($item) | Out-Null
    }
    
    # Update stats
    $statsText.Text = "Total: $($list.Items.Count) paths ($($userPaths.Count) USER, $($machinePaths.Count) SYSTEM, $($sessionOnlyPaths.Count) SESSION)"
    
    if (-not $userPaths -and -not $machinePaths) {
        $status.Text = "No paths configured"
        $status.Foreground = "Orange"
    }
}

# Help dialog function
function Show-HelpDialog {
    $helpXaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Help - PSModulePath Manager" Width="600" Height="550"
        WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <StackPanel Margin="20">
            <TextBlock FontSize="18" FontWeight="Bold" Margin="0,0,0,10">PSModulePath Manager</TextBlock>
            <TextBlock FontSize="12" Foreground="#666" Margin="0,0,0,20">Version $($script:Version)</TextBlock>
             
            <TextBlock FontSize="14" FontWeight="SemiBold" Margin="0,10,0,5">About</TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,10">
                Easily manage PowerShell module paths with a graphical interface.
                Add, remove, and organize paths where PowerShell searches for modules.
            </TextBlock>
             
            <TextBlock FontSize="14" FontWeight="SemiBold" Margin="0,10,0,5">Keyboard Shortcuts</TextBlock>
            <Grid Margin="0,0,0,10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                 
                <TextBlock Grid.Row="0" Grid.Column="0" FontFamily="Consolas" Margin="0,2">F1</TextBlock>
                <TextBlock Grid.Row="0" Grid.Column="1" Margin="0,2">Show this help dialog</TextBlock>
                 
                <TextBlock Grid.Row="1" Grid.Column="0" FontFamily="Consolas" Margin="0,2">F5</TextBlock>
                <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,2">Refresh path list</TextBlock>
                 
                <TextBlock Grid.Row="2" Grid.Column="0" FontFamily="Consolas" Margin="0,2">Delete</TextBlock>
                <TextBlock Grid.Row="2" Grid.Column="1" Margin="0,2">Remove selected path</TextBlock>
                 
                <TextBlock Grid.Row="3" Grid.Column="0" FontFamily="Consolas" Margin="0,2">Ctrl+C</TextBlock>
                <TextBlock Grid.Row="3" Grid.Column="1" Margin="0,2">Copy selected path to clipboard</TextBlock>
                 
                <TextBlock Grid.Row="4" Grid.Column="0" FontFamily="Consolas" Margin="0,2">Escape</TextBlock>
                <TextBlock Grid.Row="4" Grid.Column="1" Margin="0,2">Close window</TextBlock>
            </Grid>
             
            <TextBlock FontSize="14" FontWeight="SemiBold" Margin="0,10,0,5">Usage Tips</TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,5">
                â€¢ Green paths = USER scope (only for your account)
            </TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,5">
                â€¢ Orange paths = SYSTEM scope (all users on this computer)
            </TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,5">
                â€¢ Blue paths = SESSION scope (temporary, current session only)
            </TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,5">
                â€¢ Double-click a path to copy or open in Explorer
            </TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,5">
                â€¢ Backups are saved automatically before changes
            </TextBlock>
            <TextBlock TextWrapping="Wrap" Margin="0,0,0,10">
                â€¢ Export/Import to save or restore configurations
            </TextBlock>
             
            <TextBlock FontSize="14" FontWeight="SemiBold" Margin="0,10,0,5">GitHub</TextBlock>
            <TextBlock>
                <Hyperlink x:Name="GitHubLink" NavigateUri="$($script:GitHubRepo)">
                    $($script:GitHubRepo)
                </Hyperlink>
            </TextBlock>
             
            <TextBlock FontSize="14" FontWeight="SemiBold" Margin="0,10,0,5">Backup Location</TextBlock>
            <TextBlock FontFamily="Consolas" FontSize="10" TextWrapping="Wrap">
                %LOCALAPPDATA%\PSModulePathManager\Backups
            </TextBlock>
             
            <Button x:Name="CloseHelpBtn" Content="Close" Width="100" Height="32" Margin="0,20,0,0" HorizontalAlignment="Right"/>
        </StackPanel>
    </ScrollViewer>
</Window>
"@

    
    $helpWin = [Windows.Markup.XamlReader]::Parse($helpXaml)
    $helpWin.FindName('CloseHelpBtn').Add_Click({ $helpWin.Close() })
    
    $githubLink = $helpWin.FindName('GitHubLink')
    if ($githubLink) {
        $githubLink.Add_RequestNavigate({
            param($sender, $e)
            Start-Process $e.Uri.AbsoluteUri
            $e.Handled = $true
        })
    }
    
    $helpWin.ShowDialog() | Out-Null
}

# Browse button - folder picker
$browseBtn.Add_Click({
    $dialog = New-Object System.Windows.Forms.FolderBrowserDialog
    $dialog.Description = "Select a folder to add to PSModulePath"
    $dialog.ShowNewFolderButton = $true
    
    if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
        $pathInput.Text = $dialog.SelectedPath
        $status.Text = "Folder selected. Click '+ Add' to add it."
        $status.Foreground = "Blue"
    }
})

# Add button with validation, scope selection, and auto-backup
# Add button with validation, scope selection, and auto-backup
$addBtn.Add_Click({
    $newPath = $pathInput.Text.Trim()
    if (-not $newPath) {
        $status.Text = "WARNING: Enter a path first"
        $status.Foreground = "Red"
        return
    }
    
    # Create backup before modification
    $backupFile = Backup-PSModulePath
    if ($backupFile) {
        Write-Verbose "Backup created: $backupFile"
    }
    
    # Path validation
    if (-not (Test-Path $newPath)) {
        $result = [System.Windows.MessageBox]::Show(
            "The path does not exist. Add it anyway?",
            "Path Not Found",
            [System.Windows.MessageBoxButton]::YesNo,
            [System.Windows.MessageBoxImage]::Warning
        )
        if ($result -eq [System.Windows.MessageBoxResult]::No) { return }
    }
    
    $scope = $scopeCombo.SelectedItem.Content
    $current = [Environment]::GetEnvironmentVariable("PSModulePath", $scope)
    $paths = if($current){$current.Split(';')}else{@()}
    
    # Check for duplicates in same scope
    if ($paths -contains $newPath) {
        $status.Text = "WARNING: Path already exists in $scope scope"
        $status.Foreground = "Orange"
        return
    }
    
    # Check for duplicates in other scope
    $otherScope = if($scope -eq "User"){"Machine"}else{"User"}
    $otherPath = [Environment]::GetEnvironmentVariable("PSModulePath", $otherScope)
    if ($otherPath -and ($otherPath.Split(';') -contains $newPath)) {
        $result = [System.Windows.MessageBox]::Show(
            "This path already exists in $otherScope scope. Add to $scope scope anyway?",
            "Duplicate Path",
            [System.Windows.MessageBoxButton]::YesNo,
            [System.Windows.MessageBoxImage]::Question
        )
        if ($result -eq [System.Windows.MessageBoxResult]::No) { return }
    }
    
    $updated = (@($paths) + $newPath) -join ';'
    [Environment]::SetEnvironmentVariable("PSModulePath", $updated, $scope)
    $env:PSModulePath = $env:PSModulePath + ";$newPath"
    
    $status.Text = "SUCCESS: Path added to $scope scope (backup created)"
    $status.Foreground = "Green"
    $pathInput.Clear()
    RefreshList
})

# Remove button
$removeBtn.Add_Click({
    $pathToRemove = $pathInput.Text.Trim()
    if (-not $pathToRemove) {
        $status.Text = "WARNING: Enter a path first"
        $status.Foreground = "Red"
        return
    }
    
    # Create backup before modification
    $backupFile = Backup-PSModulePath
    if ($backupFile) {
        Write-Verbose "Backup created: $backupFile"
    }
    
    $removed = $false
    
    # Try USER scope first
    $userCurrent = [Environment]::GetEnvironmentVariable("PSModulePath", "User")
    if ($userCurrent -and ($userCurrent.Split(';') -contains $pathToRemove)) {
        $userPaths = $userCurrent.Split(';') | Where-Object {$_ -and $_ -ne $pathToRemove}
        $userUpdated = $userPaths -join ';'
        [Environment]::SetEnvironmentVariable("PSModulePath", $userUpdated, "User")
        $removed = $true
        $scope = "USER"
    }
    
    # Try MACHINE scope if not found in USER
    if (-not $removed) {
        $machineCurrent = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
        if ($machineCurrent -and ($machineCurrent.Split(';') -contains $pathToRemove)) {
            $machinePaths = $machineCurrent.Split(';') | Where-Object {$_ -and $_ -ne $pathToRemove}
            $machineUpdated = $machinePaths -join ';'
            [Environment]::SetEnvironmentVariable("PSModulePath", $machineUpdated, "Machine")
            $removed = $true
            $scope = "SYSTEM"
        }
    }
    
    if ($removed) {
        $env:PSModulePath = ($env:PSModulePath.Split(';') | Where-Object {$_ -ne $pathToRemove}) -join ';'
        $status.Text = "SUCCESS: Path removed from $scope scope"
        $status.Foreground = "Green"
        $pathInput.Clear()
        RefreshList
    } else {
        $status.Text = "WARNING: Path not found in USER or SYSTEM scope"
        $status.Foreground = "Red"
    }
})

# Refresh button
$refreshBtn.Add_Click({
    RefreshList
    $status.Text = "List refreshed"
    $status.Foreground = "Blue"
})

# Export button
$exportBtn.Add_Click({
    $saveDialog = New-Object System.Windows.Forms.SaveFileDialog
    $saveDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"
    $saveDialog.Title = "Export PSModulePath Configuration"
    $saveDialog.FileName = "PSModulePath_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
    
    if ($saveDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
        try {
            $userPath = [Environment]::GetEnvironmentVariable("PSModulePath", "User")
            $machinePath = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
            
            $content = @"
# PSModulePath Configuration Export
# Generated: $(Get-Date)
 
[USER]
$($userPath -replace ';', "`n")
 
[SYSTEM]
$($machinePath -replace ';', "`n")
"@

            $content | Out-File -FilePath $saveDialog.FileName -Encoding UTF8
            $status.Text = "SUCCESS: Configuration exported"
            $status.Foreground = "Green"
        } catch {
            $status.Text = "ERROR: Failed to export - $($_.Exception.Message)"
            $status.Foreground = "Red"
        }
    }
})

# Import button
$importBtn.Add_Click({
    $openDialog = New-Object System.Windows.Forms.OpenFileDialog
    $openDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"
    $openDialog.Title = "Import PSModulePath Configuration"
    
    if ($openDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
        try {
            $content = Get-Content $openDialog.FileName -Raw
            
            $result = [System.Windows.MessageBox]::Show(
                "This will replace your current PSModulePath configuration. Continue?",
                "Confirm Import",
                [System.Windows.MessageBoxButton]::YesNo,
                [System.Windows.MessageBoxImage]::Warning
            )
            
            if ($result -eq [System.Windows.MessageBoxResult]::Yes) {
                # Parse USER and SYSTEM sections
                if ($content -match '\[USER\](.*?)\[SYSTEM\](.*)') {
                    $userPaths = $matches[1].Trim() -replace "`n", ';'
                    $systemPaths = $matches[2].Trim() -replace "`n", ';'
                    
                    [Environment]::SetEnvironmentVariable("PSModulePath", $userPaths, "User")
                    [Environment]::SetEnvironmentVariable("PSModulePath", $systemPaths, "Machine")
                    
                    $env:PSModulePath = $userPaths + ';' + $systemPaths
                    
                    RefreshList
                    $status.Text = "SUCCESS: Configuration imported"
                    $status.Foreground = "Green"
                } else {
                    $status.Text = "ERROR: Invalid file format"
                    $status.Foreground = "Red"
                }
            }
        } catch {
            $status.Text = "ERROR: Failed to import - $($_.Exception.Message)"
            $status.Foreground = "Red"
        }
    }
})

$closeBtn.Add_Click({ $win.Close() })

# Help/About button must be defined after HelpBtn is found
$helpBtn.Add_Click({
    Show-HelpDialog
})

# ListBox mouse handler to deselect when clicking empty space
$list.Add_MouseDown({
    param($sender, $e)
    $pos = $e.GetPosition($list)
    $hit = [System.Windows.Media.VisualTreeHelper]::HitTest($list, $pos)
    
    if ($hit -and $hit.VisualHit) {
        # Check if click was on ListBoxItem or empty space
        $item = $hit.VisualHit
        while ($item -and $item -isnot [System.Windows.Controls.ListBoxItem]) {
            $item = [System.Windows.Media.VisualTreeHelper]::GetParent($item)
        }
        
        # If we didn't hit a ListBoxItem, clear selection
        if (-not $item) {
            $list.SelectedItem = $null
        }
    }
})

# ListBox selection handler
$list.Add_SelectionChanged({
    if ($list.SelectedItem) {
        $selected = $list.SelectedItem.Content.ToString()
        if ($selected -match '^\[(USER|SYSTEM)\]\s*(.+)$') {
            $pathInput.Text = $matches[2]
            $status.Text = "Click '- Remove' to delete this [$($matches[1])] path"
            $status.Foreground = "Blue"
        }
    } else {
        # Clear text field when clicking empty space
        $pathInput.Clear()
        $status.Text = ""
    }
})

# Double-click handler - copy or open folder
$list.Add_MouseDoubleClick({
    if ($list.SelectedItem) {
        $selected = $list.SelectedItem.Content.ToString()
        if ($selected -match '^\[(USER|SYSTEM)\]\s*(.+)$') {
            $path = $matches[2]
            
            $result = [System.Windows.MessageBox]::Show(
                "Copy path to clipboard or open in Explorer?`n`n$path",
                "Double-Click Action",
                [System.Windows.MessageBoxButton]::YesNoCancel,
                [System.Windows.MessageBoxImage]::Question
            )
            
            if ($result -eq [System.Windows.MessageBoxResult]::Yes) {
                [System.Windows.Clipboard]::SetText($path)
                $status.Text = "Path copied to clipboard"
                $status.Foreground = "Green"
            } elseif ($result -eq [System.Windows.MessageBoxResult]::No) {
                if (Test-Path $path) {
                    explorer.exe $path
                    $status.Text = "Opened folder in Explorer"
                    $status.Foreground = "Green"
                } else {
                    $status.Text = "ERROR: Path does not exist"
                    $status.Foreground = "Red"
                }
            }
        }
    }
})

RefreshList
$win.ShowDialog() | Out-Null

} catch {
    [System.Windows.MessageBox]::Show(
        "ERROR: $($_.Exception.Message)`n`nStack Trace: $($_.ScriptStackTrace)",
        "Error",
        [System.Windows.MessageBoxButton]::OK,
        [System.Windows.MessageBoxImage]::Error
    )
}