Powershell is low-key cool

Published: (December 4, 2025 at 08:51 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

PowerShell often gets overlooked in favor of more popular shells, but it offers powerful features that can streamline local development workflows. Below is a step‑by‑step guide showing how to build a file‑watcher for Go projects using PowerShell, from basic setup to handling long‑running processes with background jobs.

What is PowerShell?

PowerShell is both a command‑line shell and a scripting language built on the .NET runtime. Unlike traditional Unix shells (e.g., Bash) that pipe plain text, PowerShell pipelines objects, allowing richer data manipulation directly in the shell.

Setting Up the Watcher Directory

# Create a directory for the watcher
mkdir watcher

PowerShell provides the New-Item cmdlet for creating items, but common aliases like mkdir are available for convenience.

# Navigate into the directory
cd watcher

# Create a placeholder Go source file
ni main.go

# Create the PowerShell script that will perform the watching
ni watcher.ps1

Adjusting the Execution Policy

PowerShell’s execution policy determines whether scripts can run. Ensure it’s set to RemoteSigned (or a less restrictive level) before proceeding.

# View the current policy
Get-ExecutionPolicy

# If needed, set it to RemoteSigned
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force

Sample Go Program

Create a simple Go program that prints “Hello World”. Save this as main.go inside the watcher folder.

package main

import "fmt"

func main() {
    fmt.Println("Hello World")
}

Basic Watcher Script (Synchronous)

The following PowerShell script watches all .go files in the current directory (and sub‑directories). When a change is detected, it re‑runs the Go program.

# watcher.ps1
# Path to the Go file (can be overridden later)
$path = "main.go"

Write-Host 'GoWatcher *Press CTRL+C to quit*'

$dirname = "."
$files   = Get-ChildItem $dirname -Filter "*.go" -Recurse

# Initial run
go run $path

# Compute an initial signature (hash) of all Go files
$signature = $files | Get-FileHash -ErrorAction SilentlyContinue |
             Sort-Object Path | Out-String

while ($true) {
    $current_signature = $files | Get-FileHash -ErrorAction SilentlyContinue |
                         Sort-Object Path | Out-String

    if ($signature -ne $current_signature) {
        Write-Host 'File change detected: Restarting...'
        go run $path
        $signature = $current_signature
    }

    Start-Sleep -Milliseconds 300
}

Run the script:

.\watcher.ps1

Adding a Parameter for the File Path

Make the script more flexible by accepting the Go file path as a command‑line argument.

# watcher.ps1 (updated)
[CmdletBinding()]
Param(
    [Parameter(Mandatory)]
    $path
)

Write-Host 'GoWatcher *Press CTRL+C to quit*'

$dirname = "."
$files   = Get-ChildItem $dirname -Filter "*.go" -Recurse

go run $path
$signature = $files | Get-FileHash -ErrorAction SilentlyContinue |
             Sort-Object Path | Out-String

while ($true) {
    $current_signature = $files | Get-FileHash -ErrorAction SilentlyContinue |
                         Sort-Object Path | Out-String

    if ($signature -ne $current_signature) {
        Write-Host 'File change detected: Restarting...'
        go run $path
        $signature = $current_signature
    }

    Start-Sleep -Milliseconds 300
}

Execute with the path argument:

.\watcher.ps1 -path 'main.go'

Handling Long‑Running Processes with Background Jobs

When the Go application runs a web server or another blocking operation, the watcher script would freeze. PowerShell jobs allow you to run such processes asynchronously.

Useful Job Cmdlets

# Start a background job
Start-Job -Name GoServer -ScriptBlock { ... }

# Stop a job
Stop-Job -Name GoServer

# Remove a job
Remove-Job -Name GoServer

# Retrieve job output
Receive-Job -Name GoServer

# List jobs
Get-Job -Name GoServer

Advanced Watcher with Job Management

The script below launches the Go server as a background job, restarts it on file changes, and ensures clean‑up when the watcher exits.

# watcher.ps1 (advanced version)
[CmdletBinding()]
Param(
    [Parameter(Mandatory)]
    $path
)

Write-Host 'GoWatcher *Press CTRL+C to quit*'

$dirname   = "."
$jobname   = "GoServer"
$binary    = "GoApp"

function Start-ServerJob {
    # Remove any existing job with the same name
    Get-Job -Name $jobname -ErrorAction SilentlyContinue | Remove-Job -Force

    # Start a new job that builds and runs the Go binary
    $job = Start-Job -Name $jobname -ScriptBlock {
        param($path, $dirname, $binary)
        Set-Location $dirname

        # Build the binary (adjust as needed for your project)
        go build -o "bin/$binary.exe" $path

        # Execute the binary
        & "./bin/$binary.exe"
    } -ArgumentList $path, $dirname, $binary

    return $job
}

# Gather all Go source files
$files = Get-ChildItem $dirname -Filter "*.go" -Recurse

# Initial launch
$job = Start-ServerJob

# Initial signature
$signature = $files | Get-FileHash -ErrorAction SilentlyContinue |
             Sort-Object Path | Out-String

try {
    while ($true) {
        $current_signature = $files | Get-FileHash -ErrorAction SilentlyContinue |
                             Sort-Object Path | Out-String

        if ($signature -ne $current_signature) {
            Write-Host 'File change detected: Restarting...'

            # Restart the server job
            $job = Start-ServerJob
            $signature = $current_signature
        }

        Start-Sleep -Milliseconds 300
    }
}
finally {
    # Clean up the background job
    Get-Job -Name $jobname -ErrorAction SilentlyContinue | Remove-Job -Force

    # Ensure the binary process is terminated
    if (Get-Process -Name $binary -ErrorAction SilentlyContinue) {
        Stop-Process -Name $binary -Force
    }
}

Run the advanced watcher the same way:

.\watcher.ps1 -path 'main.go'

The script now:

  1. Builds the Go program into an executable.
  2. Runs the executable as a background job.
  3. Detects changes to any .go file.
  4. Restarts the background job when changes occur.
  5. Cleans up resources on termination.

Conclusion

PowerShell’s object‑oriented pipeline, built‑in aliases, and robust job system make it an excellent choice for automating development tasks such as file watching and process management. By leveraging these features, you can create lightweight, cross‑platform tooling without relying on external utilities.

Back to Blog

Related posts

Read more »

A small friction I finally removed

!Cover image for A small friction I finally removedhttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fde...

Convert Excel to PDF in C# Applications

Overview Transforming Excel files into polished, share‑ready PDFs doesn’t have to be a slow or complicated process. With the GroupDocs.Conversion Cloud SDK for...