header1   header
header
header Register : : Login header
header
connector   connector
menuleft menuright
submenu   submenu
left
Delegate parameters from one command to another
Last Post 26 Jul 2010 01:30 AM by George Howarth. 4 Replies.
Printer Friendly
  •  
  •  
  •  
  •  
  •  
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
Adam JUser is Offline
New Member
New Member
Posts:4
Avatar

--
23 Jul 2010 03: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 Shaw (MVP)User is Offline
    Veteran Member
    Veteran Member
    Posts:1641
    Avatar

    --
    24 Jul 2010 06:51 PM
    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/...oxies.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
    Adam JUser is Offline
    New Member
    New Member
    Posts:4
    Avatar

    --
    25 Jul 2010 09:04 AM

    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 Shaw (MVP)User is Offline
    Veteran Member
    Veteran Member
    Posts:1641
    Avatar

    --
    25 Jul 2010 06:11 PM
    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
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    26 Jul 2010 01: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.3
    right
    footer   footer
    footer Sponsored by Quest Software • SAPIEN Technologies • Compellent • Microsoft Windows Server 2008 R2 footer
    footer   footer