我如何为 运行 将编辑文件扩展名的 PowerShell 脚本指定一个目录?

How would I specify a directory to run a PowerShell script that would edit file extensions?

我是 PowerShell 新手,也是 IT 新手。我的老板要求我编写一个 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 ".'} 这样看起来正确吗?在获得第二意见之前,我犹豫是否要对此进行测试,因为我不想更改计算机上的每个文件扩展名或类似的愚蠢内容。总之,谢谢大家的帮助。

脚本中的逻辑 - 整体形状 - 可以理解,但不适合它按您的预期工作。

在我的电脑上测试:

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 将其限制为仅文件。

how would I specify a given directory for this script to search through, or would I even need to?

它将 运行 在当前目录中,以提示符 PS C:\wherever> 中显示的那个为准,因此如果您需要它到 运行 其他地方,是的,您需要更改为该文件夹或在 get-childitem -LiteralPath 'c:\path\to\wherever' 中指定。您还没有提到子文件夹,如果您需要包含子文件夹,get-childitem -Recurse 也可以切换。

说到子文件夹,您的 $filenew = $file.Name + ".pdf" 仅在当前目录中有意义,我认为如果您使用包含路径的完整文件名会更好,因此它们肯定会在找到它们的同一位置重命名$filenew = $file.FullName + ".pdf"

Is "Extension -eq "." the correct syntax to specify a filename with no extension?

请注意,您在问题中所写的语法是正确的,但字符串内容不正确。您在此处用引号在 Extension 左侧写的内容语法不正确。

My other thought was to use Extension -eq "null" or something similar. If I do need to use a null value, what would that look like?

请注意,"null" 不是空值,它是一个包含四个字母单词 'null'.

的字符串

你不需要在这里使用空值,通常如果你这样做看起来像$null,但在这种情况下你可以使用where-object { [string]::IsNullOrEmpty($_.Extension) }但是它没有任何好处,我想想。

而且,作为一种文体选择,""'' 都是字符串,但是 "" 可以包含变量和子表达式,所以如果你有纯文本,它是一个整洁的习惯使用 '' 因为它让 reader 清楚地知道您不打算在此字符串中发生任何特殊情况。

那么你的代码,加上参数名称,看起来更像:

$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
}

如果您想看看它会做什么,请在 Rename-Item 的末尾使用 -WhatIf:

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

那么它不会做任何改变,只是告诉你它会做什么。

I am hesitant to test this out before getting a second opinion because I don't want to change every file extension on my computer or something stupid like that

懂事。但是互联网人会告诉你在 运行 之前测试他们的代码,因为最终保护你的文件是你的责任,而不是相信来自互联网的随机代码,所以有测试文件夹,有一台备用机器,有一个好的备份,零散地使用 PowerShell 直到你对它们所做的感到满意,它们都是很好的习惯。

您可以执行类似以下操作来在目录中查找没有扩展名的文件,并将它们重命名为具有 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 是用于列出目录内容的 cmdlet(也别名为 gcilsdir)。 -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 可以 return 一个或多个文件,我们在 ScriptBlock 中使用 -Not 运算符(用 {} 表示并确保没有扩展名文件。$_$PSItem 是管道使用的特殊变量,在这种情况下 $_ 等于 return 由 Get-ChildItem 编辑的每个项目。 Extension 属性 存在于由 Get-ChildItem 编辑的 return 文件中,并且将为空,或计算为 $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 中非常强大的工具,是编写高效且不那么臃肿的脚本的关键。一开始它可能看起来很复杂,但是您使用它的次数越多,它看起来就越不令人生畏。我强烈建议阅读我在上面链接的附加文档,因为它应该有助于填补我在上面的解释中可能遗漏的任何空白。

为了简化上面的分解,该命令按以下顺序执行此操作:获取指定目录中的所有文件,仅选择没有扩展名的文件,然后将找到的每个没有扩展名的文件重命名为具有.pdf 最后。