Check a command window is closed - excel

Below is the code we use to run to check the Ping and Trace for our site address. We have a userform which we need to enter some details and when we hit run this will start running. So when we start running it will create a batch file which (opens a command window) will first the ping and then the Trace. So the ping will finish within a 5 sec but the trace root will take some time and this is not a fixed time. Once both finish running the command window closes automatically. How do the macro knows the command window is closed so that we can enable a button in our userform to submit the report. We need a code to check whether the command window is closed and then it can go to the line "cmdFinishSlow.Enabled = True"
Please can anyone help me with this? Also this will not work in a 64bit Excel, is there any solution for that too?
Dim address, NetStatAN, PingTextFile, BatchFile, TraceTextFile As String
Dim row As Integer
Dim inputline As String
Dim lineitems() As String
Dim Filepath As String
Dim MyFSO As FileSystemObject
Set MyFSO = New FileSystemObject
Filepath = "C:\Users\" & Environ("Username") & "\Desktop\"
BatchFile = "batchfile.bat"
PingTextFile = "PingSite.txt"
TraceTextFile = "TraceSite.txt"
'Call Shell("explorer.exe" & " " & Filepath, vbNormalFocus)
On Error Resume Next
Kill (Filepath & BatchFile)
Kill (Filepath & PingTextFile)
Kill (Filepath & TraceTextFile)
On Error GoTo 0
row = 1
address = Sheets("Slowness Issue").Range("C9").Value
Do Until Trim(address) = ""
Open Filepath & BatchFile For Output As #1
Print #1, "ping " & address & " >>"; Filepath & PingTextFile
Print #1, "tracert -d " & address & " >>"; Filepath & TraceTextFile
Close #1
Call Shell(Filepath & BatchFile)
Application.Wait DateAdd("s", 5, Now) ' wait for 10 seconds
Open Filepath & PingTextFile For Input As #1
Line Input #1, inputline
If Left(inputline, 10) = "Reply from" Then
lineitems() = Split(inputline, " ")
Cells(row, 2) = lineitems(2)
Cells(row, 3) = Now
End If
row = row + 1
address = Cells(row, 1)
Loop
' Here I need to check the command window is closed or not
cmdFinishSlow.Enabled = True
cmdRunSlow.Enabled = False

Related

How do you make VBA document open a copy of itself in a folder every time you open it?

When you run this program it opens a csv file in the allocated folder. What should i write in this code for when i open the file it makes a copy?
Open "C:\raspbbbb\users.csv" For Output As #1
i = 2
Do While Cells(i, 1) <> ""
myStr = ""
For j = 9 To 10
myStr = myStr & Cells(i, j) & "; "
Next
Print #1, myStr
i = i + 1
Loop
Close #1
End Sub
I tried changing the output and close types but that just makes it crash
In the code module for ThisWorkbook, create an event script for Workbook_Open:
Private Sub Workbook_Open()
Dim CopyName As String
CopyName = Split(ThisWorkbook.Name, ".")(0) & " Copy." & Split(ThisWorkbook.Name, ".")(1)
ThisWorkbook.SaveCopyAs ThisWorkbook.Path & "\" & CopyName
End Sub
Save the file as a Macro Enabled Workbook, xlsm. Now when you open the workbook, it will create a copy of itself in the same folder.
I wonder if you could possibly rephrase the question as it is not too clear what you are trying to achieve, and what is then going wrong?
Many thanks.

How do I convert a file with unix line endings to DOS using VBA (Excel) for large files (larger than 1GB) and do so quickly?

