VBscript wscript.shell execute not refreshing in winpe - vbscript

I have a DISM based imaging solution for use in WinPE as follows:
set WshShell = CreateObject("WScript.Shell")
Wscript.StdOut.WriteLine "[44m[1;37m restoring image boot partition for " & name & " [0m[40m"
Set objExec = WshShell.Exec("DISM.exe /Apply-Image /ImageFile:" & name & "/index:1 /ApplyDir:c:\")
Do
line = objExec.StdOut.ReadLine()
Wscript.StdOut.WriteLine line
Loop While Not objExec.Stdout.atEndOfStream
There are two issues with the way this executes:
The execution seems to stall and I have to press enter for it to continue.
The second problem is that the progress bar does not show up. It stays at "applying image".
Normally, if you execute DISM.exe /Apply-Image /ImageFile:" & name & "/index:1 /ApplyDir:c:\ it will look something like this:
"applying Image {1%-------------------------------------}
Interestingly this segment which prepares the disk shows each line of execution:
Set WshShell = CreateObject("WScript.Shell")
Set objExec = WshShell.Exec("diskpart.exe /s clean.sh")
Do
line = objExec.StdOut.ReadLine()
Wscript.StdOut.WriteLine line
Loop While Not objExec.Stdout.atEndOfStream
I think the DISM output is different because it only has one line that refreshes itself, but I'm not sure how to code around it.

I don't know how dism.exe outputs data (at the moment i only have a XP to test) but there is at least two cases in which code as
Set objExec = objShell.Exec( ...... )
Do
WScript.StdOut.WriteLine(objExec.StdOut.ReadLine())
Loop While Not objExec.Stdout.atEndOfStream
will not work as expected.
One is when the program output is directly send to the console buffer, not writing into stdout. As the code reads from the stdout stream of child process and there is no anything on it....
Second is when there is no end of line mark in child process output. Both Read and ReadLine return when the Enter key is pressed or when a CRLF is inside content being read. But, the tipical form of generating a progress bar in a console output is not sending the LF part, sending only the CR to return the caret to the start of the line and output the next change in progress bar just writing over the first drawn one. In this case, both the indicated methods will not return until there is a CRLF included in the output stream of the child process or the stream is closed.
As said, i've no access to DISM to test, but it seems it will fall in one of the two cases.
And no, it seems Run method has no way to run the command in the same window.
If the "same window" is a mandatory requirement, the better approach is to code something like
start a "master" batch file
this batch file starts the vbs
the vbs do what it needs to do and in the case of having to execute DISM or anything similar, generate a temporary batch file with the adecuate content and exit from vbs
the "master" batch file retrieves the control, checks for the presence of the temporary batch file and calls it
on completion of the temporary batch file, "master" retrieves the control and starts again the vbs
use the method that better adapts (arguments, environment variables, flag files, ...) to determine that this is not the first execution and continue execution as required.

Related

Run batch file in background

I've got a batch file that I want to run in the background whenever the system (Windows 2007) is turned on. The batch file monitors the task list for a given program, and when it sees that it's shut down, prompts the user to de-licence it.
I'm currently trying to do this without converting the batch file into either an executable or Windows service file.
I've found more online references than I can count which tell me that I should use "start /b file.bat" to run the batch file in the background, but this doesn't work for me, it just starts up the batch file in the same cmd line window that I'm using.
Can anyone suggest either what's going wrong, or even better; a nice simple way for me to get the batch file to run ion start up (I cannot use a GUI as I have to roll this out to several computers remotely)
Thanks
You could make a shortcut to your batch file and place the shortcut in your Startup Programs directory:
C:\Users\\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Since you have to roll this out to several computers remotely, you should be able to copy the batch file to the startup programs directory over the network assuming the remote machines have WinRM enabled and your account has adequate permissions.
If you want this batch file to run in the background at start up, you could reference your batch file from a VBScript (instead of using the batch file's short cut) and set the VBscript to run in invisible mode:
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & "C:\path\to\your\batchfile.bat" & Chr(34), 0
Set WshShell = Nothing
Just give this vbscript file the .vbs extension.
If the program you are concerned about is a GUI program (ie non console) just wait for it to exit. Batch waits for GUI programs to exit (but not when started interactively).
notepad
echo My notepad exited
Start /b says to start program in same window. See Start /?. Also Start is usually the wrong command to be using. It starts programs in abnormal ways. See end of http://stackoverflow.com/questions/41030190/command-to-run-a-bat-file/41049135#41049135 for how to start programs.
This is a VBS file.
This monitors for notepad exiting, pops up a messagebox, and restarts notepad.
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set objEvents = objWMIService.ExecNotificationQuery("SELECT * FROM Win32_ProcessStopTrace")
Do
Set objReceivedEvent = objEvents.NextEvent
msgbox objReceivedEvent.ProcessName
If lcase(objReceivedEvent.ProcessName) = lcase("Notepad.exe") then
Msgbox "Process exited with exit code " & objReceivedEvent.ExitStatus
WshShell.Run "c:\Windows\notepad.exe", 1, false
End If
Loop
This should use less battery power and CPU cycles. Batch files are read line by line so make VERY poor background tasks.
If the program you are concerned about is a GUI program (ie non console) just wait for it to exit. Batch waits for GUI programs to exit (but not when started interactively).
notepad
echo My notepad exited

Wscript make proccess not run on background or wait while finishes

Scenario: We have some scheduled jobs (Control-M) running many proccesses and some of them execute a .VBS file (with parameters) that reads the configuration from an XML file and sends it to a company's software that interprets it and loads data onto tables.
I need help with the VBS file, that as stated above, only gets the instructions from the XML and send it to the software with these steps (also, logs each step):
Finds the XML;
Creates an object to login the software (with XML parameters);
Dim object
Set object = CreateObject("service.location.id")
Login into the Database (with XML parameters);
object.Login("DATABASE_NAME")
Select which Data base (XML...);
object.SelectDatabase("DATABASE_NAME")
Sends command to start load proccess
object.LoadRepositoryTable(XML)
The problem is that since the default interpreter is wscript, when executing the script, it runs on the background and the Job Scheduler thinks it finished executing and starts the next job.
Executing the script on CMD, if I start it as cscript SCRIPT.vbs it waits for the whole load proccess to finish (it doesn't run on background), and I want to do this when running as wscript - because since there are many jobs, editing how they calls the script is not an option right now. This includes creating an .bat file that calls the SCRIPT.vbs as cscript.
I also tried searching on "how to run another .vbs file inside a VB Script" to run as cscript, but didn't manage to make it work.
What can I do?
Is there a way to make wscript wait for the load?
Is there a way to call a .vbs in the same folder (without sending it as parameter) while passing 2 arguments?
Another option I'm not seeing?
Edit: Here is what I've come to so far, but I'm getting "expected end of statement".
Dim objShell
Dim arg_dir
arg_dir = Wscript.Arguments.Item(0)
Dim arg_xml
arg_xml = Wscript.Arguments.Item(1)
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "cmd /k cscript ""C:\Folder\Scripts\SCRIPT.vbs" &" "& arg_dir &" "& arg_xml"", 1, True
cscript is the solution for your problem. Either have your scheduler run each VBScript with cscript.exe, or (if that isn't possible for some reason) make cscript the default script host by running
wscript.exe //h:cscript
once as an administrator.
The script you have cobbled together won't resolve your problem, even if you fixed the syntax error in the last line, because as long as you run it with wscript.exe it will still return immediately. It doesn't matter that the code in that script is running other scripts synchronously as long as all of that is happening in the background.

.ShellExecute and Wait

I've got a VBScript that calls multiple other scripts. (Most of them are just copying files from NAS to multiple places on users PC.
One of the VBScripts needs to be run as administrator using .ShellExecute.
It does work but there are other VBScripts after it's call that rely on it, so I get an error for the files are missing.
I know the command
shell.Run "sample.vbs", , True
for waiting till the script is done.
Is there a similar way to get ShellExecute to wait?
ShellExecute always runs asynchronously. If you have other scripts that need to run only after this script finished you could create some kind of marker upon completion to signal "go" to the other script(s).
For example, you can create a file in a specific path:
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile("C:\path\to\marker.txt", True)
If you need to run your batch of scripts more than once, have the script remove the marker when it starts and re-create it at the end.
The script that's supposed to run next needs to check for this marker and suspend execution until it appears. For example:
Set fso = CreateObject("Scripting.FileSystemObject")
Do Until fso.FileExists("C:\path\to\marker.txt")
WScript.Sleep 100
Loop
Other options are creating a registry value, or an eventlog entry.
Checking the process list (e.g. via Win32_Process) won't work, because normal users don't have access to the CommandLine property of elevated processes (which would be required to identify this particular process).

Trying to make SYSLOG DAEMON in Windows

Objective:
This daemon maintain logs at what time which text file is opened.
Step I:
I made one empty batch file and this file would be going to log the events into one temporary log file.
Step II:
Associating text files with this batch file program
i) I right clicked on one text file.
ii) I clicked on "open with" option
iii) Then I chose my batch file program.
Now as I open any text file my batch file program starts running.
Step III:
Batch file development:
i) I opened the batch file which I created as empty in Step I
ii) I wrote following batch file commands in order to above objective:
#echo off
echo %1 >>logs.txt
time >> logs.txt
notepad %1
exit
Step IV:
i) As I open any txt file, then this batch file runs, but the problem is as it comes to "time" command I have to manually press enter, so is there any command in batch file programming which can produce keystrokes.
ii) Second thing which I need is as I open my text file, cmd window pops up, I want it to remain hidden from user, so that user doesn't know about logging of events.
iii) Third thing which I need is to start the notepad process in background, so that my batch file script can proceed further.
Use %time% (see set /?) on same line as %1 to have time / filename on same line. Else type time /? for help esp time /t.
Console programs have a console. Use a different technology. VBScript can start programs hidden but you would do everything in vbscript. 0 is hidden.
Set WshShell = WScript.CreateObject("WScript.Shell")
msgbox FormatNumber(WshShell.Run("cmd /k dir c:\windows\*.*", 0, false))
As above but with 6 or 8.

Looping a batch file that calls another batch file

My embedded C compiler generates a batch file to run various build outputs in a processor simulator from the command line. I'd like to create a batch file to call that auto generated batch file that is somewhere convenient, and I'd like to be able to rerun it just by clicking a key as often as I want all day long.
Here's what I've tried
cd "C:\foo\project name\settings\"
:repeat
cls
"Project Name.Unit Test Ouput.cspy.bat" & pause
goto repeat
I see the output I expect from the batch file, followed by a:
Press any key to continue . . .
When I press enter the script ends and never executes the goto.
If I remove the pause statement the script just ends immediately.
If I type & goto repeat the script still ends immediately.
CDing to the batch file from the command line, running it, and then click the up arrow and enter effectively does what I want... I am trying to automate it a tiny bit more.
To run a batch file from another batch file, you have to use the call statement. If you don't, then your outer batch file will end when the inner one does.
call "Project Name.Unit Test Ouput.cspy.bat" & pause

Resources