Hey, Scripting Guy! How Can I Work with Directories, Files, and Folders by Using Windows PowerShell?

Hey, Scripting Guy! How Can I Work with Directories, Files, and Folders by Using Windows PowerShell?

  • Comments 1
  • Likes

Hey, Scripting Guy! Question

Hey, Scripting Guy! This may not sound too exciting, but I do a lot of work with files and folders. I constantly have to create folders and files, move files, and move folders. This was easy to do by using VBScript, but nevertheless it always required at least six lines of code to do anything. Is it possible to simplify this process by using Windows PowerShell?

- RH

SpacerHey, Scripting Guy! Answer

Hi RH,

I can definitely identify with your desire to simplify things. It is always interesting on a dive boat for example to look at one’s fellow divers. I remember one time while diving off the coast of Maui, Hawaii, in the United States. It was a clear calm day. The water was like glass, and there was not a cloud in the sky. We were doing a shallow dive, less than 40 feet (12 meters) deep. As I was looking around, I saw one guy completely decked out. He had a safety sausage, a signal mirror, a spare air bottle, a spare mask, two flashlights, two slates, two knives, a navigating board, and a camera. Although I am all about safety when diving, this dude was geared up for a night time, drift, wreck dive (an activity that really does not exist). I on the other hand simply took my camera, and I came back with the picture seen just below. My friend on the dive boat came back complaining about the lack of sea life at the site. Perhaps he lost sight of the sea turtles while fussing around with all the gear.

Image of a sea turtle off Maui, Hawaii

 

One of the exciting benefits of using Windows PowerShell and learning how to use the built-in cmdlets is that it frees us from worrying about all the details. We know Windows PowerShell is built upon the .NET Framework. But we often do not have to worry about the .NET Framework classes that are being used. If we are interested in working with files and folders, there are cmdlets we can use to provide this functionality.

This week we are looking at the basics of Windows PowerShell. Windows PowerShell is installed by default on Windows 7 and Windows Server 2008 R2. It is an optional installation on Windows Server 2008 and a download for Windows Vista, Windows XP, and Windows Server 2003. The Windows PowerShell Scripting Hub is a good place to get started with Windows PowerShell.

