PowerShell을 사용한 효율적인 파일 삭제: Remove-Item 및 WMI

서버 및 시스템을 관리할 때는 여유 디스크 공간을 유지하는 것이 중요합니다. 관리자로서 ‘디스크 가득참’ 상황에 놀라지 않도록 주의해야 합니다. 안전하게 유지하려면 PowerShell을 사용하여 파일을 삭제하는 방법을 배워야 합니다!

이 문서에서는 PowerShell을 사용하여 시스템에서 파일을 제거하는 거의 모든 방법을 배울 수 있습니다.

시작해봅시다!

필수 조건

본 문서에서는 PowerShell을 사용한 예시를 제시하며, 따라하기 위해서는 다음이 필요합니다.

  • A computer that is running Windows 10 or above.
  • Windows PowerShell 5.1 또는 PowerShell 7.0
  • A script editor such as Visual Studio Code, Atom, or Notepad++.

파일 삭제에 Remove-Item Cmdlet 사용하기

파일을 삭제해야 할 때 PowerShell을 사용하려면 아마도 즉시 Remove-Item cmdlet에 대해 배우게 될 것입니다. 이 cmdlet은 PowerShell로 파일을 제거하는 데 사용되는 사실상의 표준입니다.

Remove-ItemGet-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이 “경로의 일부를 찾을 수 없습니다”라고 합니다. 이 오류는 cmdlet이 찾으려는 경로가 존재하지 않음을 나타냅니다 – 이는 잘못된 정보입니다.

이 경우에는 Get-ChildItem이 읽으려고 하는 경로가 260자의 최대 경로 길이를 초과하여 오류가 발생했습니다.

아래 스크린샷은 경로 또는 디렉토리 및 해당 하위 디렉토리가 존재하며 하위 디렉토리의 가장 하단에 InTooDeep.txt라는 텍스트 파일이 있는 것을 보여줍니다. 중첩된 디렉토리 이름을 구성하는 모든 문자의 조합으로 장경로 문제가 발생합니다.

Nested directories creating a long path name

Windows PowerShell 5.1에서는 긴 경로 이름 문제에 대한 해결책이 있습니다. 해결책은 경로의 유니코드 버전을 사용하는 것입니다. 이렇게 경로를 지정하는 대신에 – C:\temp처럼 경로를 지정하는 대신, 이렇게 유니코드 버전을 사용하십시오 – ‘\\?\C:\temp’ 로컬에 위치한 폴더의 경우 또는 ‘\\?\UNC\<computername>\<share>\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에서는 이미 긴 경로 이름에 대한 내장 지원이 있으므로 경로의 유니코드 버전을 사용할 필요가 없습니다.

폴더도 삭제해야 하는 경우 Get-ChildItem cmdlet에서 -File 매개변수를 제거하면 됩니다. 그러면 PowerShell이 파일과 폴더를 포함한 모든 항목을 삭제해야 합니다.

x 일 전보다 오래된 파일을 삭제하는 데 PowerShell 사용하기

디스크 공간 정리의 또 다른 전형적인 예는 특정 일 수보다 오래된 파일을 삭제하는 것입니다. 이 예제는 디스크 공간을 확보하기 위해 IIS 웹 서버에서 생성된 오래된 로그 파일을 삭제하는 데 유용합니다.

이 예에서는 14일보다 오래된 c:\temp에 있는 파일이 있습니다. 아래 스크립트를 사용하여 c:\temp의 각 파일의 Name, CreationTIme, 및 AgeInDays를 표시합니다.

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:\temp에 있는 파일 중 CreationTime 값이 설정된 임계값보다 오래된 파일이 삭제됩니다.

첫 번째 줄은 Get-ChildItem이 검색할 경로를 정의합니다. 경로는 $path 변수에 저장됩니다. 그 다음으로 두 번째 줄은 임계값을 지정하는 곳입니다. $threshold의 값은 삭제할 파일이어야 하는 나이(일 수)입니다.

$threshold 변수 다음의 코드 라인은 다음을 수행합니다:

  • $path 변수에 지정된 폴더에 있는 파일의 컬렉션을 가져옵니다. 이 예에서는 경로가 C:\temp입니다.
  • $threshold 변수에 저장된 일 수보다 CreationTime 값이 오래된 파일만 출력에 필터링합니다. 이 예에서는 임계값이 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

