Powershell: Invoke-History should be able to invoke more than one command

Created on 25 Apr 2020  路  11Comments  路  Source: PowerShell/PowerShell

Summary of the new feature/enhancement

My exact use case is:
I have a series of commands in my history which I want to run one after another for example

copy-xlog
delete-xlog
start-x

These might be 101,102,103,104 in the history

one might expect to be able to run either
101..104 | invoke-history
or
Ihy 101,102,103,104

The former causes an error
Invoke-History: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input
and then invokes the previous command

The latter causes an error Invoke-History: Cannot convert 'System.Object[]' to the type 'System.String'

Ideally any cmdlet should support its "target" * coming from the pipeline and support a comma-separated list of targets. A few which could, don't, without an obvious reason to be an exception. This is a proposal to fix one of those.

* Target being the parameter telling the command what to work on, where other parameters the command how the work should be done

Area-Cmdlets-Utility Issue-Enhancement Up-for-Grabs

Most helpful comment

Let's not get off topic and bring other discussions that aren't really related to the issue at hand, please. :blush:

I don't see any reason that Invoke-History _shouldn't_ take pipeline input. It's a fairly straightforward thing to add in the design of a command, and while it might be used by everyone, it does make the command more versatile for a wider variety of use cases.

I'm gonna mark this up for grabs for now, it's not a massive or breaking change. :+1:

All 11 comments

So. You know that thing in PowerShell where you have small composable cmdlets ? And you put two or more together to get the result you want. It's value is absolutely tiny

10,11,15 | % {Invoke-History -Id $_ }

So. You know that thing in PowerShell where you have small composable cmdlets ? And you put two or more together to get the result you want. It's value is absolutely tiny

10,11,15 | % {Invoke-History -Id $_ }

That's what I did, obviously.

$list | foreach { Do-something -target $_ } is a work round for a poorly designed command i.e. one that does not support the pipeline when it _could_, and is not, itself, composable.
There is nothing wrong with code which says

$x = Command1
Command2 -Target $x 

But one should be able to write Command1 | command2 that's one of the founding principles of the language. Similarly there is nothing wrong with

Command -Target item1
Command -Target item2
Command -Target item3

if that is how one chooses to write it. But Command -Target item1, item2, item3 should be supported. Commands which don't work that way are the aberrations: that shouldn't need explaining.

Similarly the principle is not to build sorting or formatting or exporting into commands which are part of the language. Especially when they are simple to add as a functions being X <params> | Y <params>

_one should be able to write Command1 | command2 that's one of the founding principles of the language_

put two or more cmdlet together to get the result you want..its thee principle of this language

_Especially when they are simple to add as a functions being X | Y _

yes i am with you but with _invoke-history_ It's value is absolutely tiny

Let's not get off topic and bring other discussions that aren't really related to the issue at hand, please. :blush:

I don't see any reason that Invoke-History _shouldn't_ take pipeline input. It's a fairly straightforward thing to add in the design of a command, and while it might be used by everyone, it does make the command more versatile for a wider variety of use cases.

I'm gonna mark this up for grabs for now, it's not a massive or breaking change. :+1:

yes i am with you but with _invoke-history_ It's value is absolutely tiny

Actually I agree. In another thread I've just been saying "we've got this far without this".
It's one of a small number which have this failing. (Start is another). It's like the door that has squeaked for years and no one oils it, and everyone accepts it. And the harm / value from fixing it is tiny. But eventually someone needs to say "For pity's sake someone oil that door".

@vexx32

I don't see any reason that Invoke-History shouldn't take pipeline input.

If you read the examples below, you will see that was intentional at design time.
Maybe add a _confirm_ parameter if there is more than two to invoke, will be more secure.

PS > Get-History -Id 1,2,3 | Invoke-History
Invoke-History: Cannot process multiple history commands. You can only run a single command by using Invoke-History.

PS > Invoke-History -Id 1,2
Invoke-History: Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Id'. Specified method is not supported.

The latter is just a binding exception; you'll get similar results if you provide an array for any string parameter.

As for the former, sure, it may have been intentional. Without having spoken to the designer of the original command, I can't speak to their intent, though. As has already been mentioned in this issue, you can work around this with a simple ForEach-Object, so I'm not sure it makes a lot of sense in terms of its efficacy.

There is also weird behaviour with the pipeline :

PS C:\Users\Flavien> "foo"
foo
PS C:\Users\Flavien> 1 | Invoke-History
Invoke-History: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
"foo"
foo

FYI - The history command was very minimally designed and implemented in version 1. Basically we wanted to at least be able to do r N to rerun command N. This was inspired by the ksh functionality that we were used to and we (I) figured we'd add more functionality to the commands over time. In fact that didn't happen and most of the work went into interactive editing (PSReadLine). So there's a ton of functionality that could be added if people are interested. And, given that this is a user-productivity thing, I don't think the usual minimalism principles necessarily apply.

Further on the minimalism thing. Functionality should be designed as a set of composable commands but once that's done, you can selectively add "accelerators" for high-use (typically interactive) cases. This includes things like command and parameter aliases, type accelerator and extra options on cmdlets for scenarios that are used a lot (e.g. the -file and -directory parameters on Get-ChildItem.) Does that make sense?

@BrucePay - yes, it's a very good way of putting what I think I knew.

Was this page helpful?
0 / 5 - 0 ratings