If we want to produce a listing of all the folders and the dates on which those folders were modified, we can use the FileSystemObject in VBScript and produce a script that is similar to the ListFoldersAndModifiedDates.vbs script. Interestingly enough, RH, it is exactly six lines of code long. You will notice we first create an instance of the FileSystemObject and store it in the objFSO variable. We then return a folder object by using the GetFolder method to connect to the root of the C drive. Next, we return a folder collection by calling the SubFolders method. We then walk through the collection by using the For…Each…Next statement. We then use a trick I came up with several years ago to display both the name of the folder and the date the folder was changed. The trick is to include both properties on the same line as the Wscript.Echo command. The ListFoldersAndModifiedDates.vbs script is seen here:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("C:\")
Set colFOlders = objFolder.SubFolders
For Each subFolder In colFOlders
  WScript.Echo subFolder.Name, subFolder.DateLastModified
Next

In Windows PowerShell we can get a collection of files and folders by using the Get-ChildItem cmdlet. When we use the Get-ChildItem cmdlet without supplying any values for the parameters, it returns a list of all the files and folders in the root directory:

Image of a list of all files and folders returned by the Get-ChildItem cmdlet

 

To return a listing of only directories, you have to determine a way to separate the directories from the files that are returned by the default use of the Get-ChildItem cmdlet. There are actually several ways to do this, but they all involve pipelining the results of the Get-ChildItem cmdlet to the Where-Object cmdlet. Most of the time you can examine the column headings in the display results to find a property that you can use with the Where-Object cmdlet to create a filter for your command. The default column headings used with the Get-ChildItem cmdlet are listed here: Mode, LastWriteTime, Length, and Name. Of the four, the Mode column will be of the most use because it has a "d" in the first position if the item is a directory. You use the Get-ChildItem cmdlet to retrieve the file and folder objects from the root drive. Then you pipeline the objects to the Where-Object cmdlet. Inside the script-block for the Where-Object cmdlet, you use the $_ automatic variable to examine each object as it comes across the pipeline. The property that you are interested in is the mode property. You use the –like operator to perform a wildcard match of any value that begins with the letter "d" and is followed by any other value. The command to list directories off the root drive is seen here:

PS C:\> Get-ChildItem | Where-Object { $_.mode -like 'd*' }

The results of the list directory command are seen here:

Image of the results of the list directory command

 

If you want to exactly replicate the output from the ListFoldersAndModifiedDates.vbs script, you have to pass the results further down the pipeline so that you can reduce the information that is returned. There are two methods that you can use to reduce the information. The first method is to use the Select-Object cmdlet to choose only the Name and the LastWriteTime properties. When you use the Select-Object cmdlet to select certain properties, the object that is returned is a custom object that contains only the properties that you select and the methods that are common to all Windows PowerShell objects. The members of the newly created custom object are shown :

   TypeName: System.Management.Automation.PSCustomObject

Name          MemberType   Definition
----          ----------   ----------
Equals        Method       System.Boolean Equals(Object obj)
GetHashCode   Method       System.Int32 GetHashCode()
GetType       Method       System.Type GetType()
ToString      Method       System.String ToString()
LastWriteTime NoteProperty System.DateTime LastWriteTime=8/17/2008 1:23:10 PM
Name          NoteProperty System.String Name=19287a2cfb60a3bbcca7

It is important to understand the object that is returned by the query so that you can perform additional processing on the object, if you want to do so. The Get-ChildItem command that lists the name and last write time of all the directories off the root drive is shown here. This command is a single command that is broken at the pipeline character for readability:

PS C:\> Get-ChildItem | Where-Object { $_.mode -like 'd*' } | 
Select-Object -Property Name, LastWriteTime

The Get-ChildItem command are shown here:

Image of the results of the Get-ChildItem command

 

You can reduce the typing without sacrificing any of the readability of the command by using dir as the alias for Get-ChildItem, where as the alias for Where-Object, and select as the alias for Select-Object. You can also omit the –property parameter because it is the default parameter for the Select-Object cmdlet. The revised command is shown here:

PS C:\> dir | where { $_.mode -like 'd*'} | select name, lastwritetime

Another way to produce a listing of the name and the last write time of each directory in the root directory is to send the output to the Format-Table cmdlet, as illustrated here:

PS C:\> Get-ChildItem | Where-Object { $_.mode -like 'd*' } | Format-Table -Prop
erty Name, LastWriteTime

The output produced by using the Format-Table cmdlet is almost the same as the output produced by using the Select-Object cmdlet:

Image of the output produced by using the Format-Table cmdlet

 

The problem with using Format-Table to format your output is that if you have to do anything else to the data, you are left with a series of five different format objects that are basically useless for additional data manipulation. Depending on what you are trying to achieve, even the custom Windows PowerShell object that is created by the Select-Object cmdlet will cause you problems. As a best practice you should always perform all data manipulation before sending your object to an output cmdlet.

At this point, in your pipeline you have one last thing that you can easily do: You can send the output to a text file. The easiest way to do this is to use the >> redirection operator as shown here (once again we have broken the single command at the pipeline character for readability):

PS C:\> Get-ChildItem | Where-Object { $_.mode -like 'd*' } | 
Format-Table -Property Name, LastWriteTime >> c:\fso\directoryFile.txt

The text file that is produced by the redirection operator maintains the format that is displayed on the console:

Image of the text file that is produced by the redirection operator

 

Today, we have looked at using Windows PowerShell to simplify working with directories, folders, and files. With the redirection operator, it is easy to write the results of the command to a text file. I hope that you have enjoyed this look at the basics of Windows PowerShell this week. Join us tomorrow for Quick-Hits Friday as we open up the mailbag and see how many questions we can answer in just a few sentences. Until tomorrow, keep cool.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi,

    Great tutorial.
    What I try to accomplish now is to make a script that uses that code and open it automatic in notepad.

    Thanks in advanced