I have a piece of code that requires to change the path for the current terminal session.Is there a way to remove just part of the path? I need python removed from path before the application starts. Also my if statements are not functioning and I am not sure why
function anaconda {
$key = "HKLM:\System\CurrentControlSet\Control\Session Manager\Environment"
param(
[Alias('d')]
[Parameter(ParameterSetName='Deactivate')]
[switch] $Deactivate
,
[Alias('a')]
[Parameter(ParameterSetName='Activate')]
[switch] $Activate
)
if ($Activate) {
& 'C:\Anaconda3\shell\condabin\conda-hook.ps1' ; conda activate 'C:\Anaconda3'
#some way to remove C:\Program Files\Python310\Scripts\; C:\Program Files\Python310\ from path
}
elseif ($Deactivate)
{
& 'C:\Anaconda3\shell\condabin\conda-hook.ps1' ; conda deactivate 'C:\Anaconda3'
$env:path = (Get-ItemProperty -Path $key -Name PATH).Path
}
}
This removes the paths, now I just need help with those If statements.
$Environment = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
foreach ($path in ($Environment).Split(";"))
{
if ($path -like "C:\Program Files\Python310\Scripts\")
{
$Environment = $Environment.Replace($Path ,"")
}
if ($path -like "C:\Program Files\Python310\")
{
$Environment = $Environment.Replace($Path ,"")
}
}
$env:PATH = $Environment
Related
-U returns the else echo statement and I can't figure out why. Everything else works if just seems to be ignoring my first if statement. The script functions for folder navigation. -U should return the /users/username directory. Thanks in advance for the help.
function display-path {Get-ChildItem Env:Path }
function folder {
[CmdletBinding(DefaultParameterSetName='Default')]
param(
[Alias('u')]
[Parameter(ParameterSetName='User')]
[switch] $Username
,
[Alias('s')]
[Parameter(ParameterSetName='Scripts')]
[switch] $Scripts
,
[Parameter(ParameterSetName='Desktop')]
[Alias('d')]
[switch] $Desktop
,
[Alias('h')]
[Parameter(ParameterSetName='help')]
[switch] $Help
,
[Alias('r')]
[Parameter(ParameterSetName='root')]
[switch] $root
)
$targetFolder =
if ($Username) {
$targetFolder += '\user\username'
}
if ($Scripts) {
$targetFolder += '\Desktop\Scripts'
}
elseif ($Desktop) {
$targetFolder += '\Desktop'
}
if ($root) {
$targetFolder += 'c:\'
}
else {
echo "
-H Display help. This is the same as not typing any options.
-U Change to the 'Username' directory
-S Change to the 'scripts' directory
-D Change to the 'desktop' directory"
}
Push-Location -LiteralPath $targetFolder
}
EDIT:
Here is the code updated with the else if statement that doesn't work, it is ignoring the first if statement.
function display-path {Get-ChildItem Env:Path }
<#
**One of these can be used to navigate to the username directory. The first will only allow you to navigate to one user, the second allows for you to select the user.**
$targetFolder =
if ($Username) {
$targetFolder += '\user\Username' #replace with your username
}
if ($Username) {
Join-Path (Split-Path -LiteralPath $HOME) $Username
} else {
$HOME
} #>
function folder {
[CmdletBinding(DefaultParameterSetName='Default')]
param(
[Alias('u')]
[switch] $Username
,
[Alias('s')]
[Parameter(ParameterSetName='Scripts')]
[switch] $Scripts
,
[Parameter(ParameterSetName='Desktop')]
[Alias('d')]
[switch] $Desktop
,
[Alias('h')]
[Parameter(ParameterSetName = 'help')]
[switch]$Help
,
[Alias('r')]
[Parameter(ParameterSetName = 'root')]
[switch]$root
)
$targetFolder =
if ($Username) {
$targetFolder += '\users\username
}
elseif ($Scripts) {
$targetFolder += '\Desktop\Scripts'
}
elseif ($Desktop) {
$targetFolder += '\Desktop'
}
elseif ($root) {
## same as other but we can use $env:homedrive for the root of C:
$targetFolder = $env:HOMEDRIVE + '\'
$r = ' -R '
}
elseif ($Help) {
echo "
-H Display help. This is the same as not typing any options.
-U Change to the 'Username' directory
-S Change to the 'scripts' directory
-D Change to the 'desktop' directory"
}
else {
echo "
-H Display help. This is the same as not typing any options.
-U Change to the 'Username' directory
-S Change to the 'scripts' directory
-D Change to the 'desktop' directory"
}
Push-Location -LiteralPath $targetFolder
}
If you want parameters to do something mutually exclusive and show help only if none are specified, you need to chain all your checks in a single if ... elseif ... elseif ... else chain:
if ($Username) {
$targetFolder += '\user\swmur'
}
elseif ($Scripts) {
$targetFolder += '\Desktop\Scripts'
}
elseif ($Desktop) {
$targetFolder += '\Desktop'
}
elseif ($root) {
$targetFolder += 'c:\'
}
else {
echo "
-H Display help. This is the same as not typing any options.
-U Change to the 'Username' directory
-S Change to the 'scripts' directory
-D Change to the 'desktop' directory"
}
I added some colorful commentary. This should be pretty close to what you're looking for.
function display-path {
<#
.SYNOPSIS
quick shortcut to get env:PATH
.DESCRIPTION
Call Get-ChildItem with the the -path set to "env:Path" which actually just outputs out the child items of the current folder...
.EXAMPLE
display-path | Format-List
Name : Path
Value : C:\Program Files\Eclipse Adoptium\jdk-17.0.2.8-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPow
erShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\PuTTY\;C:\ProgramData\chocolatey\bin;C:\Program Files\Go\bin;C:\Program
Files\dotnet\;C:\Program Files\Eclipse Adoptium\jdk-17.0.2.8-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\Syste
m32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\PuTTY\;C:\ProgramData\chocolatey\bin;C:\Program
Files\Go\bin;C:\Program Files\dotnet\;C:\Python310\Scripts;C:\Users\jedurham\AppData\Local\Programs\Microsoft VS Code\bin
.NOTES
not sure why anyone needs this
#>
Get-ChildItem -Path Env:Path
}
function folder {
<#
.SYNOPSIS
shortcut to move between folder someone uses often
.DESCRIPTION
shortcut to move between folder someone uses often.
can be used to quickly navigate to common directories.
.PARAMETER Username
Moves to the C:\Users\currentuser\ Folder.
.PARAMETER Scripts
Moves to a hard coded path called 'C:\Users\currentuser\Desktop\Scripts'
.PARAMETER Desktop
Moves to a hard coded path called 'C:\Users\currentuser\Desktop\'
.PARAMETER Help
Displays this file.
.PARAMETER root
Moves to the root of the current drive.
.EXAMPLE
folder -Username
C:> folder -U
You chose the -U flag!! Moving to C:\Users\currentuser\
.EXAMPLE
folder -Scripts
C:> folder -S
You chose the -S flag!! Moving to C:\Users\currentuser\Desktop\Scripts
.EXAMPLE
folder -Desktop
C:> folder -D
You chose the -D flag!! Moving to C:\Users\currentuser\Desktop\
.EXAMPLE
folder -root
C:\> folder -r
You chose the -R flag!! Moving to C:\
.NOTES
Needs a lot of work ....
v0.01
#>
[CmdletBinding(DefaultParameterSetName = 'Default')]
param(
[Alias('u')]
[Parameter(ParameterSetName = 'User')]
[switch]$Username
,
[Alias('s')]
[Parameter(ParameterSetName = 'Scripts')]
[switch]$Scripts
,
[Parameter(ParameterSetName = 'Desktop')]
[Alias('d')]
[switch]$Desktop
,
[Alias('h')]
[Parameter(ParameterSetName = 'help')]
[switch]$Help
,
[Alias('r')]
[Parameter(ParameterSetName = 'root')]
[switch]$root
)
$switchoutput = 'You chose the{0} flag!! Moving to {1}{2}'
if ($Username) {
## you need more comments in your code
## are you just trying to move the \user\current logged in?
## just use $env:USERPROFILE
$targetFolder = $env:USERPROFILE
$u = ' -U'
Write-Output -InputObject ($switchoutput -f $U, $targetFolder, '')
}
elseif ($Scripts) {
## a little tougher here because you need to hard code this path
## we could also ask for it ask an addendum to this switch :P
## ill do it this way
$targetFolder = $env:USERPROFILE
$s = ' -S '
## it might be better to define this else
$scriptspath = 'Desktop\Scripts'
$targetFolder = $env:USERPROFILE + $scriptspath
Write-Output -InputObject ($switchoutput -f $S, $targetFolder, '')
}
elseif ($Desktop) {
## same as above
## it might be better to define this else
$desktop = '\Desktop\'
$targetFolder = $env:USERPROFILE + $desktop
$d = ' -D '
Write-Output -InputObject ($switchoutput -f $d, $targetFolder, '')
}
elseif ($root) {
## same as other but we can use $env:homedrive for the root of C:
$targetFolder = $env:HOMEDRIVE + '\'
$r = ' -R '
Write-Output -InputObject ($switchoutput -f $r, $targetFolder, '')
}
else {
Write-Output -InputObject "
-H Display help. This is the same as not typing any options.
-U Change to the 'Username' directory
-S Change to the 'scripts' directory
-D Change to the 'desktop' directory"
-R Change to the Root of home directory"
}
if (Test-Path -Path $targetFolder) {
Set-Location -LiteralPath $targetFolder -Verbose
}
else {
Write-Output -InputObject ('{0} was not found :( exiting' -f $targetFolder)
}
}
so I want to delete an app of which I do not know the product ID. I know you can delete an app by using msiexec.exe /x and then the product ID. How would I go about getting the product ID of a specific app also in commandline and storing the value in a variable so I can just place the variable in the delete command?
Thank in advance!!
There's always get-package. No one knows about it but me. This should work for msi installs.
get-package *software* | uninstall-package
If you know the exact name, this should work. Uninstall-package doesn't take wildcards.
uninstall-package 'Citrix HDX RealTime Media Engine 2.9.400'
Sometimes, annoyingly, it prompts to install nuget first:
install-packageprovider nuget -force
If it's not an msi install, but a programs install, it takes a little more string mangling. You may have to add a '/S' or something for silent install at the end.
$prog,$myargs = -split (get-package 'Remote Support Jump Client *' |
% { $_.metadata['uninstallstring'] })
& $prog $myargs
Maybe in this case just run it:
& "C:\Program Files (x86)\Citrix\Citrix WorkSpace 2202\TrolleyExpress.exe" /uninstall /cleanup /silent
Or
$uninstall = get-package 'Citrix Workspace 2202' |
% { $_.metadata['uninstallstring'] }
$split = $uninstall -split '"'
$prog = $split[1]
$myargs = -split $split[2]
$myargs += '/silent'
& $prog $myargs
I think I have a way that works with or without double-quotes for non-msi installs:
$uninstall = get-package whatever | % { $_.metadata['uninstallstring'] }
$prog, $myargs = $uninstall | select-string '("[^"]*"|\S)+' -AllMatches |
% matches | % value
$prog = $prog -replace '"',$null
$silentoption = '/S'
$myargs += $silentoption # whatever silent uninstall option
& $prog $myargs
Here's a script I use. You have to know what the display name of the package is...like if you went to Remove Programs, what it's name would be. It works for my MSI packages that I create with WiX, but not all packages. You might consider winget command if you are on Windows 10+. winget has an uninstall option.
param (
[Parameter(Mandatory = $true)]
[string] $ProductName,
[switch] $Interactive = $false,
[switch] $key = $false
)
$log_directory = "c:\users\public"
# $log_directory = "c:\erase\logs"
if ((-not $Interactive) -and (-not (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)))
{
$interactive = $true
# echo "Not elevated, needs to be interactive"
}
$found = $null
$productsKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products"
$rootKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($productsKeyName)
foreach ($productKeyName in $rootKey.GetSubKeyNames())
{
#$productKeyName
try
{
$installPropertiesKey = $rootKey.OpenSubKey("$productKeyName\InstallProperties")
if ($installPropertiesKey)
{
$displayName = [string] $installPropertiesKey.GetValue("DisplayName")
if ( (! [string]::IsNullOrEmpty($displayName)) -and ($displayName -eq $ProductName))
{
$found = $productKeyName
break
}
}
}
catch
{
}
finally
{
if ($installPropertiesKey) { $installPropertiesKey.Close() }
}
}
$rootKey.Close()
if (-not $found)
{
return "First search could not find $ProductName"
}
$localPackage = $null
if (! [string]::IsNullOrEmpty($found))
{
try
{
$regkey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("$productsKeyName\$found\InstallProperties")
$localPackage = $regkey.GetValue("LocalPackage")
}
catch
{
}
finally
{
if ($regkey) { $regkey.Close() }
}
}
if ($key)
{
return "Found key: $found"
}
if (![string]::IsNullOrEmpty($localPackage) -and (Test-Path $localPackage))
{
$logflags = "/lv*"
$logname = (Join-Path $log_directory "$ProductName_uninstall.log")
$args = #($logflags, $logname, "/X", $localPackage)
if (!$Interactive) { $args += "/q" }
&msiexec $args
}
else
{
"Could not find uninstall package: $ProductName"
}
I need to check if my current location contains a directory called _framework and if it does, set the location to that folder.
The Problem is, I don't know what's in the path before my keyword, or after my keyword.
So to visualize, basically if I am here:
C:\foo\bar\some\_framework\stuff\xy
I need to jump here:
C:\foo\bar\some\_framework
I've written a code that works:
$CurrentPath = (Get-Location).Path
$SplitUp = $CurrentPath -split '\\'
$Result = #()
foreach ($Split in $SplitUp) {
$Result += $Split
if ($Split -eq '_framework') { break }
}
Set-Location ($Result -join '\')
but I find it massivelly ugly. is there a simple cmdlet that would give me my desired result in an easier way, without splitting and iterating the result - or ist this the only solution?
It has to be available in PowerShell 5.1
Use a single regex -replace operation to remove anything after the \_framework\ part:
$currentPath = "$PWD"
if($currentPath -like '*\_framework\*'){
$frameworkPath = $currentPath -replace '(?<=\\_framework)\\.*'
Set-Location -LiteralPath $frameworkPath
} else {
throw 'not a valid path'
}
Alternatively, create a small utility function to resolve the correct parent for you (you can replace my implementation below with your own if you so feel):
function Get-AncestralPathByName
{
param(
[string]$Name
)
$path = "$PWD"
while($path -and $path -notmatch "\\$([regex]::Escape($Name))\\?$"){
$path = Split-Path $path
}
return $path
}
Now the code at the callsite becomes super simple:
if($targetPath = Get-AncestralPathByName -Name '_framework'){
Set-Location $targetPath
} else {
throw 'could not resolve target path'
}
The goal is to reset the current cmd.exe shell to have the original set of environment variables. This should include deleting current environment variables that were created after the cmd.exe shell started.
The System and User environment variables can be read from the registry. But, the dynamic variables such as ALLUSERSPROFILE, APPDATA, LOGONSERVER, etc. are not in those locations. Where can those be found?
Because of this, the code cannot delete a variable created after the cmd.exe shell was started. This is because it may be one of the dynamic variables.
Put both of these files in the same directory.
=== Do-Environment.bat
#ECHO OFF
SET "TEMPFILE=%TEMP%\do-environment-script.bat"
powershell -NoLogo -NoProfile -File "%~dp0Do-Environment.ps1" >"%TEMPFILE%"
type "%TEMPFILE%"
CALL "%TEMPFILE%"
EXIT /B %ERRORLEVEL%
=== Do-Environment.ps1
$Vars = #{}
$UserVars = 'HKCU:\Environment'
$SystemVars = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
(Get-Item -Path $SystemVars).Property |
ForEach-Object {
$KeyName = $_
$KeyValue = (Get-Item -Path $SystemVars).GetValue($KeyName, $null)
$Vars[$KeyName] = $KeyValue
}
(Get-Item -Path $UserVars).Property |
ForEach-Object {
$KeyName = $_
$KeyValue = (Get-Item -Path $UserVars).GetValue($KeyName, $null)
if (($null -eq $Vars[$KeyName]) -or ($KeyName -ne 'Path')) {
$Vars[$KeyName] = $KeyValue
} else {
$Vars[$KeyName] = $Vars[$KeyName] + ';' + $KeyValue
}
#'SET "{0}={1}"' -f #($KeyName, $KeyValue)
}
$Vars.Keys | Sort-Object | ForEach-Object { 'SET "{0}={1}"' -f #($_, $Vars[$_]) }
I have an apps directory in my dropbox - I'd like to be able to access all of them from the command line without having to set up loads and loads of path variables. Is there any way to set up a recursive path variable? I tried putting ** at the end - no joy.
You can't use placeholders or anything like that in the PATH environment variable. It's just a concatenation of directories, no additional features.
So either add all of the app directories to the PATHenvironment variable or think about other ways to solve the problem. For example, you could add one directory to the PATH and place batch files named like the apps there that start the apps.
Made an account for this 11 year old question.
$path = Read-Host -Prompt "Enter the exact path that needs to be recursively added to the PATH env:"
$items = gci -Path $path -Recurse -Directory -name
$nuPath = $env:Path
$r = 0
write-Host "Env started as $nuPath"
foreach ($iitem in $items){
$addpath = ($path + "\" + $iitem)
$executabledir = $addpath + '\' + "*.exe"
if(test-path $executabledir){
Write-Host $addpath
$regexAddPath = [regex]::Escape($addPath)
$arrPath = $nuPath -split ';' | Where-Object {$_ -notMatch "^$regexAddPath\\?"}
$nuPath = ($arrPath + $addPath) -join ';'
++$r
}
}
$result = ($path + ";" + $nupath) -join ';'
$temp = New-TemporaryFile
$result.ToString() > $temp
Start-Process notepad.exe -ArgumentList $temp.FullName
$title = 'WARNING'
$question = "Your new environmental variable for PATH will be in the notepad window that popped up. are you sure you want to continue?"
$choices = '&Yes', '&No'
$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 0 -and $r -gt 5) {
$title = 'Are you really sure?'
$question = 'This is larger than 5 entries and this can ruin your day if you mess it up. Just doublechecking everything is OK'
$choices = '&Yes', '&No'
$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 0) {
$env:Path > $HOME\pathbkup.txt
[Environment]::SetEnvironmentVariable("Path", $result, "Machine")
}
else {
Write-Host 'cancelled'
}
}
else {
Write-Host 'cancelled'
}
Remove-Item $temp