Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

searching for file in folders/subfolders, permission denied 2

Status
Not open for further replies.

kokser

Programmer
Sep 25, 2009
90
DK
Here is my script
strDir = "C:\Users\dude\Desktop"
Set FSO1 = CreateObject("Scripting.FileSystemObject")
Set objDir = FSO1.GetFolder(strDir)
getInfo(objDir)

Sub getInfo(pCurrentDir)

For Each aItem In pCurrentDir.Files
If LCase(Right(Cstr(aItem.Name), 3)) = "rdp" Then
Set FSO2 = CreateObject("Scripting.FileSystemObject")
Set objFile = FSO2.OpenTextFile(aItem.Name, 1, False, -1)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, "10.30.12.32", "999")
Set objFile = FSO2.OpenTextFile(aItem.Name, 2, False, -1)
objFile.WriteLine strNewText
objFile.Close
End If
Next

For Each aItem In pCurrentDir.SubFolders
getInfo(aItem)
Next

End Sub
This works perfectly fine. It searches the desktop and subfolders for RDP shortcuts, and edits the IP.

I tried changing the strDir to a level higher, so C:\Users\dude\ but then I get Permission Denied at line 8 (first For Each). I tried changing to a bunch of difference paths, but it only works with the desktop path, and I simply cannot figure out why. I AM administrator, I even tried starting the script through cmd running as Administrator. I have checked all the folders in \users\ and made sure I have full control permissions as administrator.
 
paths cannot include an ending "\". It will cause an error.

Also, good practice of defining new objects in new scopes (FSO1 and FSO2). However, make sure to destory the extra object to maintain a "clean house"

Code:
set objFSO2 = nothing

-Geates

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
Thank you for the input. I added the code :)

I tried removing the "\" but I am still denied permission to something in line 8.
 
I think you are using the wrong object. What is pCurrentDir - it's undefined? Don't you mean the folder object, objDir

Code:
Set [green]objDir[/green] = FSO1.GetFolder(strDir)
For Each aItem In [red]pCurrentDir[/red].Files

-Geates

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
I see what you mean. I changed the script according, but nothing appears to have changed.

This still works
[quite]
strDir = "C:\Users\dude\Desktop"
Set FSO1 = CreateObject("Scripting.FileSystemObject")
Set objDir = FSO1.GetFolder(strDir)
getInfo(objDir)

Sub getInfo(objDir)

For Each aItem In objDir.Files
If LCase(Right(Cstr(aItem.Name), 3)) = "rdp" Then
Set FSO2 = CreateObject("Scripting.FileSystemObject")
Set objFile = FSO2.OpenTextFile(aItem.Name, 1, False, -1)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, "10.30.12.32", "999")
Set objFile = FSO2.OpenTextFile(aItem.Name, 2, False, -1)
objFile.WriteLine strNewText
objFile.Close
End If
Next

Set FSO2 = nothing

For Each aItem In objDir.SubFolders
getInfo(aItem)
Next

End Sub
[/quote]

While this gives the same permission denied
strDir = "C:\Users"
Set FSO1 = CreateObject("Scripting.FileSystemObject")
Set objDir = FSO1.GetFolder(strDir)
getInfo(objDir)

Sub getInfo(objDir)

For Each aItem In objDir.Files
If LCase(Right(Cstr(aItem.Name), 3)) = "rdp" Then
Set FSO2 = CreateObject("Scripting.FileSystemObject")
Set objFile = FSO2.OpenTextFile(aItem.Name, 1, False, -1)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, "10.30.12.32", "999")
Set objFile = FSO2.OpenTextFile(aItem.Name, 2, False, -1)
objFile.WriteLine strNewText
objFile.Close
End If
Next

Set FSO2 = nothing

For Each aItem In objDir.SubFolders
getInfo(aItem)
Next

End Sub

Exact error:
Script: C:\Users\dude\Desktop\test.vbs
Line: 8
Char: 1
Error: Permission denied
Code: 800A0046
Source: Microsoft VBScript runtime error
 
I assume you are "dude"? The user, dude, has rights to its child nodes, but not the parent. Put yourself in the local Administrators group and you shouldn't have such issues.

-Geates

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
The user "dude" is the only administrator on this computer (I always rename administrator and delete all other users). I am running the script locally on my laptop for test purposes. This should not be a folder permission issue, as I have made sure to give my user and group Full Control of the Users folder and all subfolders.
 
I assume you are using Windows 7? The All User\Application Data is not a folder, but rather a shortcut to itself. It get caught in an infinate loop and eventually craps out.

Add a msgbox to see what I mean.

