So another JScript today that will spit out a comma separated text file listing all the subfolders for a given path and their size.
// folder_size.js - This script generates a csv file with the name
// and size of subfolders for a designated folder.
// Author - Jace Gregg
// Version 1.0 - 04 February 2009
// -----------------------------------------------------------------'
var cTITLE = "Folder Size";
var folderPath = "W:\\"; // This is the root folder - CHANGE THIS
try {
var fso = WScript.CreateObject("Scripting.FileSystemObject");
var objShell = WScript.CreateObject("Wscript.Shell");
var outputPath = objShell.SpecialFolders.Item("Desktop") + "\\" + cTITLE + ".txt"; // THIS IS WHERE YOUR OUTPUT FILE GOES
var folder = fso.GetFolder(folderPath);
var subFolders = new Enumerator(folder.SubFolders)
var fso, f1, ts;
var ForWriting = 2;
fso.CreateTextFile(outputPath);
var file = fso.GetFile(outputPath);
var output = file.OpenAsTextStream(ForWriting, true);
output.WriteLine("Path,Size (bytes)");
for (;!subFolders.atEnd(); subFolders.moveNext())
{
output.WriteLine(subFolders.item() + "," + subFolders.item().size);
}
output.Close();
}
catch(e) {
msgbox("Error " + e.number + "\n\n" + e.description, null, null, 16);
}
function msgbox(message, title, popupTime, nType) {
if(title == null) {
title = "Dawson Scripting: " + cTITLE + " - Folder Size Report Generator";
}
if(popupTime == null) {
popupTime = 0;
}
var objWSH = WScript.CreateObject("Wscript.Shell");
return objWSH.Popup(message, popupTime, title, nType);
}
I’m having to move a Home Folders folder from one server to another and I’m wanting to move the smallest first. This let me get a csv that I could manipulate in Excel and now I’m off to start the migration.
Yeah, I know. JScript is the bane of my existence. It’s really a cool scripting language, but NO ONE USES IT. I’ve spent days trying to convert some code from VBScript to JScript because no one cared enough to write it out in the first place. Today I’ve written a function that allows you to copy the contents of one folder to another without overwriting existing files of the same name at the destination. I’m having to install some old software on a few user’s computers but all they really need are the OCX and DLL files, so we got those put into a common folder. Since these files are old (not touched since at least 1998), we don’t want to overwrite newer files of the same name. There’s no batch command that I can find that will do it, so I wrote a script that looks through the files of the source and compares them one by one to the destination, copying unmatched files to the destination. Here’s the code:
function CopyFiles(SourceFolder, TargetFolder, Overwrite) {
var objFSO = WScript.CreateObject("Scripting.FileSystemObject");
var count = 0;
// handle optional variables
if(Overwrite == null) {
Overwrite = false;
}
if(SourceFolder.substr(SourceFolder.length - 1, 1) != "\\") {
SourceFolder = SourceFolder + "\\";
}
if(TargetFolder.substr(TargetFolder.length - 1, 1) != "\\") {
TargetFolder = TargetFolder + "\\";
}
if(!objFSO.FolderExists(TargetFolder)) {
objFSO.CreateFolder(TargetFolder);
}
var FileNames = new Enumerator(objFSO.GetFolder(SourceFolder).Files);
for(;!FileNames.atEnd();FileNames.moveNext()) {
// check to see if the current file exists at destination
if((objFSO.FileExists(TargetFolder + FileNames.item().Name) && Overwrite) || !objFSO.FileExists(TargetFolder + FileNames.item().Name)) {
objFSO.CopyFile(SourceFolder + FileNames.item().Name, TargetFolder + FileNames.item().Name);
count++;
}
}
return count;
}
Now, it does allow overwriting if you need it to, but it assumes you don’t. Also it doesn’t handle subfolders. It wouldn’t be too hard to add a for loop that uses the Subfolders collection from the Folder object and then call the function recursively, but I don’t need to do that. Hope this helps someone out there.
So, more JScripting… This time I need to map a network drive for a program I’m moving between servers. Currently we’ve got people using a batch file or manually mapping the drive, but on the new server we’ll be applying a script that will handle this through group policy. I figure there’s a need for me to eventually map more than one drive and to also make sure there’s not anything already mapped to another location on the same drive. So I wrote a reusable script that checks through all the user’s mapped drives to see if the one we want is already taken and asks the user if it should reclaim the drive.
// MAP-DRIVE.js - Map Network Drive using provided specifications
// Author - Jace Gregg
// Version 1.0 - 07 January 2009
// -----------------------------------------------------------------'
// Just edit these fields:
//
var cTITLE = "Drive Mapping Script";
var mapDrive = "Z:";
var mapLocation = "\\\\path\\to\\server";
//
// No need to edit past here...
try {
var shouldMap = null;
var WshNetwork = WScript.CreateObject("WScript.Network");
var oDrives = WshNetwork.EnumNetworkDrives();
for(var i = 0; i < oDrives.length; i += 2) {
if(oDrives.Item(i)==mapDrive) {
if(oDrives.Item(i + 1).toLowerCase() != mapLocation) {
// Drive is mapped to another location. Ask the user if we should map to this location.
shouldMap = msgbox("Drive " + mapDrive + " is mapped to \"" + oDrives.Item(i + 1).toLowerCase() + "\" but needs to be
mapped to \"" + mapLocation + "\". Do you want to automatically correct this?", null, null, 4 + 32);
}
else {
shouldMap = false;
}
}
}
if(shouldMap == null) {
shouldMap = true;
}
if(shouldMap) {
WshNetwork.MapNetworkDrive(mapDrive, mapLocation);
}
}
catch(e) {
msgbox("Error " + e.number + "\n\n" + e.description + "\nCould not connect network drive for this application.", null, null, 16);
}
function msgbox(message, title, popupTime, nType) {
if(title == null) {
title = cTITLE;
}
if(popupTime == null) {
popupTime = 10;
}
var objWSH = WScript.CreateObject("Wscript.Shell");
return objWSH.Popup(message, popupTime, title, nType);
}
You could add the ParseEnvironmentStrings method from my previous post and map to user directories or other various locations. Sure it’s not as efficient as it could be, but it does the trick. Feel free to change it to make it more efficient and use it however you want.
So a guy I work with needed to rename a lot of files in a folder to have the extension be upper case. I don’t know why. I don’t really care. I found a VBScript that I could modify to do what I wanted, but since I like JScript better (real error handling is the main reason I use it instead) I decided to convert it. The following is the fruit of my labor:
// BatchFileRename.js - Renames files in a specified folder
// Author - Jace Gregg
// Version 1.0 - 03 December 2008
// -----------------------------------------------------------------
var cTITLE = "Dawson Scripting: Batch File Rename";
try {
var objWMIService = GetObject("winmgmts:\\\\.\\root\\CIMV2");
var filesRenamed = 0;
var colFileList = objWMIService.ExecQuery("ASSOCIATORS OF {Win32_Directory.Name='C:\\temp'} Where ResultClass = CIM_DataFile");
var enumItems = new Enumerator(colFileList);
for (; !enumItems.atEnd(); enumItems.moveNext()) {
var objFile = enumItems.item();
var strNewName = objFile.Drive + objFile.Path + objFile.FileName + "." + objFile.Extension.toUpperCase();
errResult = objFile.Rename(strNewName);
filesRenamed ++;
}
msgbox("Renamed " + filesRenamed + " files.");
}
catch(e) {
msgbox("Error " + e.number + "\n\n" + e.description + "\nCould not rename all files.");
}
function msgbox(message, title, duration) {
if(title == null) {
title = cTITLE;
}
if(duration == null) {
duration = 10;
}
var objWSH = WScript.CreateObject("Wscript.Shell");
objWSH.Popup (message, duration, title);
}
function ParseEnvironStrings(strInput) {
var WshShell = WScript.CreateObject("WScript.Shell");
return WshShell.ExpandEnvironmentStrings(strInput);
}
This code will rename the extensions of all the files in c:\temp to the uppercase version of themselves, but the code could easily be changed to include a year before a date or you could add some regular expressions to fix a lot of problems in your pr0n folders. Up to you.
At the new job, I’m running a small domain for field users. At the old job, EDS had a nifty script that would put the user’s computer name into the office field. I decided to recreate that today because I’m needing to back up computers and I don’t have an index of who’s using which computers readily available. For any who might be interested, here’s the code:
// ComputerName.js - Set the computer name into the Office field in
// Active Directory
// Author - Jace Gregg
// Version 1.0 - 12 November 2008
// -----------------------------------------------------------------
var cTITLE = "Dawson Scripting: Computer Name";
try {
var username = ParseEnvironStrings("%username%");
var computername = ParseEnvironStrings("%computername%")
var cn = "";
var conn = WScript.CreateObject("ADODB.Connection");
var cmd = WScript.CreateObject("ADODB.Command");
conn.Open("Provider=ADsDSOObject;");
cmd.ActiveConnection = conn;
cmd.CommandText = "<ldap ://dc=dawsonfield,dc=local>;(&(objectCategory=User)(samAccountName=" + username + "));samAccountName,cn;subtree";
var rs = cmd.Execute();
if(rs.RecordCount == 0) {
msgbox("sAMAccountName: " + username + " does not exist.");
}
else {
cn = rs.Fields("cn");
msgbox(cn);
}
var objUser = GetObject("LDAP://cn=" + cn + ",ou=FieldUsers,dc=dawsonfield,dc=local");
objUser.Put("physicalDeliveryOfficeName", computername);
objUser.SetInfo();
rs.close();
conn.close();
}
catch(e) {
msgbox("Error " + e.number + "\n\n" + e.description + "\nCould not update computer name.");
}
function msgbox(message, title) {
if(title == null) {
title = cTITLE
}
var objWSH = WScript.CreateObject("Wscript.Shell");
objWSH.Popup (message, 10, title);
}
function ParseEnvironStrings(strInput) {
var WshShell = WScript.CreateObject("WScript.Shell");
return WshShell.ExpandEnvironmentStrings(strInput);
}
Save it as a .js file and run it as a startup script with group policy or some other way. Feel free to use this in your own projects/work. Took me an hour to figure it out, so I imagine someone else might need it too.