In "Real-World Scripting: Building a Code Collection," June 2001, InstantDoc ID 20795, I showed you how to build a collection of code snippets, including one-liners. A one-liner is a command sequence that can perform seemingly amazing tasks, given the small amount of code. Here are more practical one-liners that you can use to remove old files, prevent runaway scripts, and prevent other mishaps, such as running a script on the wrong computer.
Teaching Old Commands New Tricks
Have you ever thought a command or utility would be perfect for a job only to discover that it's missing an option that you need? Built-in commands, resource kit tools, and third-party utilities never seem to offer all the functionality you'd like. Fortunately, you can often use one-liners to compensate for the functionality that a command or utility lacks.
For example, suppose you have a large share, J:\public, on which users exchange and store files. Because users often forget to remove old files, you wrote a script, DelOldFiles.bat, which deletes empty folders and files more than 90 days old. For several months, this script kept the share clean. However, you recently noticed that the script hasn't been deleting many of the share's empty folders.
After watching the console during one of the script's scheduled runs, you discover that the message Access is denied appears whenever the script fails to delete an empty folder. Further investigation reveals that some users have discovered that they can keep their empty folders from being deleted by selecting the Read-only check box in the Attributes section of the folders' Properties dialog box.
With management's approval, you set out to change the read-only attribute of these empty folders so that you can delete them. Thinking that the Attrib command would be perfect for this task, you view the command's syntax, which Figure 1 shows, and discover a potential pitfall. With the Attrib command's /s and /d switches, you can change permissions for a folder and its subfolders. However, if you use these switches for J:\public, you'll also change the permissions for all the files, which you don't want to touch.
You determine that the Dir command can be of assistance. The Dir command lists files and folders in directories. By using the command
Dir /a:dr /s /b J:\public
you can locate and list all the read-only folders in J:\public. The /a:dr switch tells the Dir command to list only those items that have the attributes of directory (d) and read-only (r). The /s switch ensures that the list includes all subfolders. The /b switch tells the Dir command to provide bare output—in other words, not to include any headings or summary information.
Next, you need to redirect the Dir command's output to the Attrib command so that you can change the permissions. You can use the command
Attrib -r "%i"
In this command, the r specifies that you want to work with the read-only attribute and the hyphen (-) in front of it specifies that you want to clear that attribute. When set in the For command
For /f "tokens=*" %i in ('Dir /a:dr /s /b J:\public') Do (Attrib -r "%i")
the %i iterator variable will contain each of the read-only folders listed in the Dir command's output.
Finally, you need to log the results. You discover that you can't redirect the Attrib -r command's output to a log, but you can redirect the output of a plain Attrib command. So, you add the Attrib command and redirect its output to the file log.txt with the code
& (Attrib "%i">>C:\temp\log.txt)
The finished one-liner to change the read-only folders' permissions is
For /f "tokens=*" %i in ('Dir /a:dr /s /b J:\public') Do (Attrib -r "%i") & (Attrib "%i">>C:\temp\log.txt)
To use this code in your environment, you need to customize the share (i.e., J:\public) and type the code in one continuous line in the command-shell window. If you want to use this one-liner in a script, you need to add an extra percent sign (%) to the %i iterator variable (i.e., %%i). For information about how to use iterator variables on the command line and in scripts, see "Shell Scripting 101, Lesson 8," August 2001, InstantDoc ID 21984.
After you run this one-liner, you can check the results by viewing the log. If a folder appears in the log, you can tell that the folder's Read-only check box had been selected. If the letter R doesn't precede the folder, you can tell that the one-liner successfully cleared that check box.
Preventing Runaway Scripts
The power of scripting is that a script can perform numerous operations quickly. But that blinding speed can work against you if a script is launched in error. A misplaced double-click or accidentally pressing Enter while a .bat file is selected can send a script into action, copying files, deleting users, or performing some other operation at warp speed. A runaway script can do considerable damage before someone has the chance to cancel it. You can prevent the accidental launching of a script by requiring a password, adding the Pause command, or adding a .txt extension.
Requiring a password. You can prevent runaway scripts by requiring a simple password to launch a script. To launch a script, administrators need to enter the correct password as an argument. For example, if you require the password go to launch DelOldFiles.bat, which is in your machine's Scripts directory, administrators need to type
on the command line. Without the password, the script doesn't run. Thus, the password protects against accidental launching.
To require a password to run a script, you can use the one-liner
@If /i Not '%1'
Place this code at the top of your script. For the code to work, all the code must be on one line. You can replace go with a custom password. The password can be simple and easy to remember because it's not meant for security purposes. Anyone with read permission can open the script and find the password. At the end of your script, you can place an :EOF label if you want. This label is optional because :EOF is a special reserved expression in Windows shell scripting. (For more information about :EOF, see Bob Muzzy, Reader to Reader, "Two Tricks for Batch Files," August 2001, InstantDoc ID 21576.)
Adding the Pause command. Another way to prevent runaway scripts is to use the Pause command. This command displays the message Press any key to continue, then waits for a keystroke. The script won't continue until someone presses a key. By using the Pause command with a message that specifies what the script does and how to cancel or continue the script's execution, you can avoid not only accidental launches but also execution of the wrong scripts. For example, the one-liner in DelOldFiles .bat might be
Echo This script deletes old files and empty folders on J:\public. Press Ctrl+C to exit. Press any other key to continue. & Pause
To use the Pause command one-liner, customize the description of what the script does and place the code on one line at the beginning of the script. Don't use this one-liner (or the Pause command in general) in a script that you plan to run with Task Scheduler. (Task Scheduler comes with Microsoft Internet Explorer—IE—4.x and later.) When you use Task Scheduler, no one is present to press a key, so the script will never finish executing.
Adding a .txt extension. Another way to keep a script from running amuck is to add a .txt extension to its filename after you've executed the script. For example, the script DelOldFiles.bat becomes DelOldFiles.bat.txt. Adding a .txt extension defuses the danger of accidental launches but lets you keep the script's original filename and code intact for future reference and use. To use the script again, you just remove the .txt extension.
Although you can add the .txt extension manually, a simple one-liner will prompt a script to automatically rename itself. The one-liner
Move %0 %0.txt
uses the Move command with %0—an argument-holding environment variable whose value is the script's pathname. By using %0 as the source parameter (i.e., a pathname that specifies the file's current location and filename) and %0.txt as the destination parameter (i.e., a pathname that specifies the file's new location and filename), you're appending the .txt extension to the filename while "moving" the script to the same location.
To use the Move command one-liner, you must place it at the end of your script. It must be the final line of code; any code after it won't execute. When you run the script, you must launch it with the extension specified. For example, when you run the script DelOldFiles.bat, you need to type
on the command line. Typing only
will cause the Move command one-liner to fail.
Because you're changing the name of the .bat file while it's running, you'll likely receive the message The batch file cannot be found. Despite this message, the Move command one-liner will have successfully added the .txt extension.
If you're familiar with Windows shell scripting, you might be wondering why I didn't use the Rename command to add the .txt extension. To use this command to rename a file, you use the syntax
Rename \[drive:\] \[path\] filename1 filename2
As this syntax shows, the Rename command requires the file's path to be stated only once. If you were to use the %0 argument-holding environment variable with the Rename command, you'd be specifying the path twice because %0 contains the complete pathname, thereby causing the command to fail.
Another technique is to use the one-liner
to simply delete the script after it's executed. After all, no one can accidentally launch a script that doesn't exist. Administrators often use this approach for scripts that run locally on users' workstations. After performing a task, a script deletes itself to clean up the user's workstation. However, you need to use extreme caution with this approach. The deleted script won't be in the Recycle Bin. Thus, before you test or use a self-deleting script, make sure that you have another copy of the script. Spending many hours writing a script only to have it permanently disappear during testing or use would be quite upsetting.
Sometimes, an administrator might intentionally run a script but run it on the wrong computer. If you want to prevent this mishap, you can use a one-liner that includes an If command with the %Computername% environment variable. Take, for example, the one liner
If /i Not '%Computername%''dom1pdc' Echo You appear to be running this script on the wrong computer. Exiting now. & Goto :EOF
If an administrator tries to run this script on any computer other than dom1pdc, the script displays the message You appear to be running this script on the wrong computer. Exiting now. Then, the script goes to the end of the file and exits.
Similarly, you can use an If statement with the %Username% environment variable to test the administrator's logged-on username:
If /i Not '%Username%'=='fredr' Echo You appear to be running this script in the wrong user context. Exiting now. & Goto :EOF
In this case, if an administrator tries to run this script under any other username than fredr, the script displays the message You appear to be running this script in the wrong user context. Exiting now. Then, the script goes to the end of the file and exits.
To use the one-liner that tests for a computer name or username, you need to customize the computer name or username. Then, you need to place the code all on one line at the beginning of the script.
Shorter Is Better
As these sample one-liners show, you don't need lines and lines of code to automate tasks. With just one command sequence, you can perform amazing feats.