위의 스크린샷에서 verbose 메시지를 기반으로하면 스크립트는 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 파일 이름과 일치하는 파일을 삭제하는 방법을 보여줍니다. 이를 수행하는 한 가지 방법은 -Include 매개 변수를 사용하여 직접 Remove-Item cmdlet을 사용하는 것입니다. 아래와 같이.

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

또 다른 방법은 아마도 신중한 접근 방식입니다. 먼저 Get-ChildItem을 사용하여 삭제할 파일 목록을 수집합니다. 삭제할 파일 목록에 만족할 때까지 마침내 컬렉션을 Remove-Item cmdlet에 연결할 수 있습니다.

예를 들어, 아래 코드는 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 cmdlet에 파이핑하여 마지막으로 해당 파일을 삭제할 수 있습니다.

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

최종 코드를 실행한 후에는 선택한 파일만 삭제하는 목표를 달성하게 될 것입니다.

Deleting selected files

PowerShell에서 WMI를 사용하여 파일 삭제

이제 파일을 제거하는 데 일반적인 Remove-Item cmdlet를 사용하는 방법에 대해 잘 이해했으니, 좀 더 고급 사용 사례인 WMI 사용으로 넘어가 봅시다.

PowerShell에는 WMI 지원이 함께 제공됩니다. WMI 지원이란 PowerShell 내에서 WMI 쿼리 및 메서드를 호출할 수 있다는 것을 의미합니다. 네, WMI는 윈도우 초기에 관리자들이 사용한 Visual Basic 스크립트만을 위한 것이 아닙니다.

Microsoft는 PowerShell 3.0에서 WMI 특정 CIM cmdlet을 출시했습니다. 파일을 삭제하는 데 사용될 CIM cmdlet은 Get-CimInstanceInvoke-CimMethod입니다.

파워셸과 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에는 Cim_DataFile 클래스의 메서드 이름을 나타내는 -Name 매개변수가 있습니다.

$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

파워셸과 WMI를 사용하여 폴더 내 모든 파일 삭제하기

다음 예제에서는 파워셸과 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 변수에 저장된 값은 c:\temp의 모든 파일을 삭제하기 위해 Invoke-CimMethod로 파이프될 수 있습니다.

$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 연산자로서 “0개 이상의 문자열”을 의미합니다. 프로그래밍 용어로는 %가 와일드카드인 별표(*) 문자와 동등합니다.

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

파워쉘의 내장 cmdlet을 사용하여 파일을 검색하고 삭제하는 것이 WMI를 사용할 때보다 훨씬 빠릅니다. 예를 들어, Get-ChildItemRemove-Item을 사용합니다.

아래 예제는 WMI 및 내장된 파워쉘 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\%'"}

위의 코드를 파워쉘에서 실행하면 아래와 같은 출력이 표시됩니다.

Get-ChildItem vs. Get-CimInstance with WMI Query

위의 출력에서 볼 수 있듯이, Get-CimInstance를 사용하여 파일을 나열하는 데 걸리는 시간은 Get-ChildItem을 사용하는 데 걸리는 시간보다 거의 10배 더 오래 걸립니다!

또한, Get-ChildItem 라인이 Get-CimInstance보다 훨씬 짧다는 것에 주목했나요? Get-ChildItem을 사용하면 실행이 더 빠르고 더 깔끔하며 더 짧은 코드를 얻을 수 있습니다.

다음 단계

이 문서에서는 내장된 cmdlet과 WMI/CIM을 사용하여 파일을 삭제하는 두 가지 다른 방법을 살펴보았습니다.

파일을 삭제할 때는 항상 Get-ChildItemRemove-Item cmdlet을 사용해야 합니다. 이러한 내장 cmdlet을 사용하면 WMI를 사용할 때보다 유연하고 쉽고 빠르게 사용할 수 있습니다.

디스크 공간 정리를 수행하는 스크립트를 작성해보려고 해보세요. 이미 그러한 목적으로 스크립트가 존재한다면 참고할 수 있지만, 연습하고 배우고자 한다면 자체적으로 작성해보세요.

추가 자료

Source:
https://adamtheautomator.com/powershell-delete-file/