May 7, 2010

Run All Macros in a Folder/Group

Filed under: Automation,Scripting — Marcus Tettmar @ 3:26 pm

Someone asked me today how to run all macros found in a folder. This simple script will run all macros it finds in its own folder in turn:

GetFileList>%SCRIPT_DIR%\*.scp,MacroFiles
Separate>MacroFiles,;,Macros
If>Macros_count>0
  Let>k=0
  Repeat>k
    Let>k=k+1
    Let>this_macro=Macros_%k%
    If>this_macro<>SCRIPT_FILE
      Macro>this_macro
    Endif
  Until>k=Macros_count
Endif

Note the check to make sure it doesn’t run itself!

This could be useful where you want a quick way to schedule a series of macros. Schedule this script and then all you need to do to add another to the schedule is to drop it into the same folder (or macro group).

For a bit more control consider naming each macro with a numeric prefix and then sort the array to determine the order in which they are run. Version 12 (currently in beta) has a built in ArraySort function. Or use this QuickSort algorithm.

January 29, 2010

Running Macro Scheduler Macros over the Web Via PHP

Filed under: Automation,General,Scripting,Web/Tech — Marcus Tettmar @ 9:31 am

Here’s a quick and simple proof of concept for running Macro Scheduler macros via the web and having their output displayed in the user’s browser:

Running Macro Scheduler Macros Over the Web Via PHP

The screenshot shows the PHP script, Macro Scheduler script and Internet Explorer being used to run the macro.

1) If you don’t already have a Windows based web server with PHP running, download and install WAMPServer. It’s easy.

2) Create a simple PHP script which takes an EXE name as a parameter and any parameters you want to pass to it. The following script will run EXEs that are in the c:\wamp\ folder, passing in any parameters provided and will dispay the EXEs output.

<?php
$exe = $_GET['exe'];

$dir = "c:\\wamp\\";

$parms = "";
foreach($_GET as $key=>$val) {
  $parms .= "/$key=$val ";
}

echo shell_exec("\"$dir$exe\" $parms");
?>

3) PHP’s safemode must be disabled for this script to work.

4) Create a Macro Scheduler macro and use SOWrite or SOWriteLn to output information. Compile it with the “Create Console App” option checked. Compile the EXE (or copy it) to the c:\wamp\ folder.

5) Now the macro can be executed via the web using http://servername/runmacro.php?exe=my.exe&parm1=value&etc=… which could be a link or entered into the browser directly.

6) Consider adding further security to the script to prevent anyone running any EXE on your server, or putting it in a password protected folder. I’ll leave that to you.

Macro Scheduler Enterprise comes with the msNet Remote Controller which includes a CGI module for running Macro Scheduler macros via web servers.

January 27, 2010

Why Does My Script “Hang” and Never Continue?

Filed under: Automation — Marcus Tettmar @ 9:47 am

This is a variation of a question we get regularly. Usually it turns out that the script is waiting on a WaitWindowOpen line because of a typo in the window title.

WaitWindowOpen, given a window title, will cause the script to wait until a window with that title exists.

If you misspell the window title WaitWindowOpen will wait forever, because a matching window will never appear.

Rather than rely on your typing, you can select the window title from a drop down list. With the window you want to wait for open on the screen edit your WaitWindowOpen line in the Code Builder by right clicking on it and selecting “Edit in Code Builder”. Now, select the window title from the drop down box.

Remember you can also do a sub-string match using the asterisk:

WaitWindowOpen>Notepad*

This works for all window functions and will match the first window found that contains the given text (regardless of case). So the above will match “Untitled – Notepad” as well as something like “My Notepad – MyFile.txt”. It will stop at the first one found, so don’t be too general and try to find something unique.

More advanced users might be interested to know that we’re adding the ability to use Regular Expressions in the window functions for version 12.

December 2, 2009

Tis the Season to .. Automate

Filed under: Automation,General — Marcus Tettmar @ 11:45 am

Crumbs, is it really already December? Christmas always seems to creep up on me unprepared. Always so much to do and organise. Most people will be winding down and spending time with friends and family. But in our modern 24×7 culture many businesses still keep running. Web sites and servers still need monitoring, reports generating, data transferring, networks maintained, users, customers and holiday shoppers supported.

How many of us end up “on call” or remoting into the office network to check things over and ensure those pesky systems keep working and processes keep ticking over without causing us more work when we get back in the New Year?

A lot of these things can be automated. Macro Scheduler could be helping you relax this Christmas. It’s a good time to look at your processes and see what could be streamlined. What can be automated to prevent key staff having to log in from home, or made easier for skeleton staff to operate?

In the UK we have new VAT rules coming into effect on 1st January. I wonder how many people will be logging in on New Year’s Day to update their tax codes. We’ve already got a macro set up to do just that, scheduled for 1 minute past midnight.

What will you be automating this Christmas?

November 5, 2009

How to Sort a CSV File

Filed under: Automation,Scripting — Marcus Tettmar @ 11:39 am

This morning, forum user hip asked how a script could sort a CSV file. Seems CSV files, sorting and Excel has become a bit of a hot topic here lately. Since Excel can read and save to CSV and also has a Sort function we might as well make use of it. Here’s a little VBScript function I put together which will sort a CSV file by a given column:

VBSTART
Sub SortCSVFile(file,sort_column)
  Set XLApp = CreateObject("Excel.Application")
  XLApp.Workbooks.Open(file)
  
  XLApp.ActiveWorkbook.ActiveSheet.Sort.SortFields.Clear
  Set SortCol = XLApp.Range(sort_column)
  XLApp.ActiveWorkbook.ActiveSheet.Sort.SortFields.Add(SortCol)
  Set Cell = XLApp.ActiveWorkbook.ActiveSheet.Cells.Find("*", XLApp.ActiveWorkbook.ActiveSheet.Cells(1, 1),,,,2)
  Set mYRange = XLApp.Range("A1", XLApp.ActiveWorkBook.ActiveSheet.Cells(Cell.Row, Cell.Column))
    
  XLApp.ActiveWorkbook.ActiveSheet.Sort.SetRange(mYRange)
  XLApp.ActiveWorkbook.ActiveSheet.Sort.Apply
  
  XLApp.ActiveWorkBook.Save
  XLApp.ActiveWorkBook.Close false
  XLApp.quit
End Sub
VBEND

The function opens the CSV file in Excel – without making Excel visible – then performs the sort, saves the file and closes Excel. You won’t see Excel appear on the screen.

Here’s how to use it. If you want to sort your file on column B and don’t have a header row, use:

VBRun>SortCSVFile,C:\Documents\my.csv,B1

To sort on column A and you DO have a header row use:

VBRun>SortCSVFile,C:\Documents\my.csv,A2

UPDATE: Here’s a simplified version which should work in Excel XP/2003 and should be able to detect whether or not your data has a header row:

VBSTART
Sub SortCSVFile(file,sort_column)
  Set XLApp = CreateObject("Excel.Application")
  XLApp.Workbooks.Open(file) 
  XLApp.ActiveWorkbook.ActiveSheet.Range("A1").Sort XLApp.ActiveWorkbook.ActiveSheet.Range(sort_column),,,,,,,0  
  XLApp.ActiveWorkBook.Save
  XLApp.ActiveWorkBook.Close false
  XLApp.quit
End Sub
VBEND

What if you don’t have Microsoft Excel?

As mentioned in my reply on the forum another method you could use is to open the CSV file as a recordset using DBQuery and apply an “ORDER BY” clause to your SQL statement. That would sort it into memory. Then you would need to loop through the array and write the data back out to a CSV file using WriteLn.

Something like:

//new file to write to
Let>new_file=%SCRIPT_DIR%\example_sorted.csv
IfFileExists>new_file
  DeleteFile>new_file
Endif

//set WriteLn NOT to add line breaks (we'll add those ourselves)
Let>WLN_NOCRLF=1
//The CSV delimiter
Let>comma=,

//Connect to and query the CSV using ORDER BY PRICE to sort on Price column
Let>ConStr=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%SCRIPT_DIR%;Extended Properties='text;HDR=YES;FMT=Delimited'
DBConnect>ConStr,dbH
DBQuery>dbH,select * from example.csv ORDER BY PRICE,fields,num_recs,num_fields

