In my last article (Goodbye, Goto), I described how batch files handle common iteration (repeating or looping) and subroutines using the Goto and Call commands, and the most common PowerShell language constructs that replace those commands. Batch files have one last iteration command command that you still need to know how to replace in PowerShell: The For command.

 

The For command was added to Command.com in DOS over 30 years go, and originally it allowed you to run a command for each file in a set (hence the name). When Microsoft released Windows NT, they extended the For command in Cmd.exe into a more general command that can iterate files, directories, text files, and the output of commands. Over time, the Cmd.exe For command has turned into a complex command that has a number of tricky syntax quirks. In this article I’ll discuss how you can can replace each feature of the For command in PowerShell.

Iterating Files and Directories

Cmd.exe. The For /F command iterates files and directories--that is, it runs some command on each file or directory (folder) in a set. The syntax of the Cmd.exe For command to iterate files is as follows:

                              for [/D] %%x in (set) do command [parameters]

The set is a set of one or more files (with or without wildcards), and x is a single case-sensitive letter variable that For substitutes for each matching file’s name when it runs the specified command. The optional /D parameter instructs the For command to match against directory names instead of file names. For example, the batch file command

                              for %%f in (*.txt) do start notepad "%%f"

opens Notepad for each .txt file in the current directory.

There are two things to note about this command. First, it’s good practice to surround the variable with double-quotes (") to prevent parsing problems with the command. Second, if you want to type the command at the Cmd.exe prompt instead of putting the command in a batch file, you need to type only a single % character for the variable, as follows:

                              
for %f in (*.txt) do start notepad "%f"

These are some of the syntax quirks you’re forced to deal with in Cmd.exe.

 

PowerShell. PowerShell uses the ForEach-Object cmdlet to iterate a set of files. To open Notepad for all .txt files in the current directory, you would use the following command:

                              
Get-ChildItem *.txt | ForEach-Object {

  notepad $_

}

The vertical bar (|) character creates a pipeline, and the $_ variable means “the current object from the pipeline.” (For more information about the pipeline, see my article Presenting the PowerShell Pipeline.)

Repeating a Command in Subdirectories

Cmd.exe. The For /R command allows you to repeat a command in a directory tree (i.e., starting at a specific directory and including all of its subdirectories). The syntax is as follows:

                              
for /R ["path"] %%x in (set) do command [parameters]

For example, the batch file command

                              for /R "C:\Program Files" %%p in (*.exe) do echo %%p

will list all of the .exe files in the C:\Program Files directory and its subdirectories.

 

PowerShell. To produce the same output in PowerShell, you can use the the Get-ChildItem cmdlet’s -Recurse parameter:

                              
Get-ChildItem "C:\Program Files\*.exe" -Recurse | ForEach-Object {

  $_.FullName

}

In order to produce the same output as the batch file command, this PowerShell example outputs the FullName property of each object. (For more information about how PowerShell works with objects and output, see my article PowerShell: Objects and Output.)