使用PowerShell进行高效文件删除:Remove-Item和WMI

在管理服务器和系统时,保持空闲磁盘空间至关重要。作为管理员,您不希望陷入”磁盘已满”的窘境。为了确保您没有问题,您应该学会如何使用PowerShell删除文件!

在本文中,您将学习如何使用PowerShell从系统中删除文件的几种方法。

让我们开始吧!

先决条件

本文使用PowerShell示例,如果您打算跟随操作,您需要以下内容。

使用Remove-Item Cmdlet删除文件

当您只需要使用PowerShell删除文件时,您可能会立即了解到Remove-Item cmdlet。该cmdlet是使用PowerShell删除文件的事实标准。

使用Remove-Item结合Get-ChildItem cmdlet读取文件和文件夹,以及强大的PowerShell管道,可以让事情变得轻松愉快。

相关:Get-ChildItem:列出文件、注册表、证书等

您知道Remove-Item cmdlet有一个别名叫做del吗?在PowerShell中使用Remove-Item或del将运行相同的命令。

使用PowerShell删除文件

最有用的第一个例子是最基本的——也就是删除单个文件。要删除一个文件,只需要使用下面的命令。下面的代码删除了文件C:\temp\random.txt

Remove-Item -Path C:\temp\random.txt

在PowerShell中运行上面的代码不会在屏幕上显示任何内容,除非遇到错误。

使用PowerShell删除文件夹中的所有文件

在这个例子中,下面的代码删除了文件夹中的所有文件。Get-ChildItem cmdlet使用-Path参数定位到了C:\temp-File参数表示只包括文件类型的项目,Get-ChildItem忽略文件夹。

Get-ChildItem -Path C:\temp -File | Remove-Item -Verbose

输出应该像下面的截图一样。

Successfully deleted all files in a folder

使用PowerShell递归删除所有文件

前面的例子只删除了C:\temp文件夹中的文件。如果您还需要删除每个子目录中的文件,需要向Get-ChildItem cmdlet添加-Recurse开关,以递归获取所有文件。

Get-ChildItem -Path C:\temp -File -Recurse | Remove-Item -Verbose

运行上面的代码会强制PowerShell查看所有子文件夹并获取所有文件的列表。下面的输出显示,该代码能够删除顶层文件夹中的文件,但无法获取子文件夹中的文件。

Failed to retrieve files in sub-folders

解决长路径问题

上面显示的错误表明,PowerShell“找不到路径的一部分”。该错误表明,命令正在尝试获取的路径不存在,这是具有误导性的。

在這種情況下,錯誤是因為Get-ChildItem嘗試讀取的路徑超過了260個字符的最大路徑長度

下面的截圖顯示了路徑或目錄及其子目錄存在,並且一個名為InTooDeep.txt的文本文件位於最底層的子目錄中。構成嵌套目錄名的所有字符的組合引發了長路徑問題。

Nested directories creating a long path name

在Windows PowerShell 5.1中,有一個解決長路徑名問題的方法。解決方法是使用路徑的Unicode版本。不要像這樣指定路徑 – C:\temp,而是像這樣使用Unicode版本 – ‘\\?\C:\temp’ (如果文件夾位於本地),或者’\\?\UNC\<計算機名>\\<共享>\Temp’(如果文件夾位於UNC路徑)。

Get-ChildItem -Path '\\?\C:\temp' -File -Recurse | Remove-Item -Verbose

使用修改後的代碼,適應長路徑名,下面的輸出顯示PowerShell成功讀取了深層嵌套的路徑名並刪除了文件。

Deleted the file with a long path name

請注意,長路徑名問題不影響PowerShell 7.0。使用PowerShell 7.0,無需使用Unicode版本的路徑,因為它已內建支援長路徑名。

如果需要刪除文件夾,只需從Get-ChildItem cmdlet中刪除-File參數,PowerShell應該刪除所有項目,包括文件和文件夾。

使用PowerShell刪除超過x天的文件

磁盤空間整理的另一個典型例子是刪除比特定天數更舊的文件。此例子適用於刪除舊的日誌文件,例如由IIS Web服務器生成的文件,以釋放磁盤空間。

在這個例子中,c:\temp資料夾中有一些比14天更舊的文件。使用下面的腳本,將顯示每個文件的NameCreationTImeAgeInDays

Get-ChildItem c:\temp | Select-Object Name,CreationTime,@{n='AgeInDays';e={(New-TimeSpan -Start $PSItem.CreationTime).Days}}

如下圖所示,有一些文件的年齡分別為15天、7天和0天。

List of files in c:\temp

現在您已經知道要刪除的文件,可以創建一個腳本只刪除比特定天數更舊的文件-在這個例子中即比14天更舊的文件。

