Instantly share code, notes, and snippets.
Forked from jcwillox/toolbox-context-menu.ps1
Last active
April 1, 2022 11:18
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save ntwi/a1c554eed2efaf6c2b46ccb20655cbb4 to your computer and use it in GitHub Desktop.
PowerShell script to automatically add context menu entries for Jetbrains IDEs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Automatically add context menu entries for Jetbrains IDEs. | |
.PARAMETER Name | |
The name or names of the IDEs to add context menus for, use -List to see available IDEs. | |
.PARAMETER BasePath | |
The path to the Toolbox apps directory, defaults to "$env:LOCALAPPDATA\JetBrains\Toolbox\apps". | |
.PARAMETER Global | |
Install context menu entries in HKLM registry (machine wide), requires running as administrator. | |
.PARAMETER Force | |
Overwrite current registry entries, useful when updating existing entries. | |
.PARAMETER Remove | |
Will remove the context menu entries for specified IDEs | |
.PARAMETER List | |
List available IDEs installed via Toolbox | |
.PARAMETER UseNircmd | |
Will use nircmd (if installed) to invisibly run the IDE's batch script, this will avoid you having to | |
re-run this script each time an IDE is updated via Toolbox. | |
.PARAMETER NirCmdPath | |
Specify the location of the nircmd executable to use, will attempt to locate it from $PATH if not specified. | |
.PARAMETER AppDir | |
If you are not using Toolbox you can specify the IDE's installation directory. | |
#> | |
[CmdletBinding()] | |
param ( | |
[array]$Name, | |
[string]$BasePath, | |
[switch]$Global, | |
[switch]$Force, | |
[switch]$Remove, | |
[switch]$List, | |
[switch]$UseNircmd, | |
[string]$NirCmdPath, | |
[string]$AppDir | |
) | |
$ErrorActionPreference = 'Stop' | |
$toolbox = if ($BasePath) { $BasePath } else { Join-Path $env:LOCALAPPDATA "JetBrains\Toolbox\apps" } | |
$regRoot = if ($Global) { "HKLM" } else { "HKCU" } | |
if ($UseNircmd -and -not (Get-Command "nircmd.exe" -ErrorAction Ignore)) { | |
Write-Error "nircmd.exe is not installed or missing from the path" | |
Write-Error "either install nircmd or specify its location using '-NirCmdPath'" | |
return | |
} | |
function Get-IDEs { | |
$IDEs = @{} | |
foreach ($item in (Get-ChildItem $toolbox -Exclude Toolbox)) { | |
$versionPath = (Get-ChildItem -Path (Join-Path $item.FullName "ch-*") -Directory -Exclude "*.plugins" | Sort-Object BaseName -Descending | Select-Object -Last 1 | Select-Object -ExpandProperty FullName) | |
$binPath = Join-Path $versionPath "bin" | |
if (Test-Path $binPath) { | |
$IDEs[$item.BaseName] = $versionPath | |
} | |
} | |
return $IDEs | |
} | |
if ($List) { | |
return Get-IDEs | |
} | |
function Add-ShellKeys { | |
param ( | |
[string]$Name, | |
[string]$ExePath, | |
[string]$Path, | |
[string]$Action, | |
[string]$LaunchArgs | |
) | |
$Path = Join-Path "${regRoot}:" $Path | |
if ($UseNircmd) { | |
# extract shell link path | |
$scriptPath = Get-Content (Join-Path (Split-Path $ExePath) "../.." ".shellLink") | |
# move icon outside of version directory so it will survive updates | |
$baseName = (Split-Path $ExePath -LeafBase).Replace("64", "") | |
$iconPath = Join-Path (Split-Path $ExePath) "$baseName.ico" | |
$destPath = Join-Path (Split-Path (Split-Path (Split-Path $ExePath))) "$baseName.ico" | |
Move-Item -Path $iconPath -Destination $destPath -ErrorAction Ignore | |
$iconPath = "`"$destPath`",0" | |
# contruct args | |
$ExePath = if ($NirCmdPath) { $NirCmdPath } else { (Get-Command "nircmd.exe").Path } | |
$LaunchArgs = "execmd $scriptPath $LaunchArgs" | |
} else { | |
$iconPath = $ExePath | |
} | |
if (-not $Force -and (Test-Path -LiteralPath "$Path\$Name")) { | |
Write-Host "EXISTS: $Path\$Name" -f Yellow | |
} else { | |
New-Item ` | |
-Path "$Path\$Name" ` | |
-Value "$Action with $Name" ` | |
-Force:$Force ` | |
-Confirm:$false | Out-Null | |
Write-Host "ADDED: $Path\$Name" -f DarkGreen | |
} | |
if (-not $Force -and (Get-ItemProperty -LiteralPath "$Path\$Name" -Name "Icon" -ErrorAction Ignore)) { | |
Write-Host "EXISTS: $Path\$Name [Icon]" -f Yellow | |
} else { | |
New-ItemProperty ` | |
-LiteralPath "$Path\$Name" ` | |
-PropertyType ExpandString ` | |
-Name "Icon" ` | |
-Value $iconPath ` | |
-Force:$Force ` | |
-Confirm:$false | Out-Null | |
Write-Host "ADDED: $Path\$Name [Icon]" -f DarkGreen | |
} | |
if (-not $Force -and (Get-Item -LiteralPath "$Path\$Name\command" -ErrorAction Ignore)) { | |
Write-Host "EXISTS: $Path\$Name\command" -f Yellow | |
} else { | |
New-Item ` | |
-Path "$Path\$Name\command" ` | |
-Value "`"$exePath`" $LaunchArgs" ` | |
-Force:$Force ` | |
-Confirm:$false | Out-Null | |
Write-Host "ADDED: $Path\$Name\command" -f DarkGreen | |
} | |
} | |
function Add-RegKey([string]$Path) { | |
$Path = Join-Path "${regRoot}:" $Path | |
if (-not (Test-Path -LiteralPath $Path)) { | |
New-Item -Path $Path -Force -ErrorAction Ignore -Confirm:$false | Out-Null | |
} | |
} | |
function Add-ContextMenu { | |
param ( | |
[string]$Name, | |
[string]$ExePath | |
) | |
# ensure base folders exist | |
Add-RegKey "SOFTWARE\Classes\`*\shell" | |
Add-RegKey "SOFTWARE\Classes\Directory\shell" | |
Add-RegKey "SOFTWARE\Classes\Directory\Background\shell" | |
# add to file context menu | |
Write-Output "ACTION: Edit with $Name (Files)" | |
Add-ShellKeys $Name $ExePath "SOFTWARE\Classes\*\shell" "Edit" "`"%1`"" | |
# add to directory context menu | |
Write-Output "ACTION: Open with $Name (Directory)" | |
Add-ShellKeys $Name $ExePath "SOFTWARE\Classes\Directory\shell" "Open" "`"%1`"" | |
# add to directory background context menu | |
Write-Output "ACTION: Open with $Name (Directory Background)" | |
Add-ShellKeys $Name $ExePath "SOFTWARE\Classes\Directory\Background\shell" "Open" "`"%V`"" | |
} | |
function Remove-Reg([string]$Path) { | |
$Path = Join-Path "${regRoot}:" $Path | |
if (-not (Test-Path -LiteralPath $Path)) { | |
Write-Host "MISSING: $Path" -f Yellow | |
} else { | |
Remove-Item -LiteralPath $Path -Recurse | |
Write-Host "REMOVED: $Path" -f Red | |
} | |
} | |
function Remove-ContextMenu([string]$Name) { | |
Remove-Reg "SOFTWARE\Classes\*\shell\$Name" | |
Remove-Reg "SOFTWARE\Classes\Directory\shell\$Name" | |
Remove-Reg "SOFTWARE\Classes\Directory\Background\shell\$Name" | |
} | |
function Start-ContextMenu([string]$AppDir) { | |
$info = (Get-Content (Join-Path $AppDir "product-info.json") | ConvertFrom-Json) | |
$friendlyName = $info.Name | |
$exePath = Join-Path $AppDir $info.launch[0].launcherPath | |
if ($Remove) { | |
Write-Host "Removing Context Menu for '$friendlyName'" -ForegroundColor Cyan | |
Remove-ContextMenu -Name $friendlyName | |
} else { | |
Write-Host "Adding Context Menu for '$friendlyName'" -ForegroundColor Cyan | |
Add-ContextMenu -Name $friendlyName -ExePath $exePath | |
} | |
} | |
if ($AppDir) { | |
Start-ContextMenu $AppDir | |
} else { | |
$ides = (Get-IDEs) | |
foreach ($ide in $ides.Keys) { | |
foreach ($match in $Name) { | |
if (($match -eq "*") -or ($ide.ToLower().StartsWith($match.ToLower()))) { | |
Start-ContextMenu $ides[$ide] | |
break | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment