VBScript cannot delete folder - file-io

I have a VBScript program that creates a folder in the user's temp folder:
set fso = CreateObject("scripting.FileSystemObject")
temp = fso.GetSpecialFolder(2)
dropzone = temp & "\{d450c76c-2ad8-4f73-af8a-ccc5ba28036a}\"
If Not fso.FolderExists(dropzone) Then
set NewFolder = fso.CreateFolder(dropzone)
End If
set NewFolder = Nothing
At the end of the program, I would like to delete that folder. I tried this but it gives me a permission denied error:
set deletefolder = fso.GetFolder(dropzone)
deletefolder.Delete(True)
set fso = Nothing

No, not a problem with timing
No, not a problem with dispose
No, not a problem solved by MsgBox
No, not a problem with attributes
No, not a problem with current directory path
No, can't use Kill
No, it's not access denied
No, you don't have to shell out
No, MSDN documentation won't tell you
YOU JUST HAVE TO DELETE THE TRAILING BACKSLASH IN THE PATH BECAUSE DELETEFOLDER DOESN'T LIKE IT.
Now, feel free to shoot the messenger ...

#giodamelio Weirdly enough, I put the line msgBox dropzone before your code and it worked. When I comment out the msgbox it wont work?
Your code or pc is too fast! :D
You probably don't dispose/close files you use or store in that folder (or not closed correctly)

Check the attributes of the file and set to 0 if it's not already set.
set deletefolder = fso.GetFolder(dropzone)
if deletefolder.Attributes=0 then
deletefolder.Delete(True)
else
deletefolder.Attributes=0
deletefolder.Delete(True)
end if
set fso = Nothing

It's very, very probably not an actual "access denied". More likely it's an "can't delete while files are open". Close any open references to that folder (text streams, processes you might have started, look carefully) and do
fso.DeleteFolder(dropzone)
See MSDN documentation on DeleteFolder().

try to use Kill("folder path")

for DeleteFolder to work, the current directory for the script should not be a part of the path of the folder to be deleted.
Use Shell.CurrentDirectory to change the current directory to some system path and then call DeleteFolder.
I have verified that this works.
Check this.

If your folder path has a backslash, the method will throw an error! Most of my scripts have a backslash at the end of paths purposely using another function, so I removed the last character of my path (backslash) and viola!

Related

How to get DirectoryInfo for a Onedrive folder with VB.net

I have some code that uses System.IO to find files with a given extension. This works fine with regular folders but fails when the files are in Onedrive's local cache.
My assumption is that the problem is to do with the Onedrive cache folder because if the files are moved out of Onedrive and into a local folder e.g. c:\temp, it all works fine.
Dim Folder As New IO.DirectoryInfo(TextBox_RootFolder.Text)
Filelist = Folder.GetFiles("*.xlsx", IO.SearchOption.AllDirectories)
This is VB, so I believe there should not be any issues with string literals, so I'm stumped.
The path string comes out as something similar to: "C:\Users\user\OneDrive - ThisPlace\MyFolder" so there's nothing particularly weird about the string.
When presented with a folder on Onedrive, my variable 'Folder' is correctly assigned with the full path but an exception is thrown on calling Folder.Getfiles. This results in the error "The tag present in the reparse point buffer is invalid".
BTW, I'm a novice so example code would be really appreciated as a detailed technical explanation is likely to go whoosh over my head.
I'm please to report that I found an easy way to solve the problem.
Firstly I retained the code that uses Folder.Getfiles to provide a list of files as this is fast, elegant and retrieves files in sub-folders.
It still throws an exception when it encounters a cloud sync folder such as Onedrive, DropBox etc., so in the catch I use the Dir() function to loop through the files as this does not have problems with folders of this type.
Here is some pseudo-code to show an example:
Dim sFile As String
sFile = Dir(sPath + "\*.xlsx")
Do While sFile <> ""
[ do stuff here ]
sFile = Dir() '' Get the next file
Loop
I hope this is helpful to someone.

Folder handle not released after Dir checks for existence

The following code checks to see if a folder exists and, if not, creates it. The code works, but a handle that points to the folder is left open if it already exists, which prevents the folder from being deleted or renamed until Outlook.exe closes. I do not understand why this is happening or what to do about it, but a handle should not be open after the folder is checked and potentially created.
Sub Test()
Folder = Environ("USERPROFILE") & "\Desktop\NewFolder\"
Result = Dir(Folder, vbDirectory)
If Result = vbNullString Then
MkDir Folder
End If
End Sub
The first time through the code, the folder is successfully created and no file handles are open:
However, the second time through the code, the folder already exists. MkDir does not execute, but a file handle is left open presumably after Dir executes:
I have tried everything I could find to close all open file handles, but nothing has worked. Any help would be greatly appreciated.
Based on the comments from braX, I was able to prove that the Dir call was somehow responsible for the leftover handle. Calling Dir again on a non-existent folder caused the handle to be released, which solved my problem.
A better solution, which was also suggested by braX, is to use a File System Object. Here is a working solution:
Sub Test()
Dim FSO As FileSystemObject
Set FSO = CreateObject("Scripting.FileSystemObject")
Folder = Environ("USERPROFILE") & "\Desktop\NewFolder\"
If Not FSO.FolderExists(Folder) Then
MkDir Folder
End If
End Sub
Thanks, braX!

Check if directory exists, but string is relative path

I am currently writing a program to check if hyperlinks in a file are broken. Some hyperlinks go directly to folders on a mapped drive.
I want to use dir() to check if the folder exists, but Excel shortens the string to the relative version "../../Random folder/Another random folder"
This string returns "" so my function thinks the folder does not exist, but it does and its link functions properly.
Any help is greatly appreciated.
Thanks!
I believe you need to use the overloaded function of Dir and specify vbDirectory as the additional argument. I believe it should look something like this:
If Dir("X:\random directory\other random directory", vbDirectory) = "" Then

