Hey, Scripting Guy! Question

My scripting husband travels a great deal with his job, and he takes these really cool pictures. Unfortunately, he is somewhat lazy about downloading the pictures from the camera. As a result, we have pictures from Hawaii that are named Phoenix_Desert_05.jpg. Obviously, I know the difference between a desert and a beach, but it is rather annoying when trying to show pictures to your friends, and the pictures are named incorrectly. I am talking about thousands of pictures in hundreds of folders. I started renaming them by hand, and then it's like DUH, why don’t I e-mail the scripting guys. My husband talks about you all the time. So what's it gonna be big boy, you gonna help me or not?

- TW

SpacerHey, Scripting Guy! Answer

Hi TW,

Of course we are going to help you. I don’t think I can either write a script to make your husband download the pictures any sooner or write a script to make him take out the trash. However, I can write a script that will rename all the pictures in a folder with the name you select. You will need to copy the Hawaii pictures into a folder called Hawaii, which you can easily do by dragging and dropping. When you are sure you have only Hawaii pictures in the Hawaii folder and only Phoenix_Desert pictures in the Phoenix Desert folder, you run the script.

This week is Desktop Week-a rather vague series of loosely connected articles that may or may not be related to desktops. But the articles were written on a desktop, so maybe that counts. If you want to see some VBScript examples of Desktop Management scripts, check out these scripts in the Script Center Script Repository. The Community-Submitted Scripts Center also has a collection of scripts related to desktop management. In addition, there is the Desktop Management archive of “Hey Scripting Guy!” articles, which include scripts and explanations as well. The scripts this week will be using Windows PowerShell. To download Windows PowerShell and to find getting started information, see the Windows PowerShell hub.

Here is the RenameFiles.ps1 script. To see how to use it, you can type the following commands from within the Windows PowerShell console:

RenameFiles.ps1 –help
RenameFiles.ps1 –min
RenameFiles.ps1 –full
RenameFiles.ps1 -examples

RenameFiles.ps1

Param(
      $path = "C:\fso1",
      $Prefix = "Hawaii",
      $int = 1,
      $extension = ".jpg",
      [switch]$rename,
      [switch]$whatif,
      [switch]$help,
      [switch]$examples,
      [switch]$min,
      [switch]$full   
     )
function Rename-Files()
 {
  $colFiles = get-childitem -path $path
  Foreach($file in $colFiles)
   {
    if(!$file.psIsContainer)
       {
        if ($file.extension -eq ".avi") { "skipping $file" }
        ELSE
         { 
          rename-item -path $file.fullname -newname $Prefix$int$extension
          $int++
         }
       } #end if
   } #end foreach
 } #end rename-Files

