header
header Register : : Login header
header
divider
menuleft
menuright
submenu
left

We have a new sponsor!  Introducting Pragma Systems.  See the home page for details.

Delegate parameters from one command to another
Last Post 26 Jul 2010 09:30 AM by GWHowarth88. 4 Replies.
Printer Friendly
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
bilboaUser is Offline
New Member
New Member
Posts:4
Avatar

--
23 Jul 2010 11:34 PM  
I'm trying to do something which is trivial to do with the Unix shells I'm used to, but seems to be very cumbersome to do with Powershell.  I'm wondering if I'm just missing something though.

Occasionally I want to create a wrapper around some command, which simply passes all the arguments passed to the wrapper on to the wrapped command, but adds some additional argument. 

For example, say I want to create a command called Select-StringCS, which is a wrapper around Select-String that adds the -CaseSensitive switch to the commandline, but otherwise just passes all its parameters on to Select-String.   So if I type:

("FOOL", "tool") | Select-StringCS -Pattern 'oo'

I want it to behave exactly as if I had typed:

("FOOL", "tool") | Select-String -CaseSensitive -Pattern 'oo'

Similarly, if I pass any other options to Select-StringCS I want them to be passed on to Select-String.  What is the easiest way to implement Select-StringCS in Powershell?

In a Unix shell like bash, the "grep" command is roughly equivalent to Select-String. Grep does case-sensitive matches by default, but can be made to do case-insensitive matches by passing the -i switch.  I can create a new command called "igrep" like this:

alias igrep='grep -i'

That's it!  Now if I type:

igrep -opt1 arg1 -opt2 arg2

it's exactly as if I had typed:

grep -i -opt1 arg1 -opt2 arg2

A first stab at this in Powershell might be:

function Select-StringCS {
  Select-String -CaseSensitive @args
}

This works fine as long as I only pass positional arguments to Select-StringCS, but it breaks as soon as I try to use a -ParameterName VALUE type switch with Select-StringCS, because then it will just pass the string "-ParameterName" as a separate argument to Select-String, which isn't what I wanted.   So, this will work:

Select-StringCS 'oo'

but this won't:

Select-StringCS -Pattern 'oo'

because in the second case, Select-String will receive both "-Pattern" and "oo" as two separate arguments, which wasn't the intention. 

To fix this, I would have to explicitly declare every paramater that Select-String supports as a parameter of Select-StringCS, so then I can use @psBoundParameters to pass the actual parameters on to Select-String.   Since Select-String supports at least a dozen different parameters, of various types, this would be pretty laborious for such a simple task, so in practice I just live with Select-StringCS not supporting the same options as Select-String.  

So, is there some simple way I don't know about to write wrappers like this in Powershell, which accept the same parameters as another command?  

Thank you in advance.

marco.shawUser is Offline
Site Moderator
Advanced Member
Advanced Member
Posts:670
Avatar

--
25 Jul 2010 02:51 AM  
Yes, that's definitely something difficult to accomplish in PowerShell v1, but v2 introduces "proxy commands". Have a look here:
http://blogs.msdn.com/b/powershell/archive/2009/01/04/extending-and-or-modifing-commands-with-proxies.aspx
Marco

*Microsoft MVP - Windows PowerShell
https://mvp.support.microsoft.com/profile/Marco.Shaw
*Co-Author - Sams Windows PowerShell Unleashed 2nd Edition
*Blog - http://marcoshaw.blogspot.com
bilboaUser is Offline
New Member
New Member
Posts:4
Avatar

--
25 Jul 2010 05:04 PM  

Thank you for your response Marco. The ProxyCommand class makes it much easier to write proxies.

I don't know if this is the best place to put this, but I would like to see a more dynamic way of making a proxies. The ProxyCommand approach basically amounts to the same workaround I mentioned -- writing a new function which explicitly re-declares all the same parameters as the wrapped function, except for possibly omitting or adding some parameters. The ProxyCommand::create method just generates the initial source code for you to work with. While this certainly removes one of the disadvantages of a hand-written wrapper, having to hand-write the parameter re-declarations, it still has the other disadvantages:

  1. The generated code obscures the actual content of the wrapper. There might be dozens of lines of generated wrapper code, and one or two lines of code I actually wrote in there somewhere.
  2. Since the parameter re-declarations are hard-coded in the wrapper, if the wrapped command is ever modified such that its parameters are changed, then the wrapper becomes out of date and needs to be updated.
What I would like to see is something like the existing DynamicParameter feature, but extended to support dynamically adding an arbitrary number of parameters. So for example, here is how I might write Select-StringCS:

# A wrapper around Select-String which does case-sensitive matching
function Select-StringCS {
  # add all parameters of Select-String except for -CaseSensitive as parameters of this function
  DynamicParameters {
    $meta = New-Object System.Management.Automation.CommandMetaData (gcm Select-String)
    $params = $meta.Parameters
    [void] $params.Remove('CaseSensitive')
    $params
  }

  @PSBoundParameters['CaseSensitive'] = $true
  Select-String @PSBoundParameters
}
 
Since DynamicParameter already exists in Powershell, it seems to me that adding the plural of it shouldn't be too hard, and that this would provide a much neater way of doing this sort of meta-programming. If there is a better place for me to send this suggestion, please let me know. And thanks again for pointing me to the ProxyCommand functionality.
marco.shawUser is Offline
Site Moderator
Advanced Member
Advanced Member
Posts:670
Avatar

--
26 Jul 2010 02:11 AM  
I only read your first line... The best place to officially log suggestions:
https://connect.microsoft.com/PowerShell

The possibly a post on this site/blog/twitter and see if others support you on this and vote on your suggestion.
Marco

*Microsoft MVP - Windows PowerShell
https://mvp.support.microsoft.com/profile/Marco.Shaw
*Co-Author - Sams Windows PowerShell Unleashed 2nd Edition
*Blog - http://marcoshaw.blogspot.com
GWHowarth88User is Offline
Basic Member
Basic Member
Posts:348
Avatar

--
26 Jul 2010 09:30 AM  
Have you tried Invoke-Expression?

function Select-StringCS {
Invoke-Expression -Command "Select-String -CaseSensitive @args"
}
You are not authorized to post a reply.

Active Forums 4.1
right
   
footer Sponsored by Quest Software • SAPIEN Technologies • Compellent • Microsoft Windows Server 2008 footer
footer