VB script file system object "MoveFile" method giving permission denied error - vbscript

I have written a small script to rename a file based on an ID number within. I have never worked with vbs before, so I am still quite unfamiliar with it. I have worked out most of the issues and everything is working correctly up until the MoveFile command at the end. Just for testing purposes, I have the files saved to C:\temp and am trying to moveFile back to C:. Is this not allowed or something?
Here is my code:
Dim objFSO,foldername, folder, objFile, tsfiles, f1, textfile, line, filename, destinationfile
foldername = "C:\Temp"
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set folder = objFSO.GetFolder(foldername)
Set tsfiles = folder.Files
For each f1 in tsfiles
filename = f1.name
textfile = foldername + "\" + filename
If Instr(f1.name, ".TS") <> 0 Then
Set objFile = objFSO.OpenTextFile((textfile), ForReading)
Do Until objFile.AtEndOfStream
objFile.ReadLine
line = objFile.ReadLine
If Instr(line, "RECORDER ID:") <> 0 Then
Dim RID
RID = trim(Mid(line, 15, 15))
destinationfile = foldername + "\" + RID + ".txt"
MsgBox(destinationfile)
objFSO.MoveFile textfile, destinationfile
objFile.close
End If
Loop
End if
Next

You are opening then text file and the you try to move it while it's still open. You'll have to close it prior to moving it.
Also, this ain't specific to vbscript but usually, moving files in the system drive (in your case the C:) requires administrator privileges. I think those rules has been enforced after Windows XP so you may also need to run the script as administrator.

To run as admin you need to right click on it and specifically run as admin.
In your code you are trying to move while it's open. If you close it, thats fie but then it continues to go through the loop and when it tries to access the open file it fails. So you need to close it and break out of the loop. Exit Do will break out of the loop so it doesn't go back and try and evaluate objFile.AtEndOfStream against a closed object.
Dim objFSO,foldername, folder, objFile, tsfiles, f1, textfile, line, filename, destinationfile
foldername = "C:\Temp"
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set folder = objFSO.GetFolder(foldername)
Set tsfiles = folder.Files
For each f1 in tsfiles
filename = f1.name
textfile = foldername + "\" + filename
If Instr(f1.name, ".TS") <> 0 Then
Set objFile = objFSO.OpenTextFile((textfile), ForReading)
Do Until objFile.AtEndOfStream
objFile.ReadLine
line = objFile.ReadLine
If Instr(line, "RECORDER ID:") <> 0 Then
Dim RID
RID = trim(Mid(line, 15, 15))
destinationfile = foldername + "\" + RID + ".txt"
MsgBox(destinationfile)
objFile.close
objFSO.MoveFile textfile, destinationfile
Exit Do
End If
Loop
End if
Next

Related

Saving file into another file using VBScript after modification

I have some XML files in a folder \\demo.US\Modified\. The files in the folder are:
USA.xml
Canada.xml
Mexico.xml
The code below is changing the encoding from UTF-8 to windows-1252 and is creating a modified file mod.xml.
This mod.xml file have data from all three XML files concatenated.
I need help so I can save files separately.
If value of objFile.Name is USA.xml then it should save modified file name as USA_mod.xml. the output for \\demo.US\Modified\ folder after execution is complete should have mod files in it as below.
USA.xml
Canada.xml
Mexico.xml
USA_mod.xml
Canada_mod.xml
Mexico_mod.xml
The code I used is as follows.
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "\\demo.US\Modified\"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile In colFiles
WScript.Echo objFile.Name
Set objFile = objFSO.OpenTextFile(objStartFolder & objFile.Name, 1)
Set outFile = objFSO.OpenTextFile(objStartFolder & "mod.xml", 2, True)
Do Until objFile.AtEndOfStream
strContent = strContent & objFile.ReadLine
Loop
MsgBox strContent
strContent = Replace(strContent, "encoding=""UTF-8""", "encoding=""windows-1252""")
outFile.WriteLine strContent
outFile.Close
objFile.Close
Next
As others have already pointed out, you shouldn't do what you're attempting to do here, because it is very likely to create more problems down the road. Find the cause of the issue and fix that instead of trying to handle symptoms. You have been warned.
With that said, the reason why the content of all input files is written to the same output file is because you always specify the same output file. That file should contain only the content of the last input file, though, because you open the file for writing (thus erasing previous content) rather than for appending.
Replace these lines:
Set objFile = objFSO.OpenTextFile(objStartFolder & objFile.Name, 1)
Set outFile = objFSO.OpenTextFile(objStartFolder & "mod.xml", 2, True)
with this:
Set inFile = objFile.OpenAsTextStream
outFilename = objFSO.BuildPath(objStartFolder, objFSO.GetBaseName(objFile) & "_mod.xml")
Set outFile = objFSO.OpenTextFile(outFilename, 2, True)
and also replace the other occurrences of objFile after that with inFile (always avoid changing the value of a loop variable), and the code should do what you expect it to do. But again, be warned that the output may not be valid XML.
I managed to made it working, below is the code I used
Dim objFSO, filePath, objFile, colFiles, s , FName
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set filePath = objFSO.GetFolder("\\demo.US\Modified\")
Set colFiles = filePath.Files
For Each FName in colFiles
set objFile = objFSO.OpenTextFile(FName.Path,1)
set outFile = objFSO.OpenTextFile(LEFT(FName.Path,instr(FName.Path,".xml")-1) &"_mod.xml",2,True)
do until objFile.AtEndOfStream
strContent=objFile.ReadLine
Loop
strContent = Replace(strContent, "encoding=""UTF-8""", "encoding=""windows-1252""")
outFile.WriteLine strContent
outFile.Close
objFile.Close
Next

VBS script to rename files using the pathname

i am new to VBS scripting and I have done few stuff with Excel VBA before. Now I have a script which renames single files with the pathname of the files (truncated to 4 letter each))see below. It is some script which I modified a bit to fit my purpose. However, I would like to automatize the file rename process and rename all files in a folder and its subfolders in the same way the scipt works for single files. Can anybody help me with this question?
Set Shell = WScript.CreateObject("WScript.Shell")
Set Parameter = WScript.Arguments
For i = 0 To Parameter.Count - 1
Set fso = CreateObject("Scripting.FileSystemObject")
findFolder = fso.GetParentFolderName(Parameter(i))
PathName = fso.GetAbsolutePathName(Parameter(i))
FileExt = fso.GetExtensionName(Parameter(i))
Search = ":"
findFolder2= Right(PathName, Len(PathName) - InStrRev(PathName, Search))
arr = Split(findFolder2, "\")
For j=0 To UBound(arr)-1
arr(j) = ucase(Left(arr(j), 4))
Next
joined = Join(arr, "%")
prefix = right(joined, len(joined)-1)
fso.MoveFile Parameter(i), findFolder + "\" + prefix
next
Hoping that I can get some useful ideas.
Herbie
Walking a tree requires recursion, a function calling itself for each level.
On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
Dirname = InputBox("Enter Dir name")
ProcessFolder DirName
Sub ProcessFolder(FolderPath)
On Error Resume Next
Set fldr = fso.GetFolder(FolderPath)
Set Fls = fldr.files
For Each thing in Fls
msgbox Thing.Name & " " & Thing.DateLastModified
Next
Set fldrs = fldr.subfolders
For Each thing in fldrs
ProcessFolder thing.path
Next
End Sub
From Help on how to run another file.
Set Shell = WScript.CreateObject("WScript.Shell")
shell.Run(strCommand, [intWindowStyle], [bWaitOnReturn])
So outside the loop,
Set Shell = WScript.CreateObject("WScript.Shell")
And in the loop
shell.Run("wscript Yourscript.vbs thing.name, 1, True)
Also the VBS help file has recently been taken down at MS web site. It is available on my skydrive at https://1drv.ms/f/s!AvqkaKIXzvDieQFjUcKneSZhDjw It's called script56.chm.

Too many iterations in loop

This script collects all files in a folder and renames the files by appending the number of lines to the file name. All files are .txt files. The method (since fso.MoveFile and fso.DeleteFile are too particular, generating permissions errors) is to
create the text files,
then create a collection of the files in the folder,
then copy each file into the same folder with a new name, and
finally to delete the original file that was copied.
The script works ok, unless there are no empty text files in the collection. What happens is, the collection gets rebuilt with the new files and the script once again renames the files. I know I can prevent this by checking each file for the existence of certain repeating character strings, but I'd like to know what's happening? Why does the script rebuild the file collection and run through them again renaming each one? This continues on until I kill the process.
Another interesting factoid is, if I happen to trap an empty text file, my message is displayed and the script stops there, but has still reprocessed the first file in the collection a second time. Note that the empty file just happens to be the last one in the collection, but the first filed is once again processed.
So, by design a created text file named 'ab0.txt' gets renamed to 'ab0-15.txt' since it has 15 lines of text in it. What happens is this newly renamed file looks like 'ab0-15-15-15-15-15-15-15-15-15-15.txt'
Questions: What's going on? And is there a better and more efficient way to accomplish this objective?
Here's the code pertinent to the issue:
Set fso = CreateObject("Scripting.FileSystemObject")
Set oFolder = fso.GetFolder(strSaveTo)
Set colFiles = oFolder.Files
' Call Sub to copy and rename
ChangeFileName colFiles
MsgBox("File renaming complete.")
' Exit code
Sub ChangeFileName(collectionSet)
Const ForReading = 1
Dim oFile
For Each oFile In collectionSet
Set LineCnt = fso.OpenTextFile(oFile, ForReading)
If oFile.Size = 0 then
'if this msg is not included, weird things happen
MsgBox("The file named " & oFile & _
" is empty.You may want to verify and manually delete it.")
'[I had some code in here to delete the empty file, but nothing worked]
Else
Do While LineCnt.AtEndOfStream <> True
LineCnt.SkipLine
Loop
lineVar = lineCnt.Line-1
strNewFile = strSaveTo & Left(oFile.name, Len(oFile.name)-4) & _
"-" & lineVar & ".txt"
fso.CopyFile oFile, strNewFile
LineCnt.Close
fso.DeleteFile oFile, True
End If
Next
End Sub
I've heard anecdotal evidence that the Files collection is "live", meaning that newly created files will be added to the collection and iterated over, but I can't find any documentation that says one way or the other. In any case, it's probably a good idea to copy the File objects in the collection to an array first before processing them:
Dim oFile
Dim fileArray()
Dim i
ReDim fileArray(collectionSet - 1)
i = 0
For Each oFile in collectionSet
Set fileArray(i) = oFile
i = i + 1
Next
For Each oFile In fileArray
' Count lines and rename
Next
It seems that collectionSet is the collection of files in the folder that you are trying to modify. The problem is that with each pass through the for-each loop you are adding files to this folder, some of which are fed back into the loop. What you need to do is the find a way to take a snapshot of the folder before you try to iterate over it. The way to do this would be to replace the folder collectionSet by a collection of strings which are the names of the files before you iterate over it, and modify your code to open the files by their name (instead of via a file object). That way the collection won't be expanding while you iterate over it.
You should create your vars in the scope they are used (e.g. your
file/folder objects are used in the sub.
Always explicit(ly) declare your vars.
You don't need to copy the file and rename it then do the delete.
Just rename it with the FileObject.Name property.
Here is an example:
Option Explicit 'always declare your vars!
Dim strFolder: strFolder = "c:\temp\Rename Test"
Dim strExtension: strExtension = "txt"
' Call Sub to rename the files in the folder
ChangeFileName strFolder, strExtension
Sub ChangeFileName(strFolder, strExtension)
Const ForReading = 1
Dim FSO: set FSO = CreateObject("Scripting.FileSystemObject")
Dim objFolder: set objFolder = FSO.GetFolder(strFolder)
Dim colFiles: set colFiles = objFolder.Files
Dim objFile
Dim intCount
Dim strFileName
Dim objTextStream
For Each objFile In colFiles
msgbox "File: " & objfile.path & vbcrlf & FSO.GetExtensionName(objFile.path)
if UCase(FSO.GetExtensionName(objFile.Path)) = UCase(strExtension) and _
objFile.Size > 0 then
'set LineCnt = FSO.OpenTextFile(objFile, ForReading)
set objTextStream = objFile.OpenAsTextStream(ForReading,-2)
intCount = 0
strFileName = objFile.Name
Do While objTextStream.AtEndOfStream <> True
intCount = intCount + 1
objTextStream.ReadLine
Loop
objTextStream.Close
objFile.Name = FSO.GetBaseName(objFile.Path) & "-" & _
intCount & "." & FSO.GetExtensionName(objFile.Path)
end if
Next
End Sub

How to Copy a file that was read from a list

Hello guys I have an issue or issues with my code above
I'm trying to get "sExtension" to be search in a different folder other that the one I'm using to save my script since this script will be use as a Startup Script on many computers
(It works only if I run the script in the same folder "sExtension", "ExtAssign.txt" and sComputername are otherwise it wont find the path)
This is what it should do
Read a file called "ExtAssign.txt" (There is a full list of computer names in that file) and if it find the computer name on that file then it should copy a file with the with the extension number assigned to that computer name from a file server to "C:\" Drive
For this example I'm trying to do this locally, If I can make it then I'll try it from my File Server
Set objFSO = CreateObject("Scripting.FileSystemObject")
set oFso = CreateObject("Scripting.FileSystemObject")
Set objFS = CreateObject("Scripting.FileSystemObject")
Set fso = CreateObject("Scripting.FileSystemObject")
set oShell = WScript.CreateObject("WScript.Shell")
set oShellEnv = oShell.Environment("Process")
Set folder = Fso.GetFolder("C:\Users\XXXXX\Desktop\Test\Extensions\")
Set wshshell = CreateObject("WScript.Shell")
Set objNetwork = CreateObject("WScript.Network")
Set ObjEnv = WshShell.Environment("Process")
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
Scomputername = ObjEnv("COMPUTERNAME")
Set objFSO = CreateObject("Scripting.FileSystemObject")
set objWShell = wScript.createObject("WScript.Shell")
Dim strFile
'File to scan
strFile = "C:\Users\XXXXX\Desktop\Test\Extensions\Extassign\ExtAssign.txt"
Dim strPattern
'Look for computer name in file
strPattern = scomputername
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
Set objFile = objFS.OpenTextFile(strFile)
Do Until objFile.AtEndOfStream
Dim strLine
'Read each line and store it in strLine
strLine = objFile.ReadLine
'If the line matches the computer name, save the line to ExtArray
If InStr(strLine,strPattern)>0 Then
Dim ExtArray
'Split the line and separate the extension
ExtArray = Split(strLine,"|", -1, 1)
Dim sExtension
'Save the extension to sExtension
sExtension=ExtArray(1)
End If
Loop
'If the sExtension is empty, computer was not found, send message and terminate script.
If sExtension="" Then
WScript.Echo "ERROR: Computer "& scomputername &" not found in Extension Assignment List, so no extension has been set. Avaya will not be launched. Please contact your IT department for assistance."
Else
'If the sExtension contains a number, Copy that file to C:\ and rename it to Config.xml
fso.CopyFile "C:\Users\XXXXX\Desktop\Test\Extensions\ "& sExtension &"", "C:\Config.xml", True
End If
at the end it if it finds the file sExtension it will rename it to Config.xml but it wont do it unless I run the script in the same folder sExtension and sComputername.
I get File not found error
Thank you in advance and Happy new year!
The culprit is most likely this line:
fso.CopyFile "C:\Users\XXXXX\Desktop\Test\Extensions\ "& sExtension &"", "C:\Config.xml", True
There is a trailing space after the last backslash in the path, so you're creating a path
C:\Users\XXXXX\Desktop\Test\Extensions\ 12345
^
when you actually want a path
C:\Users\XXXXX\Desktop\Test\Extensions\12345
On a more general note: why are you creating 7(!) FileSystemObject instances (replacing one of them three times on top of that)? And 3(!) WScript.Shell instances? You don't even use most of them, not to mention that you don't need the Shell object in the first place. You only use it for determining the computer name, which could be done just fine using the WScript.Network object (that you don't use at all).
Also, please don't ever use comments like this:
'Read each line and store it in strLine
strLine = objFile.ReadLine
It's quite obvious that you read each line and assign it to the variable strLine. Comments shouldn't rephrase what you're doing (the code already does that, at least when you're using speaking variable and function names), but why you're doing it, i.e. what the purpose of a particular code section is.
Your code could be reduced to something as simple as this:
Set fso = CreateObject("Scripting.FileSystemObject")
Set net = CreateObject("WScript.Network")
computername = net.ComputerName
foldername = "C:\Users\XXXXX\Desktop\Test\Extensions"
filename = fso.BuildPath(foldername, "Extassign\ExtAssign.txt")
Set f = fso.OpenTextFile(filename)
Do Until f.AtEndOfStream
line = f.ReadLine
If InStr(line, computername) > 0 Then
arr = Split(line, "|", -1, 1)
If UBound(arr) >= 1 Then extension = arr(1)
End If
Loop
f.Close
If IsEmpty(extension) Then
WScript.Echo "ERROR: Computer "& computername &" not found in ..."
Else
fso.CopyFile fso.BuildPath(foldername, extension), "C:\Config.xml", True
End If

unable to zip 1 GB file using VBScript

I have a batch script that does the following tasks.
1. Create a backup folder
2. Zip specific files (text files in .log format) and move zipped files to backup folder
3. Delete the original files after moving
To accomplish the 2nd task, I'm writing the commands into VBScript file from batch script like below and then executing the VBScript at the end of batch script.
echo Option Explicit >> zipIt.vbs
REM remaining commands
CScript zipIt.vbs
The batch script successfully performs all 3 tasks for a file of size 100 MB.
But fails at VBScript command for file of size 1 GB. Following error is thrown at command prompt
C:\Users\Administrator\Desktop\zipIt.vbs(18, 1) Microsoft VBScript runtime error
: Permission denied
Below is the content of zipIt.vbs Written line numbers here for convenience.
1. Option Explicit
2. Dim FileToZip, Result
3. Dim oShell
4. Dim file
5. Dim oFileSys
6. Dim winShell
7. FileToZip = "C:\Program Files\logs\File_2013-04-29.log"
8. Result = "C:\Program Files\logs\File_2013-04-29.log.zip"
9. Set oShell = CreateObject("WScript.Shell")
10. Set oFileSys = CreateObject("Scripting.FileSystemObject")
11. Set file = oFileSys.CreateTextFile(Result, True)
12. file.Write "PK" & Chr(5) & Chr(6) & String(18, 0)
13. file.Close
14. Set file = nothing
15. set winShell = createObject("shell.application")
16. winShell.namespace(Result).CopyHere FileToZip
17. wScript.Sleep(5000)
18. oFileSys.DeleteFile FileToZip
Getting the same error if VBScript is run alone. Is it because of large file size?
This is most definitely a problem with memory, seeing as applications are capped at a maximum of 2GB, within windows at least, it is most likely an issue of the program trying to access memory that it was not allocated.
Alternative solution
Split large log files in little chunks:
BreakFile = "C:\Users\Administrador\Desktop\Test.txt"
limit = 400000 ' Bytes
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(Breakfile, 1)
FiletoSplit = objFSO.GetFileName(BreakFile)
FolderDest = Mid(objFSO.GetAbsolutePathName(BreakFile),1,Len(objFSO.GetAbsolutePathName(BreakFile))-(Len(FiletoSplit)))
FileSplitName = objFSO.GetBaseName(BreakFile)
dtmStart = Now()
Set objFile = objFSO.OpenTextFile(Breakfile, 1)
strContents = objFile.ReadAll
FileNum = 1
fname = FolderDest & FileSplitName & "Split " & FileNum & ".txt"
Set objFile1 = objFSO.OpenTextFile(fname, 2, True)
CountLines = 0
arrLines = Split(strContents, vbCrLf)
HeaderText = arrLines(0)
For i = 0 to ubound(arrlines)
strLine = arrLines(i) & vbCrLf
objFile1.Write strLine
If (Countlines) < limit Then
countlines = countlines + 1
ElseIf Countlines >= limit Then
objFile1.Close
Countlines = 0
FileNum = FileNum + 1
fname = FolderDest & FileSplitName & "Split " & FileNum & ".txt"
Set objFile1 = objFSO.OpenTextFile(fname, 2, True)
objFile1.Write HeaderText & vbCrLf
End If
Next
objFile.Close
dtmEnd = Now()
Then Zip it all together, and when extract the content, use a "Copy /B" batch command like this to join the chunks:
Copy /B "MyLog_Part*" "MyLog_Complete.log"

Resources