Si vous souhaitez apprendre à écrire des scripts sous Windows, cette page s'adresse à vous. Commençons tout de suite. (Attention, cette page est encore inachevée, et le restera sans doute car les technologies présentées ici peuvent souvent être remplacées avantageusement par .Net et/ou PowerShell).
↑ Un premier script
Avec le Bloc-Note, ou votre éditeur de texte préféré, créez un fichier contenant la ligne suivante.
WScript.Echo("Hello, world!");
Enregistrez-le sous le nom hello.js
et cliquez dessus. Et voilà, vous savez afficher un message à
l'aide d'un script !
↑ Comment ça marche ?
Quand vous cliquez sur ce fichier, Windows lance la commande
wscript hello.js. Le programme
wscript.exe est un
hôte de script, qui va charger le
moteur de script approprié
(javascript) pour exécuter le fichier indiqué, et
prédéfinir quelques objets comme
WScript. Le moteur de script va lire le
fichier hello.js, et appeler la
méthode Echo de l'objet
WScript, qui affiche alors le message
indiqué.
Les hôtes de scripts qui seront discutés ici sont
wscript.exe, son analogue en ligne de
commande cscript.exe (que fait la commande
cscript //nologo hello.js ?), et
mshta.exe. Pour ce qui est des moteurs de
script, Windows connaît par défaut deux langages :
javascript (aussi appelé ECMAScript ou JScript) et
VBScript (un dérivé de Visual Basic). L'exemple
ci-dessus s'écrirait ainsi en VBScript. (Le fichier pourrait
s'appeler hello.vbs).
WScript.Echo "Hello, world!"
Il est possible d'installer des moteurs de scripts pour d'autres langages, comme Perl ou Haskell. Par préférence personnelle, j'utiliserai ici du javascript.
↑ Accéder au système de fichiers
Pour faire des choses intéressantes dans nos scripts, il
va falloir créer des objets qui permettront d'interagir avec le
système. Voici par exemple comment énumérer les
fichiers contenus dans le répertoire
C:\WINDOWS.
var fso = new ActiveXObject("Scripting.FileSystemObject");
var d = fso.GetFolder("C:\\WINDOWS");
var fc = new Enumerator(d.Files);
var str = "";
for (; ! fc.atEnd() ; fc.moveNext())
{
str += fc.item().Name + "\n";
};
WScript.Echo(str);
La première ligne est sans doute la plus importante
à retenir. Elle crée un nouvel objet
Scripting.FileSystemObject. Cet objet
est un composant
COM scriptable qui permet d'accéder au système de
fichiers. Le reste du script consiste juste à manipuler les
interfaces fournies par ce composant : d'abord en créant
un objet
Folder correspondant au répertoire
voulu, puis en énumérant les éléments de la
collection
Files.
Sur le même principe, voici un script qui extrait des informations d'un fichier texte (les adresses IP des machines dont un paquet a été rejeté par le pare-feu de Windows).
var fso = new ActiveXObject("Scripting.FileSystemObject");
var lgf = fso.OpenTextFile("C:\\WINDOWS\\pfirewall.log", 1);
var tbl = new ActiveXObject("Scripting.Dictionary");
while (! lgf.AtEndOfStream) // enumerate the lines
{
var li = lgf.ReadLine();
li = li.replace(/#.*$/, ""); // discard comments
li = li.replace(/\s+$/, "");
var t = /^\S+\s+\S+\s+DROP\s+\S+\s+(\d+(?:\.\d+){3})\s/
.exec(li);
if (t != null) // discard strange lines
tbl.Item(t[1]) = null;
};
var ips = (new VBArray(tbl.Keys())).toArray();
var str = "";
var i = ips.length;
while (i != 0)
str += ips[--i] + "\n";
WScript.Echo(str);
↑ Doter un script d'une interface
Si certains scripts sont prévus pour fonctionner en arrière-plan, d'autres ont besoin de communiquer avec l'utilisateur. Dans ce cas, il est temps de songer à en faire un script HTA.
Un script HTA se présente comme une page HTML, mais son
nom de fichier porte l'extension .hta. Du
point de vue de la sécurité, il est traité comme
un script : pas de restrictions d'accès, mais c'est un
fichier exécutable à part entière. L'hôte de
script associé est mshta.exe.
Pour modifier l'affichage, on procède comme sur une page web en utilisant le DOM ou les autres objets et méthodes fournis par Internet Explorer.
Comme exemple, voici un script HTA qui utilise WMI et du VML pour afficher la proportion de mémoire physique utilisée.
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:v="urn:schemas-microsoft-com:vml"
xml:lang="en" lang="en">
<head>
<title>Memory usage</title>
<style type="text/css">
/* <![CDATA[ */
h1 { text-align: center; margin-bottom: 100px; }
div#gr { text-align: center; }
v\:* { behavior: url(#default#VML); }
#pie {
position: static;
width: 200px; height: 200px;
}
#rcirc {
position: absolute;
left: -100; top: -100;
width: 200; height: 200;
}
#bpath {
position: absolute;
left: -100; top: -100;
width: 200; height: 200;
}
/* ]]> */
</style>
<script language="javascript" type="text/javascript">
// <![CDATA[
function set_pie(x)
{
var a = Math.ceil(100 * Math.sin(x * 2 * Math.PI));
var b = -Math.floor(100 * Math.cos(x * 2 * Math.PI));
bpath.path = "ns m 0 0 wa -100 -100 100 100 0 -100 "
+ a + " " + b + " x e";
}
var perf;
function get_mem_used()
{
perf.Refresh_();
return perf.FreePhysicalMemory / perf.TotalVisibleMemorySize;
}
function init()
{
var loc = new ActiveXObject("WbemScripting.SWbemLocator");
var wmi = loc.ConnectServer("", "root\\cimv2");
var ins = wmi.InstancesOf("Win32_OperatingSystem");
perf = (new Enumerator(ins)).item();
set_pie(get_mem_used());
window.setInterval("set_pie(get_mem_used())", 1000);
}
// ]]>
</script>
</head>
<body onload="init()">
<h1>Memory usage</h1>
<div id="gr">
<v:group id="pie" coordsize="200,200" coordorigin="-100,-100">
<v:oval id="rcirc" fillcolor="red" strokecolor="black">
</v:oval>
<v:shape id="bpath" fillcolor="blue"
path="ns m 0 0 wt -100 -100 100 100 0 -100 1 -100 x e">
</v:shape>
</v:group>
</div>
</body>
</html>
↑ Envoyer un mail
Pour envoyer un mail, la collection d'objets à
connaître est
CDO, en particulier l'objet
CDO.Message.
var msg = new ActiveXObject("CDO.Message");
msg.From = "Moi <me@mycomputer.invalid>";
msg.To = "Dave <devnull@ens.fr>";
msg.Subject = "Essai avec CDO.Message";
msg.TextBody = "J'essaie mon nouveau script.\n";
msg.Send();
Pour envoyer le mail, CDO essaie par défaut d'utiliser le serveur SMTP inclus dans IIS, quand il est installé (par exemple pour un Windows XP Pro), ou les paramètres d'Outlook Express. S'il n'arrive pas à trouver les informations requises, l'envoi échoue. Dans ce cas, il faut indiquer explicitement un serveur SMTP ou un répertoire de messages en attente d'envoi. Voici comment indiquer explicitement un serveur SMTP dans l'exemple précédent.
var cfg = new ActiveXObject("CDO.Configuration");
var flds = cfg.Fields;
flds("http://schemas.microsoft.com/cdo/configuration/sendusing")
= 2;
flds("http://schemas.microsoft.com/cdo/configuration/smtpserver")
= "nef.ens.fr";
flds.Update();
var msg = new ActiveXObject("CDO.Message");
msg.Configuration = cfg;
msg.From = "Moi <me@mycomputer.invalid>";
msg.To = "Dave <devnull@ens.fr>";
msg.Subject = "Essai avec CDO.Message";
msg.TextBody = "J'essaie mon nouveau script.\n";
msg.Send();
L'objet CDO.Message permet bien
entendu de construire des messages plus complexes, avec des pièces
jointes. La méthode est expliquée
ici.
Il est également possible d'utiliser CDO pour poster des messages sur un serveur NNTP.
CDO est aussi utilisé pour personaliser le traitement des mails par le serveur SMTP d'IIS.
↑ Se connecter à un serveur HTTP
Pour aller chercher une page web, on peut se tourner vers l'objet
WinHttp.WinHttpRequest. Ainsi, le script
suivant télécharge la page d'accueil du serveur des
élèves de l'ENS.
var req = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
req.Open("GET", "http://www.eleves.ens.fr/");
req.Send();
WScript.Echo(req.ResponseText);
WinHTTP peut aussi construire des requêtes POST, ce qui peut être utile pour un script qui doit transmettre des données volumineures à un serveur.
Les connexions en HTTPS sont aussi supportées, permettant de disposer d'une connexion sécurisée en quelques lignes de script.
↑ Microsoft Office et les scripts
Beaucoup de logiciels de la suite Microsoft Office sont écrits comme des collections de composants COM, qui peuvent être utilisés dans des scripts. C'est le cas en particulier de Word, Excel et Outlook. On peut trouver la documentation de ces objets dans le chapitre de MSDN concernant Office, ou dans l'aide des produits en question (dans la partie traitant de la programmation en Visual Basic, qui utilise les mêmes objets COM).
Voici un exemple de ce que peut faire un script pilotant Microsoft Excel.
var excel = new ActiveXObject("Excel.Application");
excel.DisplayAlerts = false;
excel.Visible = true;
var sheet = excel.Workbooks.Add().ActiveSheet;
WScript.Sleep(1000);
for (var i = 1 ; i < 30 ; i++)
sheet.Cells(i,1).Value = Math.log(i);
WScript.Sleep(1000);
var chart = excel.ActiveWorkbook.Charts.Add();
chart.ChartType = -4101;
chart.SeriesCollection.Add(sheet.Range("A1:A29"));
WScript.Sleep(5000);
excel.Quit();
Dans le cas d'Outlook, certaines limitations ont été volontairement ajoutées pour compliquer l'écriture de virus. En particulier, l'accès à certaines propriétés provoque l'affichage d'une demande de confirmation. Si l'on veut éviter cela sans revenir à de la programmation en C ou C++, une solution est d'installer le composant COM Outlook Redemption de Dmitry Streblechenko.
↑ Où trouver de la documentation ?
La documentation de référence se trouve dans
MSDN Library,
en particulier dans le chapitre sur les
technologies de scripts. Les commandes
cscript et
wscript sont décrites dans l'aide de
Windows, qui comprend un
chapitre sur les scripts.
Une grande partie de la documentation disponible dans MSDN Library peut être installée localement, et fait partie du Platform SDK. Cela permet un accès beaucoup plus confortable à ces informations.
Le site des MVPs a quelques pages sur les scripts, comme celle d'Alex Angelopoulos. On trouve aussi des articles intéressants sur le TechNet, comme les Tales from the Script.