Problems with Parameters

Hello everyone,

I’m new to PowerShell and am working on my first function. I’ve been having a hard time puzzling out why I can’t properly specify a second parameter here when I try to run my function.

First off, here is the code. Like I said, this is a learning exercise, so it is very basic. Also, while testing I commented out the “Remove-Item” command.

function remove-oldfiles {
   [CmdletBinding()]   
   param(
       [parameter(Manadatory=$true,Position=0)] 
       [string]$path

       [parameter(Manadatory=$true,Position=1)]
       [int]$days,
   )

Get-ChildItem –Path $path -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-$days))} #| Remove-Item
   
   }

After I import the module and then run it, I’m getting the following behavior.

PS C:\users\swhite\Documents\WindowsPowerShell> remove-oldfiles "c:\test1" 30
remove-oldfiles : A positional parameter cannot be found that accepts argument '30'.
At line:1 char:1
+ remove-oldfiles "c:\test1" 30
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [remove-oldfiles], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,remove-oldfiles

Also, something that is very odd to me is that although I specified the property of Mandatory=$true, the second parameter isn’t being required. I know this because if I run with just a path the function works.

Thanks in advance for your assistance.

Commas.

       [parameter(Manadatory=$true,Position=0)] 
       [string]$path,

       [parameter(Manadatory=$true,Position=1)]
       [int]$days

That’s what I get for moving things around while troubleshooting. I mixed up the placement of that comma.

Pasting my code into here did point out that I had the work “mandatory” spelled incorrectly. (corrected below)

I have script with the comma in the correct place is still fails.

function remove-oldfiles {
   [CmdletBinding()]   
   param(
       [parameter(Mandatory=$true,Position=0)] 
       [string]$path,

       [parameter(Mandatory=$true,Position=1)]
       [int]$days
   )
Get-ChildItem –Path $path -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-$days))} #| Remove-Item
   }

I still get the error about: A positional parameter cannot be found that accepts argument…

Try running it and using the parameter names.

remove-oldfiles -path “c:\test1” -days 30

Positional parameters are for losers :).

Also, make sure you’re running this in a “fresh” session. E.g., if you’ve loaded this function into the console, it won’t re-read the file just because you’ve made changes. The old one will still be in memory messing with you.

In your first code you are missing a comma after the 1st parameter and have an unnecessary one after the second parameter which may be causing this behavior.

function remove-oldfiles {
   [CmdletBinding()]   
   param(
       [parameter(Manadatory=$true,Position=0)] 
       [string]$path , #<-- Comma was missing here.

       [parameter(Manadatory=$true,Position=1)]
       [int]$days
   )

Get-ChildItem –Path $path -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-$days))} #| Remove-Item
   
   }

Reloading a fresh session fixed my problem.

I had been doing this in the PowerShell ISE and just importing the module again and again.

I’m certain that in many earlier iterations of the script I had lots of problems.

Thanks for your help, I really though I was going crazy.

Ditch the ISE. Switch to VS Code. ISE has odd ideas about scope that cause me no end of stupid mistakes :).

You’re not showing how you are calling the function, but the error message indicates that you are providing more than 2 parameters. This could be:

Remove-OldFiles C:\Scripts 5 22
Remove-OldFile C:\My Scripts 33

For the first scenario, you are provide 22 and it doesn’t know what to do with it. The second is most likely what you are doing which is providing a path with a space, so it would see it as 3 params in that example. It should be “C:\My Scripts” to pass it as a string.

Here is an updated function with some basics. Write-Verbose is your friend. It allows you to show troubleshooting information or run silently just by having the -Verbose switch or no switch respectively. Usually, when you are using functions, you want to gather additional information about what is happening. If you just piped directly to Remove-Item, you don’t know what is being removed, so in the function you can split things up so that you can get verbose information if required

function Remove-OldFiles {
    [CmdletBinding()]   
    param(
        [parameter(Mandatory=$true,Position=0)] 
        [string]$Path,
        [parameter(Mandatory=$true,Position=1)]
        [int]$Days
    )
    begin{}
    process{
        $files = Get-ChildItem –Path $Path -Recurse | 
        Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-$Days))}

        Write-Verbose ("Found {0} files to be deleted" -f $files.Count)
        foreach ($file in $files) {
            Write-Verbose ("Removing file {0}." -f $file.FullName)
            $file | Remove-Item -Recurse -Confirm:$false -WhatIf
        }
    }
    end{}
}

#Use named params
Remove-OldFiles -Path C:\Scripts -Days 30 -Verbose
#Use positional params
Remove-OldFiles C:\Scripts 30