Centrum skryptów - Systemu operacyjne

Jak zastosować powłokę Windows PowerShell do usunięcia wszystkich znajdujących się w folderze plików starszych niż 90 dni?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak zastosować powłokę Windows PowerShell do usunięcia wszystkich znajdujących się w folderze plików starszych niż 90 dni?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Jak określić w powłoce Windows PowerShell różnicę w liczbie dni pomiędzy dwoma datami? Chcę usunąć wszystkie pliki znajdujące się w folderze, które są starsze niż 90 dni.

-- JN

Cześć Skrypciarze! Odpowiedź

Cześć, JN. Rety, jak ja się cieszę, że ten długi weekend się już skończył. W zasadzie to nie cieszę się, że akurat długi weekend dobiegł końca, ale że właśnie ten długi weekend się wreszcie skończył. Spędziłem za kierownicą sam nie wiem ile godzin, mogę ten czas porównać do czasu spędzonego za stołem w Boże Narodzenie. Sami więc widzicie, że to strasznie długo. Cieszę się, że coś takiego ma miejsce tylko raz w roku, częściej bym tego chyba nie przeżył. Wszyscy na pewno wiecie o co mi chodzi i nie będę nazywał rzeczy po imieniu na wypadek, gdyby wśród czytelników naszej rubryki znalazł się jakiś wielki fan takich imprez.

Straszne to było dla mnie przeżycie, ale dla niektórych z Was straszniejszy może wydawać się tylko skrypt wykorzystujący powłokę Windows PowerShell usuwającą wszystkie pliki starsze niż 90 dni znajdujące się folderze. Mnie po takim weekendzie ten skrypt już tak nie przeraża. Zresztą sami zobaczcie, że w sumie to wszystko może wydać się bardziej przerażające niż ten skrypt. Oto on:

$a = Get-ChildItem C:\Scripts

foreach($x in $a)

    {

        $y = ((Get-Date) - $x.CreationTime).Days

        if ($y -gt 90 -and $x.PsISContainer -ne $True)

            {$x.Delete()}

    }

Zanim wyjaśnię, jak on działa, spójrzmy na trochę prostszy przykład, taki, który odejmuje dwie daty. Ten skrypt testowy wygląda tak:

$x = Get-Date

$y = Get-Date "1/1/2007"

$x - $y

Jak widzimy, w tym skrypcie nie ma nic skomplikowanego. W pierwszym wierszu stosujemy polecenie cmdlet Get-Date w celu pobrania bieżącej daty i godziny i zachowania jej w zmiennej o nazwie $x. w wierszu drugim, stosujemy polecenie cmdlet Get-Date w celu pobrania wartości daty i godziny odpowiadającej 1 styczniowi 2007. Zauważcie, że nie określiłem czasu pobierając drugą wartość; w wyniku tego, nasze wystąpienie daty i godziny otrzyma domyślny czas 12:00:00 AM. A gdybyśmy tak zechcieli określić dokładny czas? Żaden problem. Jak mówią bilbordy reklamowe Nike: just do it:

$y = Get-Date "1/1/2007 9:45 PM"

Ono dobra, zatem mamy dwie wartości czasu i godziny, $x oraz $y. Co teraz? No cóż, jeżeli chcemy określić odstęp czasu pomiędzy tymi dwoma datami, wystarczy tylko odjąć jedną od drugiej. Odejmujemy $y od $x i otrzymujemy, co następuje:

Days              : 302

Hours             : 9

Minutes           : 27

Seconds           : 47

Milliseconds      : 515

Ticks             : 261268675156250

TotalDays         : 302.394299949363

TotalHours        : 7257.46319878472

TotalMinutes      : 435447.791927083

TotalSeconds      : 26126867.515625

TotalMilliseconds : 26126867515.625

Na samej górze listy znajduje się wartość, której szukamy; okazuje się, że pomiędzy datą bieżącą (30 października 2007, datą napisania tego artykułu), a 1 stycznia 2007 jest 302 dni. Nieźle, nieprawdaż?

No dobrze, macie rację: nie jest źle, ale tak całkiem dobrze też nie jest. Przyczyną tego jest fakt, iż mamy dużo właściwości (Hours, Minutes, Second, Milliseconds, itd.), które nas nie interesują. Nic nie szkodzi; zmodyfikujmy ostatni wiersz naszego skryptu i zobaczmy, co się stanie:

($x - $y).Days

Co tutaj zdziałaliśmy? Cóż, nadal odejmujemy zmienną $y od $x; jedyną różnicą jest fakt, że tym razem wykonujemy odrobinę arytmetyki z udziałem dat wewnątrz nawiasów. Dlaczego? No cóż, potrzebne mam są dwie rzeczy. Po pierwsze, musimy odjąć jedną wartość od drugiej ($x - $y); dzięki temu otrzymamy wystąpienie klasy System.TimeSpan pakietu .NET Framework.

