Flush DNS remotely output to textfile is empty - vbscript

I am trying to remotely flushdns multiple servers remotely and output the results to a textfile. After running my script, my textfile is empty.
Script:
Const ForReading = 1
Set fso = CreateObject("Scripting.FileSystemObject")
Set wshShell = WScript.CreateObject("WSCript.shell")
Set textFile = fso.OpenTextFile("C:\Scripts\servers.txt", ForReading)
Set logFile = fso.CreateTextFile("C:\Scripts\logsssss.txt")
Do Until textFile.AtEndOfStream
hostName = textFile.Readline
Do
wshShell.run("cmd /c psexec \\" & hostName &" -u IDEALCORP\acorrera -s ipconfig /flushdns >> & hostName,TRUE")
Loop Until True
Loop
Any ideas why my output is blank? What needs to be changed/modified in my script?

Quotes are not in their place and it is better to include window style in Run method
NO : wshShell.run "cmd /c psexec \\" & hostName &" -u IDEALCORP\acorrera -s ipconfig /flushdns >> & hostName,TRUE"
YES : wshShell.run "cmd /c psexec \\" & hostName &" -u IDEALCORP\acorrera -s ipconfig /flushdns >> " & hostName,0,TRUE

What do you hope to achieve with endlessly looping over the command for the first hostName?
Why don't you check the return value of the command?
How could logFile contain anything, if you don't write to it?
Did you test your command from the console?

Related

stopping VBScript exec from flashing on screen [duplicate]

