VBScript OpenTextFile File Not Found error when Windows Explorer shows the file - vbscript

I am writing a program in VBScript to automate the process of file encryption, and am struggling with a problem.
I want to test which code the script will execute based on whether a file comparison returns an errorlevel of 0 or 1. (For simplicity, I cut out that code from this post.) Google searches have pointed me to the following to start the process of modifying one of the comparison files for this purpose.
Set testFile = fso.OpenTextFile(testDestFile, 8, False, 0)
However, VBScript always throws a "File not found" error for that line unless I put
WScript.Echo "testDestFile is '" & testDestFile & "'..."
right before it.
I don't want that, because the script's actions should be invisible to the user unless necessary. When I run this script, I can see in Windows Explorer that it creates the file represented by testDestFile. What am I doing wrong?
Option Explicit
Dim baseDirLen, compareOpts, decryptOpts, destDataPath, destFolder, _
destFolderPath, encDestFile, encryptorPath, encryptOpts, file, fileName, _
folder, folderEnd, fso, keyPath, oShell, srcDataPath, srcDirEndLen, _
srcFolder, strErrorCode, testDestFile, testDiff, testFile, t
Set oShell = CreateObject("Wscript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
srcDataPath = "e:\EZcrypt\TargetData"
keyPath = "e:\EZcrypt\Key\Demo010719.key.bin"
destDataPath = "E:\EZcrypt\EncryptedData"
encryptorPath = "E:\OpenSSL-Win32\bin\openssl"
Set srcFolder = fso.GetFolder(srcDataPath)
baseDirLen = Len(srcDataPath)
recurseFolders(srcFolder)
Sub recurseFolders(srcFolder)
For Each folder In srcFolder.subfolders
srcDirEndLen = (Len(folder) - baseDirLen - 1)
folderEnd = Right(folder, srcDirEndLen)
destFolderPath = destDataPath & "\" & folderEnd & "\"
If Not fso.FolderExists(destFolderPath) Then
fso.CreateFolder(destFolderPath)
End If
For Each file In folder.Files
fileName = fso.GetFileName(file)
testDestFile = destFolderPath & "test." & fileName
encDestFile = destFolderPath & fileName & ".enc"
If Not fso.FileExists(encDestFile) Then
strErrorCode = ""
encryptOpts = encryptorPath & " enc -aes-256-cbc -salt -in """ & _
file & """ -out """ & encDestFile & _
""" -pass file:""" & keyPath & """ -pbkdf2"
oShell.Run (encryptOpts)
decryptOpts = encryptorPath & " enc -d -aes-256-cbc -in """ & _
encDestFile & """ -out """ & testDestFile & _
""" -pass file:""" & keyPath & """ -pbkdf2"
oShell.Run (decryptOpts)
WEcript.Echo "testDestFile is '" & testDestFile & "'..."
Set testFile = fso.OpenTextFile(testDestFile, 8, False, 0)
Else
WScript.Echo "'" & encDestFile & "' exists. Skipping..."
End If
Next
recurseFolders(folder)
Next
End Sub

The most likely reason for the behavior you observed is that the openssl commands you run right before trying to open that file (specifically the encryption command, which appears to be creating the file) haven't finished yet. You don't tell the Run method to wait for the commands to return, so they're running asynchronously in the background. Presumably the WScript.Echo adds just enough delay for the encryption to finish before the code proceeds to opening the file. Using WScript.Sleep instead of echoing something would probably have had the same effect.
To fix the issue, wait for the external commands to return.
Replace these lines:
encryptOpts = encryptorPath & ...
oShell.Run (encryptOpts)
decryptOpts = encryptorPath & ...
oShell.Run (decryptOpts)
with this:
encryptOpts = encryptorPath & ...
oShell.Run encryptOpts, 0, True
decryptOpts = encryptorPath & ...
oShell.Run decryptOpts, 0, True
It's also good practice to check the exit status of external commands, so you can see if something went wrong:
rc = oShell.Run(encryptOpts, 0, True)
If rc <> 0 Then
'an error occurred
End If

Related

Trouble creating TAR files using 7-zip (VBScript+CMD)

I am trying to make a VBScript for Altap Salamander that would take files from current selection and separately archive them as TAR.
Most of the code below works, but the shell command on line 27 returns Shell error 1 and no TAR files get created.
Dim FSO, WshShell
Set FSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
Dim Items, Item, result
' Pick the collection of items to make the list from.
If Salamander.SourcePanel.SelectedItems.Count = 0 Then
If Salamander.MsgBox("No items are selected. Do you want to make list from all items in the panel?", 4, "Question") = 6 Then
Set Items = Salamander.SourcePanel.Items
End If
Else
Set Items = Salamander.SourcePanel.SelectedItems
End If
ReDim args(Items.Count - 1)
For i = 0 To Items.Count - 1
args(i) = Items.Item(i).Path
Next
tarFilePath = FSO.GetParentFolderName(args(0))
For i = 0 To UBound(args)
objFile = args(i)
tarFileName = FSO.GetFile(objFile).Name & ".tar"
tarFile = tarFilePath & "\" & tarFileName
result = WshShell.Run("cmd.exe /c ""C:\Program Files\7-Zip\7zFM.exe"" a -ttar -r """ & tarFile & """ """ & FSO.GetFile(objFile).Path & """", 0, True)
Next
If result = 0 Then
result = "Shell ran successfully"
Else
result = "Shell error " & result
End If
MsgBox result, vbInformation, "Archiving Complete"
I've tried changing 7z.exe to both 7zG.exe and 7zFM.exe, adding and removing quotation marks and debugging.
I've also tried the CMD methods from here, but they didn't make much sense to me and I didn't get any to work.
What should I do to make this work?
Update & Solution:
I did a clean up on the code as advised and everything seems to be working just fine!
The for loop now looks like this:
For i = 0 To UBound(args)
objFile = args(i)
FilePath = FSO.GetFile(objFile).Path
tarFileName = FSO.GetFile(objFile).Name
tarFileName = Split(tarFileName, ".")(0) & ".tar"
tarFilePath = tarFileFold & "\" & tarFileName
strRun = """C:\Program Files\7-Zip\7z.exe"" a -ttar -r " & tarFilePath & " " & FilePath & ""
Err.Clear
On Error Resume Next
result = WshShell.Run(strRun, 0, True)
If Err Then
MsgBox "Error " & Err.Number & " " & Err.Description
End If
On Error Goto 0
Next
For anyone curious, the strRun command looks like this:
"C:\Program Files\7-Zip\7z.exe" a -ttar -r C:\Users\ondre\img123.tar C:\Users\ondre\img123.jpg
This will work with any archiving extensions 7zip has to offer. Just remember to change the file extension and the -txxx switch. You can also add the mx9 switch to ensure highest level of compression.
Example here:
"C:\Program Files\7-Zip\7z.exe" a -tzip -mx9 -r C:\Users\ondre\img123.zip C:\Users\ondre\img123.jpg
WshShell.Run returns a 1 now. I didn't manage to find any documentation from which I would tell if this is ok or not, so I guess I'll just disable the 'result' check completely and will be on my way.
Also, since this is a script for Altap Salamander, I found out an easier way of getting the files from one location to another, for example:
tarFileFold = Salamander.TargetPanel.Path
'will output the archived files to the oposing panel of Salamander, both left -> right & right -> left
tarFileFold = Salamander.SourcePanel.Path
'will output the files to the same folder as the source files. Similar to the first version, but without the use of FSO
Thanks everyone!

Copy file names at Recycle Bin

I'm trying to copy all filenames list on the Recycle Bin in Windows 10.
I go to Command Prompt:
C:\>cd C:/$Recycle.Bin
C:\$Recycle.Bin>dir S-1-5-21-2370250818-2711005194-4184312249-1165
$R8CQG1I.txt
$IURO2ZD.txt
$RV2TEJ7.txt
I have 3 files I want to copy the real file names not the names like this result.
After some search I found this VBScript. I run the code and I get this error:
Expected end of statement
Option Explicit
DIM g_objWshShell, g_objFSO, g_sLogFile, g_objWshNetwork, g_sScriptName, g_sComputerName, g_sUserName Dim g_sVer, g_objLogFile, g_sLogDir
'Setup main variables and objects Set g_objWshShell = WScript.CreateObject("WScript.Shell") 'Create a Shell Object Set g_objFSO = CreateObject("Scripting.FileSystemObject") 'create a File System Object Set g_objWshNetwork = WScript.CreateObject("WScript.Network") 'Create Network Object g_sComputerName
= g_objWshNetwork.Computername 'Gets machine Computer name g_sUserName = g_objWshNetwork.UserName 'Gets logged-on username g_sScriptName=UCase(WScript.ScriptName) '
*** Name of the script
' *** START LogFile Information - use Delete or Append info below; don't use both *** Const FORREADING = 1, FORWRITING = 2, FORAPPENDING
= 8 'Setup constants for writing, appending, etc g_sLogDir = "C:\TEMP" If Not (g_objFSO.FolderExists(g_sLogDir)) Then g_objFSO.CreateFolder(g_sLogDir) End If g_sLogFile = g_sLogDir & "\" & Left(g_sScriptName,len(g_sScriptName)
- 3) & "LOG" 'Makes log file the SCRIPTNAME.Log g_sVer = "1.0"
'To delete a logfile and create a new one each time script is ran If g_objFSO.FileExists(g_sLogFile) Then g_objFSO.DeleteFile(g_sLogFile) 'Delete logfile if it exists. End If Set g_objLogFile = g_objFSO.CreateTextFile(g_sLogFile, FORWRITING) 'Setup the logfile for writing
Call Main() Call ExitScript()
'Start main script HERE *** Sub Main() Dim objRecycleBin, objFolderItems, objItem, strSpecialFolderName strSpecialFolderName = "Recycle Bin" 'Call WriteLine("Starting " & g_sScriptName & " at " & Date & " " & Time, g_objLogFile) Set objRecycleBin
= GetSpecialFolderObject(strSpecialFolderName) 'Get Special Folder based upon input name Set objFolderItems = objRecycleBin.Items() 'Get items within Recycle Bin For Each objItem In objFolderItems 'Delete all items within Special Folder If (objItem.Type = "File Folder") Then 'Check for file type g_objFSO.DeleteFolder(objItem.Path) 'Delete Folders Else g_objFSO.DeleteFile(objItem.Path) 'Delete Files End If WScript.Echo "Deleted " & objItem.Name Next End Sub
'*-*-*-*-*- Start Subroutines here
*-*-*-*-*- 'Returns SpecialFolder based upon name of folder Function GetSpecialFolderObject(NameOfFolder) Dim objShellApp, i, objSpecialFolder Set objShellApp = CreateObject("Shell.Application") On Error Resume Next For i=0 To 40 '40 is highest value for special folders Set objSpecialFolder = objShellApp.NameSpace(i) If (StrComp(objSpecialFolder.Title,NameOfFolder,vbTextCompare)=0) Then Set GetSpecialFolderObject = objSpecialFolder Exit For End If Next Err.Clear End Function
'Closes logfile and exits script Sub ExitScript() 'Call WriteLine(Date & " " & Time & "; Completed " & g_sScriptName, g_objLogFile) If IsObject(g_objLogFile) Then
g_objLogFile.Close End If Wscript.Quit End Sub
Sub EndOnError(sErrorString) WScript.Echo sErrorString & vbcrlf & "Check " & chr(34) & g_sLogFile & Chr(34) & " for details" Call WriteLine (sErrorString, g_objLogFile) WScript.Quit() End Sub
'Shows usage if input is wrong sub ShowUsage() WScript.Echo g_sScriptName & " v" & g_sVer & " Empties Recycle Bin for logged on user" & vbcrlf _ & vbcrlf & "USAGE: [CSCRIPT] " & g_sScriptName WScript.Quit end sub
'Writes to log Sub WriteLine(ByVal strMessage, ByVal objFile)
On Error Resume Next
If IsObject(objFile) then 'objFile should be a file object
objFile.WriteLine strMessage
Else
Call Wscript.Echo( strMessage )
End If End Sub
The VBScript version of #boxdog answer:
Set objShellApp = CreateObject("Shell.Application")
Set objSpecialFolder = objShellApp.NameSpace(10) '10 = Recyle Bin
For Each objFolder In objSpecialFolder.Items
WScript.Echo "FileName = " & objFolder.Name & vbTab & "Original Path = " & objFolder.ExtendedProperty("{9B174B33-40FF-11D2-A27E-00C04FC30871} 2")
Next
Answering this in case anyone is looking for VBS only solution.
In PowerShell, you can list the current path and original name/location of the Recycle Bin contents like This:
$shell = New-Object -ComObject Shell.Application
$shell.NameSpace(0x0a).Items() |
Select-Object #{Label="OriginalLocation";Expression={$_.ExtendedProperty("{9B174B33-40FF-11D2-A27E-00C04FC30871} 2")}},Name, Path
To copy the items, you can do this:
$shell.NameSpace(0x0a).Items() |
Copy-Item -Destination "C:\RecoveredFiles\$($_.Name)" -Recurse -Force
Note that this doesn't take into account any name-clashes - you'll need to test for that and adjust accordingly.

Ping function makes the whole excel table slow/unresponsive

I have a function that pings computers from an excel list and gets the ping value of them.
While the script was running, the excel was completely unresponsive. I could fix this with DoEvents, this made it a bit more responsive.
However, the problem starts when the function gets to an offline computer. While it waits for the response of the offline PC, Excel freezes again and the script does not jump to the next PC until it gets the "timeout" from the actual one.
As the default ping timeout value is 4000ms, if I have 100 computers in my list, and 50 of them are turned off, that means I have to wait an extra 3,3 minutes for the script to finish, and also blocks the entire Excel, making it unusable for the duration.
My question is, if is there any way to make this faster or more responsive or smarter?
The actual code:
Function:
Function sPing(sHost) As String
Dim oPing As Object, oRetStatus As Object
Set oPing = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery _
("select * from Win32_PingStatus where address = '" & sHost & "'")
DoEvents
For Each oRetStatus In oPing
DoEvents
If IsNull(oRetStatus.StatusCode) Or oRetStatus.StatusCode <> 0 Then
sPing = "timeout" 'oRetStatus.StatusCode <- error code
Else
sPing = sPing & vbTab & oRetStatus.ResponseTime
End If
Next
End Function
Main:
Sub pingall_Click()
Dim c As Range
Dim p As String
Dim actives As String
actives = ActiveSheet.Name
StopCode = False
Application.EnableCancelKey = xlErrorHandler
On Error GoTo ErrH:
DoEvents
For Each c In Sheets(actives).UsedRange.Cells
If StopCode = True Then
Exit For
End If
DoEvents
If Left(c, 7) = "172.21." Then
p = sPing(c)
[...]
End If
Next c
End Sub
As already noted in the comments, to prevent this from blocking after each call, you need to invoke your pings asynchronously from your function. The way I would approach this would be to delegate your sPing(sHost) function to a VBScript that you create on the fly in a temp folder. The script would look something like this, and it takes the IP address as a command line argument and outputs the result to a file:
Dim args, ping, status
Set ping = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery _
("select * from Win32_PingStatus where address = '" & Wscript.Arguments(0) & "'")
Dim result
For Each status In ping
If IsNull(status.StatusCode) Or status.StatusCode <> 0 Then
result = "timeout"
Else
result = result & vbTab & status.ResponseTime
End If
Next
Dim fso, file
Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.CreateTextFile(Wscript.Arguments(0), True)
file.Write result
file.Close
You can create a Sub to write this to a path something like this:
Private Sub WriteScript(path As String)
Dim handle As Integer
handle = FreeFile
Open path & ScriptName For Output As #handle
Print #handle, _
"Dim args, ping, status" & vbCrLf & _
"Set ping = GetObject(""winmgmts:{impersonationLevel=impersonate}"").ExecQuery _" & vbCrLf & _
" (""select * from Win32_PingStatus where address = '"" & Wscript.Arguments(0) & ""'"")" & vbCrLf & _
"Dim result" & vbCrLf & _
"For Each status In ping" & vbCrLf & _
" If IsNull(status.StatusCode) Or status.StatusCode <> 0 Then" & vbCrLf & _
" result = ""timeout""" & vbCrLf & _
" Else" & vbCrLf & _
" result = result & vbTab & status.ResponseTime" & vbCrLf & _
" End If" & vbCrLf & _
"Next" & vbCrLf & _
"Dim fso, file" & vbCrLf & _
"Set fso = CreateObject(""Scripting.FileSystemObject"")" & vbCrLf & _
"Set file = fso.CreateTextFile(Wscript.Arguments(0), True)" & vbCrLf & _
"file.Write result" & vbCrLf & _
"file.Close"
Close #handle
End Sub
After that, it's pretty straightforward - create a new directory in the user's temp directory, plop the script in there, and then use the Shell command to run each ping in its own process. Wait for the length of your timeout, then read the results from the files:
Private Const TempDir = "\PingResults\"
Private Const ScriptName As String = "ping.vbs"
'Important - set this to the time in seconds of your ping timeout.
Private Const Timeout = 4
Sub pingall_Click()
Dim sheet As Worksheet
Set sheet = ActiveSheet
Dim path As String
'Create a temp folder to use.
path = Environ("Temp") & TempDir
MkDir path
'Write your script to the temp folder.
WriteScript path
Dim results As Dictionary
Set results = New Dictionary
Dim index As Long
Dim ip As Variant
Dim command As String
For index = 1 To sheet.UsedRange.Rows.Count
ip = sheet.Cells(index, 1)
If Len(ip) >= 7 Then
If Left$(ip, 1) = "172.21." Then
'Cache the row it was in.
results.Add ip, index
'Shell the script.
command = "wscript " & path & "ping.vbs " & ip
Shell command, vbNormalFocus
End If
End If
Next index
Dim completed As Double
completed = Timer + Timeout
'Wait for the timeout.
Do While Timer < completed
DoEvents
Loop
Dim handle As String, ping As String, result As String
'Loop through the resulting files and update the sheet.
For Each ip In results.Keys
result = Dir$(path & ip)
If Len(result) <> 0 Then
handle = FreeFile
Open path & ip For Input As #handle
ping = Input$(LOF(handle), handle)
Close #handle
Kill path & ip
Else
ping = "timeout"
End If
sheet.Cells(results(ip), 2) = ping
Next ip
'Clean up.
Kill path & "*"
RmDir path
End Sub
Note that this has exactly zero error handling for the file operations, and doesn't respond to your StopCode flag. It should give the basic gist of it though. Also note that if you need to allow the user to cancel it, you won't be able to remove the temp directory because it will still be in use. If that is the case, only create it if it isn't already there and don't remove it when you're done.
You might be able to implement something like this, but I haven't tried it with multiple servers
if your network is fast you can reduce the timeout to 500 ms or less:
.
Public Function serverOk(ByVal dbSrvrNameStr As String) As Boolean
Const PINGS As Byte = 1
Const PING_TIME_OUT As Byte = 500
Const PING_LOCATION As String = "C:\Windows\System32\"
Dim commandResult As Long, serverIsActive As Boolean
commandResult = 1
serverIsActive = False
If Len(dbSrvrNameStr) > 0 Then
Err.Clear
With CreateObject("WScript.Shell")
commandResult = .Run("%comspec% /c " & PING_LOCATION & "ping.exe -n " & PINGS & " -w " & PING_TIME_OUT & " " & dbSrvrNameStr & " | find ""TTL="" > nul 2>&1", 0, True)
commandResult = .Run("%comspec% " & PING_LOCATION & "/c ping.exe -n " & PINGS & " -w " & PING_TIME_OUT & " " & dbSrvrNameStr, 0, True)
serverIsActive = (commandResult = 0)
End With
If serverIsActive And Err.Number = 0 Then
'"DB Server - valid, Ping response: " & commandResult
Else
'"Cannot connect to DB Server, Error: " & Err.Description & ", Ping response: " & commandResult
End If
Err.Clear
End If
serverOk = serverIsActive
End Function
.
Link to "Run Method (Windows Script Host)" from Microsoft:
https://msdn.microsoft.com/en-us/library/d5fk67ky(VS.85).aspx
The 3rd parameter of this command can be overlooked: "bWaitOnReturn" - allows you to execute it asynchronously from VBA

