{"id":63683,"date":"2007-11-01T00:11:00","date_gmt":"2007-11-01T00:11:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/11\/01\/hey-scripting-guy-how-can-i-use-windows-powershell-to-delete-all-the-files-in-a-folder-older-than-90-days\/"},"modified":"2007-11-01T00:11:00","modified_gmt":"2007-11-01T00:11:00","slug":"hey-scripting-guy-how-can-i-use-windows-powershell-to-delete-all-the-files-in-a-folder-older-than-90-days","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-use-windows-powershell-to-delete-all-the-files-in-a-folder-older-than-90-days\/","title":{"rendered":"Hey, Scripting Guy! How Can I Use Windows PowerShell to Delete All the Files in a Folder Older Than 90 Days?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/H2>\n<P>Hey, Scripting Guy! In Windows PowerShell, how can I determine the number of days difference between two dates? I want to be able to delete all the files in a folder that are more than 90 days old.<BR><BR>&#8212; JN<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\"><\/A> \n<P>Hey, JN. You know, today is October 31<SUP>st<\/SUP> and, in the US at least, it\u2019s the day when the dark underworld takes over: witches parade through the streets, cackling and laughing; ghosts and goblins cavort on the front lawn; devils and demons come up and ring your doorbell; it\u2019s the one day out of the year when evil truly reigns supreme. In other words, it\u2019s \u2013 no, it\u2019s not the Scripting Editor\u2019s birthday (although that <I>would<\/I> explain a lot, wouldn\u2019t it?). Instead, it\u2019s Halloween.<\/P>\n<TABLE id=\"ECD\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. We just double-checked and it\u2019s <I>not<\/I> the Scripting Editor\u2019s birthday; her birthday is in July. For those of you who like to plan ahead, however, she <I>is<\/I> beginning to run low on eye of newt and toe of frog, although she seems to still have plenty of wool of bat and tongue of dog.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>In the US, Halloween is marked by children dressing up in costumes (the scarier the better) and going around ringing peoples\u2019 doorbells and asking for candy. You know, we\u2019re going to go <I>triple-<\/I>check that date. Now that we think about it, we\u2019re pretty sure that\u2019s exactly what the Scripting Editor did on her last birthday.<\/P>\n<P>For those of you unfamiliar with the holiday, the primary symbol of Halloween is the jack-o-lantern, a symbol you make by hollowing out a pumpkin, carving a face into the hollowed-out gourd, then placing a lighted candle inside. According to legend, the jack-o-lantern got its start many, many years ago, when a drunkard and ne\u2019er do well named Jack tricked the Devil into climbing a tree; once the Devil was safely ensconced in the branches, Jack carved a cross into the tree trunk, something that prevented the Devil from climbing down. Jack agreed to help the Devil down on one condition: that the Devil would never bother him again.<\/P>\n<P>A few years later Jack died, and when he went up to heaven he was denied entrance because of his wicked ways. That sent him \u2026 downstairs \u2026 where he was refused entrance because he had previously tricked the Devil. As a result, Jack was condemned to roam the earth forever although, as a sort of consolation prize, the Devil <I>did<\/I> give him a lighted candle to help him make his way through the dark.<\/P>\n<P>You know what? We\u2019re going to <I>quadruple<\/I>-check that date. That story sounds like it was copied, word-for-word, from the Scripting Editor\u2019s resume.<\/P>\n<P>At any rate, and in the spirit of the occasion, the Scripting Guy who writes this column decided to do something frightening and horrifying for today\u2019s column. And what could be more frightening or more horrifying than a Windows PowerShell script that deletes all the files in a folder more than 90 days old?!?<\/P>\n<P>Well, as it turns out, just about <I>everything<\/I> is more frightening than that:<\/P><PRE class=\"codeSample\">$a = Get-ChildItem C:\\Scripts\nforeach($x in $a)\n    {\n        $y = ((Get-Date) &#8211; $x.CreationTime).Days\n        if ($y -gt 90 -and $x.PsISContainer -ne $True)\n            {$x.Delete()}\n    }\n<\/PRE>\n<P>Before we explain how this works, let\u2019s look at a simpler example, one that merely subtracts two dates. Here\u2019s what <I>that<\/I> sample script looks like:<\/P><PRE class=\"codeSample\">$x = Get-Date\n$y = Get-Date &#8220;1\/1\/2007&#8221;\n$x &#8211; $y\n<\/PRE>\n<P>As you can see, there\u2019s nothing very complicated about this particular script. In the first line, we use the <B>Get-Date<\/B> cmdlet to retrieve the current date and time and store it in a variable named $x. In line 2, we use the Get-Date cmdlet to retrieve a date-time value equivalent to January 1, 2007. Note that we didn\u2019t specify a time when retrieving this second value; consequently, our date-time instance will be given a default time of 12:00:00 AM. What if we <I>wanted<\/I> to specify a particular time? No problem; as the good folks at Nike would say, just do it:<\/P><PRE class=\"codeSample\">$y = Get-Date &#8220;1\/1\/2007 9:45 PM&#8221;\n<\/PRE>\n<P>OK, so we have two date-time values, $x and $y; now what? Well, if we want to determine the time interval between these two dates all we have to do is subtract one from the other. Subtract $y from $x and look what you get back:<\/P><PRE class=\"codeSample\">Days              : 302\nHours             : 9\nMinutes           : 27\nSeconds           : 47\nMilliseconds      : 515\nTicks             : 261268675156250\nTotalDays         : 302.394299949363\nTotalHours        : 7257.46319878472\nTotalMinutes      : 435447.791927083\nTotalSeconds      : 26126867.515625\nTotalMilliseconds : 26126867515.625\n<\/PRE>\n<P>Right there, at the top of the list, is the value we\u2019re looking for; it turns out that there are 302 days between the current date (October 30, 2007, the day this column was written) and January 1, 2007. Not bad, huh?<\/P>\n<P>Well, OK, you\u2019re right: it\u2019s not bad, but it\u2019s not necessarily all that good, either. That\u2019s because we have a lot of extraneous property values (Hours, Minutes, Second, Milliseconds, etc.) that we <I>aren\u2019t<\/I> interested in. But that\u2019s all right; let\u2019s modify the last line of our script and see what happens:<\/P><PRE class=\"codeSample\">($x &#8211; $y).Days\n<\/PRE>\n<P>What have we done here? Well, we\u2019re still subtracting $y from $x; the only difference is that, this time, we\u2019re performing this little bit of date arithmetic inside a pair of parentheses. Why? Well, we need to do two things here. First, we need to subtract one date value from another ($x &#8211; $y); that\u2019s going to give us an instance of the .NET Framework class <B>System.TimeSpan<\/B>. <\/P>\n<P>Second, we want to display just the value of the <B>Days<\/B> property for that TimeSpan object. To ensure that we first get the TimeSpan object and only <I>then<\/I> try to retrieve the value of the Days property we enclose our little arithmetical equation inside a set of parentheses. PowerShell always carries out commands in parentheses before it does anything else; thus it\u2019s going to perform the date calculation first and then, once it has the TimeSpan object, go out and retrieve the value of the Days property.<\/P>\n<P>Will that really work? See for yourself:<\/P><PRE class=\"codeSample\">302\n<\/PRE>\n<P>Now, at long last, we\u2019re ready to talk about the script that deletes all the files in a folder that are more than 90 days old. That script starts out by using the <B>Get-ChildItem<\/B> cmdlet to retrieve a collection of all the objects found in the folder C:\\Scripts, storing that collection in a variable named $a: <\/P><PRE class=\"codeSample\">$a = Get-ChildItem C:\\Scripts\n<\/PRE>\n<TABLE id=\"EXF\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P><B>Note<\/B>. What\u2019s that? Some of you would like to perform this same task against all the files in any subfolders of C:\\Scripts as well? Okey-doke; in that case, just add the <B>\u2013recurse<\/B> parameter to your Get-ChildItem command:<\/P><PRE class=\"codeSample\">$a = Get-ChildItem C:\\Scripts -recurse\n<\/PRE><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Next we set up a foreach loop to loop through all the items in our collection. Inside that loop, the first thing we do is this:<\/P><PRE class=\"codeSample\">$y = ((Get-Date) &#8211; $x.CreationTime).Days\n<\/PRE>\n<P>When we first showed you this script you might have looked at this line of code and said, \u201cUh-oh.\u201d Now, however, you should be able to see exactly what we\u2019re doing here.<\/P>\n<P>So what <I>are<\/I> we doing here? Well, for starters, we\u2019re using Get-Date to retrieve the current date and time. (Note that Get-Date is in a nested pair of parentheses; that ensures that we get the current date and time before we do anything else.) Once we <I>have<\/I> the current date and time we then grab the value of the first item\u2019s <B>CreationTime<\/B> property and subtract that from the value retrieved by Get-Date. That equation, as we know, is going to return a TimeSpan object; once we have that object, we then skim off the value of the Days property and store that value in a variable named $y.<\/P>\n<P>And you\u2019re right: it only <I>sounds<\/I> complicated. In reality, it\u2019s fairly straightforward.<\/P>\n<P>That brings us to this line of code:<\/P><PRE class=\"codeSample\">if ($y -gt 90 -and $x.PsISContainer -ne $True)\n<\/PRE>\n<P>There are two things going on here. First, the variable $y tells us the number of days between the current date and time and the date and time that the first item in our collection was created. What we want to do is check to see if this value is greater than (<B>-gt<\/B>) 90; if it is, then this item is a <I>candidate<\/I> for deletion.<\/P>\n<P>Why just a \u201ccandidate\u201d for deletion? Well, we only want to delete files; we don\u2019t want to delete folders. That\u2019s where this little bit of code comes in:<\/P><PRE class=\"codeSample\">$x.PsISContainer -ne $True\n<\/PRE>\n<P>Here we\u2019re simply making sure that the <B>PsISContainer<\/B> property is not equal to (<B>-ne<\/B>) True (represented by the PowerShell built-in variable $True). If PsISContainer <I>is<\/I> true then that means we\u2019re working with a folder, and we don\u2019t <I>want<\/I> to work with (or delete) folders. If PsISContainer is False, then that\u2019s fine: that means we\u2019re dealing with a file.<\/P>\n<P>So suppose we <I>do<\/I> have a file that happens to be more than 90 days old; what then? Well, in that case, all we have to do is call the <B>Delete<\/B> method and deleted the thing:<\/P><PRE class=\"codeSample\">{$x.Delete()}\n<\/PRE>\n<P>And then it\u2019s back to the top of the loop, where we repeat the process with the next item in the collection.<\/P>\n<P>Now, admittedly, we might have been able to simplify this script a tiny bit. (Or maybe not; that\u2019s more an aesthetic judgment than anything else.) However, we went this particular route so we could kill two birds with one stone: we could show you the basics of PowerShell date arithmetic <I>and<\/I> we could delete all the old files in a folder. Consider this our Halloween treat to the scripting world: two for the price one.<\/P>\n<TABLE id=\"EDAAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. No, we didn\u2019t <I>really<\/I> kill two birds with one stone. That was all done with special effects that combined cleverly-costumed stunt men and computer animation.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Anyway, we hope that answers your question, JN. As for the Scripting Guy who writes this column, he\u2019s going to go home and hand out candy to the trick-or-treaters, despite the fact that he doesn\u2019t really like Halloween. Is that because he\u2019s opposed to devils and demons? Oh, heck no; he works at Microsoft, remember? No, it\u2019s just that Halloween used to be a holiday exclusively for kids, and now many adults have co-opted the day for themselves. In fact, many parents don\u2019t even allow their children to go trick-or-treating; they\u2019re afraid the kids will come back with poisoned candy. (The number of documented cases where children have come home from trick-or-treating with poisoned candy? Zero.) <\/P>\n<P>Instead, the parents hire a babysitter, make the kids stay at home, then <I>the parents<\/I> dress up in costumes and go out and party. The Scripting Guy who writes this column thinks that\u2019s a terrible thing to do to children, which is why he doesn\u2019t really like Halloween anymore.<\/P>\n<P>By contrast, the Scripting Editor <I>loves<\/I> Halloween; she says it\u2019s the one day out of the year when she can \u201creally be herself.\u201d You know what? We\u2019re going to go check that date one last time \u2026.<\/P>\n<TABLE id=\"E3AAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Ed<\/B><B>itor\u2019s Note:<\/B> Just to set the record straight, the Scripting Editor was not born on October 31. Not that it would mean anything negative if she had been \u2013 there are plenty of perfectly normal people out there who were born on Halloween. As for how the Scripting Editor spends Halloween? She spends it handing out candy \u2013 with the help of the Scripting Dog \u2013 to all the kids whose parents <I>do<\/I> let them trick-or-treat. (One year, only about five years ago, that wound up being over 100 kids.)<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! In Windows PowerShell, how can I determine the number of days difference between two dates? I want to be able to delete all the files in a folder that are more than 90 days old.&#8212; JN Hey, JN. You know, today is October 31st and, in the US at least, it\u2019s the [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[38,11,3,12,45],"class_list":["post-63683","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-files","tag-folders","tag-scripting-guy","tag-storage","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! In Windows PowerShell, how can I determine the number of days difference between two dates? I want to be able to delete all the files in a folder that are more than 90 days old.&#8212; JN Hey, JN. You know, today is October 31st and, in the US at least, it\u2019s the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63683","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=63683"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63683\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=63683"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=63683"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=63683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}