One-click Windows Proxy Toggle: Step-by-Step Guide

One-click Windows Proxy Toggle: Step-by-Step Guide
Proxy Toggle Tool

Introduction

Switching between proxy settings in Windows can be a tedious process, requiring multiple clicks through system settings each time. If you frequently need to enable or disable your proxy connection, a dedicated tool can save you significant time and frustration.

In this comprehensive guide, we'll walk through creating a professional-looking system tray utility that allows you to toggle your proxy with a single click. By the end, you'll have a standalone executable that runs in your system tray with color-coded status indicators.

🚀
Quickstart

If you can't wait to try it right away, simply checkout the installation instructions in our repository for a quickstart.

Why Create a Custom Proxy Toggle Tool?

  • Convenience: Toggle your proxy with just one click instead of navigating through multiple settings screens
  • Visual Feedback: Instantly see if your proxy is enabled (green) or disabled (red)
  • Time-Saving: Perfect for environments where you frequently switch between direct and proxied connections
  • Customizable: Easily adjust the proxy server address, port, and exceptions

What You'll Need

  • Windows 10 or 11
  • PowerShell 5.0 or higher
  • Basic understanding of running PowerShell scripts
  • PS2EXE module (instructions provided) for creating the standalone executable

Step 1: The PowerShell Script

First, we'll create a PowerShell script that handles all the proxy functionality. This script will:

  • Create a system tray icon that shows proxy status
  • Enable toggling proxy on/off with a single click
  • Allow customization of proxy settings
  • Apply changes to the Windows registry
# Proxy Toggle Application (Standalone version)
# This script will be converted to an EXE file using PS2EXE

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Proxy Settings - Change these to match your environment
$proxyServer = "10.147.17.29"
$proxyPort = "808"
$proxyAddress = "$proxyServer`:$proxyPort"
$proxyExceptions = "localhost;127.0.0.1;<local>"

# Registry paths
$internetSettingsPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"

# Create context menu
$contextMenu = New-Object System.Windows.Forms.ContextMenuStrip
$toggleMenuItem = New-Object System.Windows.Forms.ToolStripMenuItem
$settingsMenuItem = New-Object System.Windows.Forms.ToolStripMenuItem
$exitMenuItem = New-Object System.Windows.Forms.ToolStripMenuItem

# Create notification icon
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
$notifyIcon.Text = "Proxy Toggle"
$notifyIcon.ContextMenuStrip = $contextMenu
$notifyIcon.Visible = $true

# Function to create a better looking icon
function Create-ColoredIcon {
    param (
        [System.Drawing.Color]$mainColor
    )
    
    $bitmap = New-Object System.Drawing.Bitmap(16, 16)
    $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
    
    # Fill background with transparency
    $graphics.Clear([System.Drawing.Color]::Transparent)
    
    # Create a gradient brush for a more polished look
    $rect = New-Object System.Drawing.Rectangle(0, 0, 16, 16)
    $gradientBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush(
        $rect, 
        [System.Drawing.Color]::FromArgb(255, $mainColor.R, $mainColor.G, $mainColor.B),
        [System.Drawing.Color]::FromArgb(220, [Math]::Min(255, $mainColor.R + 40), [Math]::Min(255, $mainColor.G + 40), [Math]::Min(255, $mainColor.B + 40)),
        45
    )
    
    # Draw a filled circle with gradient
    $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
    $graphics.FillEllipse($gradientBrush, 1, 1, 14, 14)
    
    # Add a light border
    $pen = New-Object System.Drawing.Pen([System.Drawing.Color]::FromArgb(100, 255, 255, 255), 1)
    $graphics.DrawEllipse($pen, 1, 1, 14, 14)
    
    # Add a highlight effect
    $graphics.FillEllipse(
        (New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(70, 255, 255, 255))),
        4, 3, 5, 3
    )
    
    # Create icon from bitmap
    $icon = [System.Drawing.Icon]::FromHandle($bitmap.GetHicon())
    
    # Clean up
    $gradientBrush.Dispose()
    $pen.Dispose()
    $graphics.Dispose()
    
    return $icon
}

# Function to check proxy status
function Get-ProxyStatus {
    $proxyEnabled = Get-ItemProperty -Path $internetSettingsPath -Name "ProxyEnable" -ErrorAction SilentlyContinue
    
    if ($proxyEnabled -ne $null -and $proxyEnabled.ProxyEnable -eq 1) {
        return $true
    } else {
        return $false
    }
}