How to redirect output from EXE to TXT file using VBScript?

The requirement is to execute a certain script on multiple workstations using a tool such as Microsoft SCCM.
This script is required to execute the EXE 'C:\ugs\nx5\UGII\env_print.exe' on every workstation. This is to be done twice using the following parameters :
C:\ugs\nx5\UGII\env_print.exe -m
C:\ugs\nx5\UGII\env_print.exe -n
The script must be designed such that the output from the above mentioned should be stored at someplace on the workstation, from where SCCM could read the values.
To achieve this requirement, I wrote the following VBscript :
--------------------------------------------------------------------------------------------
On Error Resume Next
Const HKEY_LOCAL_MACHINE = &H80000002
Dim WshShell, fso, file, objRegistry, strKeyPath, strSysDrive, outputFile, strTEMP, file2, oTxtFile, oTxtFile2
Dim ComExec, strSysRoot, strComputer, outputFile2, EXEpath, ComExec2, return, return2, text, text2, CMDPath
strComputer = "."
Set WshShell = Wscript.CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
strSysDrive = WshShell.ExpandEnvironmentStrings("%SystemDrive%")
strSysRoot = WshShell.ExpandEnvironmentStrings("%SystemRoot%")
EXEpath = strSysDrive & "\ugs\nx5\UGII\env_print.exe"
CMDPath = strSysRoot & "\system32\cmd.exe"
'-----------------------SET TXT FILE LOCATION-----------------------
outputFile = strSysDrive & "\env_print_m.txt"
outputFile2 = strSysDrive & "\env_print_n.txt"
'-----------------------CREATE TEXT FILES-----------------------
Set oTxtFile = fso.CreateTextFile(outputFile)
Set oTxtFile2 = fso.CreateTextFile(outputFile2)
'-------COMMAND TO EXECUTE AND REDIRECT OUTPUT TO TXT FILE-------
ComExec = CMDPath & " /c " & EXEpath & " -m >> " & outputFile
ComExec2 = CMDPath & " /c " & EXEpath & " -n >> " & outputFile2
'-----------------------EXEUTE COMMANDS-----------------------
return = WshShell.Run(ComExec, 0, true)
return2 = WshShell.Run(ComExec2, 0, true)
'-----------------------READ OUTPUT FROM TXT FILES-----------------------
Set file = fso.OpenTextFile(outputFile, 1)
text = file.ReadAll
file.Close
Set file2 = fso.OpenTextFile(outputFile2, 1)
text2 = file2.ReadAll
file.Close
'-----------------------WRITE OUTPUT VALUES TO REGISTRY STRING VALUES-----------------------
strKeyPath = "SOFTWARE\env_print_Ver"
objRegistry.CreateKey HKEY_LOCAL_MACHINE, strKeyPath
WshShell.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\env_print_Ver\env_print_m", text, "REG_SZ"
WshShell.RegWrite "HKEY_LOCAL_MACHINE\SOFTWARE\env_print_Ver\env_print_n", text2, "REG_SZ"
'-----------------------DELETE TXT FILES-----------------------
fso.DeleteFile outputFile
fso.DeleteFile outputFile2
--------------------------------------------------------------------------------------------
This script executes the EXE with the required parameters and stores the output to 2 different TXT files(env_print_m.txt and env_print_n.txt).
Then reads these string values from the text files and stores them as registry string values at the following locations, so that it could be read by SCCM.
HKEY_LOCAL_MACHINE\SOFTWARE\env_print_Ver\env_print_m
HKEY_LOCAL_MACHINE\SOFTWARE\env_print_Ver\env_print_n
However, when this script is executed on workstations running Windows XP, the outputs aren't redirected to the TXT files. No errors are displayed either.
I am at my wits end. Please help.
As your first output file is not named/specified outputFile, change
Set file = fso.OpenTextFile("outputFile", 1)
to
Set file = fso.OpenTextFile(outputFile, 1)
(Same for the second one)
Trying to access a file wrongly named should abort your script with an error message. You switched of this feature by an EVIL global "On Error Resume Next". Get rid of it and see if "outputs aren't redirected' is explained by an error message.
Added wrt comment:
If something like
WshShell.Run ComExec, 0, true
'does not work' you should:
call .Run as a function and check the return value
echo the command (ComExec) and try to execute exactly this command from a console
switch /c to /k and look
sacrify a goat and think about permissions
Oh, I forgot:
manually delete the output files and check if they are created but get no content - then reconder the .exe

