Как мне указать каталог для запуска скрипта PowerShell, который будет редактировать расширения файлов? - PullRequest
0 голосов
/ 03 июля 2018

Я новичок в PowerShell и новичок в ИТ. Мой начальник попросил меня написать сценарий PowerShell, который определит имена файлов, которые не имеют расширения, а затем изменит их на файлы .PDF. Проведя некоторые исследования в Интернете, я нашел скрипт, который имел аналогичную цель, и попытался адаптировать его к моим потребностям:

   $proj_files = Get-ChildItem | Where-Object {$_.Extension -eq "."}
ForEach ($file in $proj_files) {
$filenew = $file.Name + ".pdf"
Rename-Item $file $filenew
}

Мой первый вопрос: логика в этом сценарии имеет смысл? Является ли "Extension -eq "." правильный синтаксис для указания имени файла без расширения? Другой моей мыслью было использовать Extension -eq "null" или что-то подобное. Если мне нужно использовать нулевое значение, как это будет выглядеть? Другой мой вопрос: как мне указать данный каталог для поиска в этом скрипте, или мне вообще нужно? Я подумал здесь, чтобы указать путь в Get-ChildItem, например, так: $proj_files = Get-ChildItem -Path C:\Users\mthomas\Documents | Where-Object {$_.Extension -eq ".'} Это кажется правильным? Я не решаюсь проверить это, прежде чем получить второе мнение, потому что я не хочу менять каждое расширение файла на моем компьютере или что-то глупое подобное. В любом случае, спасибо всем за помощь.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Вы можете сделать что-то вроде следующего, чтобы найти файлы в каталоге без расширения и переименовать их, чтобы иметь расширение PDF:

$directory = "C:\Path\To\Directory"

Get-ChildItem -File $directory | Where-Object { -Not $_.Extension } | Foreach-Object {
  $_ | Rename-Item -NewName "$($_.Name).pdf"
}

Давайте разберемся с этим

$directory = "C:\Path\To\Directory"

Здесь мы устанавливаем каталог, в котором мы хотим находить файлы без расширений. Его не нужно задавать как статическую переменную, но поскольку вы только начинаете работать с Powershell, это делает его простым.

Get-ChildItem -File $directory

Get-ChildItem - это командлет, который используется для отображения содержимого каталога (также псевдонимы gci, ls и dir). -File говорит, что он выводит только список файлов, а $directory ссылается на каталог, из которого мы хотим искать, который мы установили выше. Обратите внимание, что Get-ChildItem может вести себя по-разному в зависимости от поставщика (например, вы также можете использовать Get-ChildItem в разделе реестра), но если вы работаете с путем к файловой системе, вам не нужно беспокоиться о дополнительных поставщиках в этом случае .

|

Передает предыдущий вывод по конвейеру. Это распространенный оператор в Powershell, но в основном вы можете связывать команды вместе, используя его. Вы можете прочитать больше о трубопроводе на https://docs.microsoft.com/en-us/powershell/scripting/getting-started/fundamental/understanding-the-windows-powershell-pipeline?view=powershell-6

Where-Object { -Not $_.Extension }

