Yesterday we have finalized and tested the code (the first part of the code is VBScript) and the second part of the code is (in Excel VBA) to move file from one source folder to one destination folder successfully based on two hour delay (i.e. each file which will come to source folder will upload 2 hour delay), however the situation is that i have actually 15 source folders and 15 destination folders.
One method is that i should create 15 VBScript files and 15 Excel files that contains the code for each source and destination folder which i believe is not efficient way. I have tried a lot to add multiple source and destination folder options in the below mentioned code(s) but i am not successful, can anyone help me, i will be thankful.
the below mentioned code is VBscript
Dim oExcel, strWB, nameWB, wb
strWB = "E:\Delta\Folder monitor.xlsm"
nameWB = Left(strWB, InStr(StrReverse(strWB), "\") - 1)
nameWB = Right(strWB, Len(nameWB))
Set objExcel = GetObject(,"Excel.Application")
Set wb = objExcel.Workbooks(nameWB)
if wb is nothing then wbscript.quit 'the necessary workbook is not open...
dim strComputer, strDirToMonitor, strTime, objWMIService, colMonitoredEvents, objEventObject, MyFile
strComputer = "."
'# WMI needs two backslashes (\\) as path separator and each of it should be excaped.
'# So, you must use 4 backslashes (\\\\) as path separator!
strDirToMonitor = "E:\\\\Delta\\\\Source" 'use here your path
'# Monitor Above every 10 secs...
strTime = "10"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent WITHIN " & strTime & " WHERE " _
& "Targetinstance ISA 'CIM_DirectoryContainsFile' and " _
& "TargetInstance.GroupComponent= " _
& "'Win32_Directory.Name=" & Chr(34) & strDirToMonitor & Chr(34) & "'")
Do While True
Set objEventObject = colMonitoredEvents.NextEvent()
Select Case objEventObject.Path_.Class
Case "__InstanceCreationEvent"
' msgbox "OK"
'MsgBox "A new file was just created: " & _
MyFile = StrReverse(objEventObject.TargetInstance.PartComponent)
'// Get the string to the left of the first \ and reverse it
MyFile = (StrReverse(Left(MyFile, InStr(MyFile, "\") - 1)))
MyFile = Mid(MyFile, 1, Len(MyFile) - 1)
'send the information to the waiting workbook:
objExcel.Application.Run "'" & strWB & "'!GetMonitorInformation", Array(MyFile,Now)
End Select
Loop
and the second code for this purpose should be copied in a standard module:
Option Explicit
Private Const ourScript As String = "FolderMonitor.vbs"
Private Const fromPath As String = "E:\Delta\Source\"
Sub startMonitoring()
Dim strVBSPath As String
strVBSPath = ThisWorkbook.Path & "\VBScript\" & ourScript
TerminateMonintoringScript 'to terminate monitoring script, if running..
Shell "cmd.exe /c """ & strVBSPath & """", 0
End Sub
Sub TerminateMonintoringScript()
Dim objWMIService As Object, colItems As Object, objItem As Object, Msg
As String
Set objWMIService = GetObject("winmgmts:\\" & "." & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Process", "WQL", 48)
For Each objItem In colItems
If objItem.Caption = "wscript.exe" Then
'// msg Contains the path of the exercutable script and the script name
On Error Resume Next
Msg = objItem.CommandLine 'for the case of null
On Error GoTo 0
'// If wbscript.exe runs the monitoring script:
If InStr(1, Msg, ourScript) > 0 Then
Debug.Print "Terminate Wscript process..."
objItem.Terminate 'terminate process
End If
End If
Next
Set objWMIService = Nothing: Set colItems = Nothing
End Sub
Sub GetMonitorInformation(arr As Variant)
'call DoSomething Sub after 2 hours (now IT WILL RUN AFTER 1 MINUTE, for testing reasons...)
'for running after 2 hours you should change "00:01:00" in "02:00:00":
arr(0) = Replace(arr(0), "'", "''") 'escape simple quote (') character'
Application.OnTime CDate(arr(1)) + TimeValue("00:01:00"), "'DoSomething """ & CStr(arr(0)) & """'"
Debug.Print "start " & Now 'just for testing (wait a minute...)
'finaly, this line should be commented.
End Sub
Sub DoSomething(strFileName As String)
Const toPath As String = "E:\Delta\Destination\"
If Dir(toPath & strFileName) = "" Then
Name fromPath & strFileName As toPath & strFileName
Debug.Print strFileName & " moved from " & fromPath & " to " & toPath 'just for testing...
Else
MsgBox "File """ & toPath & strFileName & """ already exists in this location..."
End If
End Sub
you can see the previous query here on the link Previous Query
Please, use the next scenario. It assumes that you will fill the necessary path in an existing Excel sheet. Since, it will take the necessary paths based on a cell selection, it is necessary to name the sheet in discussion as "Folders". In Column A:A you should fill the 'Source' folder path (ending in backslash "") and in B:B, the 'Destination' folder path (also ending in backslash).
The proposed solution takes the necessary paths based on your selection in A:A column. The 'Destination' path is extracted based on the selection row.
Please, replace the existing string with the next one, adapting the two necessary paths:
Dim oExcel, strWB, nameWB, wb
strWB = "C:\Teste VBA Excel\Folder monitor.xlsm" 'use here your workbook path!!!
nameWB = Left(strWB, InStr(StrReverse(strWB), "\") - 1)
nameWB = Right(strWB, Len(nameWB))
Set objExcel = GetObject(,"Excel.Application")
Set wb = objExcel.Workbooks(nameWB)
if wb is nothing then wbscript.quit 'the necessary workbook is not open...
dim strComputer, strDirToMonitor, strTime, objWMIService, colMonitoredEvents, objEventObject, MyFile
strComputer = "."
'# WMI needs two backslashes (\\) as path separator and each of it should be excaped.
'# So, you must use 4 backslashes (\\\\) as path separator!
strDirToMonitor = "C:\\\\test\\\\test" 'use here your path !!!
'# Monitor Above every 10 secs...
strTime = "10"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent WITHIN " & strTime & " WHERE " _
& "Targetinstance ISA 'CIM_DirectoryContainsFile' and " _
& "TargetInstance.GroupComponent= " _
& "'Win32_Directory.Name=" & Chr(34) & strDirToMonitor & Chr(34) & "'")' and " _
' & "'Win32_Directory.Name=" & Chr(34) & strDirToMonitor & Chr(34) & "'")
Do While True
Set objEventObject = colMonitoredEvents.NextEvent()
Select Case objEventObject.Path_.Class
Case "__InstanceCreationEvent"
MyFile = StrReverse(objEventObject.TargetInstance.PartComponent)
' Get the string to the left of the first \ and reverse it
MyFile = (StrReverse(Left(MyFile, InStr(MyFile, "\") - 1)))
MyFile = Mid(MyFile, 1, Len(MyFile) - 1)
'send the information to the waiting workbook:
objExcel.Application.Run "'" & strWB & "'!GetMonitorInformation", Array(MyFile, Now, strDirToMonitor)
End Select
Loop
The adapted script sends also the source path to the waiting workbook...
TerminateMonintoringScript Sub remains exactly as it is.
Please, copy the next adapted code instead of existing one, in the used standard module (TerminateMonintoringScript included, even not modified):
Option Explicit
Private Const ourScript As String = "FolderMonitor.vbs"
Private fromPath As String, toPath As String
Sub startMonitoring()
Dim strVBSPath As String, actCell As Range, strTxt As String, pos As Long, endP As Long, oldPath As String
Set actCell = ActiveCell
If actCell.Parent.Name <> "Folders" Then MsgBox "Wrong activated sheet...": Exit Sub
fromPath = actCell.Value
If actCell.Column <> 1 Or Dir(fromPath, vbDirectory) = "" Then Exit Sub 'not a valid path in the selected cell
strVBSPath = ThisWorkbook.Path & "\VBScript\" & ourScript
'change the script necessary "strDirToMonitor" variable path, if the case:__________________________
strTxt = ReadFile(strVBSPath)
pos = InStr(strTxt, Replace(fromPath, "\", "\\\\"))
If pos = 0 Then 'if not the correct path already exists
pos = InStr(strTxt, "strDirToMonitor = """) 'start position of the existing path
endP = InStr(strTxt, """ 'use here your path") 'end position of the existing path
'extract existing path:
oldPath = Mid(strTxt, pos + Len("strDirToMonitor = """), endP - (pos + Len("strDirToMonitor = """)))
strTxt = Replace(strTxt, oldPath, _
Replace(Left(fromPath, Len(fromPath) - 1), "\", "\\\\")) 'replacing existing with the new one
'drop back the updated string in the vbs file:
Dim iFileNum As Long: iFileNum = FreeFile
Open strVBSPath For Output As iFileNum
Print #iFileNum, strTxt
Close iFileNum
End If
'__________________________________________________________________________________________________
TerminateMonintoringScript 'to terminate monitoring script, if running...
Application.Wait Now + TimeValue("00:00:02") 'to be sure that the next line will load the updated file...
Shell "cmd.exe /c """ & strVBSPath & """", 0 'run the VBScript
End Sub
Function ReadFile(strFile As String) As String 'function to read the vbscript string content
Dim iTxtFile As Integer
iTxtFile = FreeFile
Open strFile For Input As iTxtFile
ReadFile = Input(LOF(iTxtFile), iTxtFile)
Close iTxtFile
End Function
Sub TerminateMonintoringScript()
Dim objWMIService As Object, colItems As Object, objItem As Object, Msg As String
Set objWMIService = GetObject("winmgmts:\\" & "." & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Process", "WQL", 48)
For Each objItem In colItems
If objItem.Caption = "wscript.exe" Then
'// msg Contains the path of the exercutable script and the script name
On Error Resume Next
Msg = objItem.CommandLine 'for the case of null
On Error GoTo 0
'// If wbscript.exe runs the monitoring script:
If InStr(1, Msg, ourScript) > 0 Then
Debug.Print "Terminate Wscript process..."
objItem.Terminate 'terminate process
End If
End If
Next
Set objWMIService = Nothing: Set colItems = Nothing
End Sub
Sub GetMonitorInformation(arr As Variant)
'call DoSomething Sub after 2 hours (now IT WILL RUN AFTER 1 MINUTE, for testing reasons...)
'for running after 2 hours you should change "00:01:00" in "02:00:00":
arr(0) = Replace(arr(0), "'", "''") 'escape simple quote (') character'
fromPath = Replace(arr(2), "\\\\", "\")
Dim rngFrom As Range: Set rngFrom = ThisWorkbook.Sheets("Folders").Range("A:A").Find(what:=fromPath)
toPath = rngFrom.Offset(, 1).Value
Application.OnTime CDate(arr(1)) + TimeValue("00:00:30"), "'DoSomething """ & fromPath & "\" & CStr(arr(0)) & """, """ & toPath & CStr(arr(0)) & """'"
Debug.Print Now; " start " & arr(0) & fromPath & "\" & CStr(arr(0)) 'just for testing (wait a minute...)
'finaly, this line should be commented.
End Sub
Sub DoSomething(sourceFileName As String, destFilename As String)
If Dir(destFilename) = "" Then
Name sourceFileName As destFilename
Debug.Print sourceFileName & " moved to " & destFilename 'just for testing...
Else
Debug.Print "File """ & destFilename & """ already exists in this location..."
End If
End Sub
Sub DoSomething_(strFileName As String) 'cancelled
If Dir(toPath & strFileName) = "" Then
Name fromPath & strFileName As toPath & strFileName
Debug.Print strFileName & " moved from " & fromPath & " to " & toPath 'just for testing...
Else
MsgBox "File """ & toPath & strFileName & """ already exists in this location..."
End If
End Sub
So, you only need to replace the existing VBA code with the above adapted one, to place the 'source'/'destination' paths in columns A:B of one of Excel sheets, which to be named "Folders".
Select in column A:A a 'Source' cell and run startMonitoring.
Play with files creation and check their moving from the new 'source' to the new 'destination'...
But you have to understand that only a session of the WMI class can run at a specific moment. This means that you cannot simultaneously monitor more than one folder...
I am still documenting regarding the possibility to use a query able to be common for multiple folders. But I never could see such an approach till now and it may not be possible...
I'm having trouble deleting a file based on cell value.
I get an error message on the line with the Kill command below:
Kill path & r.Offset(1, -4) & "\" & r.Offset(1, -3)
Any ideas?
Sub INACTIVE_files()
Const path = "C:\Users\NikolouzosD\AppData\Local\Temp\vbakillfunction\"
Dim r As Range
Dim x As Integer
Set r = Cells(1, 5)
Do Until r = ""
If UCase(r.value) = "INACTIVE" Then
Kill path & r.Offset(1, -4) & "\" & r.Offset(1, -3)
End If
Set r = r.Offset(1, 0)
Loop
End Sub
The code starts from cell E1 and looks for INACTIVE files in the same column, until there's no more files to look for.
Then, it checks the folder name (Column A), combines it with the Cube (Column B)
and puts both of them in a path:
path = "C:\Users\NikolouzosD\AppData\Local\Temp\vbakillfunction\"
so for example:
for cell E2 which is INACTIVE, the path should be:
C:\Users\NikolouzosD\AppData\Local\Temp\vbakillfunction\WPO 17 02 04 3MMT All Periods\BG023104.txt
It then deletes the INACTIVE files (Cubes) from the appropriate folder.
Wrap your path in double quotes to avoid issues with spaces in filenames and folders.
Even better is to put the path in a string variable so you can debug it easily
Outside your loop:
Dim strPath As String
Inside your if block:
strPath = """" & path & r.Offset(1,-4) & "\" & r.Offset(1,-3) & """"
Debug.Print strPath ' Ctrl-G to view results
Kill strPath
EDIT - add a check for file before deleting
Under Tools | References
Add a reference to Windows Script Hosting
Then at top of sub code add
Dim fso as New FileSystemObject
Replace your Kill command with a check for existence
If fso.FileExists(strPath) Then
Kill strPath
Else
Msgbox "File Doesn't Exist: " & strPath
End If
UPDATED FOR CONTINUE TO NEXT FILE
Change loop to be:
Do Until r = ""
If UCase(r.value) = "INACTIVE" AND fso.FileExists(strPath) Then
Kill strPath
End If
Set r = r.Offset(1, 0)
Loop
It works!
I've commented out some parts of the code that were used for checking if a file exists.
Sub delete_INACTIVE_files()
Const path = "C:\Users\Dn\AppData\Local\Temp\vbakillfunction\"
Dim r As Range
Set r = Cells(1, 5)
Do Until r = ""
If UCase(r.Value) = "INACTIVE" Then
If Dir(path & r.Offset(0, -4) & "\" & r.Offset(0, -3) & ".txt") <> "" Then 'Does the file exist?
'MsgBox "file" & path & r.Offset(0, -4) & "\" & r.Offset(0, -3) & ".txt" & " exists"
Kill path & r.Offset(0, -4) & "\" & r.Offset(0, -3) & ".txt"
'Else
'MsgBox "file" & path & r.Offset(0, -4) & "\" & r.Offset(0, -3) & ".txt" & " not here"
End If
End If
Set r = r.Offset(1, 0)
Loop
End Sub
I have files stored on a WD elements hard drive. On occasions I need to copy files from here onto my pc. When I tested the following macro using both the source and destination folders on the c: drive it works fine. However when I changed the source to the external drive (I:\history\june) it says the files do not exist. How can I access the external drive? Any guidance would be welcome.
Thanks, willi
Sub CopyFiles()
Dim iRow As Integer
Dim sSourcePath As String
Dim sDestinationPath As String
Dim sFileType As String
Dim bContinue As Boolean
bContinue = True
iRow = 2
sSourcePath = "C:\Users\admin\documents\Test1\"
sDestinationPath = "C:\Users\admin\documents\Test2\"
sFileType = ".pdf"
While bContinue
If Len(Range("B" & CStr(iRow)).Value) = 0 Then
MsgBox "Files Copied"
bContinue = False
Else
If Len(Dir(sSourcePath & Range("B" & CStr(iRow)).Value & sFileType)) = 0 Then
Range("C" & CStr(iRow)).Value = "File Does Not Exist"
Range("C" & CStr(iRow)).Font.Bold = True
Else
Range("C" & CStr(iRow)).Value = "File Copied"
Range("C" & CStr(iRow)).Font.Bold = False
If Trim(sDestinationPath) <> "" Then
Dim objFSO
Set objFSO = CreateObject("scripting.filesystemobject")
If objFSO.FolderExists(sDestinationPath) = False Then
MsgBox "The destination folder " & sDestinationPath & " Does Not Exists"
Exit Sub
End If
objFSO.CopyFile Source:=sSourcePath & Range("B" & CStr(iRow)).Value & _
sFileType, Destination:=sDestinationPath
End If
End If
End If
iRow = iRow + 1
Wend
End Sub
I have a master Excel sheet designed to spit out payroll details. The numbers on the sheet are driven by a data validation dropdown in A2, which fills in B2:G2 with identifying information (Last, First, Region, PayPeriod, Year) pulled from a data tab.
What I'd like to do is have a macro save a copy of the sheet for each choice in the dropdown into a specific folder in a hierarchy based on the info in B2:G2.
For instance,
ID Last First Region PP Year
10001 Smith Scott DC PP1 2016
I'd like that to save a sheet named "2016_PP1_DC_Smith_Scott.xlsx" in the folder C:\2016\PP1\DC.
And then change to
ID Last First Region PP Year
10002 Jones Karen NY PP3 2015
And save the sheet "2015_PP3_NY_Jones_Karen.xlsx" in the folder C:\2015\PP3\NY.
I have a macro that's part of the way there. It goes through each drop down and saves the file with the correct filename (Though it's renaming the initial file) (edit) I need help adding the functionality to save the sheets in a hierarchy of folders and not overwrite the original document with the most recent saved sheet name.
Totally fine with continuing to use this macro with edits or start from scratch.
Sub PrintValidationChoices()
Dim wbSource As Workbook
Dim r As Long, i As Long
Dim relativePath As String
Dim year As String
Dim quarter As String
Dim pp As String
Dim region As String
Dim doctor As String
Set wbSource = ActiveWorkbook
r = Range("ID").Cells.Count
For i = 1 To r
Range("A2") = Range("ID").Cells(i)
year = ActiveSheet.Range("G2")
pp = ActiveSheet.Range("F2")
region = ActiveSheet.Range("E2")
hospital = ActiveSheet.Range("D2")
doctor = ActiveSheet.Range("B2") & "_" & ActiveSheet.Range("C2")
'visually validating what will be used - not needed
Range("H3") = year
Range("H4") = pp
Range("H5") = region
Range("H6") = hospital
Range("H7") = doctor
sname = year & "_" & pp & "_" & region & "_" & hospital & "_" & doctor & ".xls"
relativePath = wbSource.Path & "\" & sname 'use path of wbSource
Range("H8") = relativePath
Application.DisplayAlerts = False
ActiveWorkbook.CheckCompatibility = False
ActiveWorkbook.SaveAs Filename:=relativePath, FileFormat:=xlExcel8
Application.DisplayAlerts = True
Application.Wait (Now + TimeValue("00:00:01")) 'pausing to see actions - not needed
Next i
Range("A2") = Range("ID").Cells("1") 'return to start of list
MsgBox "Done!"
End Sub
Thank you guys for the help! If you're feeling verbose, it would be great to have some details in your response so I can learn.
edited to reflect most probable validation worksheet name
maybe you're after something like what follows:
Option Explicit
Sub main()
Dim strng As String
Dim cell As Range
With Worksheets("Report") '<--| change "Report" to your actual worksheet name
For Each cell In Range(.Range("a2").Validation.Formula1).SpecialCells(XlCellType.xlCellTypeConstants)
.Range("a2") = cell.Value
SaveWorksheet .Range("B2:G2")
Next cell
End With
End Sub
Sub SaveWorksheet(rng As Range)
Dim sname As String, relativePath As String
Dim folder As String
folder = "C:\" & rng(1, 6) & "_" & rng(1, 5) & "_" & rng(1, 4)
MkDir folder
sname = rng(1, 6) & "_" & rng(1, 5) & "_" & rng(1, 4) & "_" & rng(1, 3) & "_" & rng(1, 2) & "_" & rng(1, 3) & ".xls"
relativePath = folder & "\" & sname
Application.DisplayAlerts = False
ActiveWorkbook.CheckCompatibility = False
rng.Parent.Copy
With ActiveWorkbook
.SaveAs filename:=relativePath ', FileFormat:=xlExcel8
.Close
End With
Application.DisplayAlerts = True
Application.Wait (Now + TimeValue("00:00:01")) 'pausing to see actions - not needed
End Sub
I have a question that how to pull the questions one after the other if the student clicks on next button.
Here I have two excel workbook and one is master workbook and the other one is for the tool designed for giving test (student will view this).
Sub Button1_Click()
Dim s(6 To 100) As String`enter code here`
Dim stname As String
Dim neWb As Workbook
Dim mypath As String
Dim u As String
u = "_xlsx"
Application.DisplayAlerts = False
For i = 6 To 100
s(i) = Range("E" & i).Value
stname = s(i) & "" & u
If s(i) = "" Then
ActiveWorkbook.Open = False
End If
On Error GoTo jamun:
mypath = Range("B1").Value & "\" & stname
Set neWb =Workbooks.Open("anypath\nanoo.xls")'It can be c drive or any other drive in the system
neWb.SaveAs filename:=mypath
neWb.Close
Range("B" & i).Value = mypath & "_assigning..."
Application.Wait Now + TimeValue("00:00:02")
Range("F" & i).Value = "Done"
Range("B" & i).Value = mypath & "_assigned"
Application.Wait Now + TimeValue("00:00:01")
Range("B" & i).Select
'Adding hyper link to all the lines that shows the status to whom it has been assigned and to whom it is yet to assign
ActiveSheet.Hyperlinks.Add Anchor:=Selection, Address:="mypath", TextToDisplay:=Range("B" & i).Value
Range("B" & i).Select
Selection.Hyperlinks(1).Address = Range("B1").Value
Next
MsgBox "Test assigned successfully"
Exit Sub
jamun:
MsgBox "Test assigned successfully"
End Sub