Powershell: Add optional block scoping to pushd.

Created on 23 Jan 2019  路  10Comments  路  Source: PowerShell/PowerShell

Summary of the new feature/enhancement

As a user, I'd like to be able to easily switch directories for a short series of commands.
I'd like to be able to do this without needing to remember to manually call popd in order to switch back.

I'd imagine that most of the time pushd is used in companion with popd, therefore it makes sense to add optional block scoping to the command. e.g.

pushd "MyDirectory" {
  # Do things in MyDirectory
} # popd is called automatically here.
Area-Cmdlets-Core Issue-Enhancement

Most helpful comment

We don't allow using as a verb now but that could change...

Use is an approved verb. Not a whole lot that uses it (two default cmdlets?) but it seems like a good fit.

Also, @vexx32

Would be great to have a generalised Using-DisposableObject (or just Using-Object I guess?) too, but that's a little trickier 馃槈

The biggest problem with that is that the expression generating the disposable object would a separate sequence point. So a pipeline stop could occur between the object's creation and the start of the cmdlet. I'd love to see a using keyword built in that solves that problem, though I'm not sure how much use it'd get.

All 10 comments

@kennycoc PowerShell doesn't have block scoping as such but it's possible to add a parameter that takes a scriptblock to evaluate after the pushd. In fact you can do it yourself with a function along the lines of:

function MyPushD ($path, [scriptblock] $action) {
    Push-Location -ErrorAction stop -Path $path
     try {
        . $action
     }
     finally {
        Pop-Location
     }
}

I think this idea is awesome and will as you say make things very easy to get right.

However, I don't think the Push-Location cmdlets is the right place for it. Possibly a new cmdlet is warranted here, at least from a semantic perspective.

@vexx32 how about:

Using-Location $path {
    <# code #> 
}

We don't allow using as a verb now but that could change...

@BrucePay that's exactly what I was thinking. :smile:

Having Using as an approved verb would be a lovely addition. Would be great to have a generalised Using-DisposableObject (or just Using-Object I guess?) too, but that's a little trickier :wink:

We don't allow using as a verb now but that could change...

Use is an approved verb. Not a whole lot that uses it (two default cmdlets?) but it seems like a good fit.

Also, @vexx32

Would be great to have a generalised Using-DisposableObject (or just Using-Object I guess?) too, but that's a little trickier 馃槈

The biggest problem with that is that the expression generating the disposable object would a separate sequence point. So a pipeline stop could occur between the object's creation and the start of the cmdlet. I'd love to see a using keyword built in that solves that problem, though I'm not sure how much use it'd get.

@SeeminglyScience We could do something like:

Using-Object { New-MyObject } {
    Do-SomethingWithObject $_  # created object is passed in $_ like ForEach-Object
}

where the cmdlet takes two scriptblocks. This would defer creation of the object until after the cmdlet has started.

@BrucePay Yeah that's a great idea.

That said, using (expr) { } is already a parse error thanks to using namespace|module|etc, so maybe there's hope for a keyword? 馃 (shh, let me dream 馃槈)

I mean using is already a recognised keyword that is only usable at the very start of a script so co-opting those code paths shouldn't be all that tricky.

Just to add to this, it could also make things like the following just super clean:

Get-ChildItem -Directory | Using-Directory $_ {
  # Do things in each directory
}

In that situation it's basically just a ForEach-Object though. If all those objects being piped in were disposable, then yeah absolutely. It does still assume that the object creation won't fail, though.

Was this page helpful?
0 / 5 - 0 ratings