Share this post:

Hey, Scripting Guy! QuestionHey, Scripting Guy! At work we have a series of folders that are used to store files for a month. At the end of the month, we need to delete all of the files that are in the folders and start over. The folder structure is very nested; therefore, I do not want to have to recreate all of the folders, subfolders, and even more subfolders. Because of all the subfolders that I have to click, it takes me more than an hour to clean out these files. Worse than the amount of time it takes, I have to get up at 12:01 A.M. on the first of each month to remote into work and delete these files. I could create a scheduled task to do this, but I need to keep the subfolders. If you can figure out how to do this, I would greatly appreciate it.

-- EM

Hey, Scripting Guy! AnswerHello EM,

Microsoft Scripting Guy Ed Wilson here. Today is a coffee day for me. I look forward to having a coffee day about once a quarter. I don't schedule them on my Outlook 2010 calendar as recurring appointments, but I do plan them in advance. Last night as I finished reading The Fountainhead (if you have friended me on Facebook, you know about that already), I thought to myself, “I think tomorrow will be a coffee day.”

There is nothing more disappointing than looking forward to coffee and not having the required supplies, so I sauntered into the kitchen to check on my stash of Kona Peaberry coffee beans, coffee grinder, and French press. Fortunately, all was in readiness, and coffee day sprung forth with a light spring in the air. Because I really appreciate a good cup of coffee and tend to linger long over the aroma, I do not mind the extra manual work involved in making the perfect cup of coffee: grinding beans, slowly filling the French press with the almost boiling fresh spring water, pre-heating the milk, and measuring out the exact weight of Turbinado sugar.

If I had to make coffee every morning, I would probably grab some type of plastic coffee pot, set it on a timer, stuff a coffee baggie/filter combo pack into the slot, and wake up in the morning to a fresh pot of coffee. In other words, I would automate the task as much as possible. And because I suspect you do not savor the prospects of waking up at midnight to delete files from a nested folder structure, I will be glad to help you automate your task.

This week, we are looking at questions that have been posted to the Official Scripting Guys Forum. This forum is a great place to ask questions related to VBScript or Windows PowerShell. It is also an excellent resource for learning scripting by reading answers to others’ questions or by becoming involved in discussions through posting answers. In addition to being a learning resource, the forum is also a fun place to interact with people from around the world who have an interest in scripting. The Official Scripting Guys Forum is free. If you wish to post a question or propose an answer to a question, you will need to log in with your Windows Live ID.

EM, interestingly enough this question came up recently:

Image of question posted in the forum

To begin with, a nested folder structure is one that might look something like the one shown here.

C:\test\fso1
C:\test\fso2
C:\test\fso2\fso3
C:\test\fso2\fso3\fso4

If each of the folders contains various files, as seen in the following image, you can have problems trying to clean out the folders to make room for a new batch of data. EM, your scenario is one that is often used by applications that do file routing. It is also common for certain accounting types of applications to store invoices in folders that are batch-processed on a schedule. The problem in your case is that the application is not well behaved enough to clean up after itself.

Image of each folder containing various files

The trick to deleting the files and not the folders is to use the PSIsContainer attribute from either the file or the folder object. To retrieve the properties of the folder object, use the Get-Item cmdlet and pipe the results to the Format-List cmdlet while using a wildcard character to select the properties. We use the Format-List cmdlet instead of the Get-Member cmdlet to look at the properties of the folder object because we want to see sample values of the properties. Often the properties of the object do not display meaningful data. By piping the object returned from the Get-Item cmdlet to the Format-List cmdlet, you are able to see if the property will be useful for your specific purposes. This is seen here:

PS C:\> Get-Item –path C:\test | Format-List -property *


PSPath            : Microsoft.PowerShell.Core\FileSystem::C:\test
PSParentPath      : Microsoft.PowerShell.Core\FileSystem::C:\
PSChildName       : test
PSDrive           : C
PSProvider        : Microsoft.PowerShell.Core\FileSystem
PSIsContainer     : True
Mode              : d----
Name              : test
Parent            :
Exists            : True
Root              : C:\
FullName          : C:\test
Extension         :
CreationTime      : 11/19/2008 10:53:02 AM
CreationTimeUtc   : 11/19/2008 3:53:02 PM
LastAccessTime    : 8/28/2009 2:47:06 PM
LastAccessTimeUtc : 8/28/2009 6:47:06 PM
LastWriteTime     : 8/28/2009 2:19:19 PM
LastWriteTimeUtc  : 8/28/2009 6:19:19 PM
Attributes        : Directory

The C:\test directory returns true for the PSIsContainer property. Because you are only interested in the value of the PSIsContainer property, you can select it directly by using property notation. This is seen here:

PS C:\> (Get-Item C:\test\__Chapter_Template.doc).psiscontainer

False

PS C:\>

EM, we have now found the information we need to write your script. But before we start deleting everything, it is a good idea to perform a test run to see what might be deleted. To do this, pipeline the results to the Select-Object cmdlet and choose the FullName property. This is seen here:

Get-ChildItem -Path C:\Test -Recurse -force |

Where-Object { -not ($_.psiscontainer) } |

Select-Object FullName

When the command is run, an output similar to the following is displayed. You will notice that files in the root directory are deleted as well as files in the subfolders:

Image of output of the command

The single command to clean up all the files from the folders is seen here:

Get-ChildItem -Path C:\Test -Recurse -force |

Where-Object { -not ($_.psiscontainer) } |

Remove-Item –Force

The recurse switched parameter is used to cause the Get-ChildItem cmdlet to work its way through all the subfolders. The force switched parameter is used to cause the hidden and system files to be visible to the Get-ChildItem cmdlet. The Where-Object cmdlet is used to filter items that are not PSIsContainers (in other words, files). The Remove-Item cmdlet is used to delete the files. The force switched parameter is required because some of the files to be deleted might be read-only files.

If you put the Windows PowerShell command on a single line (I use Notepad to do this) and call that command by the Windows PowerShell executable while passing the command switch and a script block, you have a format you can use directly inside a scheduled task. Before you go to the trouble of creating a scheduled task, paste the command into the Run dialog box to see if it works. If it does, you can paste the command into the Scheduled Task tool when create a scheduled task. You will never have to wake up at midnight to delete files again. The syntax would look like this—remember it is really a single line:

PowerShell -command &{ Get-ChildItem -Path C:\Test -Recurse -force | Where-Object { -not ($_.psiscontainer) } | Remove-Item -Force }

After you have completed the Scheduled Task wizard, you can open the scheduled task and examine its properties. This is seen here:

Image of properties of scheduled task

Of course, you can write a Windows PowerShell script to create scheduled tasks as well, but for a single scheduled job like this, I personally would use the GUI tool to create the task.

EM, thank you for your question you sent to scripter@microsoft.com. It was a great question, especially because it had already been answered in the Official Scripting Guys Forum. Join us tomorrow as Forum Week continues.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, keep on scripting.

Ed Wilson and Craig Liebendorfer, Scripting Guys