Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically call Pop-Location at end of scope

Tags:

powershell

Let's say I have a simple scope that is book-ended with Push-Location and Pop-Location:

Function MyFunction($Location)
{
  Push-Location $Location
  # do other stuff here
  Pop-Location
}

Is there any way to set it up at the beginning of the scope so that I don't have to remember to put the Pop-Location at the end? Something like this:

Function MyFunction($Location)
{
  Setup-BothPushAndPopHere $Location
  # do other stuff here
  # at the end of the scope, Pop-Location is automatically called
}
like image 434
PortMan Avatar asked Mar 10 '16 17:03

PortMan


2 Answers

Short answer: No.

My take on Push-Location and Pop-Location is that you should generally avoid them, and adapt your script to use the path names in commands instead; in other words, instead of:

Push-Location $Location
Get-ChildItem
Pop-Location

Just do:

Get-ChildItem $Location

(simplified example)

If you must use the pattern, consider try/finally:

Push-Location $Location
try {
    # ...
} finally {
    Pop-Location
}

As this helps with unexpected exceptions or the user interrupting program execution.

I typically use the try/finally pattern when the code is outside my control; most often when loading the SQLPS module since it changes the current location to the SQL server provider which in my experience causes everything that uses the current location to become much slower.

As Eris points out, it's also useful when dealing with native applications. This can be especially true if it's painful to escape quotes around path names with spaces, or the application wouldn't handle it correctly anyway.

like image 130
briantist Avatar answered Sep 30 '22 10:09

briantist


Depending on what you try to do in the #do other stuff here code, you could try executing those commands as a script block in a child process. A skeleton-code example:

$ScriptBlock = {
  Push-Location $Location
  #commands
}

$Job = Start-Job -ScriptBlock $ScriptBlock   # Add other arguments if needed

# Check the status of the task:
Get-Job $Job

# Wait for the job state to be 'Completed' (do-while, maybe?)

# If your ScriptBlock writes any output, collect in a variable:
$Output = Receive-Job $Job

# Clean up:
Remove-Job $Job

The point of this approach is that you spawn a job to do the work (in the background) and you needn't worry about Pop-Location as you just let that child scope exit while you carry on doing whatever you need to do in your main script.

There are other posts here on StackExchange that go into more detail about powershell-jobs.

like image 25
Charlie Joynt Avatar answered Sep 30 '22 11:09

Charlie Joynt