2010-02-26 1 views
5

Powershell 1.0을 사용하여 배열에서 항목을 제거하고 있습니다. 내 스크립트는 다음과 같습니다.PowerShell에서 배열에서 항목을 제거하는 방법은 무엇입니까?

param (
    [string]$backupDir = $(throw "Please supply the directory to housekeep"), 
    [int]$maxAge = 30, 
    [switch]$NoRecurse, 
    [switch]$KeepDirectories 
    ) 

$days = $maxAge * -1 

# do not delete directories with these values in the path 
$exclusionList = Get-Content HousekeepBackupsExclusions.txt 

if ($NoRecurse) 
{ 
    $filesToDelete = Get-ChildItem $backupDir | where-object {$_.PsIsContainer -ne $true -and $_.LastWriteTime -lt $(Get-Date).AddDays($days)} 
} 
else 
{ 
    $filesToDelete = Get-ChildItem $backupDir -Recurse | where-object {$_.PsIsContainer -ne $true -and $_.LastWriteTime -lt $(Get-Date).AddDays($days)} 
} 

foreach ($file in $filesToDelete) 
{  
    # remove the file from the deleted list if it's an exclusion 
    foreach ($exclusion in $exclusionList) 
    { 
     "Testing to see if $exclusion is in " + $file.FullName 
     if ($file.FullName.Contains($exclusion)) {$filesToDelete.Remove($file); "FOUND ONE!"} 
    } 
} 

PowerShell의 Get-ChildItem은 System.Array 유형을 반환한다는 것을 알고 있습니다. 내가 뭘하려는 것은 ArrayList에에 $의 filesToDelete를 변환 한 후 ArrayList.Remove를 사용하여 항목을 제거입니다

Method invocation failed because [System.Object[]] doesn't contain a method named 'Remove'. 

: 제거 방법을 사용하려고 할 때 나는 때문에이 오류가 발생합니다. 이게 좋은 생각인가요? 아니면 어떤 방식 으로든 $ filesToDelete를 System.Array로 직접 조작해야합니까?

감사

답변

8

이 작업을 수행하는 가장 좋은 방법은 필터링을 수행하고 반환 된 배열을 사용하는 Where-Object을 사용하는 것입니다.

@splat을 사용하여 여러 매개 변수를 명령에 전달할 수 있습니다 (V2에서 새로 추가됨). 업그레이드 할 수 없으면 가능한 한 모두 Get-ChildItems (하나의 CmdLet 만 반복)에서 출력을 수집하고 공통 코드에서 모든 필터링을 수행해야합니다.

스크립트의 작업 일부가된다 : PSH 배열에서

$moreArgs = @{} 
if (-not $NoRecurse) { 
    $moreArgs["Recurse"] = $true 
} 

$filesToDelete = Get-ChildItem $BackupDir @moreArgs | 
       where-object {-not $_.PsIsContainer -and 
           $_.LastWriteTime -lt $(Get-Date).AddDays($days) -and 
           -not $_.FullName.Contains($exclusion)} 

은 당신이 그들을 수정할 수 없습니다, 불변,하지만 매우 쉽게 새로 만들 (배열에 += 같은 연산자는 실제로 새로운 배열을 생성 그것을 돌려라.)

+1

(한 오타'PSIsContainere') 네,'Where-Object'도 선호합니다. 그러나 질문에는 두 개의 루프가 있습니다 - 내부는'$ exclusionList'를 거쳐서'-not $ ($ f = $ _. Fullname; $ exclusionList |? {$ f.Contains ($ _)})' – stej

+0

감사합니다. 리차드 - $ 제외에 문자열 배열을 사용할 수 있습니까? 코드를 자세히 살펴보면 모든 제외에 대해 get-childitem을 호출해야한다는 것을 알 수 있습니다. 내가 많은 예외를 가지고 있다면 이것은 잘 수행되지 않을 것이다. –

+0

@stej : Correct – Richard

3

여기 리차드에 동의합니다. 여기서는 Where-Object을 사용해야합니다. 그러나 읽는 것이 더 어렵습니다. 내가 제안 것이 무엇 :

# get $filesToDelete and #exclusionList. In V2 use splatting as proposed by Richard. 

$res = $filesToDelete | % { 
    $file = $_ 
    $isExcluded = ($exclusionList | % { $file.FullName.Contains($_) }) 
    if (!$isExcluded) { 
     $file 
    } 
} 

#the files are in $res 

는 또한 컬렉션을 반복하고 변경할 수 없습니다 일반적으로 점에 유의. 예외가 발생합니다.

$a = New-Object System.Collections.ArrayList 
$a.AddRange((1,2,3)) 
foreach($item in $a) { $a.Add($item*$item) } 

An error occurred while enumerating through a collection: 
At line:1 char:8 
+ foreach <<<< ($item in $a) { $a.Add($item*$item) } 
    + CategoryInfo   : InvalidOperation: (System.Collecti...numeratorSimple:ArrayListEnumeratorSimple) [], RuntimeException 
    + FullyQualifiedErrorId : BadEnumeration 
0

이것은 고대입니다. 그러나 필자는 재귀를 사용하여 powershell 목록에서 추가하고 제거하기 위해 얼마 전에 작성했습니다. 그것은 powershell의 능력을 활용하여 multiple assignment을 수행합니다. 즉, $a,$b,[email protected]('a','b','c')을 사용하여 변수에 b와 c를 할당 할 수 있습니다. $a,[email protected]('a','b','c')을 수행하면 'a'$a@('b','c')에서 $b으로 지정됩니다.

첫 번째는 항목 값입니다. 첫 번째 발생을 제거합니다.

function Remove-ItemFromList ($Item,[array]$List(throw"the item $item was not in the list"),[array][email protected]()) 
{ 

if ($list.length -lt 1) { throw "the item $item was not in the list" } 

$check_item,$temp_list=$list 
if ($check_item -eq $item) 
    { 
     $chckd_list+=$temp_list 
     return $chckd_list 
    } 
else 
    { 
    $chckd_list+=$check_item 
    return (Remove-ItemFromList -item $item -chckd_list $chckd_list -list $temp_list) 
    } 
} 

이것은 색인으로 제거합니다. 초기 호출에서 계산할 값을 전달하여 문제를 해결할 수 있습니다.

function Remove-IndexFromList ([int]$Index,[array]$List,[array][email protected](),[int]$count=0) 
{ 

if (($list.length+$count-1) -lt $index) 
    { throw "the index is out of range" } 
$check_item,$temp_list=$list 
if ($count -eq $index) 
    { 
    $chckd_list+=$temp_list 
    return $chckd_list 
    } 
else 
    { 
    $chckd_list+=$check_item 
    return (Remove-IndexFromList -count ($count + 1) -index $index -chckd_list $chckd_list -list $temp_list) 
    } 
}