Po drugie, chcemy tylko wyświetlić wartość właściwości Days dla tego obiektu TimeSpan. Żeby upewnić się, że najpierw otrzymamy obiekt TimeSpan, a dopiero potem spróbujemy pobrać wartość właściwości Days, umieszczamy nasze małe równanie arytmetyczne wewnątrz zbioru nawiasów. Powłoka PowerShell zawsze wykonuje polecenia w nawiasach, a dopiero później wszystkie inne; w ten sposób najpierw wykona obliczenia związane z datą, a dopiero potem, mając już obiekt TimeSpan, pobierze wartość właściwości Days.

Czy to naprawdę zadziała? Sami zobaczcie:

302

Teraz wreszcie możemy zająć się skryptem, który usuwa wszystkie pliki znajdujące się w folderze, które są starsze niż 90 dni. Ten skrypt rozpoczyna się od zastosowania polecenia cmdlet Get-ChildItem w celu pobrania kolekcji wszystkich obiektów znajdujących się w folderze C:\Scripts, zachowując tę kolekcję w zmiennej o nazwie $a:

$a = Get-ChildItem C:\Scripts

Uwaga. Cóż to? Niektórzy z Was chcą wykonać to zadanie także dla wszystkich plików znajdujących się w podfolderach C:\Scripts? No dobrze; w takim przypadku, po prostu dodajemy parametr recurse do polecenia Get-ChildItem:

$a = Get-ChildItem C:\Scripts -recurse

Następnie uruchamiamy pętlę For Each, która przejdzie przez wszystkie elementy znajdujące się w naszej kolekcji. Wewnątrz tej pętli najpierw wykonujemy poniższy wiersz kodu:

$y = ((Get-Date) - $x.CreationTime).Days

Pomimo, iż na początku skrypt mógł wydawać się dziwny, teraz wszystko powinno już być jasne.

Co się zatem teraz dzieje? No cóż, na początek, stosujemy polecenie Get-Date w celu pobrania bieżącej daty i godziny. (Zauważcie, że Get-Date znajduje się w nawiasach; dzięki temu najpierw otrzymamy bieżącą datę i godzinę.) Mając datę i godzinę, pobieramy wartość właściwości CreationTime pierwszego elementu i odejmujemy ją od wartości pobranej przez Get-Date. To równanie, jak wiemy, da nam obiekt TimeSpan; mając ten obiekt, zabieramy wartość właściwości Days i zachowujemy ją w zmiennej o nazwie $y.

Macie rację: to tylko wydaje się skomplikowane. W rzeczywistości jest bardzo proste.

Teraz przechodzimy do następującego wiersza kodu:

if ($y -gt 90 -and $x.PsISContainer -ne $True)

Dzieją się tu dwie rzeczy. Po pierwsze, zmienna $y informuje nas o liczbie dni pomiędzy bieżącą datą i godziną, a datą i godziną utworzenia pierwszego elementu w naszej kolekcji. My chcemy sprawdzić, czy ta wartość jest większa niż (-gt) 90; jeżeli tak, dany element jest kandydatem do usunięcia.

Dlaczego tylko „kandydatem” do usunięcia? No cóż, chcemy tylko usunąć pliku, a nie foldery. W tym miejscu wkracza poniższy wiersz kodu:

$x.PsISContainer -ne $True

Upewniamy się teraz po prostu, że właściwość PsISContainer nie ma wartości (-ne) True (reprezentowanej przez wbudowaną w powłokę PowerShell zmienną $True). Jeżeli PsISContainer ma wartość True, oznacza to, że mamy do czynienia z folderem, a nie chcemy mieć do czynienia (ani usuwać) folderów. Jeżeli właściwość PsISContainer ma wartość False, wszystko w porządku: mamy do czynienia z plikiem.

Zatem przypuśćmy, że mamy plik, który ma więcej niż 90 dni; co teraz? No cóż, w takim przypadku wystarczy wywołać metodę Delete i usunąć ten plik:

{$x.Delete()}

Potem wracamy na początek pętli, gdzie powtarzamy proces dla następnego elementu w kolekcji. Teraz wprawdzie mógłbym uprościć nieco ten skrypt (A może jednak nie; to tylko kwestia estetyki, nic więcej.) Jednakże, obrałem tę właśnie ścieżkę, żeby złapać dwie sroki za ogon: pokazać Wam podstawy arytmetyki powłoki PowerShell oraz usunąć wszystkie stare pliku znajdujące się w folderze.

Tak czy inaczej, mam nadzieję, że odpowiedziałem wyczerpująco na Twoje pytanie JN.

 Do początku strony Do początku strony

Centrum skryptów - Systemu operacyjne