在下面的腳本示例中,將刪除位於C:\tempCreationTime值比設定的閾值更舊的文件。

第一行定義了Get-ChildItem要搜索的路徑。路徑保存在$path變量中。然後,第二行指定了閾值。變量$threshold的值為要刪除的文件的年齡(以天為單位)。

$threshold變量之後的下一行代碼將:

  • 獲取位於$path變量指定的文件夾中的文件集合。在這個例子中,路徑為C:\temp。
  • 過濾輸出,只包括CreationTime值比$threshold變量保存的天數更舊的文件。在這個例子中,閾值為14天。
  • 將篩選後的檔案清單傳送到 Remove-Item 值以執行刪除這些檔案的動作。
$path = 'C:\Temp'
$threshold = 14
Get-ChildItem -Path $path -File | Where-Object {$PSItem.CreationTime -lt (Get-Date).AddDays(-$threshold)} |Remove-Item -Verbose

執行上述程式碼後,您將看到如下所示的輸出。

The script deleted the files older than 14 days

從上述的螢幕截圖中可以看出,根據詳細訊息,該指令碼僅刪除了 14 天前的五個檔案。為了確認 14 天內較新的檔案仍然存在,請執行下面的程式碼再次列出它們。

Get-ChildItem c:\temp | Select-Object Name,CreationTime,@{n='AgeInDays';e={(New-TimeSpan -Start $PSItem.CreationTime).Days}}

以下結果確認了 Remove-Item 未刪除較新的檔案。

Newer files are left untouched

使用 PowerShell 匹配和刪除檔案模式

不論名稱、類型或副檔名,刪除全部檔案並不總是最佳方法。有時候,您需要明確地排除或包含刪除過程中的某些檔案。

下面的範例展示了如何刪除符合 *.LOG 檔案名稱的檔案。一種方法是直接使用 Remove-Item 指令碼搭配 -Include 參數,如下所示。

Remove-Item -Path C:\temp\* -Include *.log

另一種方式可能是謹慎的做法,先使用 Get-ChildItem 收集要刪除的檔案清單。只有在滿意刪除清單後,才能將收集的內容傳送到 Remove-Item 指令碼。

例如,下面的程式碼在 c:\temp 中取得 *.LOG 檔案。

Get-ChildItem -Path C:\temp\* -Include *.log

由於上面的程式碼,Get-ChildItem 會返回符合 *.LOG 檔案名稱的檔案清單。

Only files matching the *.log filename is returned

但是,如果您想要排除文件名中包含数字5的文件该如何处理呢?您可以通过添加-Exclude参数来实现,就像下面的代码所示。

Get-ChildItem -Path C:\temp\* -Include *.log -Exclude *5*

由于您排除了文件名中带有数字5的文件,所以结果现在是不同的。具体来说,文件File_5.log不再在列表中,如下所示。

The file File_5.log was excluded

当您对代码创建的文件集合感到满意时,可以将文件集合传递给Remove-Item命令来最终删除这些文件。

Get-ChildItem -Path C:\temp\* -Include *.log -Exclude *5* | Remove-Item -Verbose

运行最终的代码后,您将实现仅删除所选文件的目标。

Deleting selected files

使用PowerShell中的WMI删除文件

现在,您已经很好地了解了如何使用常见的Remove-Item命令来删除文件,让我们进入一个更高级的用例;使用WMI。

PowerShell支持WMI。支持WMI意味着可以从PowerShell内部调用WMI查询和方法。是的,WMI不仅适用于管理员在Windows早期使用的Visual Basic脚本。

微软在PowerShell 3.0中发布了专门用于WMI的CIM cmdlets。用于删除文件的CIM cmdlets是Get-CimInstanceInvoke-CimMethod

使用PowerShell和WMI刪除文件

此示例假設您知道要刪除的特定文件的路徑。使用Get-CimInstance cmdlet和Cim_DataFile類別檢索有關要刪除的文件的信息,該文件是C:\Temp\random.txt

$file2delete = Get-CimInstance -ClassName Cim_DataFile -Filter "Name = 'C:\Temp\random.txt'"
 $file2delete

在上面的代碼中,-Filter參數接受WQL格式的查詢。使用WQL需要對一些字符進行轉義,包括反斜線。而且,由於WQL轉義字符也是反斜線,導致出現雙反斜線字符- \\

運行上面的代碼會產生下面演示中顯示的結果。有關C:\Temp\random.txt的信息保存在$file2delete變量中

Getting a file using WMI query and PowerShell

現在已檢索到文件C:\Temp\random.txt的信息,可以將$file2delete變量中的結果導向Invoke-CimMethod cmdlet。 Invoke-CimMethod cmdlet有一個名為-Name的參數,該參數表示Cim_DataFile類別的方法名稱。

