none
Parameter Parsing

    Question

  • Hi,

    I'm writing a script that will parse parameters, do some additional processing, then pass those parameters to an external command (SAS).  It should allow optional parameters to be passed directly to SAS.  Many of the optional parameters for SAS look like switched parameters.

    I've reviewed these web pages:

    1) http://bsonposh.com/archives/435

    2) https://devcentral.f5.com/weblogs/Joe/archive/2009/01/13/powershell-abcs---p-is-for-parameters.aspx

    Here is an example script (let's call it sasbatch.ps1):

    Param(
       [Parameter(ValueFromPipeLine=$true)] 
       [string]$sysin = $(Throw "ERROR: SAS Program File is required")
       
       ,[Parameter(Mandatory=$false)] 
       [string]$level = "Lev1"
       
       ,[Parameter(Mandatory=$false)] 
       [string]$config = "config1.cfg"
       
       ,[Parameter(ValueFromRemainingArguments=$true)] 
       [string]$options 
    )
    
    # use here document to print debugging info
    $print_vars=
    @"
    Sysin:    $sysin
    Level:    $level
    Config:   $config
    Options:  $options
    
    "@
    
    if(! $input)
    {
       foreach($sysin in $input)
       {
          $print_vars
       }
    }
    else
    {
       $print_vars
    }
    

    Note:  -sysin is mandatory, but I didn't specify it as such since sasbatch.ps1 will be called from a scheduler, and I didn't want the scheduler to hang waiting on input if the script were called incorrectly.  However, if there is a way to get the script to timeout waiting for input, let me know.  A mandatory parameter would be useful if the script was used for both scheduled and interactive invocations.

    Sample invocations:

    Works:

    sasbatch.ps1 test1.sas

    sasbatch.ps1 lev2 AlternateConfig.cfg

    sasbatch.ps1 -config config1.cfg -level lev1 -sysin test1.sas

    Does not work:

    1) sasbatch.ps1 test1.sas -level -config -batch -noterminal -nosplash (it would be nice if "empty" -level and -config switches could be "placeholders", with the default values used since no parameter was specified)

    2) sasbatch.ps1 test1.sas lev1 config1.cfg -batch -noterminal -nosplash

    It is this second invocation that is particularly problematic.  How can I get Powershell to "leave these additional options alone", without assuming they are parameters for the script itself?  IOW, I want "-batch -noterminal -nosplash" passed as-is as parameters to SAS.

    I also tried this alternative script:

    Param(
       [Parameter(ValueFromPipeLine=$true)] 
       [string]$sysin = $(Throw "ERROR: SAS Program File is required")
       
       ,[Parameter(Mandatory=$false)] 
       [string]$level = "Lev1"
       
       ,[Parameter(Mandatory=$false)] 
       [string]$config = "config1.cfg"
    )
    
    # use here document to print debugging info
    $print_vars=
    @"
    Sysin:    $sysin
    Level:    $level
    Config:   $config
    Options:  $args
    
    "@
    
    if(! $input)
    {
       foreach($sysin in $input)
       {
          $print_vars
       }
    }
    else
    {
       $print_vars
    }
    

    It still fails, but with a different error.

    Finally, I'd like to be able to pass the programs to execute as piped objects, per http://bsonposh.com/archives/435.  For example:

    Get-Content programs.txt | sasbatch.ps1

    However, when I run the above script via PowerGUI, setting a breakpoint on if (! $input), I see that $input is set to:

    System.Array+SZArrayEnumerator, with the element:

    Exception getting "Current": "Enumeration has not started. Call MoveNext."

    What the heck does that mean :-). 

    I had to code "if (! $input)" rather than "if ($input)" in order for my script to work, but then it won't work properly for piped objects (once I get to testing this later).

    Thanks,

    Scott

    Monday, February 27, 2012 12:02 AM

Answers

All replies

  • As a followup to my own post, additional Googling found this:

    http://rkeithhill.wordpress.com/2012/01/02/powershell-v3-ctp2-provides-better-argument-passing-to-exes/

    So, what I want to do will be easier with PowerShell v3.0.

    Questions:

    1) Will PowerShell v3.0 work on Windows XP and Windows Server 2003 R2?

    2) Would it be a Really Bad Idea (tm) to use PowerShell V3 CTP 2 in a production environment?

    3) Regardless, can I get PowerShell V3 CTP2 to play with on Windows 7 at home?  Or is it a limited release just for developers?

    4) Anyone know Microsoft's planned release date for PowerShell V3?

    (I did search support.microsoft.com for "PowerShell v3" before posting this message...)

    Thanks,

    Scott

    Monday, February 27, 2012 12:20 AM
  • This Wiki on PowerShell V3 may help:

    http://social.technet.microsoft.com/wiki/contents/articles/4734.powershell-v3-faq-en-us.aspx

    There is a link to download, which is:

    http://www.microsoft.com/download/en/details.aspx?id=27548


    Richard Mueller - MVP Directory Services

    Monday, February 27, 2012 12:34 AM
  • I've found [environment]::userinteractive useful for adjusting the behaviour of scripts that may be run either interactively or as scheduled tasks.

    If that evaluates to $true, then it's being run in an interactive session, and it can ask the user for additional input.  If not, then it's in a batch environment, and it will have to throw an error and exit.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Monday, February 27, 2012 12:54 AM
  • I've found [environment]::userinteractive useful for adjusting the behaviour of scripts that may be run either interactively or as scheduled tasks.

    If that evaluates to $true, then it's being run in an interactive session, and it can ask the user for additional input.  If not, then it's in a batch environment, and it will have to throw an error and exit.


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Interesting, and useful, thanks.

    But what is userinteractive? the :: makes it look like a static method, but if you append "()" to it as is usually the case when calling static methods, you get an error:

        Method invocation failed because [System.Environment] doesn't contain a method named 'userinteractive'.


    Al Dunbar

    Tuesday, February 28, 2012 6:01 AM
  • .net accelerators can have static properties as well as static methods.  Collectively, these are static members.  See demo code below:

    Write-Host "Static properties of [environment]:" -ForegroundColor Green
    ([environment]).GetProperties() | select name
    Write-Host "Static methods of [environment]:" -ForegroundColor Green
    ([environment]).GetMethods() | select name


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Tuesday, February 28, 2012 6:25 AM