Where-Object оценивает условие для одного или нескольких элементов и отфильтровывает элементы, которые не соответствуют условию. Поскольку Get-ChildItem может возвращать один или несколько файлов, мы используем оператор -Not в ScriptBlock (обозначается {} и следим за тем, чтобы в файле не было расширения. $_ или $PSItem, это специальная переменная, используемая конвейером, в этом случае $_ равняется каждому элементу, возвращенному Get-ChildItem. Свойство Extension существует в файлах, возвращаемых Get-ChildItem, и будет пустым или оценено как $False. Таким образом, фильтрация на -Not $_.Extension - это то же самое, что сказать, что сопоставляются только объекты, у которых отсутствует расширение файла. Where-Object можно прочитать более подробно здесь: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/where-object?view=powershell-6

Foreach-Object { SCRIPTBLOCK }

Аналогично Where-Object, но запускает код для каждого объекта в конвейере, а не оценивает и фильтрует объекты, которые не соответствуют условию. В этом случае мы передаем каждый файл без расширения Rename-Item, что будет разбито ниже. Более подробную информацию о Foreach-Object можно прочитать здесь: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object?view=powershell-6

$_ | Rename-Item -NewName "$($_.Name).pdf"

Переименуйте текущий файл в блоке Foreach-Object на новое имя с добавлением .pdf. "$( ... )" называется sub-expression, который представляет собой метод интерполяции строки, который позволяет вам выполнить команду внутри строки и сделать ее выходной частью строки. Вы можете добиться того же эффекта, выполнив $_ | Rename-Item -NewName ( $_.Name + ".pdf" ), который просто добавляет .pdf в конец текущего имени.

Резюме

Конвейер является очень мощным инструментом в Powershell и является ключом к написанию эффективных и менее раздутых скриптов. Сначала это может показаться сложным, но чем больше вы его используете, тем менее пугающим он будет казаться. Я настоятельно рекомендую прочитать дополнительную документацию, на которую я ссылался выше, поскольку она должна помочь заполнить все пробелы, которые я мог упустить в моих объяснениях выше.

Чтобы упростить приведенную выше разбивку, команда делает это в следующем порядке: получает все файлы в указанном каталоге, выбирает только файлы, которые не имеют расширения, затем переименовывает каждый найденный файл без расширения, чтобы иметь * 1075. * в конце.

0 голосов
/ 03 июля 2018

Логика в сценарии - общая форма - имеет понятный смысл, но она не подходит для того, чтобы она работала так, как вы намеревались.

Тестирование на моем компьютере здесь:

new-item -ItemType File -Name 'test'

get-item test | format-list *

get-item test | foreach { $_.extension; $_.Extension.length; $_.extension.GetType().name }

файл без расширения отображается с пустой строкой (пустое содержимое, длина 0, введите String, поэтому ваш where-object { $_.Extension -eq "." } должен искать "" вместо ".".

Но:

Get-ChildItem | Where-Object { $_.Extension -eq '' }

также показывает некоторые папки, поскольку они не имеют расширения в названии, поэтому вы можете Get-ChildItem -File ограничить его только файлами.

как мне указать данный каталог для поиска в этом скрипте, или мне даже нужно?

Он будет работать в текущем каталоге, в зависимости от того, что указано в вашем приглашении PS C:\wherever>, поэтому, если вам нужно запустить его где-то еще, да, вам нужно перейти в эту папку или указать в get-childitem -LiteralPath 'c:\path\to\wherever'. Вы не упомянули подпапки, если они вам нужны, переключитесь на get-childitem -Recurse.

Говоря о подпапках, ваш $filenew = $file.Name + ".pdf" имеет смысл только в текущем каталоге, я думаю, что он будет работать лучше, если вы используете полное имя файла, включая путь, поэтому они определенно будут переименованы в том же месте, где были найдены $filenew = $file.FullName + ".pdf"

Является ли "Extension -eq "." правильным синтаксисом для указания имени файла без расширения?

Будьте осторожны, то, что вы написали в своем вопросе, было правильным синтаксис , но неверное содержимое строки. То, что вы написали здесь с кавычками слева от Расширения, является неправильным синтаксисом.

Другой моей мыслью было использование Extension -eq "null" или чего-то подобного. Если мне нужно будет использовать нулевое значение, как это будет выглядеть?

И будьте осторожны, "null" - это не нулевое значение, это строка, содержащая четырехбуквенное слово «ноль».

Вам не нужно здесь использовать нулевое значение, обычно, если вы делаете, это выглядит как $null, но в этом случае вы можете использовать where-object { [string]::IsNullOrEmpty($_.Extension) }, но я думаю, что это не принесет никакой пользы.

И, как стилистический выбор, "" и '' являются строками, но "" может содержать переменные и подвыражения, поэтому, если у вас есть простой текст, это хорошая привычка использовать для него '' потому что это дает читателю понять, что вы намерены, чтобы в этой строке ничего особенного не происходило.

Тогда ваш код с заданными именами параметров будет выглядеть примерно так:

$proj_files = Get-ChildItem -LiteralPath 'C:\Users\mthomas\Documents' | 
                  Where-Object {$_.Extension -eq '.'}

foreach ($file in $proj_files)
{
    $filenew = $file.FullName + '.pdf'
    Rename-Item -LiteralPath $file.FullName -NewName $filenew
}

Если вы хотите увидеть, что он будет делать, используйте -WhatIf в конце Rename-Item:

Rename-Item -LiteralPath $file.FullName -NewName $filenew -WhatIf

Тогда он не будет вносить изменения, просто скажу вам, что он будет делать.

Я не решаюсь проверить это, прежде чем получить второе мнение, потому что я не хочу менять каждое расширение файла на моем компьютере или что-то глупое, как это

Разумный. Но интернет-пользователи скажут вам протестировать их код перед его запуском, потому что в конечном счете вы несете ответственность за защиту своих файлов, а не за доверие случайного кода из Интернета, поэтому наличие тестовых папок, наличие запасной машины, хорошее резервное копирование, играть с PowerShell по частям до тех пор, пока вы не будете довольны тем, что они делают, у них тоже есть хорошие привычки.

...