Skip to content

Instantly share code, notes, and snippets.

@chrisfcarroll
Last active March 31, 2026 13:38
Show Gist options
  • Select an option

  • Save chrisfcarroll/f3ecb2892f996149ee039d48abb57101 to your computer and use it in GitHub Desktop.

Select an option

Save chrisfcarroll/f3ecb2892f996149ee039d48abb57101 to your computer and use it in GitHub Desktop.
Common Aliases and Paths for PowerShell Profile Microsoft.PowerShell_profile.ps1: editors, paths, git, DevAzure, docker, dotNet, Visual Studio, MsBuild, NuGet, IIS, p4merge, poshgit
# https://gist.github.com/chrisfcarroll/f3ecb2892f996149ee039d48abb57101
# Aliases and Paths for PowerShell Profile ~\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
#
# ----------------------------------------------------
# For machines where you have no privileges you should still be able to enable scripts for yourself only with:
#
# `Set-ExecutionPolicy RemoteSigned -Scope CurrentUser`
# ----------------------------------------------------
#
# Sections: Paths, Editors, Tab Completion, Git abbreviations, Docker abbreviations, other prefs, firstRun
#
Param([switch]$firstRun)
# $stopwatch=[System.Diagnostics.Stopwatch]::StartNew()
# ============================================================================
# -- Paths
# Separate secrets from publicly shareable generic profile setup
$profileDir=Split-Path $PROFILE -Parent
if(test-path $profileDir/.secrets.ps1){
. $profileDir/.secrets.ps1
function editsecrets {edit (Resolve-Path $profileDir/secrets.ps1)}
}
# Separate current-project specific setup from publically shareable generic profile setup
if(test-path $profileDir/abbreviations.ps1){
. $profileDir/abbreviations.ps1
function editabbreviations {edit (Resolve-Path $profileDir/abbreviations.ps1)}
}
# ============================================================================
# My Favourite Working Directories
# Edit this list to match your usage
# Left hand side is a directory path, right hand side is a commandline alias to use for cd to that path
$workDirShortcuts= @{
"~/Repos"="cdr"
"~/Deploy"="cdd"
"~/Scratch"="cdss"
"~/Scratch-Trusted"="cdst"
"~/3rd"="cd3"
"~/source/Workspaces"="cdw"
"~/VMMounts"="cdvmm"
}
$notOkay= @{}
foreach($sh in $workDirShortcuts.GetEnumerator()){
$myError=$null
$globalVarName = (Split-Path $sh.Name -Leaf) -replace "[^a-zA-Z0-9_]",""
iex "`$global:$globalVarName = (Resolve-Path $($sh.Name))" -ErrorVariable myError 2>&1 >$null
if($myError){
$notOkay.Add( $sh.Name , $sh.Value )
}else{
iex "function $($sh.Value) { Set-Location `$global:$globalVarName}"
}
}
if($notOkay.Count){
Write-Host "Your `$PROFILE script lists these working directory shortcuts which don't exist. Do edit the shortcut list in your profile to match your work pattern."
$notOkay | Out-Host
}
Remove-Variable workDirShortcuts,notOkay,myError,globalVarName
function Add-Path( $directoryOrFile, [switch]$permanentlyInWindowsProfileUserPath ){
if(-not $directoryOrFile -gt ""){return}
if(-not (Test-Path $directoryOrFile)){return}
if((Test-Path $directoryOrFile -PathType Leaf)){$directoryOrFile = Split-Path $directoryOrFile -Parent }
$directoryOrFile = (Resolve-Path $directoryOrFile).Path
if($env:Path.ToLower().Contains( $directoryOrFile.ToLower()) ) { return }
if($permanentlyInWindowsProfileUserPath.IsPresent){
Write-Warning "Adding $directoryOrFile permanently to your User PATH"
$userPath=[Environment]::GetEnvironmentVariable("Path","User").Trim(';')
[Environment]::SetEnvironmentVariable("Path", "$userPath;$directoryOrFile", 'User')
}
$env:Path="$($env:PATH.Trim(';'));$directoryOrFile"
}
new-alias Add-ToPath Add-Path
# ============================================================================
# -- Ensure Editors ara available in the PATH on the command line
# vscode
# Nothing to do for vscode, its installer usually adds it to the PATH.
# Look for sublime in various places if installed
if(-not (Get-Command subl -EA Silently)){
if(Test-Path "$env:ProgramFiles/Sublime Text/subl.exe")
{
New-Alias subl ((Resolve-Path "$env:ProgramFiles/Sublime Text/subl.exe").Path)
}
elseif(Test-Path "$env:APPDATA/sublime_text*/subl.exe")
{
$global:sublexe = (Get-ChildItem "$env:APPDATA/sublime_text*/subl.exe" | Select-Object -Last 1).FullName
New-Alias subl $global:sublexe
}
}
if( (Get-Command subl -EA Silent) -and -not (Get-Command sub -EA Silent))
{
New-Alias sub subl
}
# Look for vim in various places if installed
if((Test-Path "$env:ProgramFiles\Vim\Vim*\vim.exe") -and -not (Get-Command vim -EA Silent)){
$vim= (Get-ChildItem "$env:ProgramFiles\Vim\Vim*\vim.exe" | Select-Object -Last 1).FullName
new-alias vim $vim
}
if((Test-Path "$env:ProgramFiles\Vim\Vim*\gvim.exe") -and -not (Get-Command gvim -EA Silent)){
$gvim= (Get-ChildItem "$env:ProgramFiles\Vim\Vim*\gvim.exe" | Select-Object -Last 1).FullName
new-alias gvim $gvim
}
# ============================================================================
# -- Choose Your Editor preference order
'subl','code-insiders','code','vim','nvim','gvim','$env:WinDir\system32\edit.exe',"$global:EDITOR",'notepad.exe' |
Where { ("$_") -and (Get-Command $_ -EA Silent)} |
Select -First 1 |
%{
New-Alias edit $_
}
function editprofile { edit $PROFILE }
# ============================================================================
# Autocompletion and readline vvv
# This now seems to be redundant on Win10 or later, it's all built-in even for PS5?
# Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
# Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
# Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
# Autocompletion ^^^
# ============================================================================
# -- Git
Write-Host "Use source command '. pg' to load poshgit"
# I used to have poshgit load automatically but it's slow - often 2-3 seconds -
# so autoload seems unhelpful if you use new shells a lot.
function pg {
$stopwatchPG=[System.Diagnostics.Stopwatch]::StartNew()
Import-Module posh-git -EA Silent
Write-Host "PoshGit took $($stopwatchPG.ElapsedMilliseconds)ms"
$stopwatchPG=[System.Diagnostics.Stopwatch]::StartNew()
if($?){
$GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true
function Get-ShorterPromptPath {
(Get-Location).ToString().Replace("$env:USERPROFILE","~") `
-replace '([^\\]{6})([^\\]{4,})\\','$1..\' `
-replace '\\([^\\]{6})([^\\]{3,})([^\\]{6})$','\$1..$3'
}
$GitPromptSettings.DefaultPromptPath.Text = '$(Get-ShorterPromptPath)'
function nll { if(-not $GitPromptSettings.AfterStatus.Text -match "\n"){$GitPromptSettings.AfterStatus.Text += "`n" }}
}else{
function prompt {
$d=(Get-Location).ToString().Replace("$env:USERPROFILE","~") `
-replace '([^\\]{6})([^\\]{4,})\\','$1..\' `
-replace '\\([^\\]{6})([^\\]{3,})([^\\]{6})$','\$1..$3'
"$d> "
}
}
Write-Host "PoshGit customization took $($stopwatchPG.ElapsedMilliseconds)ms"
}
function gaa { git add $args :/ }
function gb { git branch $args }
function gbr { git branch --remote $args }
function gcliplast { (git show --pretty=oneline | Select-Object -first 1) -replace "^[a-f0-9A-F]+ ","" | clip }
function gco { git checkout $args}
function gitcom { git commit -m "$args"}
function gitacom { git commit -a -m "$args"}
function gitaaacom { git add :/ ; git commit -m "$args"}
function gdiff { git diff $args }
function glog { git log `
--pretty=format:'%Cred%h%Creset %C(yellow)%d%Creset %s %Cgreen%cd %C(bold blue)%an%Creset' `
--abbrev-commit --date=format:'%d-%m-%Y %H:%M' $args }
function glogg { glog --graph $args }
function glog1 {git log --pretty=oneline $args}
function grv {git remote --verbose $args}
function gs { git status $args }
function gst { git status $args }
function gpullpush {
"Checking ..."
git remote update
if( ($s=(git status | select-string -Pattern "Your branch is behind|have diverged")).Count ) {
$s
git pull
if( $s -match "can be fast-forwarded.|Successfully rebased and updated"){
"Pushing ..."
git push
} else {
"Merge or rebase wanted. Not pushing."
}
} else {
"Nothing to pull. Pushing ..."
git push
}
[DateTime]::Now
}
function openremote (
[string]
[ValidateSet("","build","release","boards","repo","files","pullrequests","branches","tags","commits","wiki","summary","/")]$what )
{
$remote = git remote -v 2>$null | select-string "https://[^ ]+" | Select-Object -First 1 | %{ "$($_.Matches.Value)" -replace "//[^@]+@","//" }
if( "$remote" -eq "" -and (Get-Command tf.exe -EA Silent))
{
$remote= tf workfold . 2>$null | select-string "https://[^ ]+" | Select-Object -First 1 | %{ "$($_.Matches.Value)" -replace "//[^@]+@","//" }
}
if($remote -match "dev.azure.com" -and (Get-Command Open-DevAzure -EA Silent)){
Open-DevAzure $what $args
}
else{
Start-Process "$remote"
}
}
#Git ^^^
# ============================================================================
# -- DevAzure
function Open-DevAzure(
[string]
[ValidateSet("","build","release","boards","repo","files","pullrequests","branches","tags","commits","wiki","summary","/")]$what ) {
$remote = "$(git remote -v | select-string "https://[^ ]+" |
Select-Object -First 1 -Property {$_.Matches.Value} |
Select-Object -ExpandProperty '$_.Matches.Value')" -replace "//[^@]+@","//"
if("build","release","boards","wiki" -contains $what)
{
$remote | select-string "https://[^ ]+(?=/_git)" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)/_$what" }
}
elseif( "summary","/" -eq $what)
{
$remote | select-string "https://[^ ]+(?=/_git)" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)" }
}
elseif( "files","repo","" -contains $what)
{
$remote | select-string "https://[^ ]+" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)" }
}
else
{
$remote | select-string "https://[^ ]+" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)/$what" }
}
}
new-alias opendaz Open-DevAzure
#DevAzure ^^^
# ============================================================================
# -- Docker
if(Get-Command docker -EA Silent){
function dockerdesktop { Start-Process "$env:ProgramFiles\Docker\Docker\Docker Desktop.exe" }
function ddls-all { docker container ls -aq }
function ddstop-all { docker container stop $(docker container ls -aq) }
function ddrm-all { docker container rm $(docker container ls -aq) }
function dockerlastone { docker attach $(docker ps -q | head -n 1) }
}
#Docker ^^^
# ============================================================================
# -- AzureCLI
if(Get-Command az -EA Silent){
Register-ArgumentCompleter -Native -CommandName az -ScriptBlock {
param($commandName, $wordToComplete, $cursorPosition)
$completion_file = New-TemporaryFile
$env:ARGCOMPLETE_USE_TEMPFILES = 1
$env:_ARGCOMPLETE_STDOUT_FILENAME = $completion_file
$env:COMP_LINE = $wordToComplete
$env:COMP_POINT = $cursorPosition
$env:_ARGCOMPLETE = 1
$env:_ARGCOMPLETE_SUPPRESS_SPACE = 0
$env:_ARGCOMPLETE_IFS = "`n"
$env:_ARGCOMPLETE_SHELL = 'powershell'
az 2>&1 | Out-Null
Get-Content $completion_file | Sort-Object | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)
}
Remove-Item $completion_file, Env:\_ARGCOMPLETE_STDOUT_FILENAME, Env:\ARGCOMPLETE_USE_TEMPFILES, Env:\COMP_LINE, Env:\COMP_POINT, Env:\_ARGCOMPLETE, Env:\_ARGCOMPLETE_SUPPRESS_SPACE, Env:\_ARGCOMPLETE_IFS, Env:\_ARGCOMPLETE_SHELL
}
}
#AzureCLI ^^^
# ============================================================================
# -- Dotnet CLI
if(test-path ~/.dotnet){ Add-toPath ~/.dotnet }
if(test-path ~/.dotnet/tools){ Add-ToPath ~/.dotnet/tools }
#DotNet ^^^
# ============================================================================
# -- Console Colours for the PowerShell White or Yellow on Blue theme
$Host.PrivateData.ErrorForegroundColor = "Yellow"
$Host.PrivateData.ErrorBackgroundColor = $Host.UI.RawUI.BackgroundColor
$Host.PrivateData.WarningForegroundColor = "DarkYellow"
$Host.PrivateData.WarningBackgroundColor = $Host.UI.RawUI.BackgroundColor
#Console Colours ^^^
# ============================================================================
# -- Other preferences
new-alias gh get-help
new-alias ll Get-ChildItem
new-alias open start
function ss { start-process "https://google.com/search?q=$([uri]::EscapeDataString($args))" }
function pss { start-process "https://google.com/search?q=$([uri]::EscapeDataString("powershell $args"))" }
# which.exe,where.exe,get-command are each subtly different
function wh { $r= Get-Command $args ; $r; if($r.GetType() -eq [System.Management.Automation.FunctionInfo]){ $r.ScriptBlock } }
if([System.Environment]::OSVersion.Platform -like 'Win*')
{
if(Test-Path "$global:onedrive\Commands\AutohotkeyForPCKeyboard.exe"){
new-alias ahwin (Resolve-Path "$global:onedrive\Commands\AutohotkeyForPCKeyboard.exe")
}
if(Test-Path "$global:onedrive\Commands\AutohotkeyForMacKeyboard.exe"){
new-alias ahmac (Resolve-Path "$global:onedrive\Commands\AutohotkeyForMacKeyboard.exe")
}
function pgrep([Parameter(Position=0,mandatory=$true)][string]$Name, [switch]$full )
{
Get-WmiObject Win32_Process `
| Where-Object { $_.Name -match $Name -or ( $full -and ($_.CommandLine -match $Name)) } `
| Select-Object -Property ProcessId, Name, CommandLine, Status
}
}
Add-Type -AssemblyName System.IO.Compression.FileSystem
function Get-ZippedChildItem {
param (
[Parameter(Mandatory=$false)]
[string]$Path,
[Parameter(Mandatory=$false)]
[string]$filePattern
)
Add-Type -AssemblyName System.IO.Compression.FileSystem
if(-not $Path){
'Usage:
Get-ZippedChildItem [ -Path ] "archive.zip" [ -FilePattern "file*.* ]"
'
return
}
if (-not $Path) {$Path="."}
if (-not $ZipPattern) {$ZipPattern="*.zip"}
if (-not $filePattern) {$filePattern="*"}
Get-ChildItem -Path $Path | ForEach-Object {
$zipFile = $_.FullName
$zipArchive = [System.IO.Compression.ZipFile]::OpenRead($zipFile)
try{
$zipArchive.Entries | Where-Object { $_.Name -like $filePattern }
} finally { $zipArchive.Dispose() }
}
}
function Get-ZippedContent{
[OutputType([String])]
[CmdletBinding()]
Param( $ZipFilePath, $FilePathInZip)
$verbose = $VerbosePreference -ne 'SilentlyContinue'
if (-not (test-path $ZipFilePath)) {
throw "Zip file ""$ZipFilePath"" not found."
}
try {
$Zip = [System.IO.Compression.ZipFile]::OpenRead( (Resolve-Path $ZipFilePath) )
write-verbose "Opened $ZipFilePath : $(($zz.Entries | measure).Count) entries"
$matchingEntries= $Zip.Entries | where-object {return $_.FullName -like $FilePathInZip}
write-verbose "$(($matchingEntries | measure).Count) entries match ""$FilePathInZip"""
$matchingEntries |
ForEach-object {
write-verbose "Found $($_.FullName)"
$ZipStream = $_.Open()
try{
$Reader = [System.IO.StreamReader]::new($ZipStream)
$s= $Reader.ReadToEnd()
write-verbose "Length $($s.Length)"
$s
}
finally{
if($Reader){$Reader.Dispose()}
}
}
}
finally {if ($Zip) { $Zip.Dispose() } }
}
# From https://www.sysadmins.lv/blog-en/test-web-server-ssltls-protocol-support-with-powershell.aspx
function Test-ServerSSLSupport {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[ValidateNotNullOrEmpty()]
[string]$HostName,
[UInt16]$Port = 443
)
process {
$RetValue = New-Object psobject -Property @{
Host = $HostName
Port = $Port
SSLv2 = $false
SSLv3 = $false
TLSv1_0 = $false
TLSv1_1 = $false
TLSv1_2 = $false
KeyExhange = $null
HashAlgorithm = $null
}
"ssl2", "ssl3", "tls", "tls11", "tls12" | %{
$TcpClient = New-Object Net.Sockets.TcpClient
$TcpClient.Connect($RetValue.Host, $RetValue.Port)
$SslStream = New-Object Net.Security.SslStream $TcpClient.GetStream(),
$true,
([System.Net.Security.RemoteCertificateValidationCallback]{ $true })
$SslStream.ReadTimeout = 15000
$SslStream.WriteTimeout = 15000
try {
$SslStream.AuthenticateAsClient($RetValue.Host,$null,$_,$false)
$RetValue.KeyExhange = $SslStream.KeyExchangeAlgorithm
$RetValue.HashAlgorithm = $SslStream.HashAlgorithm
$status = $true
} catch {
$status = $false
}
switch ($_) {
"ssl2" {$RetValue.SSLv2 = $status}
"ssl3" {$RetValue.SSLv3 = $status}
"tls" {$RetValue.TLSv1_0 = $status}
"tls11" {$RetValue.TLSv1_1 = $status}
"tls12" {$RetValue.TLSv1_2 = $status}
}
# dispose objects to prevent memory leaks
$TcpClient.Dispose()
$SslStream.Dispose()
}
$RetValue
}
}
function yesno {
while( -not ( ($choice= (Read-Host "May I continue?")) -match "^(ye?s?|no?)$")){ "Y or N ?"}
return ($choice -match "^y")
}
#Other preferences ^^^
# ============================================================================
# ============================================================================
# -- DotNet Framework Installs
# `dotnet --info` show you net core installs, these are for net framework
class PSChildNameVersionRelease { [string]$PSChildName ; [string]$Version ; [int]$Release; }
function Get-InstalledDotNetFrameworkRuntimes{
[OutputType([PSChildNameVersionRelease])]
[CmdletBinding()]
Param()
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse |
Get-ItemProperty -name Version,Release -EA 0 |
Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} |
Sort-Object -Property Version |
Select-Object PSChildName, Version, Release
}
New-Alias Get-NetFrameworkVersions Get-InstalledDotNetFrameworkRuntimes
class DisplayNameVersion { [string]$DisplayName ; [string]$DisplayVersion ; }
function Get-InstalledDotNetPacks{
[OutputType([DisplayNameVersion])]
[CmdletBinding()]
Param()
Get-ItemProperty `
-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", `
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" |
Where-Object {$_.DisplayName -like '*.NET*'} |
Select-Object DisplayName, DisplayVersion |
Sort-Object -Property DisplayName
}
#DotNet Installs ^^^
# ============================================================================
# ============================================================================
# -- IIS
function publish-to-iis($fromSolutionDirectory, $toIISAppPath, $publishProfileXmlFileNameNoPath, $buildConfiguration, [switch]$noConfirm)
{
if(-not "$fromSolutionDirectory" -or -not "$toIISAppPath" `
-or -not "$publishProfileXmlFileNameNoPath" -or -not "$buildConfiguration"){
Write-Host "Usage: publish-to-iis `$fromSolutionDirectory, `$toIISAppPath, `$publishProfileXmlFileNameNoPath, $buildConfiguration"
break
}
Get-ChildItem $fromSolutionDirectory/$publishProfileXmlFileNameNoPath -recurse
Push-Location $fromSolutionDirectory
if(Test-Path $toIISAppPath\web.config){
Remove-Item $toIISAppPath\web.config -Verbose
}else{
Write-Warning "target web.config doesn't exist. Did you already delete it (or have you set the WRONG target path)?"
if(-not $noConfirm){
while( -not ( ($choice= (Read-Host "Press Y to continue or N to stop:")) -match "^(Y|N)$")){ "Y or N ?"}
if($choice -ne 'y'){return}
}
}
$publishProfileXmlFileNameNoPath= Split-Path $publishProfileXmlFileNameNoPath -Leaf
"Removing directories..."
Get-ChildItem $toIISAppPath\* -Directory |
ForEach-Object{ $_.Name ; Remove-Item $_ -recurse }
Get-ChildItem $toIISAppPath
msbuild /p:Configuration=$buildConfiguration /p:DeployOnBuild=true /p:PublishProfile=$publishProfileXmlFileNameNoPath
Pop-Location
"Finished at $(Get-Date)"
}
#IIS ^^^
# ============================================================================
# ============================================================================
# -- Windows Only Paths, Installers included Visual Studio pieces ------------
function Show-MoreWinGetInstallersForDevTools{
@"
More WinGet DevTool installers
==============================
winget install vswhere
winget install Microsoft.VisualStudioCode --override "/mergetasks='!runcode,addcontextmenufiles,addcontextmenufolders,associatewithfiles,addtopath'" --source winget
winget install sublimeHQ.SublimeText.4.Portable
winget install git.git
winget install Microsoft.NuGet
winget install WinMerge.WinMerge
winget install Perforce.P4Merge
winget install JetBrains.Rider
winget install Microsoft.VisualStudio.Community
winget install Microsoft.VisualStudio.Professional
winget install Microsoft.AzureCLI
winget install autohotkey.autohotkey
winget install Microsoft.DotNet.Framework.DeveloperPack_4
"@
}
if(-not (Get-Command vswhere.exe -EA Silent) `
-and (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"))
{
Add-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer"
}
if(Get-Command vswhere.exe -EA Silent)
{
function Add-VsDevPaths {
$vsroot= (vswhere -latest -property installationPath)
if($vsroot -and $vsroot.Length -gt 1){
@(
"$vsroot\Common7\IDE\Extensions\TestPlatform",
"$vsroot\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer",
"$vsroot\MSBuild\Current\bin\Roslyn",
"$vsroot\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools",
"$vsroot\Team Tools\DiagnosticsHub\Collector",
"$vsroot\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console",
"$vsroot\\MSBuild\Current\Bin\amd64",
"$vsroot\Common7\IDE\",
"$vsroot\Common7\Tools\",
"$vsroot\Common7\IDE\VC\Linux\bin\ConnectionManagerExe",
"${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\",
"$env:SystemRoot\Microsoft.NET\Framework\v4.0.30319"
) | ForEach-Object{ if(Test-Path "$_") { "Adding $_" ; Add-Path $_ } }
}
}
}
function Ensure-MsBuild-Git-Nuget-If-WinVS-Installed
{
if( [System.Environment]::OSVersion.Platform -notlike "Win*" )
{
Write-Error "This function relies on a Visual Studio installation so it only runs on Windows."
return
}
$vsInstallerPath= "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer"
if(-not (Test-Path $vsInstallerPath)){
Write-Error "This function relies on a Visual Studio installation but didn't find one in ."
Write-Warning "You can install visual studio and the VSWhere tool with winget, e.g.:
winget search Microsoft.VisualStudio
# winget install <Your Choice of lastest Visual Studio version e.g. Microsoft.VisualStudio.2022.Enterprise/Professional/Community>
winget install Microsoft.VisualStudio.Community
winget install Microsoft.VisualStudio.Professional
"
return
}
elseif(-not (Get-Command vswhere.exe -EA Silent))
{
Add-Path $vsInstallerPath
}
Write-Host @"
This script will
- add Visual Studio MsBuild to your path
- add Git to your path
- Install NuGet
- Install NuGet artifacts credential provider
"@
$findVSComponents = @{
"MSBuild" = @{ Path = "MSBuild\**\Bin\MSBuild.exe" }
"Git" = @{ Path = "**\bin\Git.exe" }
# For more up-to-date Git, use winget install git.git instead of using the VS installed version
}
foreach($required in $findVSComponents.GetEnumerator()){
if(Get-command $required.Key -EA Silent){
Write-Host "$($required.Key) already in path"
continue
}
$componentExe = &vswhere.exe -latest -prerelease -products * -find $required.Value.Path
Add-ToPath "$componentExe" -permanentlyInWindowsProfileUserPath
if(-not (Get-Command $required.Key -EA Silent)){
Write-Warning "Failed to add $($required.Key) to the path at $componentExe"
}else{
"Added $($required.Key) to the path at $componentExe"
}
}
if(-not (Get-Command Git -EA Silent)){
winget install Git.Git
Write-Warning "Just installed Git. You could exit and restart powershell for the addition to your path to be picked up."
}
if(-not (Get-Command NuGet -EA Silent)){
winget install Microsoft.NuGet
Write-Warning "Just installed NuGet. You must exit and restart powershell for the addition to your path to be picked up."
}
Write-Warning "Installing the azure artifacts credential provider for netcore and NetFx."
iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) } -AddNetfx"
}
# ^^^ Windows Only Paths, Installers included Visual Studio pieces ^^^
# ============================================================================
# ============================================================================
# -- First Run and Installers ------------------------------------------------
if($firstRunGit)
{
if(Get-Command git -EA Silent - $?){
winget install git.git
}
git config --global rerere.enabled true
git config --global alias.root 'rev-parse --show-toplevel'
if((Get-Command p4merge) -and (Test-Path (Get-Command p4merge).Source))
{
git config --global merge.tool p4merge
git config --global diff.tool p4merge
}
else{Write-Warning "p4merge not found"}
Install-Module -Name posh-git -Scope CurrentUser
}
if($firstRunDotNet){
winget install Microsoft.NuGet
winget install Microsoft.DotNet.Framework.DeveloperPack_4
winget install dotnet-sdk-10
}
Remove-Variable firstRun
#First Run ^^^
#$stopwatch.ElapsedMilliseconds.ToString() + "ms"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment