So I have two working .vbs scripts do two different things, one removes the read-only attribute in a file, and the other removes all files with ".v" extension. Both work when a folder is dropped on to the script.
I tried combining them, but with my limited knowledge I get a bunch of errors.
First code:
Option Explicit
Sub main()
Dim ArgCount
Dim filExt
ArgCount = WScript.Arguments.Count
Select Case ArgCount
Case 1 'Check the count of arguments
Dim FSO,Path,File,Num_1,Num_2
Set FSO = CreateObject("Scripting.FilesystemObject")
Path = WScript.Arguments(0)
If FSO.FileExists(Path) Then
Set File = FSO.GetFile(path)
If (File.Attributes Mod 2) = 1 Then 'Check if the Read-Only is selected, and remove it.
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & Path &" "& Err.Description
Else
MsgBox "Fjernelse fuldført"
End If
Else
MsgBox "The Read-Only attribute of file is not selected"
End If
Else
RemoveSubFolder Path,Num_1,Num_2
MsgBox Num_2 & " filer fuldført" & ", " & Num_1 & " filer fejlet"
End If
Case Else
MsgBox "Træk mappen oven på denne fil"
End Select
End Sub
'This function is to remove the Read-Only of all files in a folder and its subfolder
Function RemoveSubFolder(FolderPath,Num_1,Num_2)
Dim FSObject,Folder
Dim subFolder,File
Num_1 = 0
Num_2 = 0
Set FSObject = CreateObject("Scripting.FilesystemObject")
Set Folder = FSObject.GetFolder(FolderPath)
For Each subFolder In Folder.SubFolders 'Loop the subfolder in the folder
FolderPath = subFolder.Path
RemoveSubFolder FolderPath,Num_1,Num_2
Next
For Each File In Folder.Files 'Remove the Read-Only attribute of files in the folder
If (File.Attributes Mod 2) = 1 Then
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & File.Path &" "& Err.Description
Num_1 = Num_1 + 1
Else
Num_2 = Num_2 + 1
End If
End If
Err.Clear
Next
Set FSObject = Nothing
End Function
Call main
The second code is this:
Option Explicit
Dim FSObject, Folder, File, subFolder
Set FSObject = CreateObject("Scripting.FileSystemObject")
' Get the folder dropped onto our script...
Folder = WScript.Arguments(0)
' Recursively check each file with the folder and its subfolders...
DoFolder Folder
Sub DoFolder(Folder)
' Check each file...
For Each File In FSObject.GetFolder(Folder).Files
If Right(File.name, 2) = ".v" Then
FSObject.DeleteFile(Folder & "\" & File.name)
End If
Next
' Recursively check each subfolder...
For Each subFolder In FSObject.GetFolder(Folder).SubFolders
DoFolder subFolder.Path
Next
End Sub
Now, I tried combining them, but get a Syntax error on line 34
Option Explicit
Sub main()
Dim ArgCount
Dim filExt
ArgCount = WScript.Arguments.Count
Select Case ArgCount
Case 1 'Check the count of arguments
Dim FSO,Path,File,Num_1,Num_2
Set FSO = CreateObject("Scripting.FilesystemObject")
Path = WScript.Arguments(0)
If FSO.FileExists(Path) Then
Set File = FSO.GetFile(path)
If (File.Attributes Mod 2) = 1 Then 'Check if the Read-Only is selected, and remove it.
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & Path &" "& Err.Description
Else
MsgBox "Fjernelse fuldført"
End If
Else
MsgBox "The Read-Only attribute of file is not selected"
End If
Else
RemoveSubFolder Path,Num_1,Num_2
MsgBox Num_2 & " filer fuldført" & ", " & Num_1 & " filer fejlet"
End If
Case Else
MsgBox "Træk mappen oven på denne fil"
End Select
'This function is to remove the Read-Only of all files in a folder and its subfolder
Function RemoveSubFolder(FolderPath,Num_1,Num_2)
Dim FSObject,Folder
Dim subFolder,File
Num_1 = 0
Num_2 = 0
Set FSObject = CreateObject("Scripting.FilesystemObject")
Set Folder = FSObject.GetFolder(FolderPath)
For Each subFolder In Folder.SubFolders 'Loop the subfolder in the folder
FolderPath = subFolder.Path
RemoveSubFolder FolderPath,Num_1,Num_2
Next
For Each File In Folder.Files 'Remove the Read-Only attribute of files in the folder
If (File.Attributes Mod 2) = 1 Then
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & File.Path &" "& Err.Description
Num_1 = Num_1 + 1
Else
Num_2 = Num_2 + 1
End If
End If
Err.Clear
Next
' Recursively check each file with the folder and its subfolders...
DoFolder Folder
Sub DoFolder(Folder)
' Check each file...
For Each File In FSObject.GetFolder(Folder).Files
If Right(File.name, 2) = ".v" Then
FSObject.DeleteFile(Folder & "\" & File.name)
End If
Next
' Recursively check each subfolder...
For Each subFolder In FSObject.GetFolder(Folder).SubFolders
DoFolder subFolder.Path
Next
End Sub
Set FSObject = Nothing
End Function
Call main
They just don't work together, so how would I go about combining them?
UPDATE: I get this error with this code:
Option Explicit
Sub main()
Dim ArgCount
Dim filExt
ArgCount = WScript.Arguments.Count
Select Case ArgCount
Case 1 'Check the count of arguments
Dim FSO,Path,File,Num_1,Num_2
Set FSO = CreateObject("Scripting.FilesystemObject")
Path = WScript.Arguments(0)
If FSO.FileExists(Path) Then
Set File = FSO.GetFile(path)
If (File.Attributes Mod 2) = 1 Then 'Check if the Read-Only is selected, and remove it.
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & Path &" "& Err.Description
Else
MsgBox "Fjernelse fuldført"
End If
Else
MsgBox "The Read-Only attribute of file is not selected"
End If
Else
RemoveSubFolder Path,Num_1,Num_2
MsgBox Num_2 & " filer fuldført" & ", " & Num_1 & " filer fejlet"
End If
Case Else
MsgBox "Træk mappen oven på denne fil"
End Select
End Sub
'This function is to remove the Read-Only of all files in a folder and its subfolder
Function RemoveSubFolder(FolderPath,Num_1,Num_2)
Dim FSObject,Folder
Dim subFolder,File
Num_1 = 0
Num_2 = 0
Set FSObject = CreateObject("Scripting.FilesystemObject")
Set Folder = FSObject.GetFolder(FolderPath)
For Each subFolder In Folder.SubFolders 'Loop the subfolder in the folder
FolderPath = subFolder.Path
RemoveSubFolder FolderPath,Num_1,Num_2
Next
For Each File In Folder.Files 'Remove the Read-Only attribute of files in the folder
If (File.Attributes Mod 2) = 1 Then
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & File.Path &" "& Err.Description
Num_1 = Num_1 + 1
Else
Num_2 = Num_2 + 1
End If
End If
Err.Clear
Next
' Recursively check each file with the folder and its subfolders...
DoFolder Folder
Sub DoFolder(Folder)
' Check each file...
For Each File In FSObject.GetFolder(Folder).Files
If Right(File.name, 2) = ".v" Then
FSObject.DeleteFile(Folder & "\" & File.name)
End If
Next
' Recursively check each subfolder...
For Each subFolder In FSObject.GetFolder(Folder).SubFolders
DoFolder subFolder.Path
Next
End Sub
Set FSObject = Nothing
End Function
Call main
UPDATED CODE:
Option Explicit
Sub main()
Dim ArgCount
Dim filExt,Num_1,Num_2
ArgCount = WScript.Arguments.Count
Select Case ArgCount
Case 1 'Check the count of arguments
Dim FSO,Path,File,Num_1,Num_2
Set FSO = CreateObject("Scripting.FilesystemObject")
Path = WScript.Arguments(0)
If FSO.FileExists(Path) Then
Set File = FSO.GetFile(path)
If (File.Attributes Mod 2) = 1 Then 'Check if the Read-Only is selected, and remove it.
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & Path &" "& Err.Description
Else
MsgBox "Fjernelse fuldført"
End If
Else
MsgBox "The Read-Only attribute of file is not selected"
End If
Else
RemoveSubFolder Path,Num_1,Num_2
MsgBox Num_2 & " filer fuldført" & ", " & Num_1 & " filer fejlet"
End If
Case Else
MsgBox "Træk mappen oven på denne fil"
End Select
End Sub
'This function is to remove the Read-Only of all files in a folder and its subfolder
Dim FSObject,Folder
Dim subFolder,File
Num_1 = 0
Num_2 = 0
Set FSObject = CreateObject("Scripting.FilesystemObject")
Set Folder = FSObject.GetFolder(FolderPath)
For Each subFolder In Folder.SubFolders 'Loop the subfolder in the folder
FolderPath = subFolder.Path
RemoveSubFolder FolderPath,Num_1,Num_2
Next
For Each File In Folder.Files 'Remove the Read-Only attribute of files in the folder
If (File.Attributes Mod 2) = 1 Then
File.Attributes = File.Attributes-1
If Err.Number <> 0 Then
MsgBox "Error :" & File.Path &" "& Err.Description
Num_1 = Num_1 + 1
Else
Num_2 = Num_2 + 1
End If
End If
Err.Clear
Next
' Recursively check each file with the folder and its subfolders...
DoFolder Folder
Sub DoFolder(Folder)
' Check each file...
For Each File In FSObject.GetFolder(Folder).Files
If Right(File.name, 2) = ".v" Then
FSObject.DeleteFile(Folder & "\" & File.name)
End If
Next
' Recursively check each subfolder...
For Each subFolder In FSObject.GetFolder(Folder).SubFolders
DoFolder subFolder.Path
Next
End Sub
Function RemoveSubFolder(FolderPath, Num_1, Num_2)
Set FSObject = Nothing
End Function
Call main
I get this error now:
https://i.imgur.com/TDfgvLI.png
EDIT: After removing Num_1 and Num_2 definition in line 9, I get this error:
https://i.imgur.com/uEfkGCh.png
VBScript doesn't allow nesting procedure or function defintions insode other procedures or functions. Move the definition of DoFolder outside the function RemoveSubFolder.
Sub DoFolder(Folder)
'Check each file...
For Each File In FSObject.GetFolder(Folder).Files
If Right(File.Name, 2) = ".v" Then
FSObject.DeleteFile(Folder & "\" & File.Name)
End If
Next
'Recursively check each subfolder...
For Each subFolder In FSObject.GetFolder(Folder).SubFolders
DoFolder subFolder.Path
Next
End Sub
Function RemoveSubFolder(FolderPath, Num_1, Num_2)
...
End Function
Related
Everyday around 7 AM there are 3 csv exports extracted into a specific folder and the file names are exactly the same each day except everyday the prefix of the file name is amended to the current date.
Example:
16-02-2018_Test1 will change to 17-02-2018_Test1
16-02-2018_Test2 will change to 17-02-2018_Test2
16-02-2018_Test3 will change to 17-02-2018_Test3
The file itself is not replaced, the new file with the current date is instead added to this folder.
What I need to do is identify the 3 extracts each day and copy them to a sub-folder. The best way I thought of doing this is by identifying the date at which the file was last modified.
I have the below VBS code I found and helps identifies the latest file in a directory and I added a line that will copy that file to a new directory.
The issue however, is that the code only identifies 1 file instead of 3 and I can only copy 1 file instead of 3. If anyone has better code to help me achieve the desired result or alternatively can help modify the existing code to achieve the desired result.
sPath = "C:\Users\Desktop\Test\"
Const sToDir = "C:\Users\Desktop\Test\NewFolder\"
Set oFSO = CreateObject("Scripting.FileSystemObject")
sNewestFile = GetNewestFile(sPath)
If sNewestFile <> "" Then
WScript.Echo "Newest file is " & sNewestFile
dFileModDate = oFSO.GetFile(sNewestFile).DateLastModified
If DateDiff("n", dFileModDate, Now) > 60 Then
oFSO.CopyFile sNewestFile, sToDir
End If
Else
WScript.Echo "Directory is empty"
End If
Function GetNewestFile(ByVal sPath)
sNewestFile = Null ' init value
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(sPath)
Set oFiles = oFolder.Files
' enumerate the files in the folder, finding the newest file
For Each oFile In oFiles
On Error Resume Next
If IsNull(sNewestFile) Then
sNewestFile = oFile.Path
dPrevDate = oFile.DateLastModified
Elseif dPrevDate < oFile.DateLastModified Then
sNewestFile = oFile.Path
dPrevDate = oFile.DateLastModified
End If
On Error Goto 0
Next
If IsNull(sNewestFile) Then sNewestFile = ""
GetNewestFile = sNewestFile
End Function
Invest some work in a useful format class and
just look for the 3 files of the day (FileExists)
if they are not there, look for the previous day's files
or
search for the newest file and build all three file names from the prefix
In code:
Option Explicit
' stolen from https://stackoverflow.com/a/21643663/603855
' added formatTwo; left as exercise: formatThree
Class cFormat
Private m_oSB
Private Sub Class_Initialize()
Set m_oSB = CreateObject("System.Text.StringBuilder")
End Sub ' Class_Initialize
Public Function formatOne(sFmt, vElm)
m_oSB.AppendFormat sFmt, vElm
formatOne = m_oSB.ToString()
m_oSB.Length = 0
End Function ' formatOne
Public Function formatTwo(sFmt, vElm1, vElm2)
m_oSB.AppendFormat_2 sFmt, vElm1, vElm2
formatTwo = m_oSB.ToString()
m_oSB.Length = 0
End Function ' formatOne
Public Function formatArray(sFmt, aElms)
m_oSB.AppendFormat_4 sFmt, (aElms)
formatArray = m_oSB.ToString()
m_oSB.Length = 0
End Function ' formatArray
End Class ' cFormat
Dim oFmt : Set oFmt = New cFormat
Dim sFmt : sFmt = "{0:dd-MM-yyyy}_Test{1}"
Dim dToday : dToday = Date()
Dim i
WScript.Echo "file names expected today " & oFmt.formatOne("({0:yyyy-MMM-d}).", dToday)
For i = 1 To 3
WScript.Echo oFmt.FormatTwo(sFmt, dToday, i)
Next
WScript.Echo oFmt.formatArray("look for {0} if {1} is missing on the {2:dd}th after 7 AM" _
, Array(oFmt.FormatTwo(sFmt, DateAdd("d", -1, dToday), 1), oFmt.FormatTwo(sFmt, dToday, 1), dToday))
Dim sFnd : sFnd = oFmt.FormatTwo(sFmt, dToday, 2)
WScript.Echo "if your GetNewestFile() finds " & sFnd & ", copy:"
For i = 1 To 3
WScript.Echo Left(sFnd, Len(sFnd) - 1) & i
Next
output:
cscript 48866113.vbs
file names expected today (2018-Feb-19).
19-02-2018_Test1
19-02-2018_Test2
19-02-2018_Test3
look for 18-02-2018_Test1 if 19-02-2018_Test1 is missing on the 19th after 7 AM
if your GetNewestFile() finds 19-02-2018_Test4, copy:
19-02-2018_Test1
19-02-2018_Test2
19-02-2018_Test3
Thanks to everyone for the help, I found the answer on a different thread. Here is the link: Copy 2 latest text file from a source folder to destination folder
Below is the code:
Option Explicit
Dim FolderToCheck, FolderDestination, FileExt, mostRecent, noFiles, fso, fileList, file, filecounter, oShell, strHomeFolder
' Enumerate current user's home path - we will use that by default later if nothing specified in commandline
Set oShell = CreateObject("WScript.Shell")
strHomeFolder = oShell.ExpandEnvironmentStrings("%USERPROFILE%")
'Variables -----
folderToCheck = strHomeFolder & "\Desktop\MY\MMS" ' Folder Source to check for recent files to copy FROM
folderDestination = strHomeFolder & "\Desktop\New" ' Destination Folder where to copy files TO
fileExt = "txt" ' Extension we are searching for
mostRecent = 2 ' Most Recent number of files to copy
' --------------
PreProcessing() ' Retrieve Command Line Parameters
' Display what we are intending on doing
wscript.echo "Checking Source: " & FolderToCheck
wscript.echo "For Files of type: " & FileExt
wscript.echo "Copying most recent "& mostRecent &" file(s) to: " & FolderDestination & "."
wscript.echo
noFiles = TRUE
Set fso = CreateObject("Scripting.FileSystemObject")
Set fileList = CreateObject("ADOR.Recordset")
fileList.Fields.append "name", 200, 255
fileList.Fields.Append "date", 7
fileList.Open
If fso.FolderExists(FolderToCheck) Then
For Each file In fso.GetFolder(FolderToCheck).files
If LCase(fso.GetExtensionName(file)) = LCase(FileExt) then
fileList.AddNew
fileList("name").Value = File.Path
fileList("date").Value = File.DateLastModified
fileList.Update
If noFiles Then noFiles = FALSE
End If
Next
If Not(noFiles) Then
wscript.echo fileList.recordCount & " File(s) found. Sorting and copying last " & mostRecent &"..."
fileList.Sort = "date DESC"
If Not(fileList.EOF) Then
fileList.MoveFirst
If fileList.recordCount < mostRecent Then
wscript.echo "WARNING: " & mostRecent &" file(s) specified but only " & fileList.recordcount & " file(s) match criteria. Adjusted to " & fileList.RecordCount & "."
mostRecent = fileList.recordcount
End If
fileCounter = 0
Do Until fileList.EOF Or fileCounter => mostRecent
If Not(fso.FolderExists(folderDestination)) Then
wscript.echo "Destination Folder did not exist. Creating..."
fso.createFolder folderDestination
End If
fso.copyfile fileList("name"), folderDestination & "\", True
wscript.echo fileList("date").value & vbTab & fileList("name")
fileList.moveNext
fileCounter = fileCounter + 1
Loop
Else
wscript.echo "An unexpected error has occured."
End If
Else
wscript.echo "No matching """ & FileExt &""" files were found in """ & foldertocheck & """ to copy."
End If
Else
wscript.echo "Error: Source folder does not exist """ & foldertocheck & """."
End If
fileList.Close
Function PreProcessing
Dim source, destination, ext, recent
' Initialize some variables
Set source = Nothing
Set destination = Nothing
Set ext = Nothing
Set recent = Nothing
'Get Command Line arguments
' <scriptname>.vbs /Source:"C:\somepath\somefolder" /Destination:"C:\someotherpath\somefolder" /ext:txt /recent:2
source = wscript.arguments.Named.Item("source")
destination = wscript.arguments.Named.Item("destination")
ext = wscript.arguments.Named.Item("ext")
recent = wscript.arguments.Named.Item("recent")
If source <> "" Then FolderToCheck = source
If destination <> "" Then FolderDestination = destination
If ext <> "" Then FileExt = ext
If recent <> "" Then mostRecent = int(recent)
End Function
How to replace a specific string with the filename? Example: I have several files with different names (like: Test.asp, Constant.asp, Letter.asp, etc.) within a subfolder that contain the text "ABC123". I would like to replace the "ABC123" in each file with the filename.
Below is the code I have that finds string and replaces it with a specific string but it doesn't do the job that I listed above.
Option Explicit
Dim objFilesystem, objFolder, objFiles, objFile, tFile, objShell, objLogFile,objFSO, objStartFolder, colFiles
Dim SubFolder, FileText, bolWriteLog, strLogName, strLogPath, strCount, strCount2, strOldText, strNewText, strEXT
bolWriteLog = True
Const ForReading = 1
Const ForWriting = 2
Const TriStateUseDefault = -2
Set objFilesystem = WScript.CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
strLogName = "log.txt"
strLogPath = "C:\" & strLogName
strCount = 0
strCount2 = 0
strOldText = "ABC123"
strNewText = ""
strEXT = "asp"
'Initialize log file
If bolWriteLog Then
On Error Resume Next
Set objLogFile = objFileSystem.OpenTextFile(strLogPath, 2, True)
WriteLog "############### Start Log ##################"
If Not Err.Number = 0 Then
MsgBox "There was a problem opening the log file for writing." & Chr(10) & _
"Please check whether """ & strLogPath & """ is a valid file and can be openend for writing." & _
Chr(10) & Chr(10) & "If you're not sure what to do, please contact your support person.", vbCritical, "Script Error"
WScript.Quit
End If
On Error Goto 0
End If
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "D:\MyFolder"
Set objFolder = objFSO.GetFolder(objStartFolder)
WScript.Echo objFolder.Path
Set colFiles = objFolder.Files
For Each objFile In colFiles
'WScript.Echo objFile.Name
' Now we have an exception for all files that can not be opened in text modus: all extensions such as "exe" should be listed upfront.
ReplaceText(objFile)
Next
ShowSubfolders objFSO.GetFolder(objStartFolder)
Sub ReplaceText(objFile)
If InStr(1, strEXT, Right(LCase(objFile.Name), 3)) = 0 Or objFile.Size = 0 Then
Else
strCount = strCount + 1
WriteLog("Opening " & objFile.Name)
Set tFile = objFile.OpenAsTextStream(ForReading, TriStateUseDefault)
FileText = tFile.ReadAll
tFile.Close
If InStr(FileText, strOldText) Then
WriteLog("Replacing " & strOldText & " with " & strNewText & ".")
FileText = Replace(FileText, strOldText, strNewText)
WriteLog("Text replaced")
Else
WriteLog(strOldText & " was not found in the file.")
strCount2 = strCount2 + 1
End If
Set tFile = objFile.OpenAsTextStream(ForWriting, TriStateUseDefault)
tFile.Write FileText
tFile.Close
FileText = ""
strCount = 0
strCount2 = 0
End If
End Sub
Sub ShowSubFolders(Folder)
For Each Subfolder in Folder.SubFolders
'WScript.Echo Subfolder.Path
Set objFolder = objFSO.GetFolder(Subfolder.Path)
Set colFiles = objFolder.Files
For Each objFile in colFiles
'WScript.Echo objFile.Name
ReplaceText(objFile)
Next
ShowSubFolders Subfolder
Next
End Sub
WriteLog "############### EndLog ##################"
WScript.Echo "Script Complete"
objShell.Run "C:\" & strLogName
'Clear environment and exit
On Error Resume Next
Set tFile = Nothing
Set objFile = Nothing
Set objFiles = Nothing
Set objFolder = Nothing
Set objLogFile = Nothing
Set objFilesystem = Nothing
Set objShell = Nothing
WScript.Quit
'Subs and functions ********** DO NOT EDIT ***************
Sub WriteLog(sEntry)
If bolWriteLog Then objLogFile.WriteLine(Now() & ": Log: " & sEntry)
End Sub
I can give you a one line Ruby solution, should be not too difficult to translate that in Python but somewhat more extensive in VbScript I am afraid. First a generic search and replace version.
ARGV[0..-3].each{|f| File.write(f, File.read(f).gsub(ARGV[-2],ARGV[-1]))}
Save it in a script, eg replace.rb
You start in on the command line (here cmd.exe) with
replace.rb *.txt <string_to_replace> <replacement>
broken down so that I can explain what's happening but still executable
# ARGV is an array of the arguments passed to the script.
ARGV[0..-3].each do |f| # enumerate the arguments of this script from the first to the last (-1) minus 2
File.write(f, # open the argument (= filename) for writing
File.read(f) # open the argument (= filename) for reading
.gsub(ARGV[-2],ARGV[-1])) # and replace all occurances of the beforelast with the last argument (string)
end
And finally your request to replace ABC123 with the filename.
Of course tested and working
ARGV[0..-1].each{|f| File.write(f, File.read(f).gsub('ABC123', f))}
Contents of one of my testfiles (1.txt) after executing
test phrase
1.txt
EDIT
I see you want subfolder recursion on a fixed folder, no problem
Dir['**/*'].each{|f| File.write(f, File.read(f).gsub('ABC123', f)) unless File.directory?(f) }
I am at my wits end into this. Either I am doing it the wrong way or it is not possible.
I need a vb script for the following scenario:
The script is to run on multiple Windows 7 machines (32-Bit & 64-Bit alike).
These are shared workstation i.e. different users login to these machines from time to time.
The objective of this script is to traverse through each User Profile folder and get the size of the 'My Documents' folder within each User Profile folder. This information is to be written to a .CSV file located at C:\Temp directory on the machine.
This script would be pushed to all workstations from SCCM. It would be configured to execute with System Rights
I tried the script detailed at:
http://blogs.technet.com/b/heyscriptingguy/archive/2005/03/31/how-can-i-determine-the-size-of-the-my-documents-folder.aspx
Const MY_DOCUMENTS = &H5&
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(MY_DOCUMENTS)
Set objFolderItem = objFolder.Self
strPath = objFolderItem.Path
Set objFolder = objFSO.GetFolder(strPath)
Wscript.Echo objFolder.Size
The Wscript.Echo objFolder.Size command in the script returned the value as '0' (zero) for the current logged on user. Although the actual size was like 30 MB or so.
I then tried the script at:
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/VB_Script/Q_27869829.html
This script returns the correct value but only for the current logged-on user.
Const blnShowErrors = False
' Set up filesystem object for usage
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
' Display desired folder sizes
Wscript.Echo "MyDocuments : " & FormatSize(FindFiles(objFSO.GetFolder(objShell.SpecialFolders("MyDocuments"))))
' Recursively tally the size of all files under a folder
' Protect against folders or files that are not accessible
Function FindFiles(objFolder)
On Error Resume Next
' List files
For Each objFile In objFolder.Files
On Error Resume Next
If Err.Number <> 0 Then ShowError "FindFiles:01", objFolder.Path
On Error Resume Next
FindFiles = FindFiles + objFile.Size
If Err.Number <> 0 Then ShowError "FindFiles:02", objFile.Path
Next
If Err.Number = 0 Then
' Recursively drill down into subfolder
For Each objSubFolder In objFolder.SubFolders
On Error Resume Next
If Err.Number <> 0 Then ShowError "FindFiles:04", objFolder.Path
FindFiles = FindFiles + FindFiles(objSubFolder)
If Err.Number <> 0 Then ShowError "FindFiles:05", objSubFolder.Path
Next
Else
ShowError "FindFiles:03", objFolder.Path
End If
End Function
' Function to format a number into typical size scales
Function FormatSize(iSize)
aLabel = Array("bytes", "KB", "MB", "GB", "TB")
For i = 0 to 4
If iSize > 1024 Then iSize = iSize / 1024 Else Exit For End If
Next
FormatSize = Round(iSize, 2) & " " & aLabel(i)
End Function
Sub ShowError(strLocation, strMessage)
If blnShowErrors Then
WScript.StdErr.WriteLine "==> ERROR at [" & strLocation & "]"
WScript.StdErr.WriteLine " Number:[" & Err.Number & "], Source:[" & Err.Source & "], Desc:[" & Err.Description & "]"
WScript.StdErr.WriteLine " " & strMessage
Err.Clear
End If
End Sub
The only part pending, is to achieve this for the 'My Documents' folder within each of the other User Profile folders.
Is this possible?
Please help.
I've hacked together some pretty interesting code to zip multiple files and folders.
The script will take a list of arguments (files & folders) and zips them to a zip with the date/time as the name.
So I need some code that is executed when the argument is a file. The code should add the directory structure of the file to the zip file.
'=================== THE SCRIPT =====================================
'Get command-line arguments.
Set objArgs = WScript.Arguments
Set objShell = CreateObject("Shell.Application")
'
'C:\DateYYYY-MM-DD_TimeHH-MM-SS.zip
ZipFile = "C:\DateYYYY-MM-DD_TimeHH-MM-SS.zip"
'Create empty ZIP file.
CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)
Set zip = objShell.NameSpace(ZipFile)
'
for i = 0 To objArgs.Count-1
On Error Resume Next
IF fnFileExists( objArgs(i) ) OR (NOT fnFolderIsEmpty( objArgs(i) )) THEN
'WScript.Echo "Copying - " & objArgs(i)
IF fnFileExists( objArgs(i) ) THEN
'??? Code/Function/CopyHere[option] to create a directory structure in zip and copy objArgs(i) file into it
End If
zip.CopyHere( objArgs(i) )
Else
WScript.Echo "Empty or !Exist - " & objArgs(i)
End If
Do
wScript.Sleep 200
Loop Until objShell.NameSpace(zip).Items.Count >= i
Next
WScript.Echo "THE END"
The fnFileExists() function returns TRUE only if the file exists (FALSE if folder or file doesn't exist).
The fnFolderIsEmpty() function returns TRUE if folder is empty or doesn't exist.
Given a call like this:
"wscript zip.vbs "c:\Folder1\" "c:\Folder2\Sub2-1\" "c:\Windows\System32\TestFile0.txt"
Where folders are like this:
\Folder1\
└──TestFile1.txt
└──TestFile2.txt
\Folder2\
└──\Sub2-1\
└──TestFile3.txt
└──TestFile4.txt
\Windows\
└──\System32\
└──TestFile0.txt
└──\Sub3-2\
└──TestFoo.txt
I get a zip file with a structure like this:
\Folder1\
└──TestFile1.txt
└──TestFile2.txt
\Sub2-1\
└──TestFile3.txt
└──TestFile4.txt
\TestFile0.txt
This is what I'd LIKE it to look like:
\Folder1\
└──TestFile1.txt
└──TestFile2.txt
\Folder2\
└──\Sub2-1\
└──TestFile3.txt
└──TestFile4.txt
\Windows\
└──\System32\
└──TestFile0.txt
I did find the following, but I don't know how/if Java translates to VBScript:
java.util.zip - Recreating directory structure
-AND-
Zipping files preserving the directory structure
OK, here it is.
For every individual file, I put it in a temp folder ("C:\xxMisc") creating the full path underneath the temp folder. I then zip all the folders in the temp folder. Works perfect for my purposes.
e.g. If I needed to zip "c:\windows\system32\bob.dll"
I would create a path\file "c:\xxMisc\windows\system32\" & copy bob.dll into it.
Then call: zip.MoveHere( "c:\xxMisc\Windows" );
The result is that the zip file would have a "\windows\" directory with all the sub-directories (and files) in it.
Usage: wscript <script.vbs> [/x] <FullPath[FileName]>
[]arguments are optional. Wild cards do not work. End full paths with '\'. "/x" will bring up a IE debug window.
wscript script.vbs /X "C:\My Path\" "c:\windows\system32\bob.dll"
Result: zip file at "c:\" that will contain the entire directory "c:\My Path\" (including files & subdirectories) and bob.dll in a "\windows\system32\" directory path.
Here is the code.
IF WScript.Arguments.Count = 0 THEN
WSCript.Quit
END IF
Dim objIEDebugWindow
sTempFolderName = "C:\xxMisc" 'Where individual files go
iBeforeCopy = 0 'Value to detect when a move/copy is complete
bDebug = FALSE 'Debug Flag
i = 0 'Index through the objArgs()
'Get command-line arguments.
Set objArgs = wScript.Arguments
'General objects
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Detect Debug Command Line Argument | MUST be FIRST Argument
IF UCase( objArgs( 0 ) ) = "/X" THEN
bDebug = TRUE
i = 1 'Change Which Index objArgs() to start looking for files/folders
END IF
'Test to see if Windows Script Host is >= 2.0
fnCheckWSHversion( 2000 )
'Create empty ZIP file.
'C:\DateYYYY-MM-DD_TimeHH-MM-SS.zip
ZipFile = "C:\Date" & Year(Date) & "-" & Right("0" & Month(Date),2) & "-" & Right("0" & Day(Date),2) & "_Time" & Right("0" & Hour(now), 2) & "-" & Right("0" & Minute(now), 2) & "-" & Right("0" & Second(now), 2) & ".zip"
CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)
Set zip = objShell.NameSpace(ZipFile)
CALL Debug ( objArgs.Count )
'Iterate through the command line arguments
for i = i To objArgs.Count-1
CALL Debug( "Processing objArgs = " & i & "| " & objArgs(i) )
IF FileExists( objArgs(i) ) OR (NOT fnFolderIsEmpty( objArgs(i) )) THEN
IF FileExists( objArgs(i) ) THEN
'IT'S A FILE
CALL Debug( "Copying File - " & objArgs(i) )
CALL fnMakeTempFile( sTempFolderName, objArgs( i ) )
Else 'IT'S A FOLDER
CALL Debug( "Copying Folder - " & objArgs(i) )
iBeforeCopy = objShell.NameSpace(zip).Items.Count
zip.CopyHere( objArgs(i) )
'Wait until copy is done (Items.Count goes up)
Do
wScript.Sleep 200
Loop Until objShell.NameSpace(zip).Items.Count > iBeforeCopy
End If
Else
CALL Debug( "Empty or !Exist - " & objArgs(i) )
End If
Next
IF (NOT fnFolderIsEmpty( "c:\xxMisc" )) THEN 'Just in case no FILES were backed up
'Get ArrayList of Temp Folders
Set arrDirs = fnListDirIn( "c:\xxMisc" )
CALL Debug( "Copying sTempFolder" )
For Each sFolderName in arrDirs
CALL Debug( "sFolderName=" & sFolderName )
iBeforeCopy = objShell.NameSpace(zip).Items.Count
zip.MoveHere( sFolderName )
'Wait until copy is done (Items.Count goes up)
Do
wScript.Sleep 200
Loop Until objShell.NameSpace(zip).Items.Count > iBeforeCopy
Next
CALL Debug( "COPY DONE!" )
CALL Debug( "Deleting sTempFolderName = " & sTempFolderName )
objFSO.DeleteFolder sTempFolderName, TRUE
'Wait until folder is finished deleting; because MoveHere doesn't MOVE
While objFSO.FolderExists( sTempFolderName )
wScript.Sleep 200
Wend
END IF
CALL Debug( "THE END" )
CALL MsgBox( "Backup Complete", vbOKOnly+vbInformation, "My Backup" )
Set objArgs = Nothing
Set objShell = Nothing
Set objFSO = Nothing
Set zip = Nothing
wScript.Quit
' ----------------------------------------------
'END MAIN
' ----------------------------------------------
' ----------------------------------------------
'Copies sFileName into a temporary directory specified by sTempFolder
' e.g.:
' sTempFolder = "C:\Temp\"
' sFileName = "c:\Windows\System32\bob.ocx"
' results is the creation of "C:\Temp\Windows\System32\bob.ocx"
'-Uses fnCreatePath()
'-No Return
Function fnMakeTempFile( ByVal sTempFolder, sFileName )
IF Right( sTempFolder, 1 ) <> "\" THEN
sTempFolder = sTempFolder & "\"
End If
Set objFile = objFSO.GetFile( sFileName )
FilePath = objFSO.GetParentFolderName( objFile )
FilePath = sTempFolder & Mid(FilePath, 4)
fnCreatePath( FilePath )
CALL Debug( "FILECOPY = "& objFile.Name &" -> FilePath = " & FilePath )
objFile.Copy( FilePath & "\" & objFile.Name )
While NOT objFSO.FileExists( FilePath & "\" & objFile.Name )
wScript.Sleep 200
CALL Debug( "FileCopy Waiting" )
Wend
CALL Debug( "Temp FileCopy Completed" )
Set objFile = Nothing
End Function
' ----------------------------------------------
'Recursively creates a folder path
'Based on script from:
'http://www.techcoil.com/blog/handy-vbscript-functions-for-dealing-with-zip-files-and-folders/
Function fnCreatePath( folderUrl )
folderUrl = objFSO.GetAbsolutePathName(folderUrl)
If (Not objFSO.folderExists(objFSO.GetParentFolderName(folderUrl))) then
' Call CreateFolder recursively to create the parent folder
fnCreatePath(objFSO.GetParentFolderName(folderUrl))
End If
' Create the current folder if the parent exists
If (Not objFSO.FolderExists(folderUrl)) then
CALL Debug( "fnCreatePath; FolderURL = " & folderUrl )
objFSO.CreateFolder(folderUrl)
End If
End Function
' ----------------------------------------------
' Will return TRUE if folder is Empty or !Exist
Function fnFolderIsEmpty( sFolderName )
Dim objFolderFSO 'FileSystemObject
Dim objFolder
Set objFolderFSO = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
fnFolderIsEmpty = TRUE 'Return TRUE if it doesn't exist either
If objFolderFSO.FolderExists( sFolderName ) Then
Set objFolder = objFolderFSO.GetFolder( sFolderName )
If objFolder.Files.Count = 0 And objFolder.SubFolders.Count = 0 Then
fnFolderIsEmpty = TRUE
Else
fnFolderIsEmpty = FALSE
End If
End If
objFolderFSO = Nothing
objFolder = Nothing
End Function
' ----------------------------------------------
'Purpose: Return True if the file exists, even if it is hidden.
'Arguments: strFile: File name to look for. Current directory searched if no path included.
'Note: Does not look inside subdirectories for the file.
'Author: Allen Browne. http://allenbrowne.com June, 2006.
Function FileExists( strFile )
On Error Resume Next
DIM fso
Set fso = CreateObject("Scripting.FileSystemObject")
If (fso.FileExists( strFile )) Then
FileExists = TRUE
Else
FileExists = FALSE
End If
fso = Nothing
End Function
'---------------------------------------------------------------
'Based on: http://blogs.msdn.com/b/gstemp/archive/2004/08/11/213028.aspx
' Returns ArrayList of folders found in sDirectory
Function fnListDirIn( ByVal sDirectory )
Set objWMIService = GetObject("winmgmts:\\.")
CALL Debug( "fnListDirIn() Path=" & sDirectory )
Set colFolders = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_Directory.Name='" & sDirectory & "'} " _
& "WHERE AssocClass = Win32_Subdirectory " _
& "ResultRole = PartComponent")
Set arrNames = CreateObject("System.Collections.ArrayList")
For Each objFolder in colFolders
CALL Debug( "fnListDirIn Add Folder=" & objFolder.Name )
arrNames.Add( objFolder.name )
Next
'colFolders = Nothing ?Why does this fail?
'objFolder = Nothing ?Why does this fail?
Set fnListDirIn = arrNames
End Function
' ----------------------------------------------
'Checks available Windows Scripting Host Version
' - Quit Script if not available
'Based on: http://www.robvanderwoude.com/vbstech_debugging.php
Function fnCheckWSHversion( ByVal iMinVer )
intMajorVerion = 0 + CInt( Mid( WScript.Version, 1, InStr( WScript.Version, "." ) - 1 ) )
intMinorVerion = 0 + CInt( Mid( WScript.Version, InStr( WScript.Version, "." ) + 1 ) )
intCheckVersion = 1000 * intMajorVerion + intMinorVerion
CALL Debug( "WSH Version = " & intCheckVersion )
If intCheckVersion < iMinVer Then
WScript.Echo "Sorry, this script requires WSH " & iMinVer/1000 & " or later"
WScript.Quit intCheckVersion
End If
End Function
' ----------------------------------------------
' Dumps debug myText to an InternetExplorer Window
' Based on script from:
' http://www.robvanderwoude.com/vbstech_debugging.php
Sub Debug( myText )
' Uncomment the next line to turn off debugging
IF NOT bDebug THEN
Exit Sub
END IF
If Not IsObject( objIEDebugWindow ) Then
Set objIEDebugWindow = CreateObject( "InternetExplorer.Application" )
objIEDebugWindow.Navigate "about:blank"
objIEDebugWindow.Visible = True
objIEDebugWindow.ToolBar = False
objIEDebugWindow.Width = 200
objIEDebugWindow.Height = 300
objIEDebugWindow.Left = 10
objIEDebugWindow.Top = 10
Do While objIEDebugWindow.Busy
WScript.Sleep 100
Loop
objIEDebugWindow.Document.Title = "IE Debug Window"
objIEDebugWindow.Document.Body.InnerHTML = _
"<b>" & Now & "</b></br>"
End If
objIEDebugWindow.Document.Body.InnerHTML = _
objIEDebugWindow.Document.Body.InnerHTML _
& myText & "<br>" & vbCrLf
'Do NOT set objIEDebugWindow = Nothing; Will go away
End Sub
Let me know what you think. Thanks.
Is it possible to rename a file in a folder to its folder name using vbs? I have the following script which I am just using MsgBox at this time for debugging before I implement the renaming. for some reason tho ObjFolder doesnt change.
Option Explicit
Dim strFolderToSearch, objFSO, objRootFolder, objFolder, colSubfolders, strOutput, objStartFolder, colFiles, objFile
strFolderToSearch = "D:\Shared\Films"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objRootFolder = objFSO.GetFolder(strFolderToSearch)
Set colSubfolders = objRootFolder.SubFolders
For Each objFolder in colSubfolders
objStartFolder = objFolder
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile in colSubfolders
MsgBox objFile.name & "," & objFolder.name
Next
Next
I admit that I can't follow the tangle of your folders, subfolders, and files. But if you want to rename files in a folder, use this stratege:
Dim sDName : sDName = "FancyRename"
Dim sDName2 : sDName2 = "," & sDName
Dim oFile, sNewName
For Each oFile In goFS.GetFolder(goFS.BuildPath("..\testdata", sDName)).Files
If 0 = Instr(oFile.Name, sDName2) Then
sNewName = Replace(oFile.Name, ".", sDName2 & ".")
Else
sNewName = Replace(oFile.Name, sDName2, "")
End If
WScript.Echo oFile.Name, "=>", sNewName
oFile.Name = sNewName
Next
output of running this three times:
that.txt => that,FancyRename.txt
this.txt => this,FancyRename.txt
that,FancyRename.txt => that.txt
this,FancyRename.txt => this.txt
that.txt => that,FancyRename.txt
this.txt => this,FancyRename.txt
UPDATE
How about: Given a folder D and a file name F (e.g. someavi.avi), rename all (existing) Fs in D and its sub folders to "subfoldername.avi", unless such a file already exists:
recursiveRename goFS.GetFolder("..\testdata\FancyRename"), "someavi", "avi"
Sub recursiveRename(oDir, sFiNa, sExt)
WScript.Echo "Looking into", oDir.Path
Dim sOFiNa : sOFiNa = sFiNa & "." & sExt
Dim sOFSpec : sOFSpec = goFS.BuildPath(oDir.Path, sOFiNa)
Dim sNFSpec
If goFS.FileExists(sOFSpec) Then
WScript.Echo "found ", sOFSpec
sNFSpec = goFS.BuildPath(oDir.Path, oDir.Name & "." & sExt)
If goFS.FileExists(sNFSpec) Then
WScript.Echo "found ", sNFSpec, "- can't rename"
Else
WScript.Echo "found no", sNFSpec, "- will rename"
goFS.MoveFile sOFSpec, sNFSpec
End If
Else
WScript.Echo "found no", sOFSpec
End If
Dim oSubF
For Each oSubF In oDir.SubFolders
recursiveRename oSubF, sFiNa, sExt
Next
End Sub
sample output:
Looking into M:\lib\kurs0705\testdata\FancyRename
found no M:\lib\kurs0705\testdata\FancyRename\someavi.avi
Looking into M:\lib\kurs0705\testdata\FancyRename\subfa
found no M:\lib\kurs0705\testdata\FancyRename\subfa\someavi.avi
Looking into M:\lib\kurs0705\testdata\FancyRename\subfc
found M:\lib\kurs0705\testdata\FancyRename\subfc\someavi.avi
found no M:\lib\kurs0705\testdata\FancyRename\subfc\subfc.avi - will rename
Looking into M:\lib\kurs0705\testdata\FancyRename\subfb
found M:\lib\kurs0705\testdata\FancyRename\subfb\someavi.avi
found M:\lib\kurs0705\testdata\FancyRename\subfb\subfb.avi - can't rename
UPDATE II
Changed specs: rename .avi to folder name, if there is exactly one .avi
recursiveRename03 goFS.GetFolder("..\testdata\FancyRename")
Sub recursiveRename03(oDir)
WScript.Echo "Looking into", oDir.Path
Dim sNFSpec : sNFSpec = goFS.BuildPath(oDir.Path, oDir.Name & ".avi")
If goFS.FileExists(sNFSpec) Then
WScript.Echo "found ", sNFSpec, "- can't rename"
Else
Dim oOFile : Set oOFile = Nothing
Dim oFile
For Each oFile In oDir.Files
If "avi" = goFS.GetExtensionName(oFile.Name) Then
If oOFile Is Nothing Then
Set oOFile = oFile
Else
WScript.Echo "Found second avi", oFile.Name
Set oOFile = Nothing
Exit For
End If
End If
Next
If oOFile Is Nothing Then
WScript.Echo "not exactly one avi found"
Else
WScript.Echo "found ", oOFile.Name, "- will rename"
oOFile.Name = oDir.Name & ".avi"
End If
End If
Dim oSubF
For Each oSubF In oDir.SubFolders
recursiveRename03 oSubF
Next
End Sub
UPDATE III
If you use a global FSO or pass an FSO to the Subs/Functions needing
it, you avoid its repetitive re-creation.
If you pass a folder/file object instead of a string to the
Subs/Functions dealing with such objects, you can access their
properties/methods immediately/for free (no need to reclaim/get back
info by string operations).
If you rename a file, you must check whether there is a file having
the new name (it's not sufficient to check whether the file you work
with doesn't have the new name).
Idealistically, your script should have the following features:
Recursion - For traversing folders that are 1-n deep from D:\Shared\Films
Rename file function - For renaming match files according to your rule.
I wrote the following script that features the following routines:
RenameAllVideos(strFolder) - this will recursively search subfolders
RenameVideo(strFileName) - will rename a match video file using your rule
Here's my script:
Option Explicit
Call RenameAllVideos("D:\Shared\Films")
Sub RenameAllVideos(strFolder)
Dim fso, file, folder
Set fso = CreateObject("Scripting.FileSystemObject")
' Check for AVIs to rename.
For Each file in fso.GetFolder(strFolder).Files
If Right(file.Name, 4) = ".avi" Then
Call RenameVideo(strFolder & "\" & file.Name)
End If
Next
' Check for SubFolders to recurse into.
For Each folder in fso.GetFolder(strFolder).SubFolders
Call RenameAllVideos(strFolder & "\" & folder.Name)
Next
End Sub
Sub RenameVideo(strFileName)
Dim fso, strExt, strFolder, strNewFileName
Set fso = CreateObject("Scripting.FileSystemobject")
' Note the extension (should be avi)
strExt = fso.GetExtensionName(strFileName)
' Derive the full path to the folder.
strFolder = fso.GetParentFolderName(strFileName)
' Derive the new filename.
strNewFileName = strFolder & "\" & fso.GetBaseName(strFolder) & "." & strExt
' Do the rename.
If strFileName <> strNewFileName Then
WScript.Echo "Renaming " & strFileName & " to " & strNewFileName
fso.MoveFile strFileName, strNewFileName
End If
End Sub