$file2delete | Invoke-CimMethod -Name Delete

如下面的屏幕截圖所示,ReturnValue顯示為0,表示命令成功。

File successfully deleted using WMI and PowerShell

要了解可能的ReturnValue代码,请参考此链接 – CIM_DataFile类的Delete方法

此外,下面的截图显示在运行Invoke-CimMethod Delete()方法后,CIM仅删除了C:\Temp\random.txt文件。它没有删除其他文件。

C:\Temp\random.txt file was deleted

使用PowerShell和WMI删除文件夹中的所有文件

在下一个示例中,将展示如何使用PowerShell和WMI删除文件夹中的所有文件。与前面示例中使用的相同的cmdlet,即Get-CimInstanceInvoke-CimMethod,将被使用。但是,这次WQL查询将检索文件夹中的所有文件,而不仅仅是一个特定文件。

在下面的代码中,Get-CimInstance cmdlet检索位于C:\temp的所有文件。如下所示,查询过滤了Cim_DataFile类的DrivePath属性。

$file2delete = Get-CimInstance -ClassName Cim_DataFile -Filter "Drive = 'c:' AND Path = '\\temp\\'"

运行上面的代码将保存有关C:\temp中文件的检索信息在$file2delete变量中。查看$file2delete变量的值将显示下面的输出。

List of all folders found in c:\temp using WMI

现在,将存储在$file2delete变量中的值通过管道传递给Invoke-CimMethod,以删除c:\temp中的所有文件。

$file2delete | Invoke-CimMethod -Name Delete

請記住, ReturnValue 代碼為0表示成功,並且對每個調用delete方法的文件都有自己的 ReturnValue 代碼。

All files in c:\temp deleted using WMI

使用PowerShell和WMI按文件擴展名刪除文件

在先前的示例中,您已經看到如何刪除文件夾中的所有文件,而不考慮擴展名。但是,您也可以根據擴展名控制哪些文件被刪除。

您會注意到下面的代碼中,此次查詢添加了條件( Name LIKE%.log )。此添加的條件意味著只返回與 .LOG 擴展名匹配的文件。百分比()符號是WQL LIKE 運算符,表示“零個或多個字符的字符串”。在編程術語中,等同於萬用字符,即星號( * )字符。

$file2delete = Get-CimInstance -ClassName cim_datafile `
-Filter "Drive = 'c:' AND Path = '\\temp\\' AND Name LIKE '%.log'"

$file2delete | Invoke-CimMethod -Name Delete

下面的演示顯示,在執行上述代碼之前,有九個* .LOG 文件和一個* .TXT 文件。代碼運行完畢後,* .LOG 文件被刪除,只剩下* .TXT 文件在文件夾中。

Deleting files by extension using WMI

比較WMI和Remove-Item

到目前為止,在本教程中,您已經獲得了如何使用PowerShell刪除文件的概述。您已經了解了 Remove-Item 和WMI。兩者執行類似的功能,但方式大不相同。

應該使用哪種方法來刪除文件; Remove-Item 還是WMI?

在PowerShell中使用内置的cmdlet,如Get-ChildItemRemove-Item来检索和删除文件,比使用WMI要快得多。

下面的示例展示了使用WMI和内置的PowerShell cmdlet获取C:\windows\web目录及其子目录下文件列表的比较。

## 使用Get-ChildItem递归列出C:\Windows\Web\中的所有文件
Measure-Command { Get-ChildItem C:\Windows\Web\ -Recurse}

## 使用Get-CimInstance和WMI查询递归列出C:\Windows\Web\中的所有文件
Measure-Command { Get-CimInstance -ClassName Cim_DataFile -Filter "Drive = 'c:' AND Path = '\windows\web\%'"}

在PowerShell中运行上述代码时,您将看到类似下面的输出。

Get-ChildItem vs. Get-CimInstance with WMI Query

从上面的输出中可以看出,使用Get-CimInstance列出C:\windows\web中的文件几乎比使用Get-ChildItem要慢十倍

此外,您是否注意到Get-ChildItem行要比Get-CimInstance短得多?使用Get-ChildItem不仅可以获得更快的执行速度,而且还可以获得更简洁和更短的代码。

下一步

在本文中,您已经了解了使用内置的cmdlet和WMI/CIM来删除文件的两种不同方式。

要知道,您应该始终使用Get-ChildItemRemove-Item cmdlet来删除文件。这些内置的cmdlet比使用WMI更灵活、更容易使用,速度更快。

試著撰寫一個可以為您執行磁碟空間清理的腳本。當然,已經存在一些針對此目的的腳本;您可以將它們作為參考,但如果您願意練習和學習,應該嘗試創建自己的腳本。

進一步閱讀

Source:
https://adamtheautomator.com/powershell-to-delete-files/