# Function to enable proxy
function Enable-Proxy {
    Set-ItemProperty -Path $internetSettingsPath -Name "ProxyEnable" -Value 1
    Set-ItemProperty -Path $internetSettingsPath -Name "ProxyServer" -Value $proxyAddress
    Set-ItemProperty -Path $internetSettingsPath -Name "ProxyOverride" -Value $proxyExceptions
    
    # Refresh DNS cache
    Start-Process "ipconfig" -ArgumentList "/flushdns" -WindowStyle Hidden
    
    $toggleMenuItem.Text = "Disable Proxy"
    $notifyIcon.Icon = Create-ColoredIcon -mainColor ([System.Drawing.Color]::FromArgb(80, 200, 100))
    $notifyIcon.Text = "Proxy Enabled: $proxyAddress"
    
    $notifyIcon.ShowBalloonTip(
        3000,
        "Proxy Enabled",
        "Proxy has been set to $proxyAddress",
        [System.Windows.Forms.ToolTipIcon]::Info
    )
}

# Function to disable proxy
function Disable-Proxy {
    Set-ItemProperty -Path $internetSettingsPath -Name "ProxyEnable" -Value 0
    
    # Refresh DNS cache
    Start-Process "ipconfig" -ArgumentList "/flushdns" -WindowStyle Hidden
    
    $toggleMenuItem.Text = "Enable Proxy"
    $notifyIcon.Icon = Create-ColoredIcon -mainColor ([System.Drawing.Color]::FromArgb(220, 80, 80))
    $notifyIcon.Text = "Proxy Disabled"
    
    $notifyIcon.ShowBalloonTip(
        3000,
        "Proxy Disabled",
        "System proxy has been disabled",
        [System.Windows.Forms.ToolTipIcon]::Info
    )
}

# Toggle proxy event handler
$toggleMenuItem.Add_Click({
    if (Get-ProxyStatus) {
        Disable-Proxy
    } else {
        Enable-Proxy
    }
})

# Settings menu handler
$settingsMenuItem.Add_Click({
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Proxy Settings"
    $form.Size = New-Object System.Drawing.Size(300, 200)
    $form.StartPosition = "CenterScreen"
    $form.FormBorderStyle = "FixedDialog"
    $form.MaximizeBox = $false
    $form.MinimizeBox = $false
    
    $labelServer = New-Object System.Windows.Forms.Label
    $labelServer.Location = New-Object System.Drawing.Point(10, 20)
    $labelServer.Size = New-Object System.Drawing.Size(100, 20)
    $labelServer.Text = "Proxy Server:"
    $form.Controls.Add($labelServer)
    
    $textBoxServer = New-Object System.Windows.Forms.TextBox
    $textBoxServer.Location = New-Object System.Drawing.Point(110, 20)
    $textBoxServer.Size = New-Object System.Drawing.Size(160, 20)
    $textBoxServer.Text = $proxyServer
    $form.Controls.Add($textBoxServer)
    
    $labelPort = New-Object System.Windows.Forms.Label
    $labelPort.Location = New-Object System.Drawing.Point(10, 50)
    $labelPort.Size = New-Object System.Drawing.Size(100, 20)
    $labelPort.Text = "Proxy Port:"
    $form.Controls.Add($labelPort)
    
    $textBoxPort = New-Object System.Windows.Forms.TextBox
    $textBoxPort.Location = New-Object System.Drawing.Point(110, 50)
    $textBoxPort.Size = New-Object System.Drawing.Size(160, 20)
    $textBoxPort.Text = $proxyPort
    $form.Controls.Add($textBoxPort)
    
    $labelExceptions = New-Object System.Windows.Forms.Label
    $labelExceptions.Location = New-Object System.Drawing.Point(10, 80)
    $labelExceptions.Size = New-Object System.Drawing.Size(100, 20)
    $labelExceptions.Text = "Exceptions:"
    $form.Controls.Add($labelExceptions)
    
    $textBoxExceptions = New-Object System.Windows.Forms.TextBox
    $textBoxExceptions.Location = New-Object System.Drawing.Point(110, 80)
    $textBoxExceptions.Size = New-Object System.Drawing.Size(160, 20)
    $textBoxExceptions.Text = $proxyExceptions
    $form.Controls.Add($textBoxExceptions)
    
    $buttonSave = New-Object System.Windows.Forms.Button
    $buttonSave.Location = New-Object System.Drawing.Point(110, 120)
    $buttonSave.Size = New-Object System.Drawing.Size(75, 23)
    $buttonSave.Text = "Save"
    $buttonSave.Add_Click({
        $script:proxyServer = $textBoxServer.Text
        $script:proxyPort = $textBoxPort.Text
        $script:proxyAddress = "$proxyServer`:$proxyPort"
        $script:proxyExceptions = $textBoxExceptions.Text
        
        if (Get-ProxyStatus) {
            # Update current proxy if it's enabled
            Set-ItemProperty -Path $internetSettingsPath -Name "ProxyServer" -Value $proxyAddress
            Set-ItemProperty -Path $internetSettingsPath -Name "ProxyOverride" -Value $proxyExceptions
            $notifyIcon.Text = "Proxy Enabled: $proxyAddress"
            $notifyIcon.ShowBalloonTip(2000, "Settings Updated", "New proxy settings applied: $proxyAddress", [System.Windows.Forms.ToolTipIcon]::Info)
        } else {
            $notifyIcon.ShowBalloonTip(2000, "Settings Saved", "New settings will apply when proxy is enabled", [System.Windows.Forms.ToolTipIcon]::Info)
        }
        
        $form.Close()
    })
    $form.Controls.Add($buttonSave)
    
    $buttonCancel = New-Object System.Windows.Forms.Button
    $buttonCancel.Location = New-Object System.Drawing.Point(195, 120)
    $buttonCancel.Size = New-Object System.Drawing.Size(75, 23)
    $buttonCancel.Text = "Cancel"
    $buttonCancel.Add_Click({ $form.Close() })
    $form.Controls.Add($buttonCancel)
    
    $form.Add_Shown({ $form.Activate() })
    $form.ShowDialog()
})

