DRAFTS\DEPARTMENTS\USERS - (each dept has there own folders and the users are in their own folder under their dept)
and
REVIEW\DEPARTMENTS
When users complete certain documents, they change the file extension to .fin and one of our departments has the job of going through each users folders and making a copy of all .fin files into the review section under the appropriate users. They then look over them to ensure that they are correct. I would like to write a script that could be run in a scheduled task every 6 hours or so that would go through all the subfolders of drafts, look for .fin files and make a copy based on their dept into the review directory.
I think that I need to dump the absolute paths of all the .fin files to a text file, so that I can use ReadLine to determine what directory it should be copied too. Is this the best way to do this? Any advice or code samples that you can point me to would be great.
Some questions... 1. Is there a USERS folder below REVIEW\DEPARTMENTS? If not, how do/will you avoid filename collisions?
2. Are the *.fin files to be COPIED or MOVED? (i.e., will they still exist in their original location after the scheduled job runs?).
3. If they are just COPIED, should they be re-COPIED on subsequent runs if they are newer than the copy already in the REVIEW... path?
1. There are no users folder below review\dept, this is due to the fact that the naming scheme uses julian date, employee id, series, so filename collisions cannot happen. We do not want individual users folders below this because we want everything to be centrally located (300) users, I do not want them having to go into 300 different folders to look for new files.
2 & 3. They should be copied if the archive bit (or some other mechanism) can detect changes. If not then moving would be sufficent. I do not want to be overwriting the same file 3-4 times a day.
While we wait for further information - do you think that this (kind of) code would be a frame'work'/starting point to develop a solution?
Wow I have no idea. That is way over my head. I haven't been able to get arrays down. here is what I had come up with with the help of a few postings in this forum and a few websites. Right now all it does is get the path of all files with .fin and append each to the bottom of the found.log, it also displays each one for testing (it will not do this in production). So I was thinking if I could use the found.log as an input and based on which department the users were in they could be moved to the same department without the individual user folders. Is the script you wrote more efficent? Will yours do what I want? Let me know what you think.
I have a VBScript app that I wrote a few months ago that includes all the logic to perform this task. Everything is cone in script... no shelling to run external command is necessary. I'll try to segment this code out of the larger (much, much larger) app and post it sometime this evening.
Here is the script I carved out of the larger app... I've only performed minimal testing, but it appears to be sound.
'***************************************************************************************** ' Promote.vbs ' ' This script "promotes" files from the DRAFTS\departments\users folders to the ' REVIEW\departments folders and changes their extension to ".fin". ' ' Only copies files that are not already at destination or are newer than at destination. ' Files are determined to be newer if the "DateLastUpdated" is more recent. ' '*****************************************************************************************
Option Explicit
Dim oFSO Dim DraftsRoot, ReviewRoot Dim buFileCount Dim StopNow, arrDept, n Dim Folder
Set oFSO = CreateObject("Scripting.FileSystemObject")
'-- determine if directory root structures exist... If Not oFSO.FolderExists(DraftsRoot) Then Wscript.Echo "Path to root of DRAFTS is invalid." StopNow = True End If
If Not oFSO.FolderExists(ReviewRoot) Then Wscript.Echo "Path to root of REVIEW is invalid." StopNow = True End If
If StopNow Then Wscript.Echo "Terminating due to error(s)." Wscript.Quit(16) End If
'-- ensure that all department folders exist under REVIEW arrDept = GetFolders(DraftsRoot) For n = 0 To UBound(arrDept) Folder = ReviewRoot & arrDept(n) If Not oFSO.FolderExists(Folder) Then oFSO.CreateFolder Folder End If Next
'-- Let's get to work... For n = 0 To UBound(arrDept) ScanFiles DraftsRoot & arrDept(n), ReviewRoot & arrDept(n) Next
Sub ScanFiles(SrcPath, DestPath) Dim oFolder, colFiles Dim SrcFileName, DestFileName Dim nExtPos, oFile Dim SrcFile, oSrcFile Dim DestFile, oDestFile Dim arrUser, UserPath Dim n
arrUser = GetFolders(SrcPath) For n = 0 To UBound(arrUser) UserPath = SrcPath & arrUser(n) Set oFolder = oFSO.GetFolder(UserPath) Set colFiles = oFolder.Files For Each oFile In colFiles SrcFileName = oFile.Name nExtPos = InStrRev(oFile.Name, ".") DestFileName = Left(oFile.Name, nExtPos) & "fin" SrcFile = UserPath & "\" & SrcFileName Set oSrcFile = oFSO.GetFile(SrcFile) DestFile = DestPath & "\" & DestFileName
If Not oFSO.FileExists(DestFile) Then oSrcFile.Copy DestFile, False buFileCount = buFileCount + 1 Else Set oDestFile = oFSO.GetFile(DestFile) If oSrcFile.DateLastModified > oDestFile.DateLastModified Then oSrcFile.Copy oDestFile, True buFileCount = buFileCount + 1 End If End If Next Next
Set oSrcFile = Nothing Set oDestFile = Nothing Set colFiles = Nothing Set oFolder = Nothing
End Sub
Function GetFolders(BaseFolder) Dim oBaseFolder Dim SubFolder Dim strArr
Set oBaseFolder = oFSO.GetFolder(BaseFolder) For Each SubFolder In oBaseFolder.SubFolders If Not IsEmpty(SubFolder) Then strArr = strArr & "+" & Mid(SubFolder, Len(BaseFolder) + 1) End If Next
GetFolders = Split(Mid(strArr, 2), "+") Set oBaseFolder = Nothing
I proposed this (rather simple) framework for two reasons
It keeps the code needed for different sub problems of whole solution separate
You can switch between different attempts to solve a sub problem by the simple method of [un]commenting calls to subs/functions
To show what I mean
To work with your problem, I need to set up a testing environment (no 300 users on my maschine); doFinCSetup() will do this for me (and I hope for Xandros too); you don't need it, but if you find some flaw in the concept or the code we can concentrate on just one function
Now I know that there are no user directories under REVIEW\DEPARTMENTS; the concept of doCheck() - looking for files in parallel directories - is wrong; we have to assert that for each .fin file under DRAFTS\DEPARTMENTS there is a file with a corresponding name directly REVIEW\DEPARTMENTS
To tackle the sub problem "corresponding name" I insert "aRVal = doFName()" into the main code to call this function
Now we can discuss/work on/test the format for the date in the new file name, the best method to determine the exmployee id (hard coding into script, database access, ...) and the meaning of 'series'.
Looking at Xandros' code and the text of the first post, I realized my error concerning the directory structure under DRAFTS\DEPARTMENTS\. But I only had to replace the array aTests with entries like
and run doFinCSetup( aTests ) to create the more complex test environment.
But of course now I have to ask - shound it be
and "Are the user names (directory names) unique?"
Then I took Xandros' code, promoted his main code to a function promoteXandros(), changed the *Root vars, added oFS and buFileCount as parameters to the functions ScanFiles() and GetFolders(), called promoteXandros() from my maincode and - as I expected - it worked like a charm.
But I think we have to work on the "create corresponding file name" problem und to think about this scenario:
06/28/2005 17:00 carl saves his work in DRAFTS\DEP01\carl\xxx.fin and goes home
06/29/2005 01:00 the script copies the file to \REVIEW\DEP01\yyy.fin
06/29/2005 11:00 reviewer robert saves his changes to yyy.fin
06/29/2005 11:01 carl changes DRAFTS\DEP01\carl\xxx.fin
06/30/2005 01:00 the script copies the file to \REVIEW\DEP01\yyy.fin and clobbers robert's work
DRAFTS\DEPARTMENTS\USERS - (each dept has there own folders and the users are in their own folder under their dept)
and
REVIEW\DEPARTMENTS
When users complete certain documents, they change the file extension to .fin and one of our departments has the job of going through each users folders and making a copy of all .fin files into the review section under the appropriate users. They then look over them to ensure that they are correct. I would like to write a script that could be run in a scheduled task every 6 hours or so that would go through all the subfolders of drafts, look for .fin files and make a copy based on their dept into the review directory.
I think that I need to dump the absolute paths of all the .fin files to a text file, so that I can use ReadLine to determine what directory it should be copied too. Is this the best way to do this? Any advice or code samples that you can point me to would be great.
XANDROS & EHVBS -
First off: Thanks for taking the time to help me.
Second: Let me clarify a few points.
-File Structure DRAFTS\%DEPARTMENT%\%USER% (the %department% and %user% being variables, all of them unique) REVIEW\%DEPARTMENT% (the %department% directory contains no subfolders, all documents for the particular department or copied/moved from the Drafts side of the house)
-File Names Users will work on the files in the files with the proper file extension (.doc) then when ready for them to be reviewed they manually rename them (.fin) this way the reviewer can find them (they have a file association so it still works). All users working documents are stored in the Drafts directory, finished ones are moved/copied out. File names are created by the users manually upon document creation. Users name them based on the julian date (numbered day of the year) employee id (all unique) and series number (001 for the first doc of the day, 002 for the second etc.). So xxx.fin should be copied/moved and maintain the same name (not renamed to yyy.fin).
I hope this clears everything up. If you have specific questions about what I need you can email me at mattnmel.mattoon@NOSPAM.gmail.com (remove "NOSPAM.")
Likewise, it appears I should have read more closely as well . I believe I implemented the directory traversal logic correctly, however. Here is a modified version of the script I posted earlier that limits the processing to files already named with the ".fin" extension. It has two additional options coded (but disabled, by default). It can optionally remove the file after copying and it can optionally remove old files which were previously copied manually.
'***************************************************************************************** ' Promote.vbs ' ' This script "promotes" files from the DRAFTS\departments\users folders to the ' REVIEW\departments folders. Only files with the extension of ".fin" are processed. ' Copied files can optionally be deleted from users folder. ' ' Only copies files that are not already at destination or are newer than at destination. ' Files are determined to be newer if the "DateLastUpdated" is more recent. ' '*****************************************************************************************
Option Explicit
Dim oFSO Dim DraftsRoot, ReviewRoot Dim buFileCount, ofFileCount Dim StopNow, arrDept, n Dim Folder Dim DeleteAfterCopy Dim DeleteOldFiles Dim Message
DraftsRoot = "E:\ee\drafts" ReviewRoot = "E:\ee\review" DeleteAfterCopy = False ' change to TRUE if you want to remove the original file ' from the user's folder after copying it to REVIEW.
DeleteOldFiles = False ' change to TRUE if you want to remove old ".FIN" files ' from the user's folder (they were previously copied to REVIEW)
buFileCount = 0 ofFileCount = 0
Set oFSO = CreateObject("Scripting.FileSystemObject")
'-- determine if directory root structures exist... If Not oFSO.FolderExists(DraftsRoot) Then Wscript.Echo "Path to root of DRAFTS is invalid." StopNow = True End If
If Not oFSO.FolderExists(ReviewRoot) Then Wscript.Echo "Path to root of REVIEW is invalid." StopNow = True End If
If StopNow Then Wscript.Echo "Terminating due to error(s)." Wscript.Quit(16) End If
'-- ensure that all department folders exist under REVIEW arrDept = GetFolders(DraftsRoot) For n = 0 To UBound(arrDept) Folder = ReviewRoot & arrDept(n) If Not oFSO.FolderExists(Folder) Then oFSO.CreateFolder Folder End If Next
'-- Let's get to work... For n = 0 To UBound(arrDept) ScanFiles DraftsRoot & arrDept(n), ReviewRoot & arrDept(n) Next
Message = "Finished! " & buFileCount & " files backed up" If DeleteAfterCopy Then Message = Message & " files backed up and removed" End If
If DeleteOldFiles Then Message = Message & ", " & ofFileCount & " old files removed" End If Wscript.Echo Message & "."
Set oFSO = Nothing
Sub ScanFiles(SrcPath, DestPath) Dim oFolder, colFiles Dim FileName, oFile Dim SrcFile, oSrcFile Dim DestFile, oDestFile Dim arrUser, UserPath Dim n
arrUser = GetFolders(SrcPath) For n = 0 To UBound(arrUser) UserPath = SrcPath & arrUser(n) Set oFolder = oFSO.GetFolder(UserPath) Set colFiles = oFolder.Files For Each oFile In colFiles FileName = oFile.Name If LCase(Right(FileName, 4)) = ".fin" Then SrcFile = UserPath & "\" & FileName Set oSrcFile = oFSO.GetFile(SrcFile) DestFile = DestPath & "\" & FileName
If Not oFSO.FileExists(DestFile) Then oSrcFile.Copy DestFile, False buFileCount = buFileCount + 1 If DeleteAfterCopy Then oSrcFile.Delete End If Else Set oDestFile = oFSO.GetFile(DestFile) If oSrcFile.DateLastModified > oDestFile.DateLastModified Then oSrcFile.Copy oDestFile, True buFileCount = buFileCount + 1 If DeleteAfterCopy Then oSrcFile.Delete End If ElseIf DeleteOldFiles Then oSrcFile.Delete ofFileCount = ofFileCount + 1 End If End If End If Next Next
Set oSrcFile = Nothing Set oDestFile = Nothing Set colFiles = Nothing Set oFolder = Nothing
End Sub
Function GetFolders(BaseFolder) Dim oBaseFolder Dim SubFolder Dim strArr
Set oBaseFolder = oFSO.GetFolder(BaseFolder) For Each SubFolder In oBaseFolder.SubFolders If Not IsEmpty(SubFolder) Then strArr = strArr & "+" & Mid(SubFolder, Len(BaseFolder) + 1) End If Next
GetFolders = Split(Mid(strArr, 2), "+") Set oBaseFolder = Nothing
Likewise, it appears I should have read more closely as well . I believe I implemented the directory traversal logic correctly, however. Here is a modified version of the script I posted earlier that limits the processing to files already named with the ".fin" extension. It has two additional options coded (but disabled, by default). It can optionally remove the file after copying and it can optionally remove old files which were previously copied manually.
'***************************************************************************************** ' Promote.vbs ' ' This script "promotes" files from the DRAFTS\departments\users folders to the ' REVIEW\departments folders. Only files with the extension of ".fin" are processed. ' Copied files can optionally be deleted from users folder. ' ' Only copies files that are not already at destination or are newer than at destination. ' Files are determined to be newer if the "DateLastUpdated" is more recent. ' '*****************************************************************************************
Option Explicit
Dim oFSO Dim DraftsRoot, ReviewRoot Dim buFileCount, ofFileCount Dim StopNow, arrDept, n Dim Folder Dim DeleteAfterCopy Dim DeleteOldFiles Dim Message
DraftsRoot = "E:\ee\drafts" ReviewRoot = "E:\ee\review" DeleteAfterCopy = False ' change to TRUE if you want to remove the original file ' from the user's folder after copying it to REVIEW.
DeleteOldFiles = False ' change to TRUE if you want to remove old ".FIN" files ' from the user's folder (they were previously copied to REVIEW)
buFileCount = 0 ofFileCount = 0
Set oFSO = CreateObject("Scripting.FileSystemObject")
'-- determine if directory root structures exist... If Not oFSO.FolderExists(DraftsRoot) Then Wscript.Echo "Path to root of DRAFTS is invalid." StopNow = True End If
If Not oFSO.FolderExists(ReviewRoot) Then Wscript.Echo "Path to root of REVIEW is invalid." StopNow = True End If
If StopNow Then Wscript.Echo "Terminating due to error(s)." Wscript.Quit(16) End If
'-- ensure that all department folders exist under REVIEW arrDept = GetFolders(DraftsRoot) For n = 0 To UBound(arrDept) Folder = ReviewRoot & arrDept(n) If Not oFSO.FolderExists(Folder) Then oFSO.CreateFolder Folder End If Next
'-- Let's get to work... For n = 0 To UBound(arrDept) ScanFiles DraftsRoot & arrDept(n), ReviewRoot & arrDept(n) Next
Message = "Finished! " & buFileCount & " files backed up" If DeleteAfterCopy Then Message = Message & " files backed up and removed" End If
If DeleteOldFiles Then Message = Message & ", " & ofFileCount & " old files removed" End If Wscript.Echo Message & "."
Set oFSO = Nothing
Sub ScanFiles(SrcPath, DestPath) Dim oFolder, colFiles Dim FileName, oFile Dim SrcFile, oSrcFile Dim DestFile, oDestFile Dim arrUser, UserPath Dim n
arrUser = GetFolders(SrcPath) For n = 0 To UBound(arrUser) UserPath = SrcPath & arrUser(n) Set oFolder = oFSO.GetFolder(UserPath) Set colFiles = oFolder.Files For Each oFile In colFiles FileName = oFile.Name If LCase(Right(FileName, 4)) = ".fin" Then SrcFile = UserPath & "\" & FileName Set oSrcFile = oFSO.GetFile(SrcFile) DestFile = DestPath & "\" & FileName
If Not oFSO.FileExists(DestFile) Then oSrcFile.Copy DestFile, False buFileCount = buFileCount + 1 If DeleteAfterCopy Then oSrcFile.Delete End If Else Set oDestFile = oFSO.GetFile(DestFile) If oSrcFile.DateLastModified > oDestFile.DateLastModified Then oSrcFile.Copy oDestFile, True buFileCount = buFileCount + 1 If DeleteAfterCopy Then oSrcFile.Delete End If ElseIf DeleteOldFiles Then oSrcFile.Delete ofFileCount = ofFileCount + 1 End If End If End If Next Next
Set oSrcFile = Nothing Set oDestFile = Nothing Set colFiles = Nothing Set oFolder = Nothing
End Sub
Function GetFolders(BaseFolder) Dim oBaseFolder Dim SubFolder Dim strArr
Set oBaseFolder = oFSO.GetFolder(BaseFolder) For Each SubFolder In oBaseFolder.SubFolders If Not IsEmpty(SubFolder) Then strArr = strArr & "+" & Mid(SubFolder, Len(BaseFolder) + 1) End If Next
GetFolders = Split(Mid(strArr, 2), "+") Set oBaseFolder = Nothing
End Function
BAM!!!! It worked like a charm. One more thing (I did not include this in my original post). How can I write an event to the app or sys log that enumerates all the files that are moved original and new absolute pathnames in only one entry?
Revised script to include recording actions taken in the App Event Log... If this (and/or other processes) write heavily to the event logs, I would suggest you use an automated monitor to keep tabs on the sizes of these logs.
'***************************************************************************************** ' Promote.vbs ' ' This script "promotes" files from the DRAFTS\departments\users folders to the ' REVIEW\departments folders. Only files with the extension of ".fin" are processed. ' Copied files can optionally be deleted from users folder. ' All files copied, moved, or removed are logged to the Application Event Log. ' ' Only copies files that are not already at destination or are newer than at destination. ' Files are determined to be newer if the "DateLastUpdated" is more recent. ' '*****************************************************************************************
Option Explicit
Dim oFSO, oShell Dim DraftsRoot, ReviewRoot Dim buFileCount, ofFileCount Dim StopNow, arrDept, n Dim Folder Dim DeleteAfterCopy Dim DeleteOldFiles Dim LogMessage, Message
DraftsRoot = "E:\ee\drafts" ReviewRoot = "E:\ee\review" DeleteAfterCopy = False ' change to TRUE if you want to remove the original file ' from the user's folder after copying it to REVIEW.
DeleteOldFiles = False ' change to TRUE if you want to remove old ".FIN" files ' from the user's folder (they were previously copied to REVIEW)
buFileCount = 0 ofFileCount = 0 LogMessage = "PROMOTE.VBS -- Started at " & Now()
Set oFSO = CreateObject("Scripting.FileSystemObject") Set oShell = CreateObject("Wscript.Shell")
'-- determine if directory root structures exist... If Not oFSO.FolderExists(DraftsRoot) Then Wscript.Echo "Path to root of DRAFTS is invalid." StopNow = True End If
If Not oFSO.FolderExists(ReviewRoot) Then Wscript.Echo "Path to root of REVIEW is invalid." StopNow = True End If
If StopNow Then Wscript.Echo "Terminating due to error(s)." Set oFSO = Nothing Set oShell = Nothing Wscript.Quit(16) End If
'-- ensure that all department folders exist under REVIEW arrDept = GetFolders(DraftsRoot) For n = 0 To UBound(arrDept) Folder = ReviewRoot & arrDept(n) If Not oFSO.FolderExists(Folder) Then oFSO.CreateFolder Folder End If Next
'-- Let's get to work... For n = 0 To UBound(arrDept) ScanFiles DraftsRoot & arrDept(n), ReviewRoot & arrDept(n) Next
Message = "Finished! " & buFileCount & " files backed up" If DeleteAfterCopy Then Message = Message & " files backed up and removed" End If
If DeleteOldFiles Then Message = Message & ", " & ofFileCount & " old files removed" End If Wscript.Echo Message & "."
LogMessage = LogMessage & vbCrLf & "Ended at " & Now() & vbCrLf If Not oShell.LogEvent(4, LogMessage) Then Wscript.Echo "PROMOTE.VBS failed to write to the Application Event Log!" Wscript.Echo LogMessage End If
Set oFSO = Nothing Set oShell = Nothing
Sub ScanFiles(SrcPath, DestPath) Dim oFolder, colFiles Dim FileName, oFile Dim SrcFile, oSrcFile Dim DestFile, oDestFile Dim arrUser, UserPath Dim n
arrUser = GetFolders(SrcPath) For n = 0 To UBound(arrUser) UserPath = SrcPath & arrUser(n) Set oFolder = oFSO.GetFolder(UserPath) Set colFiles = oFolder.Files For Each oFile In colFiles FileName = oFile.Name If LCase(Right(FileName, 4)) = ".fin" Then SrcFile = UserPath & "\" & FileName Set oSrcFile = oFSO.GetFile(SrcFile) DestFile = DestPath & "\" & FileName
If Not oFSO.FileExists(DestFile) Then oSrcFile.Copy DestFile, False buFileCount = buFileCount + 1 If DeleteAfterCopy Then oSrcFile.Delete LogMessage = LogMessage & vbCrLf & "Moved " & SrcFile & " to " & DestFile Else LogMessage = LogMessage & vbCrLf & "Copied " & SrcFile & " to " & DestFile End If Else Set oDestFile = oFSO.GetFile(DestFile) If oSrcFile.DateLastModified > oDestFile.DateLastModified Then oSrcFile.Copy oDestFile, True buFileCount = buFileCount + 1 If DeleteAfterCopy Then oSrcFile.Delete LogMessage = LogMessage & vbCrLf & "Moved/Replaced " & SrcFile & " to " & DestFile Else LogMessage = LogMessage & vbCrLf & "Copied/Replaced " & SrcFile & " to " & DestFile End If ElseIf DeleteOldFiles Then oSrcFile.Delete ofFileCount = ofFileCount + 1 LogMessage = LogMessage & vbCrLf & "Removed " & SrcFile End If End If End If Next Next
Set oSrcFile = Nothing Set oDestFile = Nothing Set colFiles = Nothing Set oFolder = Nothing
End Sub
Function GetFolders(BaseFolder) Dim oBaseFolder Dim SubFolder Dim strArr
Set oBaseFolder = oFSO.GetFolder(BaseFolder) For Each SubFolder In oBaseFolder.SubFolders If Not IsEmpty(SubFolder) Then strArr = strArr & "+" & Mid(SubFolder, Len(BaseFolder) + 1) End If Next
GetFolders = Split(Mid(strArr, 2), "+") Set oBaseFolder = Nothing