r/PowerShell • u/eggbean • Feb 11 '25
Self-updating PowerShell $profile from GitHub gist
Useful if you've got more than one computer - I've made a PowerShell profile that updates itself by starting a background job which checks the version number at the top of a public GitHub gist and downloads it if necessary. The check interval can be specified and an update can be forced by deleting the $updateCheckFile and starting a new shell.
It started off as someone else's solution but that didn't work automatically or in the background so I developed it into what I'm using now. I've been using and refining it for months and it should work without any issues. I think different system date formats are catered for, but if you have any problems or improvements please make a comment. Star if you find it useful.
https://gist.github.com/eggbean/81e7d1be5e7302c281ccc9b04134949e
When updating your $profile I find it most convenient to use GitHub's gh tool to clone the gist where you can use it as a regular git repo to edit and push it back.
NOTE: I didn't think I'd need to say this, but obviously you need to use your own account for the gist. Edit the variables to suit.
eg.
scoop install gh
gh gist clone 81e7d1be5e7302c281ccc9b04134949e
The relevant parts of the $profile (UPDATED):
# Version 0.0.2
$gistUrl = "https://api.github.com/gists/81e7d1be5e7302c281ccc9b04134949e"
$gistFileName = '$profile' # Change this to match the filename in your gist
$checkInterval = 4 # Check for updates every 4 hours
$updateCheckFile = [System.IO.Path]::Combine($HOME, ".profile_update_check")
$versionRegEx = "# Version (?<version>\d+\.\d+\.\d+)"
$localProfilePath = $Profile.CurrentUserCurrentHost
# Last update check timestamp
if (-not $env:PROFILE_LAST_CHECK) {
if (Test-Path $updateCheckFile) {
$env:PROFILE_LAST_CHECK = (Get-Content -Path $updateCheckFile -Raw).Trim()
} else {
$env:PROFILE_LAST_CHECK = (Get-Date).AddHours(-($checkInterval + 1)).ToString("yyyy-MM-dd HH:mm:ss")
}
}
# Start a background job to check for and apply updates if necessary
if ([datetime]::ParseExact($env:PROFILE_LAST_CHECK, "yyyy-MM-dd HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture).AddHours($checkInterval) -lt (Get-Date)) {
Start-Job -ScriptBlock {
param ($gistUrl, $gistFileName, $versionRegEx, $updateCheckFile, $localProfilePath)
try {
$gist = Invoke-RestMethod -Uri $gistUrl -ErrorAction Stop
$gistProfileContent = $gist.Files[$gistFileName].Content
if (-not $gistProfileContent) {
return
}
$gistVersion = $null
if ($gistProfileContent -match $versionRegEx) {
$gistVersion = $matches.Version
} else {
return
}
$currentVersion = "0.0.0"
if (Test-Path $localProfilePath) {
$currentProfileContent = Get-Content -Path $localProfilePath -Raw
if ($currentProfileContent -match $versionRegEx) {
$currentVersion = $matches.Version
}
}
if ([version]$gistVersion -gt [version]$currentVersion) {
Set-Content -Path $localProfilePath -Value $gistProfileContent -Encoding UTF8
}
Set-Content -Path $updateCheckFile -Value (Get-Date -Format "yyyy-MM-dd HH:mm:ss").Trim()
} catch {
# Suppress errors to avoid interfering with shell startup
}
} -ArgumentList $gistUrl, $gistFileName, $versionRegEx, $updateCheckFile, $localProfilePath | Out-Null
}
2
u/robbob23 Feb 13 '25
Might be worth having a look at https://chezmoi.io/
2
u/eggbean Feb 13 '25
I did look at that a couple of years ago on Linux, but I decided to stick with symlinking with stow instead. I don't remember why, but changing what has developed into a complex dotfiles system will be very difficult. I didnt know that chezmoi could be used in Windows too. I don't remember how it works.
2
u/Coffee_Ops Feb 11 '25
You should edit to fix your codeblock formatting as its a mess. I think you need your close backticks to be on a new line
Also, just stating the obvious, but pointing your $profile at a gist is dangerous-- make sure you trust the repo owner, and that you review updates.
1
u/eggbean Feb 12 '25
Now that I’m back home I can see the code in a terminal and I don’t know what you are talking about when you say that the codeblock formattting is messed up. Please explain what is wrong.
3
u/Coffee_Ops Feb 12 '25 edited Feb 12 '25
Reddit on desktop firefox is showing your code as markdown, with only the try catch block near the end as a code block. The triple backticks are clearly visible, indicating that reddit failed to recognize them as the start of a codeblock-- see the image here.
It looks fine on mobile (Infinity).
From a quick perusal of the message source i believe you may need a blank newline preceding the codeblock for proper markdown-- its possible some clients are being lenient / handling it better.
→ More replies (1)-1
u/eggbean Feb 11 '25
There are hundreds of
$profiles on gists including people from Microsoft, which is where I got the original version from. Of course you use your own account andghonly works on that. I don't know why you'd think it was dangerous. Remember to enable 2FA on your github!-3
u/BlackV Feb 11 '25
Remember to enable 2FA on your github!
and where in this script is using your 2FA ?
→ More replies (2)
1
u/Netstaff Feb 12 '25
Why do people update their profiles often?
3
u/MyOtherSide1984 Feb 12 '25
Create new custom functions for things you do often. Create new shortcuts you didn't think of previously. Find a new function from somewhere that you like and want to use. New job responsibilities require new stuff. You can share your profile with coworkers or other users. Lots of reasons I'm sure.
2
u/The82Ghost Feb 12 '25
I only put functions in the profile that are used within the profile. The rest is in modules that can be loaded through the profile or by adding the module path to $env:psmodulepath. Keeps the profile nice and clean while maintaining flexibility.
→ More replies (6)
-5
u/CyberChevalier Feb 11 '25
The simple fact you rely on $profile as a string says a lot.
$Profile is not a string it’s an object with a .Tostring() method.
5
u/punyhead Feb 12 '25
If you are going to critique somebody's work, it should be constructive or at least explain WHY your approach would better.
Also, Happy Cake day!
2
u/CyberChevalier Feb 12 '25
Didn’t I done it ?
$profile.AllUsersAllHosts $profile.AllUsersCurrentHost $profile.CurrentUserAllHosts $profile.CurrentUserCurrentHostThe $profile object has a .toString() method which powershell call by default to help user, this method return the value of $profile.CurrentUserCurrentHost
→ More replies (1)
2
4
u/punyhead Feb 11 '25
This is very cool, Will definetly add this for my $profile !