none
Powershell - Parsing arguments - What am i missing ? RRS feed

  • Question

  • HI

    I have little hair left to pull out so help me out ! thanks

    I have a function (parts borrowed)

    Function CleanupFiles
    {
    	Param
    	(
    		[Parameter(Mandatory=$true,Position=0,ParameterSetName='DeleteSpecified', `
    		HelpMessage="File deletion level")]
    		[Alias("deld")][int]$DeleteLevel = 0,
    		[Parameter(Mandatory=$true,Position=0,ParameterSetName='ListAll', `
    		HelpMessage="Lists all space saving ")]
    		[Alias("listall")][switch]$ListAllItems
    	)

    If i call this inside the ps1 it works, e.g.

    	CleanupFiles -ListAllItems
    	CleanupFiles -DeleteLevel 1

    First line in this ps1 is

    param([string]$Passedargs='')

    >> OK so now this is where we come undone

    If from another PS1 i call this or from a CMD line with 'powershell -file "<path.ps1>" -PassedArgs -ListAllItems
    i get :
    -ListAllItems
    CleanupFiles : Cannot process argument transformation on parameter 'DeleteLevel'. Cannot convert value "-ListAllItems"
    to type "System.Int32". Error: "Input string was not in a correct format."
    At \\syd-file01\knowledge management\Product Development\OurIT_Needs\PowerShellScripts\PC_Cleanup\cleanup_1.ps1:303
    char:15
    +     CleanupFiles $Passedargs
    +                  ~~~~~~~~~~~
        + CategoryInfo          : InvalidData: (:) [CleanupFiles], ParameterBindingArgumentTransformationException
        + FullyQualifiedErrorId : ParameterArgumentTransformationError,CleanupFiles

    >> There seems nothing i can do to make it work ???

    When these lines are used

    	Write-Host $Passedargs
    	CleanupFiles $Passedargs

    I get the same, notice how $Passedargs prints out correctly, however this cause a failure, yet if i replace this with the hard coded values it works

    >> What am i missing ?

    Thanks and regards


    Friday, October 31, 2014 6:42 AM

Answers

  • I don't think you can use variable as the parameter for functions or commands.
    Variable is understood as the first argument and if the type does not match, it raised the error.

    PS C:\> get-date -Hour 2
    
    Friday, October 31, 2014 2:24:49 AM
    
    PS C:\> $A = "-Hour 2"
    
    PS C:\> get-date $A
    Get-Date : Cannot bind parameter 'Date'. Cannot convert value "-Hour 2" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
    At line:1 char:10
    + get-date $A
    +          ~~
        + CategoryInfo          : InvalidArgument: (:) [Get-Date], ParameterBindingException
        + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand
    
    PS C:\>
    

    Maybe you can work around by hard coding.

    if ($Passedargs -eq "-ListAllItems")
    {
       CleanupFiles -ListAllItems
    }

    • Marked as answer by Greg B Roberts Sunday, November 2, 2014 11:59 PM
    Friday, October 31, 2014 7:31 AM
  • The issue is only that a function in a called PS1 file cannotbe accessed without dot-sourcing the file.

    At a new prompt (start new PS CLI) load your file with the function and attempt to call the function.

    .\myfile.ps1
    now call the function
    CleanupFiles -ListAllItems
    CleanupFiles -DeleteLevel 1

    YOu will get an issue.

    Now do this:

    . .\myfile.ps1

    notice the extra dot<space>

    Now call the function.

    See this blog article on how to call functions in external script files:

    http://blogs.technet.com/b/heyscriptingguy/archive/2009/12/23/hey-scripting-guy-december-23-2009.aspx

    Tell the guys at Schneider to give us a set of good Power Management CmdLets.  C'mon guys your falling behind.


    ¯\_(ツ)_/¯

    • Marked as answer by Greg B Roberts Monday, November 3, 2014 12:00 AM
    Friday, October 31, 2014 9:39 AM

All replies

  • I don't think you can use variable as the parameter for functions or commands.
    Variable is understood as the first argument and if the type does not match, it raised the error.

    PS C:\> get-date -Hour 2
    
    Friday, October 31, 2014 2:24:49 AM
    
    PS C:\> $A = "-Hour 2"
    
    PS C:\> get-date $A
    Get-Date : Cannot bind parameter 'Date'. Cannot convert value "-Hour 2" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
    At line:1 char:10
    + get-date $A
    +          ~~
        + CategoryInfo          : InvalidArgument: (:) [Get-Date], ParameterBindingException
        + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand
    
    PS C:\>
    

    Maybe you can work around by hard coding.

    if ($Passedargs -eq "-ListAllItems")
    {
       CleanupFiles -ListAllItems
    }

    • Marked as answer by Greg B Roberts Sunday, November 2, 2014 11:59 PM
    Friday, October 31, 2014 7:31 AM
  • The issue is only that a function in a called PS1 file cannotbe accessed without dot-sourcing the file.

    At a new prompt (start new PS CLI) load your file with the function and attempt to call the function.

    .\myfile.ps1
    now call the function
    CleanupFiles -ListAllItems
    CleanupFiles -DeleteLevel 1

    YOu will get an issue.

    Now do this:

    . .\myfile.ps1

    notice the extra dot<space>

    Now call the function.

    See this blog article on how to call functions in external script files:

    http://blogs.technet.com/b/heyscriptingguy/archive/2009/12/23/hey-scripting-guy-december-23-2009.aspx

    Tell the guys at Schneider to give us a set of good Power Management CmdLets.  C'mon guys your falling behind.


    ¯\_(ツ)_/¯

    • Marked as answer by Greg B Roberts Monday, November 3, 2014 12:00 AM
    Friday, October 31, 2014 9:39 AM
  • Try using this format and structure and the $PSBoundParameters to test how a function is behaving.

    Function CleanupFiles{
        Param(
            [Alias('deld')]
            [Parameter(
                Position=0,
                Mandatory=$true,
                ParameterSetName='DeleteSpecified',
                HelpMessage="File deletion level"
            )][int]$DeleteLevel=0,
            [Alias('listall')]
            [Parameter(
                ParameterSetName='ListAll',
                Position=0,
                Mandatory=$true,
                HelpMessage="Lists all space saving "
            )]
            [switch]$ListAllItems
        )
        
        $PsBoundParameters
    }
    

    Remember to dot source


    ¯\_(ツ)_/¯

    Friday, October 31, 2014 9:46 AM
  • Also note how autocomplete works correctly and how the parameterset gets correctly chisen

    Try

    CleanupFiles 3

    and

    CleanupFiles -listall

    Notice how the function displays all chosen parameters and values.


    ¯\_(ツ)_/¯

    Friday, October 31, 2014 9:48 AM
  • hysh_00

    You are on the right track but the remedy is wrong.  The arguments with a dash in front are not variables.

    In the function any variable wll be seen in the undeclared parameterset because it is not a switch variable.  If the first positional variable is an integer it will work but any non-integer will not work.

    This fails:

    PS C:\scripts> CleanupFiles "4"
    CleanupFiles : Cannot process argument transformation on parameter 'ListAllItems'. Cannot convert value
    "System.String" to type "System.Management.Automation.SwitchParameter". Boolean parameters accept only Boolean values
    and numbers, such as $True, $False, 1 or 0.

    This works:

    PS C:\scripts> CleanupFiles 3

    Key                                                                                                               Value
    ---                                                                                                               -----
    DeleteLevel                                                                                                           3

    Can you see what is happening? Of course the assumes the script ws loaded by dot-sourcing.


    ¯\_(ツ)_/¯

    Friday, October 31, 2014 9:56 AM
  • One other useful note.

    To make functions available to all scripts and code in a session use a module.  A module loads functions and objects into a session and eliminates many issues of script calls.


    ¯\_(ツ)_/¯

    Friday, October 31, 2014 9:57 AM
  • Thanks all

    For now i have gone woth the quick fix , regards

    if ($Passedargs -eq '')
    {
        # menu system in here
    }
    else
    {
    	Write-Host $Passedargs
    	if ($Passedargs.ToLower() -eq '-listallitems')
    	{
    		CleanupFiles -ListAllItems
    	}
    
    	if ($Passedargs.ToLower().StartsWith('-deletelevel'))
    	{
    		$Level = $Passedargs.Substring(13)
    		CleanupFiles -DeleteLevel $Level
    	}
    }

    Sunday, November 2, 2014 11:56 PM
  • Sorry guy but I don't think you understand how PowerShell works.  Please take some time to learn how this is designed to work.  You attempt at a kludge will come back to haunt you in the future.  It is also not even close to a correct answer.

    The answer you marked from hysh_00 is completely wrong and has absolutely nothing to do with PowerShell by design or by accident.

    I know this won't convince you but I am posting this for others so they will not be mislead by naïve and incorrect information.

    Please review the basics of PowerShell to understand how this works.


    ¯\_(ツ)_/¯

    Monday, November 3, 2014 12:14 AM
  • Fair comment, i will revisit my approach based on what you said.

    In my case i want to leave some BAT files so users can either get the menu or the direct option. The schedules task will cleanup the VMs directly my using the BAT or directly the
    powershell -file <path>.ps1 args

    regards

    Monday, November 3, 2014 12:30 AM