Code:
Sub getInfo(objDir)
    [red]msgbox objDir.Path[/red]
    For Each aItem In objDir.Files

-Geates


"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
I did not foresee that! Do you have any ideas to solve this? Perhaps it is possible to exclude a folder from the search?
 
I would exclude the folders. Test the objDir.Name for validity using a function to see if the objDir should be enumerated.

Code:
[red]
dim arrInvalidProfiles(3)

arrInvalidProfiles(0) = "All Users"
arrInvalidProfiles(1) = "Default"
arrInvalidProfiles(2) = "Default User"
arrInvalidProfiles(3) = "Public"
[/red]

strDir = "C:\Users"
Set FSO1 = CreateObject("Scripting.FileSystemObject")
Set objDir = FSO1.GetFolder(strDir)
getInfo(objDir)	

[red]
function isValid(strDir)
    isValid = true
    for each strInvalidProfile in arrInvalidProfiles
        if (objDir.Name = strInvalidProfile) then isValid = false
    next
end function
[/red]

Sub getInfo(objDir)
    [red]if (isValid(objDir.Name)) then[/red]
        For Each aItem In objDir.SubFolders    
            getInfo(aItem)
        Next

        For Each aItem In objDir.Files
            If LCase(Right(Cstr(aItem.Name), 3)) = "rdpj" Then
                Set FSO2 = CreateObject("Scripting.FileSystemObject")
                Set objFile = FSO2.OpenTextFile(aItem.Name, 1, False, -1)
                strText = objFile.ReadAll
                objFile.Close
			
                strNewText = Replace(strText, "10.30.12.32", "999")
                Set objFile = FSO2.OpenTextFile(aItem.Name, 2, False, -1)        
                objFile.WriteLine strNewText        
                objFile.Close    
            End If
        Next
        Set FSO2 = nothing
    [red]end if[/red]
End Sub

msgbox "Done"

Also, I found the iterating folders before files works best.

-Geates




"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
This did not appear to work.

First I tried copy/pasting yours, resulting in a Permission Denied at the first For Each.

I then tried adding more excludes, but was still denied permission to whatever it is.

I see your logic in iterating folders before files, but decided to try and switch it back around, but to no avail. I am still denied permission at the first For Each the script reaches.

I also changed rpdj to rdp.


Now, what if we instead changed Invalid profiles to valid folders.

So instead of excluding certain folders, the script would only search through each user folder and the desktop subfolder. Do you think this might work?

I'm not sure how I'd go about finding usernames and adding them to a validfolders array though..
 
That won't solve your problem because even legitimate profiles (on Windows 7) have a the bogus Application Data shortcut. What you got works. We just need to tweak it so the we bypass folders name "Application Data"

Code:
sub getInfo(objDir)
    if (isValid(objDir.Name)) then
        [red]if (objDir.Name <> "Application Data") then[/red]
             ...
        [red]end if[/red]
    end if
end sub

-Geates

Note: Yes, there is another way to grab "valid" profiles. Each user account (system and human) have a unique identifier called a SID. Luckily, only human user accounts hav a SID beginning with S-1-5-21. Therefore, we can enumerate all SIDs from the registry and work with the ones that begin with S-1-5-21.


"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
Didn't seem to work either :/ I am running out of ideas.

dim arrInvalidProfiles(5)

arrInvalidProfiles(0) = "All Users"
arrInvalidProfiles(1) = "Default"
arrInvalidProfiles(2) = "Default User"
arrInvalidProfiles(3) = "Public"
arrInvalidProfiles(4) = "AppData"
arrInvalidProfiles(5) = "Application Data"

strDir = "C:\Users"
Set FSO1 = CreateObject("Scripting.FileSystemObject")
Set objDir = FSO1.GetFolder(strDir)
getInfo(objDir)

function isValid(strDir)
isValid = true
for each strInvalidProfile in arrInvalidProfiles
if (objDir.Name = strInvalidProfile) then isValid = false
next
end function

Sub getInfo(objDir)
If (isValid(objDir.Name)) Then
If (objDir.Name <> "Application Data") Then
For Each aItem In objDir.SubFolders
getInfo(aItem)
Next
For Each aItem In objDir.Files
If LCase(Right(Cstr(aItem.Name), 3)) = "RDP" Then
Set FSO2 = CreateObject("Scripting.FileSystemObject")
Set objFile = FSO2.OpenTextFile(aItem.Name, 1, False, -1)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, "10.30.12.32", "999")
Set objFile = FSO2.OpenTextFile(aItem.Name, 2, False, -1)
objFile.WriteLine strNewText
objFile.Close
End If
Next
Set FSO2 = nothing
End if
End if
End Sub

