loading...

Developer tooling on Windows: A cleaner PowerShell profile

thatfrankdev profile image Francis Cote ・4 min read

Developer tooling on Windows: A cleaner PowerShell profile

I originally published this post in french on 42 lignes à l'heure

If you've been talking code with me, there's a chance PowerShell came to the table at some point. Before PowerShell was introduced in 2006, developers on Windows who wanted to take a shot at the command line would have to deal with good old BATCH (cmd.exe). Sure, one can manage to get some things done with it and somehow cope with all its awkward bits, but the fact is that BATCH is far from being a great tool.

Enters PowerShell, that takes us much further by solving several pain points that make developers' life miserable in BATCH. One of them is the lack of native support for profile scripts. That is what this post is about.

This quick guide suggests a simple way to create a reusable, structured and evolutive PowerShell profile.

Create a Git repository for our scripts

This is the obvious way to store profile scripts. I personnaly chose GitHub, but a number of options exist out there. Gitlab and Bitbucket both offer free private repositories, if that matters to you.

Repository structure

powershell-dev-environment/
├── src/
│   ├── profile.ps1
│   ├── _imports.ps1
│   ├── _prompt.ps1
│   └── _ui.ps1
└── install.ps1

The entry point

The file profile.ps1 is the entry point of our profile.

# profile.ps1

$env:devProfileDir = $PSScriptRoot

. "$env:devProfileDir\_imports.ps1";
. "$env:devProfileDir\_ui.ps1";
. "$env:devProfileDir\_prompt.ps1";

Note that we define $env:devProfileDir, an environment variable that will store the location of our scripts. It may be of use.

The file _imports.ps1 is used to load all third-party modules that we want to have available in our PowerShell sessions.

# _imports.ps1

Import-Module posh-git
# an so on...

CAREFUL HERE, some modules can take a lot o time to load (yep, I'm totally looking at you Carbon), so be selective on what you choose to include in this file.

Colors

Terminal display colors are configured in _ui.ps1

# _ui.ps1

$console = $host.UI.RawUI

$console.ForegroundColor = "white"
$console.BackgroundColor = "black"

$colors = $host.PrivateData
$colors.VerboseForegroundColor = "white"
$colors.VerboseBackgroundColor = "blue"
$colors.WarningForegroundColor = "yellow"
$colors.WarningBackgroundColor = "darkgreen"
$colors.ErrorForegroundColor = "white"
$colors.ErrorBackgroundColor = "red"

Clear-Host

Prompt function

The Prompt function is a special, kind of "reserved" PowerShell function. It is executed to render the command line prompt. Once you define it in your profile, you have total control over how your prompt will look. Here's mine:

# _prompt.ps1

function Prompt {    
    $realLASTEXITCODE = $LASTEXITCODE

    $Host.UI.RawUI.ForegroundColor = $GitPromptSettings.DefaultForegroundColor

    Write-Host
    Write-Host "$ENV:USERNAME@" -NoNewline -ForegroundColor DarkYellow
    Write-Host "$ENV:COMPUTERNAME" -ForegroundColor Magenta -NoNewline
    Write-Host (Get-Date -Format " | MM/dd/yyyy | HH:MM:ss") -ForegroundColor DarkGray

    Write-Host $($(Get-Location) -replace ($env:USERPROFILE).Replace('\','\\'), "~") -NoNewline -ForegroundColor Gray

    Write-VcsStatus

    Write-Host

    $global:LASTEXITCODE = $realLASTEXITCODE

    return ""
}

Here's how it looks in the terminal :

Screenshot of a customized command prompt

Execute profile scripts on PowerShell session startup

If you're like me, you like to have all your repositories in the same place. So the path of your newly created repostory might be something like c:\users\me\dev\powershell-dev-environment, and you probably want to keep it this way.

There is a built-in $profile variable that stores the path of the current user's PowerShell profile. It typically points to something like C:\Users\Me\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1. When this file exists, Powershel will automatically execute it on each new session.

Problem is we can't change that path. Our only option is to call our profile directly from there. We just have to tap into this file by adding the following line that calls our script:

. "c:\users\me\dev\powershell-dev-environment\src\profile.ps1"

Because we're all so lazy : a little install script

The previous step can easily be automated with the following bits:

# install.ps1

$installedHint = "#https://github.com/thatfrankdev/powershell-dev-environment"
$installed = $false

if(-not (Test-Path $profile)){
    New-Item $profile
}
else{    
    $installed = (Select-String -Path $profile -pattern $installedHint | Measure-Object).Count -gt 0
}

if(-not $installed){
    Add-Content $profile ""
    Add-Content $profile ". `"$PSScriptRoot\src\profile.ps1`" $installedHint"
    powershell.exe
}

The next step

We now have versatile base structure to build on. That's just a start...

In a next post, I will explore some handy helper functions that can greatly improve your daily flow.


Thanks for reading, hope you enjoyed it :)

English is my second language, so please tell me if you spot a typo, a grammar error or anything that could make this post hard to read. I'm constantly trying to get better at it.

Discussion

markdown guide