Permission Denied Error During Update of a Local MSOffice Add-In from Network

I am attempting to write a procedure in PowerPoint 2003 that will allow automatic updating of an installed add-in. The general process is as follows:
Uninstall the add-in
For Each objAddIn In Application.AddIns
If UCase(objAddIn.Name) = UCase(AddInName) Then
With objAddIn
.Registered = msoFalse
.AutoLoad = msoFalse
.Loaded = msoFalse
End With
End If
Next
Delete the file from the local Add-Ins directory
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(FileName) Then
Set objFSO = Nothing
Kill FileName
End If
Copy over the file from the network location
Install the updated add-In
Upon reaching step 2, any attempt at deleting the file post-uninstall using either the FileSystemObject or a straight Kill inevitably generates Run-time error '70': Permission denied. If I hit Debug and then play, it runs through as if there was never a problem.
Side note: I realize I can use FSO to overwrite the local file, but that gives me the same run-time error.
I'm guessing the problem has to do with some aspect of the file being in use, but I can't figure out how to "release" the old add-in so that the underlying file can be deleted.
Does anyone have insight that can help?
You need to remove it from the Addins Collection before it can get physically deleted. Put this, right after your End With:
Application.AddIns.Remove objAddIn.Name
The KB Article that refers to a VBA function you can use to CHECK for a locked file is here.
http://support.microsoft.com/kb/209189
It contains a simple function you can add to your VBA to check that a file is not locked and uses the same code sample that Otaku refers to in his answer.
What I would do is...
Replace the Kill Filename line in your code
If FileLocked(Filename) = True Then
SetAttr Filename, vbNormal
Kill Filename
End If
*Where FileLocked is a custom function referred to in KB209189
**If this doesn't work, reply back, we could also look at replacing the Kill statement above with a lower level Win32 function that does the same thing (but perhaps more throughly). :D

Deleting a file in VBA

Using VBA, how can I:
test whether a file exists, and if so,
delete it?
1.) Check here. Basically do this:
Function FileExists(ByVal FileToTest As String) As Boolean
FileExists = (Dir(FileToTest) <> "")
End Function
I'll leave it to you to figure out the various error handling needed but these are among the error handling things I'd be considering:
Check for an empty string being passed.
Check for a string containing characters illegal in a file name/path
2.) How To Delete a File. Look at this. Basically use the Kill command but you need to allow for the possibility of a file being read-only. Here's a function for you:
Sub DeleteFile(ByVal FileToDelete As String)
If FileExists(FileToDelete) Then 'See above
' First remove readonly attribute, if set
SetAttr FileToDelete, vbNormal
' Then delete the file
Kill FileToDelete
End If
End Sub
Again, I'll leave the error handling to you and again these are the things I'd consider:
Should this behave differently for a directory vs. a file? Should a user have to explicitly have to indicate they want to delete a directory?
Do you want the code to automatically reset the read-only attribute or should the user be given some sort of indication that the read-only attribute is set?
EDIT: Marking this answer as community wiki so anyone can modify it if need be.
An alternative way to code Brettski's answer, with which I otherwise agree entirely, might be
With New FileSystemObject
If .FileExists(yourFilePath) Then
.DeleteFile yourFilepath
End If
End With
Same effect but fewer (well, none at all) variable declarations.
The FileSystemObject is a really useful tool and well worth getting friendly with. Apart from anything else, for text file writing it can actually sometimes be faster than the legacy alternative, which may surprise a few people. (In my experience at least, YMMV).
I'll probably get flamed for this, but what is the point of testing for existence if you are just going to delete it? One of my major pet peeves is an app throwing an error dialog with something like "Could not delete file, it does not exist!"
On Error Resume Next
aFile = "c:\file_to_delete.txt"
Kill aFile
On Error Goto 0
return Len(Dir$(aFile)) > 0 ' Make sure it actually got deleted.
If the file doesn't exist in the first place, mission accomplished!
The following can be used to test for the existence of a file, and then to delete it.
Dim aFile As String
aFile = "c:\file_to_delete.txt"
If Len(Dir$(aFile)) > 0 Then
Kill aFile
End If
In VB its normally Dir to find the directory of the file. If it's not blank then it exists and then use Kill to get rid of the file.
test = Dir(Filename)
If Not test = "" Then
Kill (Filename)
End If
set a reference to the Scripting.Runtime library and then use the FileSystemObject:
Dim fso as New FileSystemObject, aFile as File
if (fso.FileExists("PathToFile")) then
aFile = fso.GetFile("PathToFile")
aFile.Delete
End if
Here's a tip: are you re-using the file name, or planning to do something that requires the deletion immediately?
No?
You can get VBA to fire the command DEL "C:\TEMP\scratchpad.txt" /F from the command prompt asynchronously using VBA.Shell:
Shell "DEL " & chr(34) & strPath & chr(34) & " /F ", vbHide
Note the double-quotes (ASCII character 34) around the filename: I'm assuming that you've got a network path, or a long file name containing spaces.
If it's a big file, or it's on a slow network connection, fire-and-forget is the way to go.
Of course, you never get to see if this worked or not; but you resume your VBA immediately, and there are times when this is better than waiting for the network.
You can set a reference to the Scripting.Runtime library and then use the FileSystemObject. It has a DeleteFile method and a FileExists method.
See the MSDN article here.
A shorter version of the first solution that worked for me:
Sub DeleteFile(ByVal FileToDelete As String)
If (Dir(FileToDelete) <> "") Then
' First remove readonly attribute, if set
SetAttr FileToDelete, vbNormal
' Then delete the file
Kill FileToDelete
End If
End Sub