Created
June 11, 2024 20:08
-
-
Save Bill-Stewart/cbe4596e00e49b62ee7a34616d237599 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Renamer.js | |
// Written by Bill Stewart (bstewart AT iname.com) | |
// | |
// Renames files and/or directories using regular expressions. | |
var SCRIPT_NAME = "Renamer.js", | |
ERROR_INVALID_PARAMETER = 87; | |
var FSO; | |
WScript.Quit(main()); | |
// Displays a usage message and exits the script. | |
function usage() { | |
WScript.Echo("Renames files and/or directories using regular expressions.\n" | |
+ "\n" | |
+ "Usage:\t" + SCRIPT_NAME + " <directory> [...] [/f:<str>] [/r:<str>] [/o:<d|f|df>] [/c]\n" | |
+ "\t[/p] [/s] [/t]\n" | |
+ "\n" | |
+ "<directory> - Specify one or more directory names on the command line\n" | |
+ "/f:<str> - Regular expression to find in file/directory names (default=space)\n" | |
+ "/r:<str> - Replacement string (default=_)\n" | |
+ "/o:<d|f|df> - What to rename? d=directories, f=files, df=both (default=f)\n" | |
+ "/c - Case-sensitive pattern matching (don't ignore case)\n" | |
+ "/p - Prompt to rename each file/directory\n" | |
+ "/s - Recurse through subdirectories\n" | |
+ "/t - Test mode: Only display what will be renamed\n" | |
+ "\n" | |
+ "USE THIS SCRIPT WITH EXTREME CAUTION. It can potentially render a system\n" | |
+ "unbootable by renaming system files/directories, and it can break applications\n" | |
+ "by renaming critical files/directories.\n" | |
+ "\n" | |
+ "The script does not test whether a directory or a file's new name is valid\n" | |
+ "before attempting to rename it, so test mode (/t) may report inaccurate results\n" | |
+ "if a new name is not valid."); | |
WScript.Quit(0); | |
} | |
// Returns the script host that executing this script, in lowercase | |
// (cscript.exe or wscript.exe). | |
function scriptHost() { | |
return WScript.FullName.substring(WScript.Path.length + 1).toLowerCase(); | |
} | |
// Workalike to VBScript's Hex function. | |
function hex(n) { | |
if ( n < 0 ) { | |
return (n + 0x100000000).toString(0x10).toUpperCase(); | |
} | |
else { | |
return n.toString(0x10).toUpperCase(); | |
} | |
} | |
// Displays a prompt and waits for user input. Returns true if the | |
// user types a string that begins with the letter "y", or false | |
// otherwise. | |
function query(prompt) { | |
WScript.StdOut.Write(prompt); | |
var response = WScript.StdIn.ReadLine().toLowerCase().charAt(0); | |
return response == "y"; | |
} | |
// Renames the specified File or Folder object (o) to a new name. | |
// Returns true if operation succeeded, or false if it failed. Note: | |
// Returns true if options.testMode is true. Errors get output to | |
// stderr. | |
function rename(o,newName,options) { | |
var oldName = FSO.BuildPath(FSO.GetParentFolderName(o),o.Name); | |
try { | |
if ( ! options.testMode ) { | |
if ( options.prompt ) { | |
if ( ! query(oldName + " -> " + newName + " ? ") ) { | |
return false; | |
} | |
} | |
o.Name = newName; | |
} | |
if ( ! options.prompt ) { | |
WScript.Echo(oldName + " -> " + newName); | |
} | |
return true; | |
} | |
catch(err) { | |
WScript.StdErr.WriteLine("Error 0x" + hex(err.number) + " renaming " + oldName + " to " + newName); | |
options.errorCount++; | |
return false; | |
} | |
} | |
// Processes the specified Folder object based on the parameters | |
// passed in the options object. | |
function process(folder,options) { | |
// Process directory names if requested. | |
if ( options.dirs ) { | |
var folderColl = new Enumerator(folder.SubFolders); | |
for ( ; ! folderColl.atEnd(); folderColl.moveNext() ) { | |
var subFolder = folderColl.item(); | |
if ( subFolder.Name.search(options.re) != -1 ) { | |
var newName = subFolder.Name.replace(options.re,options.newStr); | |
if ( rename(subFolder,newName,options) ) { | |
options.dirCount++; | |
} | |
} | |
} | |
} | |
// Recurse if requested. | |
if ( options.recurse ) { | |
var folderColl = new Enumerator(folder.SubFolders); | |
for ( ; ! folderColl.atEnd(); folderColl.moveNext() ) { | |
var subFolder = folderColl.item(); | |
process(subFolder,options); | |
} | |
} | |
// Process file names if requested. | |
if ( options.files ) { | |
var fileColl = new Enumerator(folder.Files); | |
for ( ; ! fileColl.atEnd(); fileColl.moveNext() ) { | |
var file = fileColl.item(); | |
if ( file.Name.search(options.re) != -1 ) { | |
var newName = file.Name.replace(options.re,options.newStr); | |
if ( rename(file,newName,options) ) { | |
options.fileCount++; | |
} | |
} | |
} | |
} | |
} | |
function main() { | |
var args = WScript.Arguments; | |
if ( (args.Unnamed.length == 0) || (args.Named.Exists("?")) ) { | |
usage(); | |
} | |
if ( scriptHost() != "cscript.exe" ) { | |
WScript.Echo("You must run this script using the CScript host"); | |
return 1; | |
} | |
// Create an options object to pass to the process function. | |
var options = { | |
oldStr: "", // String to search for | |
newStr: "", // String to replace it with | |
re: null, // Search regexp | |
recurse: false, // Recurse subdirectories? | |
testMode: false, // Test mode? | |
dirs: false, // Rename directories? | |
files: false, // Rename files? | |
prompt: false, // Prompt before each rename? | |
dirCount: 0, // Number of directories renamed | |
fileCount: 0, // Number of files renamed | |
errorCount: 0 // Number of errors | |
}; | |
// If /f specifies a string to find, use it; | |
// otherwise, default to a space. | |
if ( args.Named("f") != undefined ) { | |
options.oldStr = args.Named.Item("f"); | |
if ( options.oldStr == "" ) { | |
WScript.Echo("Find expression not specified"); | |
return ERROR_INVALID_PARAMETER; | |
} | |
} | |
else { | |
options.oldStr = " "; | |
} | |
// If /r specifies a replacement string, use it; | |
// otherwise, default to an underscore. | |
if ( args.Named("r") != undefined ) { | |
options.newStr = args.Named.Item("r"); | |
} | |
else { | |
options.newStr = "_"; | |
} | |
if ( options.oldStr == options.newStr ) { | |
WScript.Echo("/f and /r must specify different strings"); | |
return ERROR_INVALID_PARAMETER; | |
} | |
// Test for the presence of /p, /s, and /t. | |
options.prompt = args.Named.Exists("p"); | |
options.recurse = args.Named.Exists("s"); | |
options.testMode = args.Named.Exists("t"); | |
// /t takes precendence over /p. | |
if ( options.testMode ) { | |
options.prompt = false; | |
} | |
// If /o specifies something, see if d and/or f are specified as | |
// arguments. Otherwise, assume /o:f. | |
if ( args.Named.Item("o") != undefined ) { | |
options.dirs = args.Named.Item("o").toLowerCase().indexOf("d") != -1; | |
options.files = args.Named.Item("o").toLowerCase().indexOf("f") != -1; | |
} | |
else { | |
options.files = true; | |
} | |
// Fail if d and/or if not specified after /o. | |
if ( (! options.dirs) && (! options.files) ) { | |
WScript.Echo("You must specify /o:d, /o:f, or /o:df"); | |
return ERROR_INVALID_PARAMETER; | |
} | |
// Create the RegExp containing the find expression. If /c exists | |
// on the command line, don't ignore case. | |
if ( args.Named.Exists("c") ) { | |
options.re = new RegExp(options.oldStr,"g"); | |
} | |
else { | |
options.re = new RegExp(options.oldStr,"gi"); | |
} | |
FSO = new ActiveXObject("Scripting.FileSystemObject"); | |
// Iterate the collection of directories named on the command line. | |
var dirColl = new Enumerator(args.Unnamed); | |
for ( ; ! dirColl.atEnd(); dirColl.moveNext() ) { | |
var dir = dirColl.item(); | |
if ( ! FSO.FolderExists(dir) ) { | |
WScript.Echo("Directory not found - " + dir); | |
} | |
else { | |
process(FSO.GetFolder(dir),options); | |
} | |
} | |
var output = options.testMode ? "\nTest results:" : "\nResults:"; | |
if ( options.dirs ) { | |
if ( options.dirCount == 1 ) { | |
output += "\n1 directory renamed"; | |
} | |
else { | |
output += "\n" + options.dirCount.toString() + " directories renamed"; | |
} | |
} | |
if ( options.files ) { | |
output += "\n" + options.fileCount.toString() + " file(s) renamed"; | |
} | |
if ( options.errorCount > 0 ) { | |
output += "\n" + options.errorCount.toString() + " error(s)"; | |
} | |
WScript.Echo(output); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment