I run some CMD commands in my HTA file like
<script>
var WShell = new ActiveXObject('WScript.Shell');
WShell.run('cmd /c the_first_command');
WShell.run('cmd /c the_second_command');
</script>
and the first command may need a time to be fully executed, for example a few seconds
I need to run the next command only after the CMD output says that the previous task is fully completed.
As I understand, after the first command I can run an interval for example
var timer = setInterval(function() {
var cmd_output_of_the_first_command = ???;
if(~cmd_output_of_the_first_command.indexOf('A text about the task is completed')) {
clearInterval(timer);
WShell.run('cmd /c the_second_command');
}
}, 500);
So the question is how to get the CMD output?
Ok, I've found the answer:
var WShell = new ActiveXObject('WScript.Shell');
var WShellExec = WShell.Exec('cmd /c the_first_command');
var WShellResult = WShellExec.StdOut.ReadAll();
if(~WShellResult.indexOf('A text about the task is completed')) {
WShell.Run('cmd /c the_second_command');
}
No need in any interval
OR
just
execute CMD synchronously one by one without the need to check CMD output
WShell.Run('cmd /c the_first_command', 0, true);
WShell.Run('cmd /c the_second_command', 0, true);
Related
I created folder shortcuts for my taskbar and I would like them to stop launching a new explorer every time
So I decided to create a batch script, howover I can not get the kids from explorer.exe
#echo off
pushd
tasklist /nh /fi "imagename eq explorer.exe C:\Users\danil\Desktop\ISO" | find /i "explorer.exe C:\Users\danil\Desktop\ISO" > nul ||(start explorer.exe C:\Users\danil\Desktop\ISO)
The issue with your attempt is that tasklist will list only one instance of explorer.exe but not the titles of each window openned.
With some edits over this I've created listWindows.bat - it will list all visible windows names and their coresponding executable. So you can try this:
call listWindows.bat|findstr /i /b /e "explorer::Downloads" >nul 2>nul || (
start "" explorer.exe "C:\Users\%username%\Downloads"
)
To check the windows you need to start you can just try this:
call listWindows.bat|findstr /i /b "explorer::"
You cannot check the opening folders by checking the command line options, because the arguments stay the same across the whole lifetime of the process even after you changed to some other folders in that window. You need to use scriptable shell objects to get the current address.
Here's a PowerShell script to open a folder if it's not already opened in explorer
$folder = 'C:\Users\danil\Desktop\ISO'
$folderOpened = $false
foreach ($w in (New-Object -ComObject Shell.Application).Windows()) {
if ($w.LocationURL -ieq ([uri]$folder).AbsoluteUri) {
$folderOpened = $true; break
}
}
if (-not $folderOpened) { Invoke-Item $folder } # or start $folder
Below is an equivalent hybrid batch-jscript snippet
#if (#CodeSection == #Batch) #then
#echo off
cscript //e:jscript //nologo "%~f0" %*
exit /b
#end
// JScript Section
var objShell = new ActiveXObject("shell.application");
var objShellWindows;
objShellWindows = objShell.Windows();
if (objShellWindows != null)
{
// the folder you want to open
var folder = "file:///C:/Users/danil/Desktop/ISO";
var folderOpened = 0;
for (var objEnum = new Enumerator(objShellWindows);
!objEnum.atEnd(); objEnum.moveNext())
{
if (folder == objEnum.item().LocationUrl)
{
folderOpened = 1;
break;
}
}
if (!folderOpened) // open the folder if it's not already opened
objShell.Explore(folder); // or objshell.Open(folder)
}
Each explorer window is represented by an InternetExplorer object that can be retrieved from the Shell.Windows() collection. You need to use a file URI scheme instead of a normal Windows path, but it works. Of course you can even further change it to switch to the folder window if it's being opened. You can also use VBS or any other languages that support scriptable shell objects
Update:
You can avoid the file URI scheme by changing objEnum.item().LocationUrl to objEnum.item().Document.Folder.Self.Path
In the PowerShell version above it means changing
if ($w.LocationURL -ieq ([uri]$folder).AbsoluteUri) {
to
if ($w.Document.Folder.Self.Path -ieq $folder) {
There are situations when it is important to identify whether double quotes are passed as arguments to a WSH script. For example because they should be passed to another executable to be run.
The standard parsing functions/objects:
objArgs = WScript.Arguments;
for (i = 0; i < objArgs.length; i++)
{
WScript.Echo(objArgs(i));
}
do not differentiate between:
cscript foo.js "bar"
and
cscript foo.js bar
Is it possible with some other approach?
Note: I also tried to sort of escape them with several combinations like:
cscript foo.js '"bar"'
It seems that they are simply stripped away.
Following #Ekkehard.Horner suggestions:
Solution
// parseArgs.js
// Parsing jscript script arguments verbatim
var Shell = new ActiveXObject("WScript.Shell"),
wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2"),
guid = (new ActiveXObject("Scriptlet.TypeLib")).GUID.substring(0,38),
windir=Shell.ExpandEnvironmentStrings("%WinDir%"),
winver="\"" + windir + "\\System32\\winver.exe\" " + guid,
pcol, pid, cmd;
// Run winver.exe hidden and get this script ID as its ParentProcessId
winver=winver.replace(/\\/g, "\\\\");
Shell.Run("winver " + guid, 0);
pcol = new Enumerator (wmi.ExecQuery(
"SELECT * From Win32_Process WHERE CommandLine='"+ winver + "'",
"WQL", 32));
for (; !pcol.atEnd(); pcol.moveNext()){
var prc = pcol.item();
pid=prc.ParentProcessId;
prc.Terminate;
}
// Get the command line for the found PID
pcol = new Enumerator (wmi.ExecQuery(
"SELECT * From Win32_Process WHERE ProcessID="+ pid,
"WQL", 32));
for (; !pcol.atEnd(); pcol.moveNext()){
var prc = pcol.item();
cmd =prc.CommandLine;
}
WScript.Echo(cmd);
// Parse command line for arguments
var ags,
parseCmd=function(cmd){// WMI trims initial spaces
var p = new Object(),
re =/^"/.test(cmd) ? /"[^"]+" */ : /\S+\s*/;
p.nxt=re.test(cmd) ? cmd.match(re)[0] : ""; // extract next token
p.rst=cmd.replace(re, "") ; // remainder
return(p);
}
// Strip c/wscript path
ags=parseCmd(cmd).rst
//WScript.Echo(ags);
// Remove WSH "//xxx" options
ags=ags.replace(/\/\/\w+ +/g, "")
//WScript.Echo(ags);
// Strip script name and get arguments
ags=parseCmd(ags).rst
WScript.Echo(ags);
// Loop args and store as an array
var i=1, aags=[];
while(ags != ""){
var p =parseCmd(ags);
ags=p.rst;
aags.push(p.nxt.replace(/ +$/, ""));
WScript.Echo(i, p.nxt);
i++;
}
WScript.Echo(aags);
Test
Running parseArgs.js gives:
> cscript //nologo parseArgs.js "hello" world
cscript //nologo parseArgs.js "hello" world
"hello" world
1 "hello"
2 world
"hello",world
The line:
> parseArgs.js "hello" world
gives similar results.
Comments
Do we need such a convoluted script? Short answer: no. Long: depends.
In general, assuming you know the name of your script when it is run, you could query WMI for it.
Anyway, when you deploy your script, you do not normally have control on the deploy directory. So, if there is another script running under the same name, you can't know for sure which one is yours.
Another not so edge case is when there are two or more instances of your script running.
The strategy here is to run some dummy standard Windows executable (winver.exe) hidden, passing to it a GUID. In this way, it is safe to identify winver.exe command line by the unique GUID and consequently your script as the parent of winver.exe.
winver.exe does not require arguments, but does not protest if you pass some to it.
I am faced with the issue of IIS express stopping abruptly without any stack trace while debugging in local.
I have found a work around for this by writing the stack trace to a html file.
string file = #"C:\Users\INLASKD\Desktop\ExceptionHandlerError.html";
using (FileStream fs = new FileStream(file, FileMode.Create))
{
using (StreamWriter w = new StreamWriter(fs, Encoding.UTF8))
{
w.WriteLine(sb.ToString());
}
}
Now, I want to open this ExceptionHandlerError.html automatically everytime its modified when IIS Express stops.
I want bat file or a script to automate this. How can I go about this?
Note: I am connected to a network that doesn't allow administrator access and can't access event viewer.
After some research, I was able to open the browser right after writing it to the file with
System.Diagnostics.Process.Start(file);
Final code is as below:
string file = #"C:\Users\iraacn-9ajm\Desktop\ExceptionHandlerError.html";
using (FileStream fs = new FileStream(file, FileMode.Create))
{
using (StreamWriter w = new StreamWriter(fs, Encoding.UTF8))
{
w.WriteLine(sb.ToString());
}
}
System.Diagnostics.Process.Start(file);
You should be able to use this:
#echo off
set "file=C:\Users\INLASKD\Desktop\ExceptionHandlerError.html"
:loop
attrib "%file%" | findstr /B /L A 1>nul
if %errorlevel% equ 0 (
::open the file here
start "" "%file%"
attrib -A "%file%"
)
timeout /t 2 /nobreak >nul
goto loop
I have node js file which will excute my bat file. I tried using exec of node js child-process module but no luck
Let me share you my node js script:
var startTime = '2014-11-27 17:0:42';
var threadName = '<Thread 0>';
var categoryName ='AlarmCategory';
var alarmLevel = 'Fatal';
var alarmCategory = 'OS';
var alarmMessage = 'corrupt';
var cp = require('child_process');
msg = cp.exec('handler.bat' +" " + startTime ,function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: '+error.code);
console.log('Signal received: '+error.signal);
}
console.log('Child Process STDOUT: '+stdout);
console.log('Child Process STDERR: '+stderr);
});
My bat script . This script takes input parms and echos.
#echo off
set startTime=%1
set thread=%2
set categoryName=%3
set alarmLevel=%4
set alarmCategory=%5
set alarmMessage=%6
Echo #####################
Echo This tool will help you get the users info
Echo #####################
Echo hi %arg1%
For now i am printing only one arg.
Error i am getting :
"C:\Program Files (x86)\JetBrains\WebStorm 8.0.4\bin\runnerw.exe" "C:\Program Files\nodejs\node.exe" test\test_cmd.js
Error: Command failed: 'handler.bat' is not recognized as an internal or external command,
operable program or batch file.
I resolved my issue. I am using execFile() function now since i also need to pass arguments. It is very important to note that when you use execute command using execFile() make sure you set the "cwd" option in command of exeFile(). Since it looks for the child process file and it does not find the file. Setting full path directly for .bat file do not work .
I did like this ,
msg = cp.execFile('handler.bat' ,[startTime,threadName] ,{cwd:'/Node Js/baflog/sigma-logger/test'},function (error, stdout, stderr) {
.... ..
...
}
Does anyone know how to create an installation project using Visual Studio 2010 that creates a Windows Scheduler task? I'm building an installer for a Console Application that needs to run every X minutes, and it would be nice for the customer not to have to schedule it manually.
Thanks!
in Wix (.wixproj) you can do it in a CustomAction, written in Jscript, that invokes Schtasks.exe .
I don't know about VS2010's support of WIX, I think it is built-in.
The custom action module (the .js file) should have a function to run a schtasks command, something like this:
function RunSchtasksCmd(command, deleteOutput) {
deleteOutput = deleteOutput || false;
var shell = new ActiveXObject("WScript.Shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var tmpdir = fso.GetSpecialFolder(SpecialFolders.TemporaryFolder);
var tmpFileName = fso.BuildPath(tmpdir, fso.GetTempName());
var windir = fso.GetSpecialFolder(SpecialFolders.WindowsFolder);
var schtasks = fso.BuildPath(windir,"system32\\schtasks.exe") + " " + command;
// use cmd.exe to redirect the output
var rc = shell.Run("%comspec% /c " + schtasks + "> " + tmpFileName, WindowStyle.Hidden, true);
if (deleteOutput) {
fso.DeleteFile(tmpFileName);
}
return {
rc : rc,
outputfile : (deleteOutput) ? null : tmpFileName
};
}
And then, use that from within the custom action function itself, something like this
var r = RunSchtasksCmd("/Create Foo bar baz");
if (r.rc !== 0) {
// 0x80004005 == E_FAIL
throw new Error("exec schtasks.exe returned nonzero rc ("+r.rc+")");
}
var fso = new ActiveXObject("Scripting.FileSystemObject");
var textStream = fso.OpenTextFile(r.outputfile, OpenMode.ForReading);
// Read from the file and parse the results.
while (!textStream.AtEndOfStream) {
var oneLine = textStream.ReadLine();
var line = ParseOneLine(oneLine); // look for errors? success?
}
textStream.Close();
fso.DeleteFile(r.outputfile);
Some people say writing CA's in script is the wrong thing to do, because they are hard to maintain, hard to debug, or it's hard to do them right. I think those are bad reasons. CA's implemented correctly in script, work well.
WIX has its own custom action for creating windows task and scheduling them.
<CustomAction Id="CreateScheduledTask" Return="check" Directory="Application" ExeCommand=""[SystemFolder]SCHTASKS.EXE" /CREATE /SC DAILY /TN "My Task" /ST 12:00:00 /TR "[INSTALLLOCATION]Apps\File.exe" /RU [%USERDOMAIN]\[LogonUser]" />
Above command will create a task with name 'My Task' which will execute everyday at 12 AM.
SCHTASKS command is used to create and schedule a windows task.