Set-Location scope - powershell

Given this file
Set-Location C:\
If I run it
.\foo.ps1
It will change the directory in the script. However once the script is finished the parent console directory has also been changed. Can Set-Location be called in such a way as to affect only the running script?

try
{
Push-Location
Set-Location c:\
# your code here ...
}
finally
{
Pop-Location
}

Related

Directory not created relative to the working directory

I have an issue with Start-Job and [System.IO.Directory]::CreateDirectory. I'm using PowerShell version 5.1.22621.608, so the working directory for jobs is set to $HOME\Documents on Windows.
To see the issue, open PowerShell and run the following snippet. Notice that [System.IO.Directory]::CreateDirectory creates new-dir in the working directory of the PowerShell terminal. This is quite surprising, as it should have been created inside $HOME\Documents, as New-Item does. Now, change directory in the PowerShell terminal and run the snippet again. Notice that [System.IO.Directory]::CreateDirectory creates new-dir in the directory first opened in the PowerShell terminal, and not the current working directory!
Start-Job -ScriptBlock {
"Current working directory: $PWD"
# `new-dir` will be created inside the folder where PowerShell was first started,
# regardless of where the script is called from and the current working directory.
$CreatedDir = [System.IO.Directory]::CreateDirectory("new-dir")
"Created directory (CreateDirectory): $($CreatedDir.FullName)"
Remove-Item $CreatedDir.FullName
# New-Item works as expected
$CreatedDir = New-Item -Path "new-dir" -ItemType Directory
"Created directory (New-Item): $($CreatedDir.FullName)"
Remove-Item $CreatedDir.FullName
} | Wait-Job | Receive-Job
How can I set the root directory for [System.IO.Directory]::CreateDirectory?

How to prevent Set-Location in powershell script from changing the path of calling shell

Let's say I have a simple powershell script:
# File: myscript.ps1
set-location C:\Windows
Then I invoke this script from the prompt as follows:
PS> Get-Location
C:\User\Dude
PS> .\myscript.ps1
PS> Get-Location
C:\Windows #!!!!!!!!!
I don't want my script to change the calling shells path... how to prevent this? Can I put something in the code to turn off exporting the PATH to the parent? or is there a way to somehow set it back to the original value before exiting the script, either on error or normal termination?
Rather than
Set-Location C:\Windows
Try using the Push-Location and Pop-Location in your script
#start of script
Push-Location C:\Windows
...
Pop-Location
#end of script
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/push-location?view=powershell-7.2
When to use Push-Location versus Set-Location?
# Run ScriptBlock from a Temporary Path
function better_with_path {
param(
[string]$newpath,
[ScriptBlock]$action
)
Push-Location $newpath
try
{
& $action
}
finally
{
Pop-Location
}
}

Can't remove PowerShell alias via ps1 script

Every time I run a script, I need to remove the curl alias from PowerShell in order to use the actual curl which is installed on my machine.
From PowerShell, I can remove the alias perfectly fine by using: Remove-Item alias:curl
But for some reason, when I put this code into a ps1 script and run that script, the alias is not removed.
Does anyone know why this is the case?
You can also update your profile to remove the alias each time PowerShell starts; $profile is an automatic variable that stores the paths to the PowerShell profiles that are available in the current session.
if (!(Test-Path -Path $profile)) {
New-Item -Path $profile -Force
}
Add-Content -Path $profile -Value "Remove-Item alias:curl"
. $profile

Powershell script changes directory of parent powershell

When running a powershell script which changes a directory via cd (or set-location/push-location/etc.), the console that the script was run from also ends up in that directory.
Example:
script.ps1
cd c:\tmp
# do stuff
If I run this from c:\users\me, i end up in c:\tmp.
PS C:\users\me> .\script.ps1
PS C:\tmp> |
Now I know that I could use push-location and later do pop-location. However this wouldn't work if the script stopped somewhere in the middle (via Exit).
How can I solve this? Why doesn't the script have it's own location stack?
You could always use Try/Catch/Finally. Set the current directory path to a variable and then cd c:\tmp before the Try, and have the directory changed to variable in the Finally?
Example 1
$path = (Get-Item -Path ".\" -Verbose).FullName
cd c:\temp
Try
{
#Do stuff
#exit is fine to use
#this will output the directory it is in, just to show you it works
Write-Host (Get-Item -Path ".\" -Verbose).FullName
}
Catch [system.exception]
{
#error logging
}
Finally
{
cd $path
}
Example 2 using popd and pushd
pushd c:\temp
Try
{
#Do stuff
#exit is fine to use
#this will output the directory it is in, just to show you it works
Write-Host (Get-Item -Path ".\" -Verbose).FullName
}
Catch [system.exception]
{
#error logging
}
Finally
{
popd
}
I'd also recommend looking at what arco444 suggested, which is calling the powershell script via the -File parameter. Depending on the scenario that might work as an option.

How do I make a powershell function that expands filename arguments to include their paths if unqualified?

Starting up notepad++ or many other GUI applications in Windows that will accepted fully qualified filenames of documents on the command line, but which do not accept them if they are not fully qualified, is often done in DOS/Windows batch files like this:
#echo off
start "notepad++" "C:\Program Files (x86)\Notepad++\notepad++.exe" %*
The above, if saved as "npp.cmd" will let you type "npp foo.txt" and it will work.
Note that without the npp.cmd, even typing out the full path to the exe, but not fully qualifying the file to edit doesn't work, like this:
"C:\Program Files (x86)\Notepad++\notepad++.exe" foo.txt
This however, DOES work:
"C:\Program Files (x86)\Notepad++\notepad++.exe" c:\users\warren\foo.txt
A way to easily work around this limitation is to make a batch file (.cmd) as shown at the top of this file. I'm learning PowerShell and trying to find the equivalent magic to the "start .... %*" incantation in the batchfile at the top. I believe it would have to be a 'powershell function'.
Here's what I have so far:
new-item -path alias:nppapp -value "C:\Program Files (x86)\Notepad++\notepad++.exe"
function npp { nppapp $args }
The above is equivalent, in the end to simply an alias, because $args is really not equivalent to %*, in that it does not do parameter expansion. I think I need something like this:
new-item -path alias:nppapp -value "C:\Program Files (x86)\Notepad++\notepad++.exe"
function npp { nppapp globexpand($args) }
globexpand is of course, a placeholder, for some kind of expansion/globbing routine, which I haven't been able to find yet in PowerShell.
try this:
new-item -path alias:nppapp -value "C:\Program Files (x86)\Notepad++\notepad++.exe"
function npp { nppapp (join-path -Path $pwd -ChildPath $args[0]) }
$pwd is an automatic variable with the current working path as value
Edit:
function npp {
if ($args[0] -match '.:\\.+')
{
nppapp $args[0]
}
else
{
nppapp (join-path -Path $pwd -ChildPath $args[0]) }
}