VBS Run cmd.exe output to a variable; not text file

This is what I have so far. It works; outputing the folder path to temp to a text file.
What I really want, is to output the data to a variable. Every example I see online, show how to do this using something like:
set objScriptExec = wshShell.Exec (strCommand)
followed by
strresult = LCase(objScriptExec.StdOut.ReadAll. // code
I want this to run with Run, not Exec, because I want the command prompt windows to be hidden as I will performing many commands with the code below. How can I capture that output to a variable?
Set wsShell = CreateObject("WScript.Shell")
strCommand = "cmd /c echo %temp% > %temp%\test.txt"
wsShell.Run strcommand,0,True
This may be done with the Windows Script Host Exec command. StdOut, StdIn, and StdErr may all be accessed, and ERRORLEVEL is available when the command completes.
Dim strMessage, strScript, strStdErr, strStdOut
Dim oExec, oWshShell, intErrorLevel
Dim ComSpec
Set oWshShell = CreateObject("WScript.Shell")
ComSpec = oWshShell.ExpandEnvironmentStrings("%comspec%")
intErrorLevel = 0
strScript = ComSpec & " /C echo %temp%"
On Error Resume Next
Set oExec = oWshShell.Exec (strScript)
If (Err.Number <> 0) Then
strMessage = "Error: " & Err.Message
intErrorLevel = 1
Else
Do While oExec.Status = 0
Do While Not oExec.StdOut.AtEndOfStream
strStdOut = strStdOut & oExec.StdOut.ReadLine & vbCrLf
Loop
Do While Not oExec.StdErr.AtEndOfStream
strStdErr = strStdErr & oExec.StdErr.ReadLine & vbCrLf
Loop
WScript.Sleep 0
Loop
intErrorLevel = oExec.ExitCode
strMessage = strStdOut & strStdErr & CStr(intErrorLevel)
End If
WScript.Echo (strMessage)
NOTE: Replacing "ReadLine" above with "Read(1)" accomplishes the same thing, but adds an ability to process characters rather than whole lines.
Of course Wscript.Shell would be a lot easier, but, since you want more fine grain control of your session, consider using Win32_Process. Usually, one uses this to control the placement of a new window, but, in your case, you want it hidden, so I set startupInfo.ShowWindow = 0 which means SW_HIDE. The following declares a VBScript function called RunCmd and which will run a command in an invisible window saving the output to a text file and then return the contents of the text file to the caller. As an example, I invoke RunCmd with the HOSTNAME command:
Function RunCmd(strCmd)
Dim wmiService
Set wmiService = GetObject("winmgmts:\\.\root\cimv2")
Dim startupInfo
Set startupInfo = wmiService.Get("Win32_ProcessStartup")
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
Dim cwd
cwd = fso.GetAbsolutePathname(".")
startupInfo.SpawnInstance_
startupInfo.ShowWindow = 0
' startupInfo.X = 50
' startupInfo.y = 50
' startupInfo.XSize = 150
' startupInfo.YSize = 50
' startupInfo.Title = "Hello"
' startupInfo.XCountChars = 36
' startupInfo.YCountChars = 1
Dim objNewProcess
Set objNewProcess = wmiService.Get("Win32_Process")
Dim intPID
Dim errRtn
errRtn = objNewProcess.Create("cmd.exe /c """ & strCmd & """ > out.txt", cwd, startupInfo, intPID)
Dim f
Set f = fso.OpenTextFile("out.txt", 1)
RunCmd = f.ReadAll
f.Close
End Function
MsgBox RunCmd("HOSTNAME")
References:
Create method of the Win32_Process class
Win32_ProcessStartup class

Resources