msgbox "Done"

 
As a test user, it wasn't until I added him to the administrators group that I got it to mostly work. However, I still got permission denied accessing some folders. I think you need to have full control (maybe ownership) of the drive for it to work correctly.

Or add ... just before each of the for loops in getInfo() to simply blow off the errors. Of course, you wouldn't know how well it worked - or if all.

Code:
on error resume next


-Geates

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
I have made sure that the Administrators group has Full Access to the C: drive and all subfolders. My user is of course an administrator.

I added the on error resume next, and the script did finish. Without changing any RDP files though. I added RDP files at different levels to see if it got any of them.

C:\
C:\Users\
C:\Users\Dude
C:\Users\Dude\Desktop

No RDP files were changed.
 
Is this something that could be added to a logon script? User's would have rights of child files and folders and thus, the rights to change the RDP file.

-Geates

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
I don't know that this will fix all your problems, but based on the last full script that you provided, some observations:
1. You are changing the case of the extension to lower-case, and comparing it to upper-case "RDP"... this will never get a hit
2. You are trying to open a file using its "name" property, which is the only the filename, minus the path... you should use the "path" property":

Code:
        For Each aItem In objDir.Files
            If LCase(Right(Cstr(aItem.Name), 3)) = "[COLOR=blue][b]rdp[/b][/color]" Then
                Set FSO2 = CreateObject("Scripting.FileSystemObject")
                Set objFile = FSO2.OpenTextFile(aItem.[COLOR=blue][b]Path[/b][/color], 1, False, -1)
                strText = objFile.ReadAll
                objFile.Close
                strNewText = Replace(strText, "10.30.12.32", "999")
                Set objFile = FSO2.OpenTextFile(aItem.[COLOR=blue][b]Path[/b][/color], 2, False, -1)
                objFile.WriteLine strNewText
                objFile.Close
            End If
        Next

Another observation:
"On Error Resume Next" will ignore all runtime errors. If you are okay with that as a programmer, meaning, you are expecting runtime errors and are okay with ignoring ALL OF THEM, then fine.

But usually, you are only okay with ignoring certain runtime errors... other runtime errors can screw you up, and ignoring them can mess with the output of your script. Awkward as it may be, you are better off not ignoring all runtime errors, and instead analyzing certain "key" lines of code for runtime errors as follows:

Code:
[COLOR=blue]On Error Resume Next[/color] [COLOR=green]'continue, even if a runtime error happens[/color]
[b][i]One line of code that could generate an error[/i][/b]
[COLOR=blue]If Err.Number <> 0 Then[/color]
   [COLOR=green]'handle the error...[/color]
[COLOR=blue]End If
On Error Goto 0[/color] [COLOR=green]'stop at runtime errors again[/color]

In other words, first suppress runtime errors, then run one line of code that could generate a runtime error, then check if an error has occurred (and handle it if necessary), then undo the "suppress runtime errors" command.

This error handling does not need to be done for every line of code! But some lines (for example, any line invoking the "OpenTextFile" method) are prime candidates for this error handling.
 
I think you are starting to try and fix a lot of things that really work right now.

The script works perfectly fine if I just tell it to run in C:\Users\any username\Desktop

As I want to search through several users on many, many computers, I would simply like to be able to run in C:\Users\ but am somehow denied permission at the first 'For Each' loop (no matter what I put first).

I prefer not to use On Error Resume Next, as it is really not a fix.

Unfortunately this cannot be added to a logon script, as I need to use it on many non-domain computers.
 
kokser said:
I think you are starting to try and fix a lot of things that really work right now.

The script works perfectly fine if I just tell it to run in C:\Users\any username\Desktop

Um, okay. Your last post from 11 Apr 11 2:13 says exactly the opposite, but okay.
 
Guitarzan points out several things we over looked. MOST IMPORTANTLY, the fact that we are comparining a lower-case extension with an upper-case string. Because of this, the IF statement will always be false and thus never run the code within.

I would also agree with guitarzan on using the .Path property to open a file. Even though using just the .Name property seems to work in this case, if the file has certain attributes (system, hidden) or is not within the current directory, objFSO will return an error. It is a good idea to use .Path because this value is absolute to the interpreter, whereas .Name in not absolute and thus can be controversial.

As for error handling, guitarzan makes another good suggestion. I follow a similar practice (with production scripts) for error handling - the last line of a routine does the handling.

Code:
sub mySub
   on error resume next
   ...
   if (err.number <> 0) then msgbox "mySub: " & err.description
end sub

-Geates

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
- Martin Golding

"There are seldom good technological solutions to behavioral problems."
- Ed Crowley, Exchange guru and technology curmudgeon
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top