//If we have records, loop through records and fields, writing out to new file
If>num_recs>0
  //first need to copy the header record ...
  ReadLn>%SCRIPT_DIR%\example.csv,1,header_line
  WriteLn>new_file,wlnres,%header_line%%CRLF%

  //the loop
  Let>rec=0
  Repeat>rec
    Let>rec=rec+1
    Let>field=0
    Repeat>field
      Let>field=field+1
      Let>this_field=fields_%rec%_%field%
      //write the field out to the new file
      WriteLn>new_file,wlnres,this_field
      //add the comma delimiter if needed
      If>field<num_fields
        WriteLn>new_file,wlnres,comma
      Endif
    Until>field=num_fields
    //add CRLF at end of line
    WriteLn>new_file,wlnres,%CRLF%
  Until>rec=num_recs
Endif
DBClose>dbH

//if you want, delete the input file and replace with the new sorted one:
//DeleteFile>%SCRIPT_DIR%\example.csv
//RenameFile>%SCRIPT_DIR%\example_sorted.csv,%SCRIPT_DIR%\example.csv

October 30, 2009

Convert XML to CSV

Filed under: Automation,Scripting — Marcus Tettmar @ 12:27 pm

Earlier this month I wrote about how you can read and write data from/to CSV files as if they were database tables using DBQuery. Andrew asked if I knew of a way that XML files could be treated as database tables in the same way. I did find a couple of references to some ODBC drivers online but one was not yet available and the other was part of a larger commercial package so I was unable to try them.

Since then it has occurred to me that there is a way we can convert XML files to CSV (or XLS) files using Excel. Once the data is in CSV file format we can then retrieve it easily using DBQuery.

The more technically aware will probably ask why we can’t just use the MSXML.DomDocument object in VBScript to read in the XML and parse it. Well, while that is of course possible, many will find the ability to access the XML data in a tabular database-like format easier and more familiar.

So, without further ado, here’s my ConvertXMLtoCSV function:

VBSTART
Sub ConvertXMLtoCSV(xmlFile,csvFile)
    Set xlApp = CreateObject("Excel.Application")
    Set xlBook = xlApp.Workbooks.OpenXML(xmlFile,2)
    xlBook.SaveAs csvFile, 6
    xlBook.close false
    xlApp.quit
End Sub
VBEND

You will need Excel installed for this to work. Use the function like this:

VBRun>ConvertXMLtoCSV,c:\docs\my.xml,c:\docs\converted.csv

And now you can quickly read the data into an array using DBQuery.

The function works quietly in the background. You won’t see Excel open – just a short delay while the CSV file is created.

To convert to an Excel file rather than a CSV file change the code to:

VBSTART
Sub ConvertXMLtoXLS(xmlFile,xlsFile)
    Set xlApp = CreateObject("Excel.Application")
    Set xlBook = xlApp.Workbooks.OpenXML(xmlFile,2)
    xlBook.SaveAs xlsFile, 56
    xlBook.close false
    xlApp.quit
End Sub
VBEND

Please note I’m using Excel 2007 and haven’t tried this with earlier versions though I believe Excel 2003 can also read from XML files. Success may also depend on the format of your XML.

See:
Reading From CSV Files
More on Reading and Writing CSV Files
Retrieve Entire Excel Sheet Using DBQuery

August 28, 2009

Determine IE Version and Automate IE Dialogs

Filed under: Automation,Scripting — Marcus Tettmar @ 2:25 pm

If you are automating web pages or web applications you may at some point need to automate dialog boxes produced by client side script, like the one that pops up when you click the link below:

Confirm Popup

So you might want to be aware that the title of these popups varies between different versions of Internet Explorer. In IE6 it was “Microsoft Internet Explorer”. In IE7 it is “Windows Internet Explorer” and in IE8 it is now “Message from webpage”.

I much prefer the last one from an automation point of view since it differs significantly from the title of the main IE window which usually contains the phrase “Microsoft Internet Explorer” in IE7 and “Windows Internet Explorer” in IE8.

So if we wanted to click on the Yes button if we were writing a script for IE8 we could use the following code:

SetFocus>Message from webpage
Press Enter

But what if we didn’t know what version of IE our script would be automating? If you were giving your script to someone else or putting it on some other PC you may not know what version of IE was being used. What we need to do is make the script find out what version of IE is installed on the computer.

Here’s how to make the script determine which version of IE is in use:

RegistryReadKey>HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Internet Explorer,Version,IEver
Separate>IEVER,.,bits
Let>IEVER=bits_1

IEVER now contains the major version number of Internet Explorer.

So we could now use this to define the title we expect from the dialog box and confirm it:

RegistryReadKey>HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Internet Explorer,Version,IEver
Separate>IEVER,.,bits
Let>IEVER=bits_1

Let>dialogTitle_IE6=Microsoft Internet Explorer
Let>dialogTitle_IE7=Windows Internet Explorer
Let>dialogTitle_IE8=Message from webpage

SetFocus>dialogTitle_IE%IEVER%
Press Enter

Of course this is all assuming you’re using the English version of Internet Explorer. I cannot vouch for other languages.

August 25, 2009

The Power of DOS: Looping Through Subfolders

Filed under: Automation,Scripting — Marcus Tettmar @ 7:37 pm

Twice today, for two different people, I needed to write some code to iterate through files in a tree of subfolders. The subfolder structure could not be known up front and there may be any number of subfolders and any number of folders deep.

One could use GetDirList iteratively, or use VBScript’s FileSystem Object. But then I was reminded of the power of DOS by JRL in this post.

The following returns a file containing a list of the jpg files throughout all folders, starting in c:\root_folder\ with full paths:

dir c:\root_folder\*.jpg /s /b > outputfile.txt

So, as JRL suggests, we can call that command from Macro Scheduler and then read in the output file. We should use a temporary file:

Let>RP_WINDOWMODE=2
Let>RP_WAIT=1
Run>cmd /c dir c:\root_folder\*.jpg /s /b > %TEMP_DIR%~temp_dir_list~
ReadFile>%TEMP_DIR%~temp_dir_list~,dir_list

Now we can explode that list into an array and loop through it, doing whatever it is we need to do to each file:

Separate>dir_list,CRLF,files
If>files_count>0
Let>f=0
Repeat>f
  Let>f=f+1
  Let>this_file=files_%f%
  //do something with this_file
Until>f=files_count

It’s easy to forget the power of DOS – it can save you a fair few lines of code sometimes.

Remember that any DOS command can be “piped” to an output file by appending >filename to the command line. This is very useful as we can then use ReadFile to get the output from the command, as we have done above.

August 11, 2009

Find and Click on Screen Text with MODI

Filed under: Automation,Scripting — Marcus Tettmar @ 8:21 am

Gale Dyvig has just posted some code in the forums showing how to use the Microsoft Office Document Imaging OCR component to locate text on the screen, find its position and click on it. Very useful. You’ll find it here.

MODI is a component that comes with Microsoft Office. You need to ensure Microsoft Office Document Imaging and Office Shared Features / Proofing Tools is installed in Office Tools.

Thanks Gale!

July 27, 2009

Think like a user, not a programmer

Filed under: Automation — Marcus Tettmar @ 3:23 pm

I just helped out a customer who was getting increasingly frustrated trying to get a macro to select a menu. The menu shortcut key was “g” and all he was trying to do was send Alt-g to the window. But whatever he tried he couldn’t get it to work.

Being an experienced programmer who had built Windows interfaces he had assumed that ALT-g (Alt together with “g”) would work:

Press ALT
Send>g
Release ALT

But nothing happened. He added waits in all sorts of various places but no cigar.

Eventually he called me up for a BeamYourScreen session and I took a look. I went back to basics, and tried the app out manually, making no assumptions. I entered ALT-G (g together with the ALT key) and found nothing happened. I then pressed the ALT key and released it. The app focused the first “File” submenu. I then hit “g” on its own and the required menu opened. Bingo.

Turns out the app doesn’t work the way either of us expected. The shortcuts should work when sent with the ALT key held down. But that wasn’t the case. One had to press ALT, release it, then send the shortcut character on its own. So the working code was:

Press ALT
Release ALT
Send>g

The mistake here was making assumptions based on our expectations and prior knowledge. A less experienced user may actually have got it working sooner by not taking anything for granted.

The trick to automating an app is to go back to basics, break it down and actually watch what you do. If my customer had actually tried it manually and taken a closer note of what exact keystrokes he had pushed, he would have made progress faster, instead of assuming that the app worked the way any UI guru would expect, and blaming the macro when it didn’t.

Think like a user not a programmer. To automate something first try it manually, write down or remember what sequence worked then replicate that in the macro – just as I preach in the Beginner’s Guide and Getting Started Guide.

No matter how technical you might be, this getting started guide is helpful.

« Newer PostsOlder Posts »