Странный «Позиционный параметр не может быть найден» с помощью Rename-Item

#.net #powershell #powershell-7.0

#.net #powershell #powershell-7.0

Вопрос:

Используя Powershell 7, это работает отлично:

 dir foo* | Rename-Item -Path {$_.Name} -NewName{$_.Name -replace 'bar-(.*)', 'bar-$1'}
  

Это не удается:

 dir foo* | Rename-Item {$_.Name} {$_.Name -replace 'bar-(.*)', 'bar-$1'}
  

Со следующей ошибкой:

 Rename-Item: A positional parameter cannot be found that accepts argument '$_.Name'.
  

Основываясь на документах, вот -Path первая позиция Rename-Item . Кроме того, работает следующая команда: Rename-Item 'foo-one' 'foo-one-one' . Почему происходит вышеупомянутый сбой?

Комментарии:

1. @AdminOfThings почти правильно, dir это псевдоним, на Get-ChildItem который выводится объект со свойством PSPath. Rename-Item Функция использует PSPath в качестве псевдонима для параметра LiteralPath , поэтому вы фактически используете другой набор параметров (который не включает -Path ).

2. @Dabombber Это имеет наибольший смысл, поскольку пропуск {$_.Name} фактически заставляет команду работать. Не стесняйтесь публиковать его в качестве ответа.

3. @iRon Когда я это делаю, это дает мне неожиданный результат, показывающий фоновые задания. Предполагается ли, что <ScriptBlock> преобразуется в <string> ?

Ответ №1:

Хотя ваш пример кода на самом деле не переименовывает ни один файл ( -replace 'bar-(.*)', 'bar-$1' приведет к точно такому же имени.), Основная проблема здесь заключается в том, что вы добавляете {$_.Name} непосредственно после Rename-Item командлета, где это не требуется, поскольку вы уже передаете объекты FileInfo по конвейеру, поэтому now {$_.Name} обрабатывается так, как если бы это былимя параметра.
Затем вы забываете добавить имя для параметра -NewName .

Повторяя путь, подобный foo* тому, который вы делаете, так же, как -Path 'foo' -Recurse и, и в этом есть ошибка..

Особенно при переборе множества файлов и передаче их по конвейеру, есть вероятность, что файлы, которые уже были переименованы, снова будут выбраны Get-ChildItem (псевдонимом dir ), а затем будут переименованы дважды.

Чтобы преодолеть это, поместите часть для сбора файлов в квадратные скобки, чтобы сбор всех объектов FileInfo был завершен, а затем передайте это следующему командлету следующим образом:

 (Get-ChildItem -Path 'foo' -File -Recurse) | 
 Rename-Item -NewName {$_.Name -replace 'bar-(.*)', 'baz-$1'} 
  

для наглядности это меняет часть имени с bar на baz