function Get-HelpTopic()
{
 $descriptionText= `
@"
 NAME: RenameFiles.ps1
 DESCRIPTION:
 Renames all files in a folder. Useful when
 deleting files from a folder, and then you
 want them to all have unique names in order
 Also useful when merging folders of files and
 you wish to ensure each filename is unique.
 To rename a sequence of files, specify int larger
 than the max number of files in folder, run. Then
 run again beginning with 1.
 This script supports prototyping by using
 the -whatif switch. 

 PARAMETERS: 
 -path path to files to be renamed
 -prefix first part of name to use
 -int beginning number to use in file name
 -extension file extension to use in file name
 -rename causes script to rename the files
 -whatif Prototypes the command
 -help prints help description and parameters file
 -examples prints only help examples of syntax
 -full prints complete help information
 -min prints minimal help. Modifies -help

"@ #end descriptionText

$examplesText= `
@"

 SYNTAX:
 RenameFiles.ps1 

 Displays missing parameter, and calls help

 RenameFiles.ps1  -path c:\pictures\keywest -prefix keywest -int 1 
 -extension .jpg -rename
 Renames all pictures in the c:\pictures\keywest folder to begin with 
 prefix of keywest starting counting with 1 and extnsion of .jpg. 
 Example first picture will be named keywest1.jpg

 RenameFiles.ps1 -path c:\pictures\keywest -prefix keywest -int 1 
 -extnesion .jpg -whatif
 
  Displays what if: Perform operation rename files in c:\pictures\keywest
  using prefix keywest beginning with number 1
  using extension .jpg.
  filenames will be pattern: keywest1.jpg
 
 RenameFiles.ps1 -pa c:\pictures\keywest -pre keywest -int 1 
 -ext .jpg -r
 
  Renames all files in c:\pictures\keywest folder using prefix keywest 
  beginning with number 1 using the extension .jpg. filenames will 
  be in the pattern: keywest1.jpg

 RenameFiles.ps1 -help

 Prints the help topic for the script

 RenameFiles.ps1 -help -full

 Prints full help topic for the script

 RenameFiles.ps1 -help -examples

 Prints only the examples for the script

 RenameFiles.ps1 -examples

 Prints only the examples for the script
"@ #end examplesText

$remarks = `
"
REMARKS
     For more information, type: $($MyInvocation.ScriptName) -help -full
" #end remarks

  if($examples) { $examplesText ; $remarks ; exit }
  if($full)     { $descriptionText; $examplesText ; exit } 
  if($min)      { $descriptionText ; exit }
  $descriptionText; $remarks 
  exit
} #end Get-HelpTopic function

Function Get-WhatIf()
{
 "
  what if: Perform operation rename files in $path
  using prefix $prefix beginning with number $int
  using extension $extension. 
  filenames will be pattern: $Prefix$int$extension
 "
 exit
} #end Get-WhatIf

# Entry Point

if($examples)  { Get-HelpTopic }
if($full)      { Get-HelpTopic }
if($whatif)    { Get-WhatIf }
if($help)      { Get-HelpTopic }
if(!$rename)   {"missing parameter" ; Get-HelpTopic }
if($rename)    { Rename-Files }

The RenameFiles.ps1 script is a rather long script, but most of the length is taken up by the Help topic. The actual code that renames the files is rather short. Let’s start at the beginning, and work our way through the script. The first thing we come to is a series of command-line parameters. The Param statement is used to create command-line parameters. When you have a variable and assign a value to that variable, the parameter has a default value.

This can be quite useful because it allows the script to run with a set of defaults that do not need overriding, which gives you a point-and-click type of functionality. Later, when you have other values you wish to use, you can easily override them from the command line, without the need to physically edit the script. Several of the parameters are switched parameters: They only take effect when they are present on the command line. This adds some safety to the script and offers a variety of flexibility in displaying the Help information. To cause the script to actually rename files, you need to run the script with the –rename switch. If you want to see what the script would do, you can run it with the –whatif switch.

Each of these switches causes the script to execute a different function. The command-line parameters are seen here:

 
Param(
      $path = "C:\fso1",
      $Prefix = "Hawaii",
      $int = 1,
      $extension = ".jpg",
      [switch]$rename,
      [switch]$whatif,
      [switch]$help,
      [switch]$examples,
      [switch]$min,
      [switch]$full   
     )
The Rename-Files function is used to rename the files in the folder. To do this, it uses the Get-ChildItem cmdlet to obtain a collection of all the files in the folder specified by the $path variable. It then uses the ForEach statement to walk through the collection of files. If an item in the collection is a folder (indicated by the psIsContainer property), it is skipped. Also if the file is an .avi file, it is also skipped. Once the function has filtered out the distracters, it calls the Rename-Item cmdlet to rename the file by using the pattern, the prefix, integer, and file extension. The integer is the next number in the sequence starting with the value the $int variable is set to. By default it will start numbering at 1. The $int variable is then incremented by one, and the process starts again. The Rename-Files function is seen here:
 
function Rename-Files()
 {
  $colFiles = get-childitem -path $path
  Foreach($file in $colFiles)
   {
    if(!$file.psIsContainer)
       {
        if ($file.extension -eq ".avi") { "skipping $file" }
        ELSE
         { 
          rename-item -path $file.fullname -newname $Prefix$int$extension
          $int++
         }
       } #end if
   } #end foreach
 } #end rename-Files
 
The Get-HelpTopic function is the longest section of the script. It uses a here string to create the Help topic. The Help topic is stored in different variables and is displayed in response to different command-line switches. This enables the RenameFiles.ps1 script to behave similarly to Windows PowerShell cmdlets. For more information about this technique, you can refer to the Microsoft Press book, Windows PowerShell Scripting Guide.

A here string begins with the @" and ends with "@. There are different sections of the Help text. Each section is assigned to a different variable. The sections are the description, the examples, and the remarks. This is seen here (in a truncated fashion):

$descriptionText= `
@"
 NAME: RenameFiles.ps1
 DESCRIPTION:
"@
$examplesText= `
@"
 SYNTAX:
 RenameFiles.ps1
"@
$remarks = `
"
REMARKS
"@

Depending on which combination of command-line switches was used in launching the script, we will print out the value of the different variables. This evaluation is done by using a series of if statements as seen here:

if($examples) { $examplesText ; $remarks ; exit }
  if($full)     { $descriptionText; $examplesText ; exit } 
  if($min)      { $descriptionText ; exit }
  $descriptionText; $remarks 
  Exit

Did you ever wonder what would happen when you typed a command on the command line? The Windows PowerShell team solved that eternal question by implementing the whatif switch. I thought it was a great idea, and implemented it in the RenameFiles.ps1 script as well. It is useful not only from a "Gee, I wonder what happens when I type this command" but also from a troubleshooting perspective, in that it will display the values of the variables you supply to the script. The Get-Whatif function is called when the script is run with the –whatif parameter. It tells you which operation will be performed, the prefix, the starting integer, file extension, and a sample file name. The Get-Whatif function is seen here:

Function Get-WhatIf()
{
 "
  what if: Perform operation rename files in $path
  using prefix $prefix beginning with number $int
  using extension $extension. 
  filenames will be pattern: $Prefix$int$extension
 "
 exit
} #end Get-WhatIf

The remainder of the script is the actual entry point. It is used to evaluate the command-line switches and to call the appropriate functions. This is seen :

if($examples)  { Get-HelpTopic }
if($full)      { Get-HelpTopic }
if($whatif)    { Get-WhatIf }
if($help)      { Get-HelpTopic }
if(!$rename)   {"missing parameter" ; Get-HelpTopic }
if($rename)    { Rename-Files }

Well, TW, that is it for the RenameFiles.ps1 script. As you can see, even though the script was rather long, it was rather easy to follow. The pattern of using functions to encapsulate the logic for separate pieces of functionality is a pretty good practice. In addition, the Get-HelpTopic function can add a new level of usability to your scripts. We will see you tomorrow when Desktop Week continues.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys