 |
|
|
Give me getopts or give me frustration
Last Post 16 Jun 2011 04:39 AM by halr9000. 5 Replies.
|
Sort:
|
|
Prev Next |
You are not authorized to post a reply. |
|
Andy
 New Member Posts:1

 |
| 12 Jun 2011 07:08 AM |
|
I really hate the idea of using positional values for command line arguments.
Has anyone found or developed an equivalent to Perl getopt?
I could always write something but I'd rather not have to. :) |
|
|
|
|
halr9000 PowerShell MVP, Site Admin
 Advanced Member Posts:565

 |
|
whertzing56
 New Member Posts:48

 |
| 14 Jun 2011 06:48 PM |
|
I miss getopts too, for command line arguments to scripts. But even getopts didn't have everything I wanted when I was writing perl scripts. I'm trying to figure out a framework that will let me 1) define default values for command line arguments in the script itself 2) define "MyScript.SystemPreferences.ps1" that lives in the same dir as the script, containing some or all of the script's argument values 3) define "MyScript.UserPreferences.ps1" that lives in the user's powershell path subdirs (like (resolve-path "[Environment]::GetFolderPath("MyDocuments")\WindowsPowerShell").Path 4) accept named argument values defined in the Environment 5) accept a ps1 file on the command line containing some or all of the argument values 6) accept individual named parameters on the command line The idea is that each is additive, the higer number having higher priority, and (somehow), the higher priority mechanisms can either augment or completly replace a lower priority value. It should work for modules as well as scripts, so if you build up a script from various modules, you can specify individual preference files for each module and/or include module arguments in the parent script's Preferences file or command line. (Whew, that last is not going to be easy) I had written a module with some of these capabilities for Perl that extended getopts (a decade ogo!), and I've been studying the problem in Powershell (still a newbie). You interested in a collaboration on this? Anybody else worked along these lines? I've seen some interesting code in the latest ShowUI modules for function arguments I'm still trying to wrap my head around... |
|
|
|
|
EBGreen
 Veteran Member Posts:1092

 |
| 15 Jun 2011 05:26 AM |
|
Here is a quick first pass through your requirements: 1) define default values for command line arguments in the script itself The param block will let you set a default value: param( $foo = 'bar' ) 2) define "MyScript.SystemPreferences.ps1" that lives in the same dir as the script, containing some or all of the script's argument values You could simply dot source the file in your script: if(Test-Path .\MyScript.SystemPreferences.ps1){ . .\MyScript.SystemPreferences.ps1 } 3) define "MyScript.UserPreferences.ps1" that lives in the user's powershell path subdirs (like (resolve-path " [Environment]::GetFolderPath("MyDocuments")\WindowsPowerShell").Path See #2 4) accept named argument values defined in the Environment Not sure exactly what you want for this one 5) accept a ps1 file on the command line containing some or all of the argument values Just add a $ParamFile (or whatever name you want) variable to your params then dot source it just like #2 6) accept individual named parameters on the command line Anything in the param block can be passed at the command line The real issue is with working out the priority. That really is just an issue of the order that you check things in the script. |
|
| "Look Ma...no strings!" |
|
|
whertzing56
 New Member Posts:48

 |
| 15 Jun 2011 08:54 PM |
|
"The real issue is with working out the priority".. - Aye - there's the rub... For in that prioritization, who knows what subtle bugs may come to trouble our dreams... Gawd, the Bard is spinning in his grave... Seriously - I'd like to have a hash $defaultargs = {paramname1 = paramvalue1; paramname2 = paramvalue2) in the script/module. Next, create a copy $currentargs = $defaultargs.Clone(). Next, look for the file MyScript.SystemPreferences.ps1 in it's various places (priority given to the current dir, then the dir where the top-level script lives, then the regular PATH subdirs and Powershell subdirs), and merge with $currentargs Next, look for the file MyScript.UserPreferences.ps1 in the same various places), and merge with $currentargs Next, look in the environment for any variables of name "paramname1" or "paramname2" (walk the keys of $currentargs). Some Automated test tools would like to set parameter name/value pairs in the environment Next, see if a $ParamFile was passed on the command line, and merge with $currentargs Next, see if any named parameters are present on the command line, and merge with $currentargs Finally, execute the module or function with $currentargs Why so complex? BuiltInDefaults are the ultimate fallback in nothing else is specified. System Preferences let the script writer define (and later extend) default values of any parameters (I have in mind here a set of SQL query strings - distribute an initial set, and later release additional queries) User Preferences let the script consumer add their own values to the parameters Environment Variables - really just for completeness, I've seen automated testing/regression testing harnesses that like to set script arguments using environment variables Argument File specified on the command line - While developing or extending the paramter default values, specify the new default values in a file and pass it on the command line to the script Individual Arguments specified by name on the command line - the traditional way Writing this would be straightforward, but here's where I lose my way... If there is an argument $SQLCommandStrings = @{cmd1='Select 1'; cmd2='Select2'} as part of the builtin, how can I (simply/concisly) indicate that the next highest priority file should extend this argument by adding another key/value pair? and how should we indicate that the next highest priority file should replace the entire hashtable @{cmd1='Select 1'; cmd2='Select2'} with a different one @{cmd99='Select ninetynine'}. To make this an actionable question... # given these from the various preference files or command line file $lowpriargs = @{cmdstrings=@{cmd1='Select 1'; cmd2='Select2'}} $hipriargs = @{cmdstrings=@{cmd99='Select ninetynine'}} # there are two outcomes of merging: augmented or supplanted(replaced) $mergedargs_augmented=@{cmdstrings=@{cmd1='Select 1'; cmd2='Select2';cmd99='Select ninetynine'}} $mergedargs_supplanted=@{cmdstrings=@{cmd99='Select ninetynine'}} How can we specify in the preferences file, perhaps as an attribute for each argument, that tells the module/script to augment the lower priority value with the higher priority value,or supplant it? and finally - does anybody beside Andy (the OP) and myself even care? getopts was a great Perl module, but it's not quite the Powershell way. And I'm not interested in writing a Pwoershell getopts - What I really want is a way to cascade/combine parameter default values, so that I (the script author) can define a set of default values, my users can augment/extend/replace them, and later I can update/extend the default values, all without having to modify the script/module, just modify the various preferences file(s). Maybe somebody can point me to some prior work in this area? |
|
|
|
|
halr9000 PowerShell MVP, Site Admin
 Advanced Member Posts:565

 |
| 16 Jun 2011 04:39 AM |
|
Check out splatting (a powershell v2 feature). Splatting takes a hashtable and applies the keys as parameter names and their values as parameter values. You supply it in one go like so: $foo = @{ Name = 'value1' Color = 'blue' Number = 43 OtherThing = ( Get-Process powershell ) # or whatever } Get-Bar @foo As ebgreen suggests, you can do work in a separate file and dot-source it. So, you could define $foo in that file, or you can have that file check $env for the presence of certain variables, and if present, put them in the hashtable. Note the splatting doesn't affect parameters not defined in the hashtable. Let's say that Get-Bar was defined like so: function Get-Bar { Param( $Name = 'default name', $Color = 'red', $Number = '0.34', $OtherThing, [string[]]$Filter = @( 1, 'two', 'three', 0.4 ), $ComputerName = 'localhost' ) } In the splatting example above, I only defined 4 of the 6 possible parameters. In that case, the Filter and ComputerName parameters will use the defaults that I just defined here. |
|
Community Director, PowerShellCommunity.org Co-host, PowerScripting Podcast Author, TechProsaic |
|
|
| You are not authorized to post a reply. |
|
Active Forums 4.3
|
|
 |