Friday, April 20, 2012

File paths and backslashes

If you stumbled across this post, be glad you did.  There are a few times in a scripters life where a script goes out and something breaks.  Usually it’s the code not working and it’s a matter of finding the bug and fixing it.  And then there is a worst case scenario where your code breaks every computer in the company.

This is that case.

Now before I continue, I should stress the script in question was not created by me.  I’m very careful about file paths but this particular coder was not.

So this person’s script, let’s call him Bob, had a sub routine that was designed to take in a folder path, enumerate the files in that path, and delete them.  Many of us have similar code and there is certainly nothing wrong with putting this in a sub routine.  Let’s look at some example code:

strFolderPath = “C:\Temp”

set objFSO = CreateObject(“Scripting.FileSystemObject”)

set objFolder = objFSO.GetFolder(strFolderPath & “\”)

In the example above, Bob sets the C:\Temp folder path to strFolderPath.  Next he properly initializes the FSO object.  The last line is correct too, however, he appended the file path to add a backslash.  Here’s the problem:  If the strFolderPath variable never gets set, the net file path used by objFSO.GetFolder is “\”. 

Why is a net path of “\” a bad thing?  The script engine treats “\” as a valid file path to the root of the drive.  Now, remember what Bob’s sub routine was designed to do.  After it connected to a valid file path, it enumerated every file in that path and deleted them.  Now you’ve got a real problem.  Then consider that the root folder also contains your boot files.  If that machine reboots, it will not boot back up until those files are replaced.  Now you’ve got an even bigger problem.  Then start thinking about how many machines this code has touched as part of some GPO or logon script and you’ve got one really bad week.

So what should Bob have done?  Well first off, he never should have appended a file path with a backslash.  In the old days of command lines, that was sometimes needed to make copy and delete routines know your target was a folder, not a file.  But the FSO is much more exact that that.  If you tell it to GetFolder, it won’t GetFile.  There is no need for a backslash on the of a file path.  Even if you think you are saving some time, don’t. 

Also, since this was a sub routine, Bob could have added a quick line to the top of his script that would have checked the folder path variable before doing anything with it.  Such as If Not objFSO.FolderExists(strFolderPath) Exit Sub.  It’s not the most elegant way to check but it would have prevented the problem.  If you absolutely knew you’d never ever connect to the root of a drive to delete files, you could even add   If Len(strFolderPath) <4 Then Exit Sub.   This would also have worked since the root paths are generally in the format of C:\.

So remember, be very careful in your file paths and if you are ever deleting files from FSO, remember to always try and break your own code before someone else does.

4 comments:

Anonymous said...

Hi Corey! Very good blog site. You mentioned before about adding HTA information. I'd really like to see what you have to say about that. I struggle to understand how to write a visually appealing html application (hta). The scripting side I'm okay with, but putting it all together doesn't quite for for me. Any help on HTAs?

DaveK said...

Very good blog. You mentioned before about adding HTA information. I'd really like to see what you have to say about that. I struggle to understand how to write a visually appealing html application (hta). The scripting side I'm okay with, but putting it all together doesn't quite for for me. Any help on HTAs?

Corey Thomas said...

Hi DaveK,

Sorry for the slow response! The best tip I can give you for making an appealing HTA is to use a simple WYSIWYG html editor. There are many free ones out there so take your pick. Start by designing your basic layout and then adding elements. Each element can be modified by your code. For example, you can add items to a form, you can hide/show buttons, you can hide show DIV tags. Typically I set all my elements in an individual DIV tag. Then I write the code to the tag. This also lets me hide and show the DIV so I can have tabbed solutions, or info popups, etc.

Keep in mind that HTA runs in a very scaled down version and some tags are unavailable. You will still find DIV tags which are your best friend. Tables of course still work as well as embedded javascript. You can also use embedded and inline CSS. I've used all of these in an HTA tool I wrote several years back. It has tabs, refreshing time in a status bar, a scrolling newsbox, and more.

A few more tips:
1. If this is going to be more "app like", specify a window size (window.resizeTo xxx,xxx)
2. Check out the HTA:APPLICATION variables you can set.
3. You CAN encode your vbscript! Despite what some may.
4. Don't forget to set the Title Bar
5. In HTA, you can use a mix of vbscript and javascript. You can also cross call functions between the two and use standard HTML javascript functions (like window.resizeTo from above).

Good luck and have fun! If you need help let me know.

-Corey

Corey Thomas said...

One more thing to add, check out sites like http://www.dynamicdrive.com for useful menus, buttons, DIVs, and containers. This will help you make your HTA feel more like an actual application!