# Exit event handler
$exitMenuItem.Add_Click({
    $notifyIcon.Visible = $false
    [System.Windows.Forms.Application]::Exit()
})

# Set initial menu items
$toggleMenuItem.Text = "Toggle Proxy"
$settingsMenuItem.Text = "Settings"
$exitMenuItem.Text = "Exit"
$contextMenu.Items.Add($toggleMenuItem)
$contextMenu.Items.Add($settingsMenuItem)
$contextMenu.Items.Add("-") # Separator
$contextMenu.Items.Add($exitMenuItem)

# Set initial icon based on current proxy status
if (Get-ProxyStatus) {
    $toggleMenuItem.Text = "Disable Proxy"
    $notifyIcon.Icon = Create-ColoredIcon -mainColor ([System.Drawing.Color]::FromArgb(80, 200, 100))
    $notifyIcon.Text = "Proxy Enabled: $proxyAddress"
} else {
    $toggleMenuItem.Text = "Enable Proxy"
    $notifyIcon.Icon = Create-ColoredIcon -mainColor ([System.Drawing.Color]::FromArgb(220, 80, 80))
    $notifyIcon.Text = "Proxy Disabled"
}

# Also allow left-click to toggle
$notifyIcon.Add_Click({
    if ($_.Button -eq [System.Windows.Forms.MouseButtons]::Left) {
        if (Get-ProxyStatus) {
            Disable-Proxy
        } else {
            Enable-Proxy
        }
    }
})

# Show notification on startup
$notifyIcon.ShowBalloonTip(
    2000,
    "Proxy Toggle",
    "Left-click to toggle proxy, right-click for menu",
    [System.Windows.Forms.ToolTipIcon]::Info
)

# Keep the application running
$appContext = New-Object System.Windows.Forms.ApplicationContext
[System.Windows.Forms.Application]::Run($appContext)

Save this script as ProxyToggle.ps1.

Important: Modify the proxy server address and port at the top of the script to match your environment.

Step 2: Creating a Custom Icon (Optional)

