Using PowerShell to Add “Open PowerShell Here” and “Open Command Prompt Here” to Explorer Context Menus
Description
I recently reloaded my primary workstation. When I do that, I run my PowerShell profile file manually once, and it configures quite a few things, including dot sourcing that same file into the main profile file, which it also creates. When I was all done, I realized I didn’t have the “Open PowerShell Here” options when right clicking in Windows Explorer. Being old and forgetful, I did some searching and was quite surprised (and disappointed) that every method for setting this was either using an .inf file, a .reg file, or manually editing the registry. What a travesty that no one was showing how to do it via PowerShell. So a bottle of Mountain Dew Throwback and some Pink Floyd was all I needed.
The right-click options can be visible in three different places. The first is when you right-click a folder. Second is when you right-click a root drive. And the third is when you right-click the background in Explorer. The method I’ll be showing here will include setting the option for all three. Additionally, I’ll show how to add an option to open an elevated PowerShell session, as well as a command prompt. When finished, you’ll end up with something like this:
All options are configured in the HKEY_CLASSES_ROOT hive of the registry. The folder level option resides under \Directory\shell; the root drive option resides under \Drive\shell; and the Explorer background option resides under \Directory\Background\shell. For each, we create a new key with a unique name for each of the options (PowerShell, PowerShell elevated, cmd prompt), some values for the display text and icon, and a sub key with a value that shows what commands will run when executed. This is easily accomplished using the New-Item and New-ItemProperty cmdlets in an elevated PowerShell session.
Add “Open PowerShell Here”
#folders New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Value "Open PowerShell Here" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere\command" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command Set-Location '%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -Force | Out-Null #background New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Value "Open PowerShell Here" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere\command" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command Set-Location '%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -Force | Out-Null #root drives New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Value "Open PowerShell Here" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere\command" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command Set-Location '%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -Force | Out-Null
Add “Open PowerShell Here (Admin)”
#folders New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Value "Open PowerShell Here (Admin)" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin\command" -Value "PowerShell -Command `"Start-Process $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe`" -verb runAs -ArgumentList '-NoExit','Set-Location','''%L'''" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe,1" -Force | Out-Null #background New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Value "Open PowerShell Here (Admin)" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin\command" -Value "PowerShell -Command `"Start-Process $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe`" -verb runAs -ArgumentList '-NoExit','Set-Location','''%V'''" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe,1" -Force | Out-Null #root drives New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Value "Open PowerShell Here (Admin)" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin\command" -Value "PowerShell -Command `"Start-Process $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe`" -verb runAs -ArgumentList '-NoExit','Set-Location','''%L'''" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe,1" -Force | Out-Null
Add “Open Command Prompt Here”
#folders New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere" -Value "Open Command Prompt Here" -ItemType string -Force | Out-Null New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere\command" -Value 'cmd.exe /k pushd %L' -ItemType string -Force | Out-Null New-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere" -Name "Icon" -Value "C:\Windows\System32\cmd.exe,0" -Type string -Force | Out-Null #background New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere" -Value "Open Command Prompt Here" -ItemType string -Force | Out-Null New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere\command" -Value 'cmd.exe /k pushd %L' -ItemType string -Force | Out-Null New-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere" -Name "Icon" -Value "C:\Windows\System32\cmd.exe,0" -Type string -Force | Out-Null #root drives New-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere" -Value "Open Command Prompt Here" -ItemType string -Force | Out-Null New-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere\command" -Value 'cmd.exe /k pushd %L' -ItemType string -Force | Out-Null New-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere" -Name "Icon" -Value "C:\Windows\System32\cmd.exe,0" -Type string -Force | Out-Null
Now we can put that all together, and add some checks to ensure the settings are not already configured, to avoid errors.
# folders if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere")){ New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Value "Open PowerShell Here" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere\command" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command Set-Location '%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -Force | Out-Null } if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin")){ New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Value "Open PowerShell Here (Admin)" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin\command" -Value "PowerShell -Command `"Start-Process $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe`" -verb runAs -ArgumentList '-NoExit','cd','%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe,1" -Force | Out-Null } if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere")){ New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere" -Value "Open Command Prompt Here" -ItemType string -Force | Out-Null New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere\command" -Value 'cmd.exe /k pushd %L' -ItemType string -Force | Out-Null New-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdHere" -Name "Icon" -Value "C:\Windows\System32\cmd.exe,0" -Type string -Force | Out-Null } # Explorer background if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere")){ New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Value "Open PowerShell Here" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere\command" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command Set-Location '%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -Force | Out-Null } if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin")){ New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Value "Open PowerShell Here (Admin)" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin\command" -Value "PowerShell -Command `"Start-Process $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe`" -verb runAs -ArgumentList '-NoExit','cd','%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe,1" -Force | Out-Null } if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere")){ New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere" -Value "Open Command Prompt Here" -ItemType string -Force | Out-Null New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere\command" -Value 'cmd.exe /k pushd %L' -ItemType string -Force | Out-Null New-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdHere" -Name "Icon" -Value "C:\Windows\System32\cmd.exe,0" -Type string -Force | Out-Null } # root drives if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere")){ New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Value "Open PowerShell Here" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere\command" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command Set-Location '%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -Force | Out-Null } if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin")){ New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Value "Open PowerShell Here (Admin)" -Force | Out-Null New-Item -ItemType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin\command" -Value "PowerShell -Command `"Start-Process $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe`" -verb runAs -ArgumentList '-NoExit','cd','%V'" -Force | Out-Null New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Name "Icon" -Value "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe,1" -Force | Out-Null } if(-not (Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere")){ New-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere" -Value "Open Command Prompt Here" -ItemType string -Force | Out-Null New-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere\command" -Value 'cmd.exe /k pushd %L' -ItemType string -Force | Out-Null New-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdHere" -Name "Icon" -Value "C:\Windows\System32\cmd.exe,0" -Type string -Force | Out-Null }
Since the file that’s dot sourced in my PowerShell profile is shared among all of my machines, I tossed the above code in it to ensure that all machines are configured this way, and to ensure that if I reload one of them, it gets reconfigured with no additional work.
Moving to sub-menu
If your right-click menu is already full of other options, and you’d rather have them on a menu when you hit SHIFT+Right Click, that’s easy. We add a property called “extended”, with an empty value, to the key for each option. We can do them all at once using this code (after running the above code first):
#folders if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Name "extended" -Value $null | Out-Null } if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Name "extended" -Value $null | Out-Null } if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdPromptHere" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdPromptHere" -Name "extended" -Value $null | Out-Null } #background if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Name "extended" -Value $null | Out-Null } if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Name "extended" -Value $null | Out-Null } if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdPromptHere" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdPromptHere" -Name "extended" -Value $null | Out-Null } #root drives if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Name "extended" -Value $null | Out-Null } if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Name "extended" -Value $null | Out-Null } if(-Not (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdPromptHere" -Name "extended")){ New-ItemProperty -PropertyType String -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdPromptHere" -Name "extended" -Value $null | Out-Null }
Removing the options
If you decide you’re not a fan of the options, removing them is really easy using the Remove-Item cmdlet.
#folders if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHere" -Recurse -Confirm:$False } if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\PowerShellHereAdmin" -Recurse -Confirm:$False } if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdPromptHere"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\CmdPromptHere" -Recurse -Confirm:$False } #background if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHere" -Recurse -Confirm:$False } if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\PowerShellHereAdmin" -Recurse -Confirm:$False } if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdPromptHere"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\Background\shell\CmdPromptHere" -Recurse -Confirm:$False } #root drives if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHere" -Recurse -Confirm:$False } if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\PowerShellHereAdmin" -Recurse -Confirm:$False } if(Test-Path -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdPromptHere"){ Remove-Item -Path "Registry::HKEY_CLASSES_ROOT\Drive\shell\CmdPromptHere" -Recurse -Confirm:$False }
Donations
I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.
As always, GREAT SCRIPT! One thing I did notice was when using the context menu on a folder to open Powershell, it throws an error if there’s a space in the folder name. Otherwise, this thing is getting tons of use!