1

When did changing filenames become so complicated?? All I want to do is add '_a' to a directory of files (with no extension)

The following does not work:

Rename-Item -newname { $_BaseName + '_a' } -whatif

Rename-Item : Cannot evaluate parameter 'NewName' because its argument is specified as a script block and there is no
input. A script block cannot be evaluated without input.
At line:1 char:22
+ Rename-Item -newname { $_BaseName + '_a' } -whatif
+                      ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [Rename-Item], ParameterBindingException
    + FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.RenameItemCommand

then:

Rename-Item -Path C:\users\r-waibel\Downloads\Mar723_pod3-m $_.basename -Newname ($_.basename + "_a") -whatif

Rename-Item : A positional parameter cannot be found that accepts argument '$null'.
At line:1 char:1
+ rename-item -Path C:\users\r-waibel\Downloads\Mar723_pod3-m $_.basena ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Rename-Item], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.RenameItemCommand
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    An example: `Get-Item -Path .\DataFiles | ForEach-Object {$_ | Rename-Item -WhatIf -NewName ($_.BaseName + '_a')}` returns _`What if: Performing the operation "Rename Directory" on target "Item: D:\PShell\DataFiles Destination: D:\PShell\DataFiles_a".`_ See [`$_` contains the current object in the pipeline object](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-7.3#_) – JosefZ Apr 05 '23 at 16:25

2 Answers2

2

As the first error message states, you need to provide some sort of input for -NewName {...} to work.

Pipe the corresponding file items to Rename-Item and it'll work:

Get-ChildItem path\to\directory -File |Rename-Item -NewName { $_.BaseName + "_a" } -WhatIf
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
2

Let me add some background information to Mathias R. Jessen's effective solution:

  • The automatic $_ variable only ever has a meaningful value inside script blocks ({ ... }), and most commonly refers to the current input object received via the pipeline.

  • The script block passed to -NewName in your
    Rename-Item -NewName { $_BaseName + '_a' } -WhatIf command is a so-called delay-bind script block, which therefore indeed requires pipeline input:

    • Note that delay-bind script blocks only work with parameters that are explicitly designed to bind to pipeline input (and that they mustn't be of type [script block] or [object]).

    • In effect, instead of providing a static value to -NewName you're passing a piece of code that gets evaluated for each pipeline input object and therefore allows the calculation of dynamic, per-input-object values.

    • If there is no pipeline input, the command cannot function, and you'll get the error that includes Cannot evaluate parameter 'NewName' because its argument is specified as a script block and there is no input.

  • By contrast, -NewName ($_.basename + "_a") passes an (ultimately) static value to -NewName; that is, the expression is evaluated once, up front, and its result is passed as a static value to the parameter.

    • For the reasons explained above, $_ has no meaningful value in this context; it is $null, so $_.basename is $null too, and the overall result is just _a.

    • However, because you also tried to use $_.basename as an additional, positional argument
      (rename-item -Path C:\users\r-waibel\Downloads\Mar723_pod3-m $_.basename -Newname ($_.basename + "_a") -whatif), the Rename-Item call broke fundamentally, due to that argument (whose value happens to be $null) not being recognized.

    • This is what the error message A positional parameter cannot be found that accepts argument '$null'. indicates.

    • To solve your task without a delay-bind script block (the latter being preferable), but without having to hard-code the input file name, you'd need an aux. custom variable; e.g.:

       $file = Get-Item -LiteralPath C:\users\r-waibel\Downloads\Mar723_pod3-m
       $file | Rename-Item -NewName ($file.BaseName + '_a') -WhatIf
      
      • The above is the - more cumbersome, single-file-only - equivalent to using a delay-bind script block as follows:

         Get-Item -LiteralPath C:\users\r-waibel\Downloads\Mar723_pod3-m | 
           Rename-Item -NewName { $_.BaseName + '_a' } -WhatIf
        

As for:

All I want to do is add '_a' to a directory of files (with no extension)

Using the flexibility of delay-bind script blocks discussed above, this is then as simple as piping the output from a Get-ChildItem call that outputs all files to rename to your Rename-Item call:

Get-ChildItem -File -LiteralPath C:\users\r-waibel\Downloads\ | 
  Rename-Item -NewName { $_.BaseName + '_a' } -WhatIf
mklement0
  • 382,024
  • 64
  • 607
  • 775