While our tool generates colored icons dynamically for the system tray, you might want a custom application icon for the executable itself. Here's a simple SVG icon you can use:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
  <!-- Background circle -->
  <circle cx="32" cy="32" r="30" fill="url(#gradientBg)"/>
  
  <!-- Globe network grid lines -->
  <path d="M32 2 A30 30 0 0 1 32 62 A30 30 0 0 1 32 2" fill="none" stroke="#ffffff" stroke-width="1" stroke-opacity="0.3"/>
  <path d="M2 32 A30 30 0 0 1 62 32 A30 30 0 0 1 2 32" fill="none" stroke="#ffffff" stroke-width="1" stroke-opacity="0.3"/>
  <ellipse cx="32" cy="32" rx="30" ry="15" fill="none" stroke="#ffffff" stroke-width="1" stroke-opacity="0.3"/>
  <ellipse cx="32" cy="32" rx="15" ry="30" fill="none" stroke="#ffffff" stroke-width="1" stroke-opacity="0.3"/>
  
  <!-- Connection lines -->
  <path d="M18 32 L32 20 L46 32 L32 44 Z" fill="none" stroke="#ffffff" stroke-width="3" stroke-linejoin="round"/>
  
  <!-- Connection nodes -->
  <circle cx="18" cy="32" r="5" fill="#ffffff"/>
  <circle cx="32" cy="20" r="5" fill="#ffffff"/>
  <circle cx="46" cy="32" r="5" fill="#ffffff"/>
  <circle cx="32" cy="44" r="5" fill="#ffffff"/>
  
  <!-- Highlight overlay -->
  <circle cx="26" cy="24" r="14" fill="url(#highlightGradient)"/>
  
  <!-- Definitions for gradients -->
  <defs>
    <linearGradient id="gradientBg" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="#50c864"/>
      <stop offset="100%" stop-color="#2a9641"/>
    </linearGradient>
    <radialGradient id="highlightGradient" cx="50%" cy="50%" r="50%" fx="25%" fy="25%">
      <stop offset="0%" stop-color="#ffffff" stop-opacity="0.4"/>
      <stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
    </radialGradient>
  </defs>
</svg>

You'll need to convert this SVG to an ICO file for use with your executable. Several online tools can do this conversion, such as:

Save the resulting ICO file as ProxyToggle.ico in the same directory as your PowerShell script.

Step 3: Converting to an Executable

To make our tool more user-friendly, we'll convert the PowerShell script to a standalone executable using PS2EXE. This eliminates the need for running PowerShell scripts directly and creates a more professional application.

  1. Open PowerShell as Administrator
  2. Navigate to the folder containing your saved PowerShell script

Convert the script to an executable with our custom icon:

Invoke-ps2exe -InputFile ProxyToggle.ps1 -OutputFile ProxyToggle.exe -IconFile ProxyToggle.ico -NoConsole -NoOutput -NoError -Title "Proxy Toggle" -Product "Proxy Toggle Utility" -Version "1.0.0"

Install the PS2EXE module:

Install-Module -Name ps2exe -Scope CurrentUser

Step 4: Using Your New Proxy Toggle Tool

  1. Double-click ProxyToggle.exe to run the application
  2. A small icon will appear in your system tray:
    • Green icon: Proxy is enabled
    • Red icon: Proxy is disabled
  3. Left-click the icon to toggle the proxy on/off
  4. Right-click the icon to access additional options:
    • Toggle Proxy
    • Settings (to change proxy server, port, and exceptions)
    • Exit

Adding to Windows Startup (Optional)

To have your Proxy Toggle tool start automatically with Windows:

  1. Press Win + R to open the Run dialog
  2. Type shell:startup and press Enter
  3. Create a shortcut to your ProxyToggle.exe file in this folder

Troubleshooting

If you encounter any issues:

  • Script execution policy: If you can't run the PowerShell script, you might need to adjust your execution policy with Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
  • Missing .NET components: Ensure you have .NET Framework 4.5 or higher installed
  • Icon not displaying: Make sure the ICO file is in the correct format and accessible at the path specified
  • Registry access issues: The tool requires permission to modify registry settings; try running it as administrator

Customization Options

You can easily customize this tool by modifying the PowerShell script:

  • Change the proxy server address and port
  • Adjust the color scheme for the system tray icons
  • Add additional menu options or features
  • Modify the exception list for local addresses

Conclusion

With this simple but powerful utility, you can now toggle your proxy settings with a single click instead of navigating through multiple Windows settings screens. The color-coded system tray icon gives you immediate visual feedback on your proxy status, saving you time and reducing frustration.

By converting the PowerShell script to a standalone executable with a custom icon, you've created a professional tool that can be easily shared with colleagues or used across multiple computers.

This project demonstrates how a small utility can significantly improve workflow efficiency when dealing with routine system configuration tasks.


Have you created any custom Windows utilities to improve your workflow? Share your experiences in the comments below!