2010-02-26 23 views
5

Używam Powershell 1.0 do usuwania elementu z tablicy. Oto mój skrypt:Jak usunąć element z tablicy w 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!"} 
    } 
} 

Zdaję sobie sprawę, że Get-ChildItem w powershell zwraca typ System.Array. I dlatego ten błąd, gdy próbuje użyć metody usunięcia:

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

Co chciałbym zrobić, to przekształcić $ filesToDelete do ArrayList, a następnie usunąć elementy używając ArrayList.Remove. Czy jest to dobry pomysł, czy powinienem bezpośrednio manipulować $ filesToDelete jako System.Array w jakiś sposób?

Dzięki

Odpowiedz

8

Najlepszym sposobem, aby to zrobić jest użycie Where-Object wykonać filtrowanie i używać wracającą tablicę.

Można również użyć @splat, aby przekazać wiele parametrów do polecenia (nowe w V2). Jeśli nie możesz uaktualnić (i powinieneś, jeśli w ogóle to możliwe, po prostu zbieraj dane wyjściowe z Get-ChildItems (tylko powtarzanie tego jednego CmdLet) i wykonaj wszystkie filtrowanie we wspólnym kodzie).

Część robocza skryptu staje:

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

W tablicach PSH są niezmienne, nie można ich modyfikować, ale bardzo łatwo stworzyć nową (operatorzy jak += na tablicach rzeczywiście stworzyć nową tablicę i wróć to).

+1

(jeden litero 'PSIsContainere') Tak, wolałbym również' Where-Object'. Jednak w pytaniu są dwie pętle - wewnętrzna przechodzi przez '$ exclusionList', więc warunek powinien prawdopodobnie wyglądać jak' -nie $ ($ f = $ _. Pełna nazwa; $ exclusionList |? {$ F.Contains ($ _)}) ' – stej

+0

Dzięki Richard - czy mogę użyć tablicy łańcuchów dla $ wykluczenia. Jeśli przyjrzysz się bliżej kodowi, zobaczysz, że będę musiał wywołać get-childitem dla każdego wykluczenia. Nie działałoby to dobrze, jeśli mam wiele wyjątków. –

+0

@stej: Poprawnie – Richard

3

Zgadzam się z Richardem, że należy tu użyć Where-Object. Jednak trudniej to odczytać. Co proponuję:

# 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 

Należy również zauważyć, że na ogół nie jest możliwe iteracyjne nad kolekcji i zmienić go. Dostaniesz wyjątek.

$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

To jest starożytne. Ale, napisałem je jakiś czas temu, aby dodawać i usuwać z listy PowerShell za pomocą rekursji. Wykorzystuje zdolność powershell do zrobienia multiple assignment. Oznacza to, że możesz zrobić $a,$b,[email protected]('a','b','c'), aby przypisać b i c do ich zmiennych. Wykonanie $a,[email protected]('a','b','c') przypisuje 'a' do $a i @('b','c') do $b.

Pierwsza wartość według wartości. Usunie pierwsze wystąpienie.

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

Ten usuwa według indeksu. Prawdopodobnie możesz zepsuć to dobrze, przekazując wartość do zliczenia podczas pierwszego połączenia.

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