I was able to get the higher rated answer (Alex K.) working to revise smaller files than the file I want to convert (1.7Gb) from here:
Loading linux text file into excel using VBA
I think using the Buffer has a memory limitation or I'm getting an error I wasn't expecting for large UNIX format files.
This problem has plagued me for sometime, and I usually just use Notepad++ and Edit→EOL conversion→Windows, but I'd like to be able to convert the file native to Excel so that my other, more complex, programs can work properly.
My files for those other programs aren't always UNIX carriage returns, but when they are, it throws a user error. Sometimes the user may not understand the work around (fix).
If the solution takes much much longer than Notepad++ or using unix2dos in linux then maybe I have to continue with those alternatives, but I'd really prefer a way to do this in EXCEL VBA.
Thanks in advance!
EDIT
: I'm adding the code I have, that works for files less than 1GB in size. Perhaps someone can fix it or poke holes at the approach (I think reading the whole file into memory throws an error and line by line doesn't seem possible that I know of). This code roughly takes 10 minutes for a test file I had which is just short of 1GB (14,581,137 lines):
Sub unix2Dos()
Dim FName As Variant
Dim myfilename As String
Dim FNum As Integer
Dim chars As Integer
Dim StartTime As Date, EndTime As Date
FNum = FreeFile
Dim FSO As Object
Set FSO = VBA.CreateObject("Scripting.FileSystemObject")
Set fs2 = CreateObject("Scripting.FileSystemObject")
FName = Application.GetOpenFilename _
(filefilter:="All Files (*.*),*.*,Text Files(*.txt),*.txt,Bulk Files(*.bdf),*.bdf,Bulk Files(*.blk),*.blk,Bulk Files(*.bulk),*.bulk,Control Decks(*.dat),*.dat,")
If FName = False Then
MsgBox "You didn't select a file", vbCritical
Exit Sub
End If
On Error GoTo user_interupt
If FileExists(FName) Then
Set f = fs2.GetFile(FName)
filesize1 = f.Size / 1024 'in Kb
Else
filesize1 = 0
End If
If filesize1 >= 1048576 Then
MsgBox "File Size too large for this VBA to handle, please Convert to DOS another way. For Notepad++ go to Edit->EOL conversion->Windows." & Chr(13) & _
"Or Ultra Edit go to Advanced->Conversions->Unix/Mac (Legacy) to Dos" & Chr(13) & _
"Or in Linux, Cygwin, or Unix Environment from the comand line use this command:> unix2dos filename"
ElseIf filesize1 < 1048576 Then
StartTime = Timer
Open FName For Input As #1
'//load all
buff = Input$(LOF(1), #1)
Close #1
chars = Len(FName)
If Right(FName, 3) = "bdf" Then
myfilename = (Left(FName, chars - 4)) & "_DOS.bdf"
ElseIf Right(FName, 4) = "bulk" Then
myfilename = (Left(FName, chars - 5)) & "_DOS.bulk"
ElseIf Right(FName, 3) = "txt" Then
myfilename = (Left(FName, chars - 4)) & "_DOS.txt"
ElseIf Right(FName, 3) = "blk" Then
myfilename = (Left(FName, chars - 4)) & "_DOS.blk"
ElseIf Right(FName, 3) = "dat" Then
myfilename = (Left(FName, chars - 4)) & "_DOS.dat"
Else
myfilename = FName & "_DOS.txt"
End If
Open myfilename For Output Access Write As #FNum
'//Use Below; Testing showed very little distance in compute time
'buff = Replace$(buff, vbLf, vbCrLf)
' Print #FNum, buff
'//*or* line by line
Dim lines() As String: lines = Split(buff, vbLf)
For i = 0 To UBound(lines)
'MsgBox lines(i)
Print #FNum, lines(i)
Next
Close #FNum
EndTime = Timer
MsgBox "Unix2Dos: File Converted From UNIX to DOS " & Chr(13) & _
"If your file had a mix of Carriage returns (DOS AND UNIX), " & Chr(13) & _
"then you may have undesired blanks " & Chr(13) & _
" Run Time : " & Strings.Format(EndTime - StartTime, "0.0") & " sec"
End If
user_interupt:
If Err = 0 Then
'do nothing
Else:
MsgBox "The most recent error number is " & Err & _
". Its message text is: " & Error(Err)
End If
End Sub
Public Function FileExists(ByVal FileToTest As String) As Boolean
FileExists = (Dir(FileToTest) <> "")
End Function

Email Attachment only working when statically coded - Excel Visual Basic

Everything is working for me in sending an email with an attachment from Excel using Visual Basic via Thunderbird when the attachment path is hard-coded.
attachment=C:\Users\Desktop2017\Desktop\customer\customerNumber\invoiceNumber.pdf"
But I need to change part of the file path for attachment based on what's in cell M4 and have the file name change based on what's in cell J4.
Example: M4 value is currently 101. J4 value is currently 2000-01. The output should be "C:\Users\Desktop2017\Desktop\customer\101\2000-01.pdf"
I have tried using 'Range' to get the value and setting a string but instead of getting the data from the cell or string it just outputs whatever I have after the equals sign.
I've tried adding and moving quotation marks around but nothing has worked at this point.
Thanks in advance for any help, Dalton.
PS: Sorry for hobbled together code.
Private Sub EmailInvoice_Click()
Dim FileNumber As Integer
Dim retVal As Variant
Dim strName As String
Dim strFile As String
Dim wsCustomer As Worksheet
strName = Range("Q2").Value
strFile = Dir(strFolder & "*.xlsx")
Const MY_FILENAME = "C:\Users\Desktop2017\Dropbox\temp\invoice.BAT"
FileNumber = FreeFile
'create batch file
Open MY_FILENAME For Output As #FileNumber
Print #FileNumber, "cd ""C:\Program Files (x86)\Mozilla Thunderbird"""
Print #FileNumber, "thunderbird -compose"; _
" to=" + ThisWorkbook.Sheets("hourlyInvoice01").Range("N21") _
+ ",subject=Invoice " + ThisWorkbook.Sheets("hourlyInvoice01").Range("J4") + ",format="; 1; _
",body=""<HTML><BODY>Hello "; ThisWorkbook.Sheets("hourlyInvoice01").Range("N20") _
+ "&#44<BR><BR>Please see attached.<BR><BR>Thanks&#44 Dalton.<BR><BR><BR>Contact Info Text Line 1<BR>Contact Info Text Line 2<BR>Contact Info Text Line 3</BODY></HTML>"",attachment=C:\Users\Desktop2017\Desktop\test\script\someFile.txt"
Print #FileNumber, "exit"
Close #FileNumber
'run batch file
retVal = Shell(MY_FILENAME, vbNormalFocus)
' NOTE THE BATCH FILE WILL RUN, BUT THE CODE WILL CONTINUE TO RUN.
If retVal = 0 Then
MsgBox "An Error Occured"
Close #FileNumber
End
End If
'Delete batch file
'Kill MY_FILENAME
End Sub
Add this before that line
Dim FlName As String
FlName = "C:\Users\Desktop2017\Desktop\customer\" & Range("M4").Value & "\" & Range("J4").Value & ".pdf"
and then change the line
"&#44<BR><BR>Please see attached.<BR><BR>Thanks&#44 Dalton.<BR><BR><BR>Contact Info Text Line 1<BR>Contact Info Text Line 2<BR>Contact Info Text Line 3</BODY></HTML>"",attachment=C:\Users\Desktop2017\Desktop\test\script\someFile.txt"
to
"&#44<BR><BR>Please see attached.<BR><BR>Thanks&#44 Dalton.<BR><BR><BR>Contact Info Text Line 1<BR>Contact Info Text Line 2<BR>Contact Info Text Line 3</BODY></HTML>"",attachment=" & FlName
Note: To concatenate strings, use & instead of +

Function to direct debug to text file

I would like to write a function to would allow me to use Print #Debug, "text" throughout my future modules to collect debug statements.
Sub output_debug()
Dim WshShell As Object
Dim Desktop As String
Dim Debug As Integer
Debug = FreeFile()
Set WshShell = CreateObject("WScript.shell")
Desktop = WshShell.specialfolders("Desktop")
Open Desktop & "\VBA_output.txt" For Output As #Debug
Print #Debug, "test"
Close #Debug
End Sub
How can I move from the above, to defining a function that would allow me to use call output_debug() in a module so all my Print #Debug, would print to that file ? I would imagine I need to create another function called close_output() that has close #Debug
I did something like this in the past. Here is what I came up with. It relies on having a reference to Microsoft Scripting Runtime in any project that uses it. You can store the following subs in a module e.g. DebugLogger (which is what I use) that can be first exported then imported into any module that you want to have this functionality. It mimics the behavior of Debug.Print but sends the output to a file whose name is a function of the workbook's name. I toyed with the idea of time-stamping individual entries but rejected the idea as being too far from the functionality of Debug.Print (I do, however, time stamp the date of creation). Once you import the module and establish the right reference then you can just use DebugLog anywhere you would have used DebugPrint. As a default it also prints to the debug window. You can drop that part of the code entirely or switch what the default is.
Function GetFullDebugName() As String
'This function returns a string of the form
'*xldebug.txt, where *.* is the full name of the workbook
Dim MyName As String
Dim NameParts As Variant
MyName = ThisWorkbook.FullName
NameParts = Split(MyName, ".")
GetFullDebugName = NameParts(0) & "xldebug.txt"
End Function
Sub CreateDebugFile()
'file created in same directory as
'calling workbook
Dim DebugName As String
Dim fso As FileSystemObject
Dim MyStream As TextStream
Set fso = New FileSystemObject
DebugName = GetFullDebugName
Set MyStream = fso.CreateTextFile(DebugName)
MyStream.WriteLine "This debug file was created " _
& FormatDateTime(Date) _
& " at " & FormatDateTime(Time)
MyStream.Close
End Sub
Sub DebugLog(DebugItem As Variant, Optional ToImmediate As Boolean = True)
Dim DebugName As String
Dim fso As FileSystemObject
Dim MyStream As TextStream
Set fso = New FileSystemObject
DebugName = GetFullDebugName
'check to see if DebugFile exist
'if not, create it:
If Not fso.FileExists(DebugName) Then CreateDebugFile
Set MyStream = fso.OpenTextFile(DebugName, ForAppending)
MyStream.WriteLine DebugItem
MyStream.Close
If ToImmediate Then Debug.Print DebugItem
End Sub
Try a subroutine like this...
It will log text to a text file with a date stamp, so new file new day.
You have an option to pass it the ERR object if you trap the error in your code and it will log the error message with a highlight.
call debuglog("my log entry")
call debuglog("my log entry",err)
Public Sub DebugLog(sLogEntry As String, Optional ByVal oErr As Object)
' write debug information to a log file
Dim iFile As Integer
Dim sDirectory As String
Dim errNumber, errDescription As Variant
Dim l As Integer
If Not oErr Is Nothing Then
errNumber = oErr.Number
errDescription = oErr.Description
l = IIf(Len(errDescription) > Len(sLogEntry), Len(errDescription), Len(sLogEntry))
End If
On Error GoTo bail
sfilename = VBA.Environ("Homedrive") & VBA.Environ("Homepath") & "\My Documents\Debuglog" & "\debuglog" & Format$(Now, "YYMMDD") & ".txt"
iFile = FreeFile
Open sfilename For Append As iFile
If Not oErr Is Nothing Then
sLogEntry = "/" & String(5 + (l - Len(sLogEntry)), "-") & " " & sLogEntry & " " & String(5 + (l - Len(sLogEntry)), "-") & "\"
Print #iFile, Now; " "; sLogEntry
Print #iFile, Now; " "; errNumber
Print #iFile, Now; " "; errDescription
Print #iFile, Now; " "; "\" & String(Len(sLogEntry) - 2, "-") & "/"
Else
Print #iFile, Now; " "; sLogEntry
End If
bail:
Close iFile
End Sub
example logfile output
27/03/2015 10:44:27 -- COMIT Form Initialize - Complete
27/03/2015 10:44:27 - COMIT Active
27/03/2015 10:44:34 /----- -- Error Populating Opportunity Form: frmBluesheet.PopulateForm() -----\
27/03/2015 10:44:34 381
27/03/2015 10:44:34 Could not get the Column property. Invalid property array index.
27/03/2015 10:44:34 \-----------------------------------------------------------------------------/

Calling BAT with VBA - CMD Loads and Closes Immediately

I'm using VBA to write a command file and a BAT file which calls PLink to log in to a server and run a script. The Plink portion is now functioning as expected thanks to some help on here. Unfortunately VBA seems to be having some difficulty with opening the cmd and finding plink as a usable command.
I've tried multiple different ways of calling it, but the results are all the same. The cmd prompt opens and then closes immediately giving me an error stating:
"plink is not recognized as an internal or external command, operable program, or batch file."
The files generate perfectly, and if I run the bat file outside of VBA, it runs as expected. With the files, I keep a copy of plink.exe on the desktop. I've even tried adding a copy of cmd.exe to the desktop with the links and plink.exe as well, but I get the same problem.
Here are some of the ways I've tried, though modified for my code: 1 2 3
Here's the most recent code for the macro:
Dim vPath As String
Dim vscript As String
UserID = Range("F1").Value
Passwd = Range("F2").Value
Server = Range("F3").Value
StartDate = Range("F4").Value
EndDate = Range("F5").Value
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CopyFile "C:\Program Files (x86)\PuTTY\plink.exe", "C:\Users\MikeDesktop\"
'fso.CopyFile "C:\Windows\System32\cmd.exe", "C:\Users\Mike\Desktop\"
vPath = "C:\Users\Mike\Desktop"
Open vPath & "\pcmd.txt " For Output As #1
Print #1, "cd /opt/test/srt"
Print #1, "./srt.tool " & StartDate & " " & EndDate & " > /opt/test/srt/test.txt &"
Print #1, "rm test.txt"
Print #1, "sleep 60; exit"
Close #1
Open vPath & "\Chg.bat" For Output As #1
Print #1, "plink " & UserID & "#" & Server & " -pw " & Passwd & " < " & vPath & "\pcmd.txt"
Close #1
vscript = vPath & "\Chg.bat"
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 5
wsh.Run vscript, windowStyle, waitOnReturn
Application.Wait (Now + TimeValue("0:01:00"))
Kill vPath & "\Chg.bat"
Kill vPath & "\pcmd.txt"
Kill vPath & "\plink.exe"
If someone can tell me why the cmd isn't recognizing plink as an option, that would be much appreciated
Either pass the path to plink.exe in the batch file, or make sure that %Path% includes the folder that contains plink.exe.

Resources