I'm trying to execute this simple test script, but a command shell window is appearing after I execute the script.:
Set objShell = WScript.CreateObject("WScript.Shell")
strCommand = "cmd /C tasklist"
Set objExecObject = objShell.Exec(strCommand)
wscript.echo "Test"
How can I prevent it from showing up?
Update
I was able to improve it with this code change:
strCommand = "cmd /C /Q tasklist"
Now the window only shows up for a split second. But I don't want it to show up at all.
You're always going to get a window flash with Exec(). You can use Run() instead to execute the command in a hidden window. But you can't directly capture the command's output with Run(). You'd have to redirect the output to a temporary file that your VBScript could then open, read, and delete.
For example:
With CreateObject("WScript.Shell")
' Pass 0 as the second parameter to hide the window...
.Run "cmd /c tasklist.exe > c:\out.txt", 0, True
End With
' Read the output and remove the file when done...
Dim strOutput
With CreateObject("Scripting.FileSystemObject")
strOutput = .OpenTextFile("c:\out.txt").ReadAll()
.DeleteFile "c:\out.txt"
End With
The FileSystemObject class has methods like GetSpecialFolder() to retrieve the path of Windows temp folder and GetTempName() to generate a temporary filename that you can use instead of hardcoding an output filename as I've done above.
Also note that you can use the /FO CSV argument with tasklist.exe to create a CSV file which should make parsing it much easier.
Finally, there are VBScript "native" ways to retrieve the list of running processes. WMI's Win32_Process class, for example, can do this without the need for Run/Exec.
Edit:
For the sake of completeness, I should mention that your script can relaunch itself in a hidden console window where you can run Exec() silently. Unfortunately, this hidden console window will also hide your output from functions like WScript.Echo(). Aside from that, however, you probably won't notice any differences running your script under cscript vs wscript. Here's an example of this method:
' If running under wscript.exe, relaunch under cscript.exe in a hidden window...
If InStr(1, WScript.FullName, "wscript.exe", vbTextCompare) > 0 Then
With CreateObject("WScript.Shell")
WScript.Quit .Run("cscript.exe """ & WScript.ScriptFullName & """", 0, True)
End With
End If
' "Real" start of script. We can run Exec() hidden now...
Dim strOutput
strOutput = CreateObject("WScript.Shell").Exec("tasklist.exe").StdOut.ReadAll()
' Need to use MsgBox() since WScript.Echo() is sent to hidden console window...
MsgBox strOutput
Of course, if your script expects command-line parameters, those would need to be forwarded when relaunching your script as well.
Edit 2:
Yet another possibility is to use the Windows clipboard. You can pipe the output of your command to the clip.exe utility. Then, retrieve the text via any number of available COM objects that can access the contents of the clipboard. For example:
' Using a hidden window, pipe the output of the command to the CLIP.EXE utility...
CreateObject("WScript.Shell").Run "cmd /c tasklist.exe | clip", 0, True
' Now read the clipboard text...
Dim strOutput
strOutput = CreateObject("htmlfile").ParentWindow.ClipboardData.GetData("text")
You can use .Exec() method, without console window flash, temp files and unexpected WScript.Echo output muting. The method is slightly tricky, and requires to launch secondary linked script, so I added the comments:
Option Explicit
Dim objDummy, strSignature, objPrimary, objSecondary, objContainer, objWshShell, objWshShellExec, strResult
' this block is executed only in the secondary script flow, after primary script runs cscript
If WScript.Arguments.Named.Exists("signature") Then
' retrieve signature string from argument
strSignature = WScript.Arguments.Named("signature")
Do
' loop through all explorer windows
For Each objContainer In CreateObject("Shell.Application").Windows
' check if the explorer's property with signature name contains the reference to the live script
If ChkVBScriptTypeInfo(objContainer.getProperty(strSignature)) Then
Exit Do
End If
Next
WScript.Sleep 10
Loop
' create shell object within secondary script
Set objWshShell = CreateObject("WScript.Shell")
' retrieve the primary script me object reference from explorer's property with signature name
Set objPrimary = objContainer.getProperty(strSignature)
' quit explorer window to release memory as it's no longer needed
objContainer.Quit
' assign the secondary script me object to the primary script's variable
Set objPrimary.objSecondary = Me
' emtpy loop while primary script is working
Do While ChkVBScriptTypeInfo(objPrimary)
WScript.Sleep 10
Loop
' terminate secondary
WScript.Quit
End If
' the code below is executed first in the primary script flow
' create signature string
strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
' create new hidden explorer window as container to transfer a reference between script processes
Set objContainer = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
' put this script's me object reference into explorer's property
objContainer.putProperty strSignature, Me
' launch new secondary process of the same script file via cscript.exe with hidden console window, providing signature string in named argument to identify host script
CreateObject("WScript.Shell").Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0
' wait until secondary script has been initialized and put his me object into this script variable
Do Until ChkVBScriptTypeInfo(objSecondary)
WScript.Sleep 10
Loop
' here is your code starts...
' create exec object within hidden console window of secondary script, execute cmd instruction
Set objWshShellExec = objSecondary.objWshShell.Exec("%comspec% /c tasklist")
' read cmd output
strResult = objWshShellExec.StdOut.ReadAll()
WScript.Echo strResult
' ...
' utility check if me object is live
Function ChkVBScriptTypeInfo(objSample)
On Error Resume Next
If TypeName(objSample) <> "VBScriptTypeInfo" Then
ChkVBScriptTypeInfo = False
Exit Function
End If
ChkVBScriptTypeInfo = True
End Function
UPDATE
I've slightly reworked the code to make it more straightforward:
Option Explicit
Dim strCmd, strRes, objWnd, objParent, strSignature
If WScript.Arguments.Named.Exists("signature") Then WshShellExecCmd
strCmd = "%comspec% /c tasklist"
RunCScriptHidden
WScript.Echo strRes
Sub RunCScriptHidden()
strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty strSignature, Me
CreateObject("WScript.Shell").Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0, True
End Sub
Sub WshShellExecCmd()
For Each objWnd In CreateObject("Shell.Application").Windows
If IsObject(objWnd.getProperty(WScript.Arguments.Named("signature"))) Then Exit For
Next
Set objParent = objWnd.getProperty(WScript.Arguments.Named("signature"))
objWnd.Quit
objParent.strRes = CreateObject("WScript.Shell").Exec(objParent.strCmd).StdOut.ReadAll()
WScript.Quit
End Sub
BTW, here is VBScript "multithreading" implementation that uses the same container approach.
Some great suggestions are listed above. I'd like to make one more suggestion which is more of a workaround. You can use Sysinternals Desktops (a free program) to run your macro on another desktop on your same machine. That way the flashing can all happen on its own desktop and won't interrupt your work.
I use Sysinternals PSEXEC
https://learn.microsoft.com/sv-se/sysinternals/downloads/psexec
Created a Batch-file (in the same folder as the vbs and exe-file) that runs the script as system user.
I can not Access the user profile and I need to be local Admin but when i run the script without interaction with the desktop it will hide all annoying popups.
Run Script as system without interaction with desktop
"%~dp0PsExec.exe" -s wscript.exe "%~dp0MyScript.vbs"
Run Script as system with interaction with desktop
"%~dp0PsExec.exe" -s -i wscript.exe "%~dp0MyScript.vbs"
To hide the command line windows in VBscipt is use Run in WshShell Object
Then to get the result you can send this result to text file in %temp%
Then read this result with FileSystemObject
Set Sh = CreateObject("WScript.Shell")
tFile=Sh.ExpandEnvironmentStrings("%Temp%")&"\t.txt"
Sh.Run "cmd.exe /C tasklist > """&tFile&""" ",0,False
Wscript.echo CreateObject("Scripting.FileSystemObject").openTextFile(tFile).readAll()
OR
If StrComp(right(WScript.FullName,11),"wscript.exe",1) = 0 Then '' get only wscript.exe from "c:\windows\system32\wscript.exe" to compere with wscript.exe
WScript.Quit CreateObject("WScript.Shell").Run("cscript.exe """ & WScript.ScriptFullName & """", 0, False)
End If
MsgBox CreateObject("WScript.Shell").Exec("cmd.exe /c tasklist /v /fi ""imagename EQ explorer*"" /FO LIST | FIND ""PID:""").StdOut.ReadAll()
An alternative to using to windows scripting host is here: Run a batch program(.bat) through a Visual Basic 6.0
It runs a program and captures its screen output. It works for me in VB6, but not in VBA (hangs at WaitForSingleObject, don't know why).
After trying the main solutions without success, I was able to solve my problem with the following code:
With CreateObject("WScript.Shell")
.Run "cmd /c start /b tasklist.exe > c:\out.txt", 0, True
End With
The real deal was the "/b" as the console help display:
START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED]
[/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL]
[/NODE <NUMA node>] [/AFFINITY <hex affinity mask>] [/WAIT] [/B]
[command/program] [parameters]
"title" Title to display in window title bar.
path Starting directory.
B Start application without creating a new window. The
application has ^C handling ignored. Unless the application
enables ^C processing, ^Break is the only way to interrupt
the application.

Modify Windows hosts file from vbscript with admin privileges

Our network team uses a .VBS script file that runs every time a user logs into the network. They asked me to edit their script so that it will modify the windows hosts file.
The problem is the script needs admin privileges on the user's computer. From the script, how do I open the hosts file with elevated privileges, make some changes, and then save the file?
Something like that :
If Not WScript.Arguments.Named.Exists("elevate") Then
CreateObject("Shell.Application").ShellExecute WScript.FullName _
, WScript.ScriptFullName & " /elevate", "", "runas", 1
WScript.Quit
End If
Hosts = "%windir%\system32\drivers\etc\hosts"
Command = "cmd /c attrib "& Hosts &" -r"
Set Ws = WScript.CreateObject("WScript.Shell")
Result = Ws.run(Command,0,True)
EditHostsFile = Ws.run("cmd /c Notepad "& Hosts,0,True)
HostsReadOnly = Ws.run("cmd /c attrib "& Hosts &" +r",0,True)

Multiple commands in command prompt using vbscript

Set oShell = CreateObject("WScript.Shell")
oShell.Run "cmd /c c:"
This line executes perfectly fine. Now I need to enter a text.
For example: c:\users> "abcd"
How do I go about it in the already opened cmd prompt.
You must add & after each command and change cmd /c to cmd /k
The first command is : CD /D c:\
The second command is : Dir
The third command is : ping 127.0.0.1
Try like this :
Set oShell = CreateObject("WScript.Shell")
Command = "cmd /K cd /d c:\ & Dir & ping 127.0.0.1"
oShell.Run Command,1,True

Run a command from cmd prompt and capture data in text file using vbscript

I am trying to run the below command from command prompt using vbscript and then capture the result in a text file.
netstat -an -p tcp | find /c ":80" > C:\Users\Swarnabha\Desktop\test.txt
I have written the below code but it is not working... Help me here plz!
Dim filepath
filepath= "C:\Users\Swarnabha\Desktop\test.txt"
Dim connstr
Dim portno
portno = ":80"
connstr = "cmd netstat -an -p tcp | find /c "& portno &" > "& filepath
Dim oShell
Set oShell = WScript.CreateObject ("WScript.Shell")
oShell.run connstr
Set oShell = Nothing
WScript.Quit
I think what you need to do is edit the connstr to include the /c switch which carries out the command specified by the string and then terminates. You need to do that since you are specifying the > redirect command which "is a feature of the shell" to quote Bill Stewart.
connstr = "cmd.exe /c netstat -an -p tcp | find /c "& chr(34) & portno & chr(34) & " > " & filepath
You also need to put your port number variable in quote. 34 is the ANSI code for double quotes. That way your command will look like the following
cmd.exe /c netstat -an -p tcp | find /c ":80" > "C:\Users\Swarnabha\Desktop\test.txt"
I would consider as well grouping all your variable declarations as it is a good coding practice. You should also quote your filepath as that is likely to contain spaces at some point as well.

CMD in vbscript

I want to write a simple vb script to automate shutdown in windows.
the code I am using is :
Dim ti
ti=InputBox("enter time in minutes")
ti=ti*60
Set objShell=CreateObject("WScript.Shell")
objShell.Run "cmd shutdown /s /t "& ti & " "
but when I enter the time and press enter , all I get is an command prompt window and nothing happens
I even tried by setting a default value for time and specifing the complete path for shutdown.exe ,but nothing seems to be working
Set WshShell = WScript.CreateObject("WScript.Shell")
Command = "C:\Windows\System32 shutdown.exe -s -t 600 "
WshShell.Run Command
can u please correct me and guide me towards the right code ....
It looks like you're missing a backslash in your path:
Set WshShell = WScript.CreateObject("WScript.Shell")
Command = "C:\Windows\System32\shutdown.exe -s -t 600 "
WshShell.Run Command
If you want to run commands in cmd you have to use either /k (keep cmd window open after command finishes) or /c (close cmd window after command finishes). Here's the canonical way to do this:
ti = InputBox("enter time in minutes")
ti = ti * 60
CreateObject("WScript.Shell").Run "%COMSPEC% /c shutdown -s -t " & ti
%COMSPEC% is a system environment variable with the path to cmd.exe.

Resources