How to find a file using a pattern? - vbscript

I have a script that is supposed to grab a file from a folder and attach it to an email.
The code runs but nothing happens. I assume it's because strLocation is empty.
Here is an example of the file path I am trying to grab:
"C:\Users\MChambers\Desktop\Pricing Reports\Pricing_Report_201908121239 Formatted.xlsx"
Option Explicit
Const olMailItem = 0
Function FindFirstFile(strDirPath, strPattern)
Dim strResult
Dim objRegExp, objMatches
Set objRegExp = New RegExp
objRegExp.Pattern = strPattern
objRegExp.IgnoreCase = True
Dim objFso, objFolder, objFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strDirPath)
For Each objFile in objFolder.Files
Set objMatches = objRegExp.Execute(objFile.Name)
If objMatches.Count > 0 Then
strResult = objMatches(0).Value
Exit For
End If
Next
If Len(strResult) > 0 Then
If Right(strDirPath, 1) <> "\" Then strDirPath = strDirPath & "\"
strResult = strDirPath & strResult
End If
FindFirstFile = strResult
End Function
Sub SendBasicEmail()
Dim olApp: Set olApp = CreateObject("Outlook.Application")
Dim olEmail: Set olEmail = olApp.CreateItem(olMailItem)
Dim strLocation
Dim strPattern
strPattern = "Pricing_Report_*Formatted.xlsx"
strLocation = FindFirstFile("C:\Users\MChambers\Desktop\Pricing Reports\", strPattern)
If strLocation <> "" Then
With olEmail
.SentOnBehalfOfName = "genericemail"
.Attachments.Add (strLocation)
.To = "myemail"
.Subject = "Subject"
.Send
End With
End If
End Sub
SendBasicEmail
Update: The solution below was correct. In addition, I had to call the sub directly at the end of the file which I have updated in the code above.

The pattern you're using doesn't do what you apparently think it does.
strPattern = "Pricing_Report_*Formatted.xlsx"
You seem to expect the above to do a wildcard match (i.e. "Pricing_Report_" followed by any amount of text and "Formatted.xlsx"). That is not how regular expressions work. * in a regular expression means "zero or more times the preceding expression". The character . also has a special meaning in regular expressions, which is "any character except line-feed. Because of that your pattern would actually match the string "Pricing_Report" followed by any number of consecutive underscores, the string "Formatted", any single character except line-feed, and the string "xlsx".
Change the pattern to this
strPattern = "Pricing_Report_.*Formatted\.xlsx"
and the code will do what you want.
For further information about regular expressions in VBScript see here.

Related

VBscript Replace text with part of filename

I have a directory of files that I want to Loop through and use part of their filename to replace text in a template doc.
For example one filename may be 'NV_AD32_city.dxf'. All files in the directory follow the same filename pattern of XX_XXXX_string.dxf, using two underscores.
I need to capture the string to the right of the first "_" and to the left of the "."so for this example that would be 'AD32_city'
How do I script to use capture that text of the active file to replace text in the template? I guess I need to create an object? But what is the object to use for the current file from a directory?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thx for the replies, guys. After several days of trying your code I am just not "getting it". I understand it is set up to take the part of the filename's string that I want but how do I tell the script to use the current file I am looping through? Here is my script so far. I have your code on line 20 under the Sub 'GetNewInputs'
Set fso = CreateObject("Scripting.FileSystemObject")
Option Explicit
Dim WritePath : WritePath = "S:\TempFolder\"
Dim OutFile : OutFile = "VEG_DXF-2-SHP_script-"
Dim WorkingFile : WorkingFile = GetFileContent(SelectFile())
Dim NewState, NewSection, NewArea
Dim OldState, OldSection, OldArea
Call GetNewInputs()
Call GetOldInputs()
Sub GetNewInputs()
NewState = UCase(InputBox("INPUT STATE:", _
"INPUT STATE", "SOCAL"))
NewSection = ("Section_" & InputBox("INPUT SECTION NUMBER:", _
"INPUT SECTION", "14"))
NewArea = "^[^_]+_(.*)\.dxf$"
End Sub
Private Sub GetOldInputs()
OldState = "XX"
OldSection = "_X"
OldArea = "ZZZZ"
End Sub
Function SelectFile()
SelectFile = vbNullString
Dim objShell : Set objShell = WScript.CreateObject("WScript.Shell")
Dim strMSHTA : strMSHTA = "mshta.exe ""about:" & "<" & "input type=file id=FILE>" _
&"<" & "script>FILE.click();new ActiveXObject('Scripting.FileSystemObject')" _
&".GetStandardStream(1).WriteLine(FILE.value);close();resizeTo(0,0);" & "<" & "/script>"""
SelectFile = objShell.Exec(strMSHTA).StdOut.ReadLine()
If SelectFile = vbNullString Then
WScript.Echo "No file selected or not a text file."
WScript.Quit
End If
End Function
Private Function GetFileContent(filePath)
Dim objFS, objFile, objTS
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objFile = objFS.GetFile(filePath)
Set objTS = objFile.OpenAsTextStream(1, 0)
GetFileContent = objTS.Read(objFile.Size)
Set objTS = Nothing
End Function
For Each FileRefIn fso.GetFolder("S:\SOCAL\Section_14\Veg DXFs\").Files
NewFile = WorkingFile
NewFile = Replace(NewFile, OldState, NewState)
NewFile = Replace(NewFile, OldSection, NewSection)
NewFile = Replace(NewFile, OldArea, NewArea)
WriteFile NewFile, WritePath & OutFile & ".gms"
WScript.Echo NewArea
Next
Private Sub WriteFile(strLine,fileName)
On Error Resume Next
Dim objFSO, objFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Do Until IsObject(objFile)
Set objFile = objFSO.OpenTextFile(fileName, 8, True)
Loop
objFile.WriteLine strLine
objFile.Close
End Sub
Well, that’s actually two questions.
To enumerate files in a directory, you can use FileSystemObject, like this (untested)
const strFolderPath = "C:\Temp\Whatever"
set objFSO = CreateObject( "Scripting.FileSystemObject" )
set objFolder = objFSO.GetFolder( strFolderPath )
set colFiles = objFolder.Files
for each objFile in colFiles
' Do whatever you want with objFile
next
Here's the reference of those objects properties/methods.
And to extract portion of file names, you could use a regular expression.
Here’s some guide how to use'em in VBScript.
The following expression should work for you, it will capture the portion of that file names you asked for:
"^[^_]+_(.*)\.dxf$"
If you need to edit the content of the .dxf files, you will need to work within the AutoCAD VBA (Visual Basic for Applications) environment.
If that is the case, you will need to start with something like below:
GetObject("AutoCAD.Application.20")
CreateObject("AutoCAD.Application.20")
https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2015/ENU/AutoCAD-ActiveX/files/GUID-0225808C-8C91-407B-990C-15AB966FFFA8-htm.html
** Please take note that "VBA is no longer distributed with the AutoCAD installation; it must be downloaded and installed separately. The VBA Enabler for Autodesk AutoCAD can be downloaded here."

"Type Mismatch" when downloading image

I'm creating a program that helps me download images from a weather website, so I can get radar images. It creates a file named "radar" and then the time. For example if it was 5:00 PM it would be named Radar500.png.
The downloading works fine, but it says I have an error on a certain line:
Const adSaveCreateOverWrite = 2
Const adTypeBinary = 1
if hour(time) > 12 then
a=hour(time)-12
else
if hour(time) = 0 then
a="12"
else
a=hour(time)
b=minute(time)
end if
end if
b=minute(time)
strSource = ""
strDest = "C:\Users\Gabriel\Desktop\Overnight weather\radar"+a+"s"+b+".jpg"
WScript.Echo "path: "+strDest
'*****************************************************************
'** Download the image
strResult = GetImage(strSource, strDest)
If strResult = "OK" Then
wscript.quit(0)
Else
wscript.quit(1)
End If
Function GetImage(strPath, strDest)
Dim objXMLHTTP, nF, arr, objFSO, objFile
Dim objRec, objStream
'create XMLHTTP component
Set objXMLHTTP = CreateObject("Microsoft.XMLHTTP")
'get the image specified by strPath
objXMLHTTP.Open "GET", strPath, False
objXMLHTTP.Send
'check if retrieval was successful
If objXMLHTTP.statusText = "OK" Then
'create binary stream to write image output
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open
objStream.Write objXMLHTTP.ResponseBody
objStream.SavetoFile strDest, adSaveCreateOverwrite
objStream.Close
GetImage = "OK"
Else
GetImage = objXMLHTTP.statusText
End If
End Function
They say the error is at Line 29 Char 1.
Use strDest = "C:\Users\...\radar" & a & "s" & b & ".jpg". As per MSDN: Addition Operator (+) (VBScript)
Although you can also use the + operator to concatenate two
character strings, you should use the & operator for concatenation
to eliminate ambiguity. When you use the + operator, you may not be
able to determine whether addition or string concatenation will occur.
The type of the expressions determines the behavior of the +
operator in the following way:
If Then
Both expressions are numeric Add
Both expressions are strings Concatenate
One expression is numeric and the other is a string Error: type mismatch
...
Your script should work with next changes:
assign a valid strSource value, e.g. strSource = "http://www.goes.noaa.gov/FULLDISK/GMIR.JPG"
objXMLHTTP.Open "GET", strSource, False. Note strSource instead of your strDest

vbscript adding qoutes to base64 converted string

I got some script to convert string to base64 and write encoded data to text file that's all goes fine and result stored in encoded.txt but I need each line to be double quoted at the start and '& _' with double quotes at the end so how to make this script do that automatically for each line? here is my script
Option Explicit
Const fsDoOverwrite = true
Const fsAsASCII = false
Const adTypeBinary = 1
Dim objFSO
Dim objFileOut
Dim objXML
Dim objDocElem
Dim objStream
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open()
objStream.LoadFromFile(Wscript.scriptfullname)
Set objXML = CreateObject("MSXml2.DOMDocument")
Set objDocElem = objXML.createElement("Base64Data")
objDocElem.dataType = "bin.base64"
objDocElem.nodeTypedValue = objStream.Read()
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFileOut = objFSO.CreateTextFile("encoded.txt", fsDoOverwrite, fsAsASCII)
objFileOut.Write objDocElem.text
objFileOut.Close()
Set objFSO = Nothing
Set objFileOut = Nothing
Set objXML = Nothing
Set objDocElem = Nothing
Set objStream = Nothing
Sub encodeFileBase64( inputFile, outputFile )
Const fsDoOverwrite = True
Const fsAsASCII = False
Const adTypeBinary = 1
Dim stream, strBuffer
Set stream = WScript.CreateObject("ADODB.Stream")
With stream
.Type = adTypeBinary
.Open
.LoadFromFile inputFile
End With
With WScript.CreateObject("MSXML2.DOMDocument").CreateElement("Base64Data")
.dataType = "bin.base64"
.nodeTypedValue = stream.Read()
strBuffer = .Text
End With
stream.Close
With New RegExp
.Multiline = True
.Global = True
.IgnoreCase = False
.Pattern = "[\r\n]+(?=[0-9A-Za-z])"
strBuffer = Chr(34) & .Replace(strBuffer, Chr(34) & " & _" & vbCrLf & Chr(34) ) & Chr(34)
End With
WScript.CreateObject("Scripting.FileSystemObject").CreateTextFile( outputFile, fsDoOverwrite, fsAsASCII ).Write strBuffer
End Sub
encodeFileBase64 WScript.ScriptFullName, WScript.ScriptFullName & ".b64"
This will use a regular expression object to replace all intermediate line endings with the adecuated line termination/start and two aditional quotes, one at the start and one at the end.
Split the text by a line break, then loop through and put it all back together while you add the quotes. (not tested, but probably close, code follows; there is a strong chance you'll need to find the right type of line feed for your situation - I picked vbCr as an example):
allTextArray = SPLIT(originalText, vbCr)
For i=0 to UBound(allTextArray)
allTextWithQuotes = allTextWithQuotes & """" & allTextArray(i) & """"
Next

Vbs script to add space if it finds a string like abc11adv to abc11 adv

Hi I am novice in vbs script. I have one text file every line has statements like
minis1in use by bla bla
rit34in use by someone
atp34in use by someone2
I want a vbs script to convert this text file to
minis1 in use by bla bla
rit34 in use by someone
atp34 in use by someone2
I found one vbs script but it replaces string at particular position in every line. But I want to search for a number only in first string in every line and number may be one digit or two digit or three digit after that number it should give space. Without replacing character with a space.
StrFileName = "C:\Users\Desktop\Scheduled\output.txt"
Const ForReading = 1
Const ForWriting = 2
Dim objFSO
Dim objTF
Dim objRexex
Dim StrFileName
Dim strTxt
StrFileName = "C:\Users\Desktop\Scheduled\output.txt"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTF = objFSO.OpenTextFile(StrFileName, ForReading)
Set objregex = CreateObject("vbscript.regexp")
strTxt = objTF.ReadAll
objTF.Close
With objregex
.Global = True
.MultiLine = True
.Pattern = "^(.{6})[^-](.*)$"
strTxt = .Replace(strTxt, "$1" & " " & "$2")
End With
Set objTF = objFSO.OpenTextFile(StrFileName, ForWriting)
objTF.Write strTxt
objTF.Close
Maybe the pattern "^(\w+)(\d+)(\w+)" used non-globally will do what you want:
Option Explicit
Dim r : Set r = New RegExp
r.Global = False ' just the first
r.Pattern = "^(\w+)(\d+)(\w+)"
Dim s
For Each s In Split("minis1in use by+rit34adv use+atp34in use not34in use+not here1in use", "+")
WScript.Echo s
WScript.Echo r.Replace(s, "$1$2 $3")
WScript.Echo
Next
output:
cscript 25228592.vbs
minis1in use by
minis1 in use by
rit34adv use
rit34 adv use
atp34in use not34in use
atp34 in use not34in use
not here1in use
not here1in use
If "every line has statements like" what you've shown, and you're sure of that, make it easy on yourself:
strTxt = Replace(strTxt, "in use by ", " in use by ")

VBScript for moving like files

I need a script to be able to move files with like names once there are 4 like files.
Example:
Cust-12345.txt
Addr-12345.txt
Ship-12345.txt
Price-12345.txt
The files will always start with those for names, the numbers after the "-" will always be different. I need to be able to search a folder and when all 4 files are there move them into a completed folder.
option explicit
dim objFS : dim strShareDirectory : dim strDumpStorageDir : dim objFolder : dim colFiles : dim re : dim objFile
dim dictResults ' dictionary of [filename] -> [matching substring]
dim dictResultsCount ' dictionary of [matching substring] -> [count]
dim dictResultsFinal ' only the valid entries from dictResults
dim keyItem
dim strMatch
dim message
message = "Yes"
set dictResultsFinal = CreateObject("Scripting.Dictionary")
set dictResults = CreateObject("Scripting.Dictionary")
set dictResultsCount = CreateObject("Scripting.Dictionary")
Set objFS = CreateObject("Scripting.FileSystemObject")
strShareDirectory = "c:\Test"
strDumpStorageDir = "c\Test\Out"
Set objFolder = objFS.GetFolder(strShareDirectory)
Set colFiles = objFolder.Files
Set re = New RegExp
re.Global = True
re.IgnoreCase = False
re.Pattern = "-\d"
Dim curFile, matchValue
Dim i: i = 0
For Each objFile in colFiles
' test if the filename matches the pattern
if re.test(objFile.Name) then
' for now, collect all matches without further checks
strMatch = re.execute(objFile.Name)(0)
dictResults(objFile.Name) = strMatch
' and count
if not dictResultsCount.Exists(strMatch) then
dictResultsCount(strMatch) = 1
else
dictResultsCount(strMatch) = dictResultsCount(strMatch) +1
end if
end if
next
' for testing: output all filenames that match the pattern
msgbox join(dictResults.keys(), vblf)
' now copy only the valid entries into a new dictionary
for each keyItem in dictResults.keys()
if dictResultsCount.Exists( dictResults(keyItem) ) then
if dictResultsCount( dictResults(keyItem) ) = 4 then
dictResultsFinal(keyItem) = 1
end if
end if
next
I had an answer here that involved using an array but, come to think of it, I don't think you even need an array. Just iterate each file and check for the existence of the others.
Set re = New RegExp
re.Global = True
re.IgnoreCase = True
re.Pattern = "\\(Cust|Addr|Ship|Price)-(\d+)\.txt"
For Each File In objFS.GetFolder(strShareDirectory).Files
' Test to make sure the file matches our pattern...
If re.Test(File.Path) Then
' It's a match. Get the number...
strNumber = re.Execute(File.Path)(0).SubMatches(1)
' If all four exist, move them...
If AllFourExist(strNumber) Then
For Each strPrefix In Array("Cust-", "Addr-", "Ship-", "Price-")
objFS.MoveFile strShareDirectory & "\" & strPrefix & strNumber & ".txt", _
strDumpStorageDir & "\" & strPrefix & strNumber & ".txt"
Next
End If
End If
Next
And here's the AllFourExist function (I'm assuming objFS is global):
Function AllFourExist(strNumber)
For Each strPrefix In Array("Cust-", "Addr-", "Ship-", "Price-")
If Not objFS.FileExists(strShareDirectory & "\" & strPrefix & strNumber & ".txt") Then Exit Function
Next
AllFourExist = True
End Function
I'm not sure how the FSO will handle the fact that you're moving files out of a folder that you're currently iterating. If it complains, you may need to resort to an array after all. Something to keep in mind.

Resources