Programmeren met Visual Basic Script
- Introductie
- Scripts uitvoeren
- Uitvoer produceren
- Invoeren van gegevens
- Variabelen en constanten
- Objecten, classes, properties en methods
- Loops (in relatie tot arrays en collections)
- Het if-statement
- Het case-select-statement
- Subroutines, functions en bibliotheekbestanden
- Standaardfuncties
- Dictionaries (woordenboeken)
- Programma's starten vanuit een script
- Tekstbestanden
- Bestanden en mappen
- Bestanden en mappen via WMI
- Register
- Gebruik maken van voorgedefinieerde informatie (zoals WMI)
- Foutzoeken en fouten voorkomen
- Links
Introductie
Deze pagina is niet bedoeld als programmeercursus, maar meer als handige referentie voor wat wel kan, wat niet kan, welke technieken je kan gebruiken, waar je op moet letten, tegen welke problemen je aan kan lopen, etc.
Ik ga echter (voorlopig in elk geval) niet uitleggen wat variabelen en constanten zijn, en waarom je in het ene geval beter een constante kan gebruiken en in het andere niet.
Scripts uitvoeren
Zet je script in een bestand met extensie .VBS
Voer het script uit vanuit de
grafische interface (bv. Verkenner (Explorer)
)
door er bv. op te dubbelklikken, of vanaf
de commandoregel.
Dat laatste doe je via het commando
cscript scriptnaam.vbs
Je kan ook parameters meegeven aan je script, en die vanuit het script benaderen.
Als je het script bv. aanroept met
cscript dinner.vbs 2
dan kan je in het script met
Choice = Wscript.Arguments.Item(0)
de waarde van de 1e parameter (2) in de variabele
Choice
krijgen.
Script hosts
cscript
is een zgn. script host.
Het kan scripts interpreteren en uitvoeren.
In de Windows Script Host (WSH) omgeving is er ook nog een andere script host:
Wscript
De .VBS
-extensie is standaard gekoppeld aan
Wscript
, en als je dus in Verkenner
op zo'n bestand dubbelklikt wordt automatisch
Wscript
uitgevoerd.
Datzelfde gebeurt als je op de commandoregel 'cscript' zou weglaten, en
bv. alleen test.vbs
intikt.
Ook dan wordt Wscript
ingeschakeld.
Je kan de standaard script host veranderen met
cscript //H:cscript
of
wscript //H:wscript
Verschil tussen Cscript en Wscript
In principe zijn de verschillen niet groot, behalve dat
Cscript
de commandoregel-versie is, en Wscript
de grafische.
Maar dat maakt alleen verschil als je het Wscript.Echo
commando gebruikt.
Als Cscript
dan je standaard script host is, en je
voert het script vanuit Verkenner
uit, dan gaat je
uitvoer naar het commandoregel venster, dat na afloop van het script ook weer
verdwenen is.
Als je het MsgBox
-commando gebruikt voor uitvoer,
dan maakt het niet uit welke script host je gebruikt.
Opties en help-informatie
Met de commando's cscript /?
en
wscript /?
krijg je help-informatie.
//NOLOGO
Normaal gesproken krijg je aan het begin van het script informatie over de versie van WSH e.d. (kortom, een soort logo).
Als je dat niet wilt kan je het commando als volgt geven:
C:\> cscript test.vbs //nologo
//B
De B staat voor Batch mode.
Het gevolg is dat je geen enkele uitvoer meer krijgt: geen logo, geen normale uitvoer en geen foutinformatie.
Er zijn situaties waarin dat handig kan zijn (bv. als je scripts maakt voor leken, en je wilt niet dat ze rare dingen voorbij zien komen).
//T
Soms schrijf je wel eens scripts die in een eindeloze loop terecht komen.
Om dat te vermijden geef je een commando als
cscript test.vbs //T:5
Het script houdt dan na 5 seconden gegarandeerd op.
Scripts stoppen
Naast de manier met de //T-optie kan je een script dat
gestart is met cscript
ook makkelijk stoppen met
Ctrl+C
Scripts die gestart zijn met Wscript
kan je alleen
stoppen met bv. Task
Manager
En er is ook een commando om een script van binnenuit te stoppen:
Wscript.Quit
Uitvoer
Met het commando WScript.Echo
kan je uitvoer
produceren.
Dingen die je tussen dubbele quotes zet worden ongewijzigd afgedrukt,
op getallen wordt de geëigende bewerking losgelaten, en je kan zelfs
functies (zoals Now
) meegeven.
In dat laatste geval wordt de datum afgedrukt.
Uitvoer verschijnt in een dialoogvenster als je een script vanuit de
grafische interface uitvoert (met
WScript
).
Het nadeel daarvan kan zijn dat je voor elke regel uitvoer op
OK
moet klikken voor het script verder gaat.
Vanaf de commandoregel komt alle uitvoer gewoon achter
elkaar te staan (als je cscript
gebruikt).
Het volgende script
Wscript.Echo "Line One"
Wscript.Echo 100
Wscript.Echo 100 + 100
Wscript.Echo "100 + 100"
Wscript.Echo Now
Wscript.Echo "Now"
produceert de volgende output:
Line One
100
200
100 + 100
28-5-2013 23:44:33
Now
Meer mogelijkheden voor een message box
Naast het Echo
-commando is er ook een functie
Msgbox
Daarmee kan je bv. ook de titel van je dialoogvenster veranderen, en
verschillende knoppen (OK
,
Cancel
, etc.) toevoegen.
Voorbeeld:
strMessage = "Here is my message."
Msgbox strMessage, 0, "This is my message box"
De 1e parameter is de boodschap die in het venster vertoond wordt, met de 2e kan je de knoppen opgeven (afhankelijk van het getal wat er staat) en met de 3e verander je de titel van het dialoogvenster.
Invoeren van gegevens
InputBox
Een eenvoudige manier om 1 regel tekst in te voeren is de functie
InputBox
Voorbeeld: strMessage = InputBox("Voer tekst in: ")
Nadat de gebruiker iets heeft ingevoerd, en op Enter
heeft gedrukt, zit de tekst in StrMessage
Variabelen en constanten
Variabelen
Variabelen hoef je niet te declareren.
Je kan dus gewoon zeggen:
i = 1
name = "Henk"
j = 3 + 5
Naamgeving
Het is wel handig om variabelen duidelijke (Hongaarse) namen te geven, d.w.z. dat het type vooraf gaat aan de eigenlijke naam.
Voorbeelden:
strName = "Henk"
intNumber = 3
arrArray(5) = "Mei"
dtToday
objOS ' obj = object
colDrives ' col = collection
Lokale en globale variabelen
Met het DIM
-statement maak je een variabele geldig
op dat niveau.
Dat betekent dat als je DIM
gebruikt om een variabele
op het hoogste niveau te declareren, maar daarna dezelfde naam ook declareert
binnen een subroutine, de waarde van binnen de subroutine weer verdwenen is
als hij is afgelopen.
Het volgende script levert 13 op:
Dim a
a = 4
b = 9
ChangeA
Wscript.Echo a + b
Sub ChangeA
Dim a
a = 10
End Sub
Variabelen die alleen in een subroutine gebruikt worden (met of zonder
DIM
) bestaan niet meer als de subroutine is afgelopen.
Het volgende script levert dus 9 op:
b = 9
ChangeA
Wscript.Echo a + b
Sub ChangeA
a = 10
End Sub
Constanten
Constanten moet je wel declareren, en zijn daarna niet meer van waarde te veranderen (redelijk logisch, gezien de naam). Dat doe je als volgt:
Const i = 2 * 7
Predefined constanten
Een flink aantal constanten zijn al standaard door VBScript gedefiniëerd.
Die beginnen allemaal met 'vb', dus bv. vbOKCancel
.
Objecten, classes, properties en methods
Objecten aanmaken
Je hebt classes voor bv. processen of services.
Voor elke class kan je nieuwe objecten aanmaken, en je hebt daarvoor het
Set
-statement nodig.
Het gebruik maken van een bestaande class, bv. in WMI
,
Active Directory
,
of ADO
, heet binding,
connecting, of instantiation.
Het object is een instance van de class.
CreateObject
Als je een nieuw object wilt aanmaken gebruik je normaal gesproken
CreateObject
Voorbeeld:
Set objExcel = CreateObject("Excel.Application")
GetObject
Je gebruikt GetObject
om een referentie te krijgen
naar een object dat al bestaat.
Je gebruikt het dus bv. om WMI
te benaderen.
Het grote verschil is dat Excel
normaal niet per
definitie draait, maar WMI
wel.
Dat betekent dat WMI
-objecten altijd beschikbaar
zijn als de computer aanstaat.
En je gebruikt de volgende rare regel om die objecten te kunnen benaderen:
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
'winmgmts' is een soort bijnaam voor het SWbemServices
object.
De '.' staat voor de computer waarop je werkt.
En 'root\cimv2' is de namespace in WMI die je wilt gebruiken.
Nu je een referentie naar de WMI
service hebt, kan je
methodes gebruiken om verdere objecten te benaderen: de method
Get
of de method ExecQuery
De 1e is meer om 1 specifiek object te krijgen, en de 2e om een verzameling objecten te krijgen, gebaseerd op allerlei criteria.
Een object opruimen
Je kan een object als volgt vrijgeven:
Set objReference = Nothing
Maar doorgaans is het niet nodig, want het gebeurt automatisch aan het eind van het script.
Methods
Een method is een soort functie/subroutine die deel uitmaakt van een class.
Als je een method aanroept zonder het resultaat op te vragen kan je geen haakjes om de parameters zetten.
Loops (in relatie tot arrays en collections)
Collections
Collections zijn verzamelingen van 0, 1 of meer dingen van hetzelfde type.
Je kan collections geen waarde geven, alleen de inhoud ervan opvragen.
Voorbeeld:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDrives = objFSO.Drives
De verzameling colDrives
is nu
een object met de namen van alle disks op je PC.
Arrays
Je kan arrays op 2 manieren vullen: door waarden aan de elementen toe te kennen,
alsof elk element een variabele is, of
door de Array
-method
te gebruiken.
In het 1e geval moet je arrays declareren als volgt:
Dim arrArray(aantal)
In dit geval heb je een array gekregen van aantal+1 elementen, omdat het 1e element index 0 heeft.
De reden voor het declareren met Dim is dat VBScript dan weet dat het om een array gaat. Methods worden nl. ook aangeroepen met ronde haakjes om de parameters.
Als je op het moment van declaratie van de array nog niet weet hoeveel elementen
er in zullen komen geef je gewoon geen aantal op.
Zodra je het wel weet gebruik je een
ReDim
statement.
Array method
In dit geval heb je geen Dim
-statement nodig,
omdat VBScript nu automatisch weet dat het om een array gaat.
Voorbeeld (compleet script):
arrArray = Array("H","e","n","k")
Wscript.Echo arrArray(0) & arrArray(1) & arrArray(2) & arrArray(3)
Loops
Er komen 2 soort loops aan de orde: For Each ... Next
en For Next
Verder een manier om loops voortijdig te beëindigen.
For Each ... Next
We willen nu iets doen met elke disk op onze PC. We hadden al een verzameling met alle disks.
For Each objDrive in colDrives
' do something
Next
De naam objDrive
is een vrije keuze.
Een compleet voorbeeld (probeer maar op je PC):
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDrives = objFSO.Drives
For Each objDrive in colDrives
Wscript.Echo "Drive letter: " & objDrive.DriveLetter
Next
Wscript.Echo "Done"
In mijn geval is de uitvoer (de laatste 2 zijn resp. de DVD-speler en een USB-stick):
Drive letter: C
Drive letter: D
Drive letter: E
Drive letter: G
Done
For Next
Deze vorm wordt meer gebruikt voor arrays (maar je kan
For Each
ook gebruiken voor
arrays).
Een voorbeeld (ook dit is een compleet script):
Dim arrCount()
size = 3
ReDim arrCount(size)
For i = 0 to size
arrCount(i) = i
Wscript.Echo arrCount(i)
Next
Wscript.Echo "Done "
i
is een door jezelf te kiezen variabele, en de
begin- en eindwaarde (in dit geval 0
en
size
kan je ook zelf kiezen).
Ze moeten natuurlijk wel binnen de grenzen van de array vallen.
De uitvoer is dan:
0
1
2
3
Done
In dit script ging je met stappen van 1 omhoog (dus alle elementen bij langs). Je kan met een kleine toevoeging ook grotere stappen vooruit of zelfs achteruit maken (zoals in onderstaand voorbeeld):
Dim arrCount()
size = 3
ReDim arrCount(size)
For i = size to 0 Step -1
arrCount(i) = i
Wscript.Echo arrCount(i)
Next
Wscript.Echo "Done "
Voortijdig de loop verlaten
Dat doe je met het statement
Exit For
Het IF-statement
Om te beginnen een voorbeeld, omdat dat de zaken al aardig duidelijk maakt:
A = 5
B = 10
If A > B Then
Wscript.Echo "A is greater than B"
ElseIf A = B Then
Wscript.Echo "A is equal to B"
Else
Wscript.Echo "A is less than B"
End If
De ElseIf
- en Else
-takken
zijn (vanzelfsprekend) niet verplicht.
Verder kan je in elk van de 3 situaties meer dan 1 commando geven.
Het case-select-statement
Een voorbeeldscript:
Choice = 1
Select Case Choice
Case 2
Wscript.Echo "Eten bestellen"
Case 3
Wscript.Echo "Koken"
Case 1
Wscript.Echo "Buitenshuis eten"
Case Else
Wscript.Echo "Niet eten"
End Select
Je hebt een variabele met een bepaalde waarde (in dit geval
Choice
), en vervolgens ga je in een aantal takken
testen wat voor waarde die variabele heeft.
Bij verschillende waardes kan je verschillende acties ondernemen.
De Case Else
-tak moet altijd als laatste staan.
De acties die erachter staan worden uitgevoerd als de variabele geen van de
andere waardes heeft.
Je mag deze tak ook helemaal weglaten.
Dan gebeurt er gewoon niets als de variabele een andere waarde heeft.
Subroutines, functions en bibliotheekbestanden
Subroutines
Parameters worden in VBScript default by reference (
ByRef
) doorgegeven.
Als je ze by value wilt doorgeven moet je ByVal
gebruiken.
Een voorbeeldscript van by reference:
x = 7
Wscript.Echo "Before subroutine call x = " & x
TestSub x
Wscript.Echo "After subroutine call x = " & x
Sub TestSub(a)
Wscript.Echo "In subroutine, original value of a = " & a
a = 10
Wscript.Echo "In subroutine, changed value of a = " & a
End Sub
De uitvoer van dit script is:
Before subroutine call x = 7
In subroutine, original value of a = 7
In subroutine, changed value of a = 10
After subroutine call x = 10
Als je de 1e regel van de subroutine verandert in
Sub TestSub(ByVal a)
krijg je de volgende uitvoer:
Before subroutine call x = 7
In subroutine, original value of a = 7
In subroutine, changed value of a = 10
After subroutine call x = 7
Functions
Het idee is hetzelfde als subroutines, alleen heeft een functie een resultaat. In de functie geef je een waarde aan dat resultaat door hem toe te kennen aan de naam van de functie (alsof het een variabele was):
x = 4
y = TestFunc(x)
Wscript.Echo y
Function TestFunc(a)
Wscript.Echo a
TestFunc = a + 2
End Function
Uitvoer is:
4
6
Bibliotheekbestanden
We willen procedures en functies graag kunnen delen tussen verschillende scripts, en dat kan op de volgende manier:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("procedures.txt", ForReading)
Execute objFile.ReadAll()
De naam procedures.txt
is willekeurig (extensie maakt
ook niet uit), en bevat een verzameling subroutines en functions.
Het Execute
-statement leest het bestand, zet alles
in het geheugen, en daarna kunnen de subroutines e.d. door andere scripts
worden aangeroepen.
Onderstaand een beetje een ingewikkeld voorbeeld van een script dat van een subroutine in zo'n bibliotheek gebruik maakt:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colFiles = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_Directory.Name='C:\Scripts'} Where " _
& "ResultClass = CIM_DataFile")
For Each objFile in colFiles
If objFile.Extension = "txt" Then
Wscript.Echo objFile.Name
strText = strText & ReadFile(objFile) & vbCrLf
End If
Next
Wscript.Echo strText
En dit is de bijbehorende bibliotheek-file:
Function ReadFile(oFile)
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
(oFile.Name, ForReading)
ReadFile = objTextFile.ReadLine
objTextFile.Close
End Function
Standaardfuncties
Getallen
IsNumeric
Soms is het belangrijk om te weten of een variabele een getal bevat:
a = 5
b = "A"
If IsNumeric(a) And IsNumeric(b) Then
c = a + b
Wscript.Echo c
Else
Wscript.Echo "Beide waardes moeten numeriek zijn. a = " & a & " and b = " & b
End If
FormatNumber
Deze functie heeft 5 parameters:
- Number
Het getal dat je wilt formatteren. - NumberOfDigits
Het aantal cijfers dat er achter de komma moet komen. - LeadingZeroes
Als deze parameter -1 is, dan betekent het dat er een 0 voor de komma komt te staan. Het getal zou dus bv. 0,13 zijn en niet ,13.
Een waarde van 0 betekent dat er geen 0 voor de komma komt.
Een waarde van -2 tenslotte betekent dat de instellingen op de computer leidend zijn. - NegativesInParens
Als deze parameter -1 is, dan betekent het dat bv. -4 wordt weergegeven als (4).
Een waarde van 0 betekent dat er geen haakjes worden gebruikt.
Een waarde van -2 tenslotte betekent dat de instellingen op de computer leidend zijn. - GroupDigits
Als deze parameter -1 is, dan betekent het dat duizendtallen worden gegroepeerd m.b.v. de waarde die op je computer is gedefinieerd. 5000000 zou dus kunnen worden weergegeven als 5.000.000 of als 5,000,000 (laatste is meer Amerikaans).
Een waarde van 0 betekent dat je geen groepering wilt.
Een waarde van -2 tenslotte betekent dat de instellingen op de computer leidend zijn.
Alleen de 1e parameter is verplicht. Als je de andere weglaat worden de instellingen van de computer gebruikt.
Een voorbeeld:
a = 2.5793
b = "400"
c = FormatNumber(a, 2)
d = FormatNumber(b, 4)
Wscript.Echo c
Wscript.Echo d
Dit zou de volgende uitvoer opleveren:
2.58
400.0000
Int
Deze functie levert je het gedeelte van het getal voor de komma, dus
bv. Int(6,3)
levert de waarde 6 op.
Rnd en Randomize
Rnd
produceert een random getal tussen 0 en 1.
Voordat je Rnd
gebruikt moet je altijd eerst een
keer Randomize
aanroepen.
De systeemtijd wordt dan gebruikt als basis voor een willekeurige waarde.
Dus, als je een random getal tussen 1 en 100 wilt produceren, doe je:
upper = 100
lower = 1
Randomize
For i = 1 to 5
a = Int((upper - lower + 1) * Rnd + lower)
Wscript.Echo a
Next
Conversie
CInt
Doet hetzelfde als Int
, maar rond ook af naar de
dichtstbijzijnde gehele waarde.
CInt(5,7)
levert dus 6 op.
Hex
Zet een getal om in een hexadecimaal getal.
Je kan aan VBScript aangeven dat een getal hexadecimaal is door er '&H' voor te zetten. Dus 25 = &H19
Asc
Geeft je de numerieke waarde van een ASCII-teken.
letter = "B"
Wscript.Echo Asc(letter)
geeft als uitvoer 66
CDate
Deze method zet een datum in string-formaat om in een echt datum-formaat.
Strings
Je hebt een aantal handige functies die met strings kunnen werken.
Right
De 1e is string Right(string, integer)
Voorbeeld:
str = "voetbal"
intCharacters = 3
strNew = Right(str, intCharacters)
Wscript.Echo strNew
Als het goed is zal er "bal" afgedrukt worden, omdat de teller begint bij 1.
Je had ook in 1 keer het volgende kunnen doen, met hetzelfde resultaat:
Wscript.Echo Right("voetbal", 3)
Left
Het principe is hetzelfde. De volgende code
str = "voetbal"
intCharacters = 4
strNew = Left(str, intCharacters)
Wscript.Echo strNew
levert "voet" op.
Mid
De definitie van deze functie is
string Mid(string, integer [, integer])
De 2e parameter is nu de beginpositie, en de 3e het aantal tekens dat je wilt hebben.
De volgende functie-aanroep
Wscript.Echo Mid("voetbal", 3, 4)
levert "etba" op.
Als je de laatste parameter weglaat krijg je alles vanaf de beginpositie. In het bovenstaande voorbeeld zou dat "etbal" zijn.
Voorbeeld met Left, Right en Mid
Het volgende script pakt een datum in het formaat 'mmddyyyy', en zet hem in het formaat 'mm/dd/yyyy':
strDate = "08112006"
intDayMonthCharacters = 2
intYearCharacters = 4
intStart = 3
strNew = Left(strDate, intDayMonthCharacters)
strNew = strNew & "/"
strNew = strNew & Mid(strDate, intStart, intDayMonthCharacters)
strNew = strNew & "/"
strNew = strNew & Right(strDate, intYearCharacters)
Wscript.Echo strNew
Lengte van een string
Met de functie integer Len(string)
kom je de lengte van een string te weten.
String naar uppercase omzetten
Met de functie UCase
kan je een string naar
uppercase omzetten.
Dus bv.:
Wscript.Echo UCase(strMessage)
drukt de string in strMessage
in uppercase af.
Datums en tijden
Date en Now
De method Date
geeft je de datum, in het formaat
zoals dat in je regionale instellingen staat.
De method Now
geeft datum en tijd.
DateAdd
Met de method DateAdd
kan je vooruit of achteruit
gaan in de tijd, door bv. het aantal jaren te verhogen, het aantal maanden
te verlagen, etc.
Een voorbeeld:
dt = DateAdd("m", 2, today)
Wscript.Echo "Twee maanden na vandaag: " & dt
'm' staat voor maand (month), en staat tussen dubbele quotes omdat het anders zou worden opgevat als een variabele.
I.p.v. 'm' kan je ook gebruik maken van bv. 'yyyy' (jaar), 'q' (kwartaal), 'h' (uur), 'n' (minuten) en 's' (seconden).
DateDiff
Net als bij DateAdd
is de 1e parameter de tijdseenheid, zoals dagen of maanden.
De 2e parameter is de 1e datum, en 3e parameter de 2e datum.
Het verschil in tijd tussen beide tijden wordt berekend.
Een voorbeeld:
Wscript.Echo "Days left in the year: " & DateDiff("d", today, #1/1/2014#)
Er van uitgaande dat het nu 2013 is, berekent deze method het resterende aantal
dagen van dit jaar, nl. tussen vandaag (today
) en
1-1-2014.
Om aan te geven dat de 3e parameter een echte datum is, moet je hem tussen hekjes zetten.
Day, Year en Month
Deze 3 methods doen wat je van ze verwacht: ze geven de dag (nummer), het jaar en de maand (nummer) van een datum weer.
Het is vandaag 27-8-2013, dus Month(today)
zou als
uitkomst 8 hebben.
Weekday en WeekdayName
Deze method levert het nummer van de dag in de week, waarbij de nummering begint bij zondag, met 1.
Dus als vandaag vrijdag is, en je voert
Weekday(today)
uit, dan is het resultaat 6.
Als je de dag van de week wilt weten in letters, dan gebruik je
WeekdayName
.
Zie bv. het volgende script:
dy = Weekday(today)
Wscript.Echo "Day of the week, readable: " & WeekdayName(dy)
WMI datums
UTC datumformaat
WMI slaat de datums in UTC formaat op.
Dus als je bv. de datum wilt weten waarop het OS geinstalleerd is zou je
als resultaat
20130731185109.000000+120
kunnen krijgen.
Eerst zie je jaar, maand, dag, dan de tijd (de 6 tekens voor en na de punt) en tenslotte de offset t.o.v. GMT.
Er bestaan kant-en-klare functies om dit rare formaat om te zetten naar een normale datum en tijd.
Dictionaries (woordenboeken)
Index en item
Arrays bestaan uit series van gelijksoortige dingen, die je kan benaderen met een index (getal).
Bij dictionaries heb je ook een index, alleen kan dat van alles zijn (bv. namen van personen). De index noem je de key, de waarde die erbij hoort het item. De index moet uniek zijn, en is case-sensitive (d.w.z. "Henk" is niet hetzelfde als "HENK").
Het dictionary object
Om überhaupt iets met dictionaries te kunnen doen moet je een dictionary
object aanmaken, m.b.v. een regel als deze (de naam voor het '='-teken is vrij):
Set objDictionary = CreateObject("Scripting.Dictionary")
Wijzigingen aanbrengen in de dictionary
M.b.v. de method Add
kan je key-item paren aan
de dictionary toevoegen.
Voorbeeld
Hieronder een goed voorbeeld van hoe je een dictionary kunt gebruiken, bv. om alle gestopte services op het systeem af te drukken.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colServices = objWMIService.ExecQuery _
("Select * from Win32_Service")
Set objDictionary = CreateObject("Scripting.Dictionary")
For Each objService in colServices
objDictionary.Add objService.Name, objService.State
Next
colKeys = objDictionary.Keys
For Each strKey in colKeys
If objDictionary.Item(strKey) = "Stopped" Then
Wscript.Echo strKey
End If
Next
Eerst maak je een verzameling services (colServices
),
dan voeg je de Name
en State
als keys en items aan de dictionary toe.
Tenslotte zet je alle keys in de verzameling colKeys
,
en druk je alleen de servicenamen af van de services die gestopt zijn.
Testen of een key al bestaat
Als je niet-unieke keys toevoegt krijg je een foutmelding en crasht je script.
Je kan met de method Exists
ook van tevoren testen:
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.Add "Key1", "Item"
objDictionary.Add "Key2", "Item"
If objDictionary.Exists("Key1") Then
Wscript.Echo "Key1 exists"
Else
Wscript.Echo "Adding Key1"
objDictionary.Add "Key1", "Item"
End If
Dit script geeft keurig een melding, omdat Key1
al bestond.
Case sensitive
Een dictionary object heeft een property CompareMode
De waarde 1 is bedoeld voor texts (case insensitive), de waarde 0 voor binaire vergelijkingen (case sensitive).
Programma's starten vanuit een script
Met objShell.Run
Gewone grafische programma's kan je starten met een script als het volgende:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
Om een commandoregel programma uit te voeren moet je een andere truc uithalen:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ping 127.0.0.1"
Als je als 2e regel alleen dit zou doen:
objShell.Run "ping 127.0.0.1"
zou het commando wel uitgevoerd worden, maar buiten de commandoregel om.
(En je zou geen uitvoer te zien krijgen.)
(Terzijde: Soms krijg je trouwens een foutmelding als je op bovenstaande
manier een commando, bv. het dir
-commando uitvoert:
I:\test.vbs(2, 1) (null): The system cannot find the file
specified.
De verklaring is dat commando's als dir
zitten
ingebakken in de commandoregel-verwerker, tegenwoordig meestal het programma
CMD.EXE
Er bestaat dus werkelijk geen bestand DIR.EXE
op
het systeem.)
Vandaar de omgevingsvariabele %COMSPEC%
, die een
commandoregel-venster opent (door op de meeste systemen
C:\Windows\system32\cmd.exe
aan te roepen).
Maar dat zou nog niet voldoende zijn, omdat het commandoregel venster standaard
ook na afloop automatisch zou sluiten als het op deze manier wordt aangeroepen.
Daarom geef je de K
-optie mee.
Het zou kunnen zijn dat dit script niet werkt onder Windows 7 als je bv.
ipconfig
wil starten, waarschijnlijk omdat je dan meer
privileges nodig hebt.
Maar vanaf een elevated commandoregel draait het bij mij prima.
Parameters van de Run method
De 2e parameter van de Run method heeft betrekking op het type venster dat geopend wordt (bv. gemaximaliseerd).
De 3e parameter is standaard False
, en betekent dat
het script onmiddellijk doorgaat met het volgende commando.
Als je dus wilt dat het ene commando wacht op het volgende, moet je zoiets doen:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ping 127.0.0.1",,True
objShell.Run "%COMSPEC% /k nslookup 127.0.0.1"
Je krijgt een venster met de uitvoer van het
ping
-commando, en daarna gebeurt er niets meer.
Want de commandoregel die erbij hoort is nog steeds actief.
Zodra je die beëindigt wordt een nieuw commandoregel-venster met
nslookup
gestart.
Resultaat van de Run method
Deze method geeft een status code terug, en die kan je opvragen. Je moet dan wel de parameters tussen haakjes zetten. Dus:
Set objShell = CreateObject("WScript.Shell")
iErrorCode = objShell.Run("ping 127.0.0.1",,True)
WScript.Echo iErrorCode
Met objShell.Exec
Deze method is handig voor commandoregel programma's, zoals
ipconfig
.
Het resultaat van objShell.Exec
is nl. een
WshScriptExec
-object, dat status- en foutinformatie
bevat.
Maar via het object kan je ook toegang krijgen tot
STDOUT
, de "stream" waar de uitvoer van het
programma heengeschreven wordt.
Het werkt als volgt:
Set objShell = CreateObject("Wscript.Shell")
Set objWshScriptExec = objShell.Exec("ipconfig.exe")
WScript.Echo objWshScriptExec.StdOut.ReadAll
Afhankelijke van de scripting host die je gebruikt komt de uitvoer op het scherm of in een dialoogvenster.
Het gebruik van speciale tekens in het commando
Het volgende script levert een fout:
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "notepad.exe "c:\my scripts\logfile.txt""
Na de 2e dubbele quote denkt WSH dat het commando is afgelopen.
In Windows 7 kan je de binnenste dubbele quotes vervangen door dubbele dubbele quotes, dus:
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "notepad.exe ""c:\my scripts\logfile.txt"""
Maar er is nog een truc.
Met de standdaardfunctie Chr
kan je een code omzetten
in een speciaal teken.
Op die manier wordt bovenstaand script:
strArgument = "notepad.exe " & chr(34) & _
"c:\my scripts\logfile.txt" & chr(34)
Wscript.Echo strArgument
chr(34)
is gelijk aan de dubbele quote, en met de
&
worden de strings aan elkaar geknoopt.
Programma's op andere machines starten
Dat kan met het WshController
-object, maar het
werkt nogal moeizaam.
Je kan beter WMI gebruiken.
WMI Create
De WMI
-klasse Win32_Process
heeft een method Create
, waarmee je programma's
(grafisch en commandoregel) lokaal en remote kunt uitvoeren, en die als
resultaat het proces ID(entificatie) teruggeeft.
Voorbeeeld:
strCommand = "notepad.exe"
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
intReturn = objProcess.Create _
(strCommand, Null, Null, intProcessID)
De Create
-method heeft 4 parameters:
- Een string met het programma dat je wilt uitvoeren en de bijbehorende parameters;
- Het pad voor het proces dat gestart moet worden;
- Een object van het type
Win32_ProcessStartup
, dat de start-configuratie voor het proces bevat; - Het process ID van het proces dat gestart wordt. Dit is de enige parameter die je niet zelf invoert, maar die je als resultaat terugkrijgt.
Om een proces op een remote computer te starten gebruik je bv. de volgende code:
strComputer = "server1"
strCommand = "notepad.exe"
Set objProcess = GetObject("winmgmts:\\" & strComputer & _
"\root\cimv2:Win32_Process")
intReturn = objProcess.Create _
(strCommand, Null, Null, intProcessID)
Win32_ProcessStartup
De class Win32_ProcessStartup heeft 14 properties, bv. de prioriteit waarop het proces moet lopen en het type venster.
Om redenen die ik nog niet helemaal doorgrond moet je na het aanmaken van
een object van deze class nog een object aanmaken (in deze regel:
Set objConfig = objStartup.SpawnInstance_
), en pas
daarna kan je er de eigenschappen aan toekennen.
In dit geval willen we kladblok (notepad)
starten
in een normaal venster (NORMAL_WINDOW
) en aan het
eind ook nog het resultaat (intReturn
) testen.
Als alles goed is gegaan is de waarde 0.
Const NORMAL_WINDOW = 1
strComputer = "."
strCommand = "notepad.exe"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = NORMAL_WINDOW
Set objProcess = objWMIService.Get("Win32_Process")
intReturn = objProcess.Create _
(strCommand, Null, objConfig, intProcessID)
If intReturn = 0 Then
Wscript.Echo "Process Created." & _
vbCrLf & "Command line: " & strCommand & _
vbCrLf & "Process ID: " & intProcessID
Else
Wscript.Echo "Process could not be created." & _
vbCrLf & "Command line: " & strCommand & _
vbCrLf & "Return value: " & intReturn
End If
Je kan er ook een loop van maken, als volgt:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitorProcess = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent " _
& " Within 1 WHERE TargetInstance ISA 'Win32_Process'")
WScript.Echo "Waiting for process to start or stop ..."
Do
Set objLatestEvent = colMonitorProcess.NextEvent
WScript.Echo VbCrLf & objLatestEvent.Path_.Class
Wscript.Echo "Process Name: " & objLatestEvent.TargetInstance.Name
Wscript.Echo "Process ID: " & objLatestEvent.TargetInstance.ProcessId
WScript.Echo "Time: " & Now
Loop
Dan krijg je dit soort output (en het gaat eindeloos door tot je
Ctrl+C
indrukt):
__InstanceModificationEvent
Process Name: csrss.exe
Process ID: 624
Time: 3-12-2013 15:08:23
__InstanceModificationEvent
Process Name: iexplore.exe
Process ID: 7280
Time: 3-12-2013 15:08:23
__InstanceModificationEvent
Process Name: FlashPlayerPlugin_11_9_900_117.exe
Process ID: 7376
Time: 3-12-2013 15:08:23
__InstanceModificationEvent
Process Name: plugin-container.exe
Process ID: 7456
Time: 3-12-2013 15:08:23
__InstanceModificationEvent
Process Name: svchost.exe
Process ID: 752
Time: 3-12-2013 15:08:23
Als je alleen wilt selecteren op het starten en stoppen van processen doe je:
If objLatestEvent.Path_.Class = "__InstanceCreationEvent" _
Or objLatestEvent.Path_.Class = "__InstanceDeletionEvent" Then
WScript.Echo VbCrLf & objLatestEvent.Path_.Class
Wscript.Echo "Process Name: " & objLatestEvent.TargetInstance.Name
Wscript.Echo "Process ID: " & _
objLatestEvent.TargetInstance.ProcessId
WScript.Echo "Time: " & Now
End If
WMI heeft nog 3 classes die te maken hebben met proces events:
Win32_ProcessTrace
,
Win32_ProcessStartTrace
en
Win32_ProcessStopTrace
Voorbeeldscript:
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessStopTrace = objWMIService.ExecNotificationQuery _
("SELECT * FROM Win32_ProcessStopTrace")
WScript.Echo "Waiting for process to stop ..."
Do
Set objLatestEvent = colProcessStopTrace.NextEvent
WScript.Echo
Wscript.Echo "Process Name: " & objLatestEvent.ProcessName
Wscript.Echo "Process ID: " & objLatestEvent.ProcessId
Wscript.Echo "Time: " & objLatestEvent.TIME_CREATED
'Property exists only on Windows Server 2003.
Wscript.Echo "Exit Code: " & objLatestEvent.ExitStatus
Loop
De tijd die je terugkrijgt is van het type uint64
en
de inhoud is het aantal 100 nano-seconde-intervallen sinds 1 januari 1601.
Niet zo handig, dus.
Sinds Server 2003 levert de WMI scripting API een nieuw object,
SWbemDateTime
, dat functionaliteit heeft om met 3
datum/tijd-formaten om te gaan: DATETIME
(de
bovenstaande uitvoer), FILETIME
, en een
voor mensen iets aangenamer formaat, VT_DATE
Tekstbestanden
Om met files te kunnen werken maak je gebruik van het voorgedefinieerde
FileSystemObject
Een (nieuw) bestand aanmaken
Zo maak je bv. een bestand aan:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("C:\Scripts\FreeSpace.log")
De extensie van het bestand maakt niet uit, maar het wordt als een tekstbestand
behandeld.
CreateTextFile
is 1 van de methods van het file
system object.
Als je niet wilt dat een al bestaande file wordt overschreven, moet je
het statement als volgt veranderen:
Set objFile = objFSO.CreateTextFile("C:\Scripts\FreeSpace.log", False)
Je kan ook (bv.) elke dag een nieuwe file aanmaken, en de datum in de filenaam opnemen:
dt = Date
dt = Replace(dt,"/","-")
strFileName = "C:\Scripts\" & dt & "-FreeSpace.log"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile(strFileName)
In de 2e regel gebruik je de Replace
method om
voor de zekerheid (hangt af van je regionale instellingen) evt. '/' in de
datum te vervangen door hyphens ('-').
Een bestand sluiten
Eenvoudiger is bijna niet mogelijk:
objFile.Close
Schrijven naar een bestand
Dat doe je met het statement:
objFile.WriteLine (wat_je_wilt_schrijven)
Een voorbeeldscript, waarin je de vrije ruimte en de totale ruimte op disk
C
opvraagt en naar een bestand schrijft:
strComputer = "."
dt = Replace(Date,"/","-")
strFileName = "C:\Scripts\" & dt & "-FreeSpace.log"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile(strFileName)
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colDisks = objWMIService.ExecQuery _
("Select * from Win32_LogicalDisk Where DeviceID = 'C:'")
For Each objDisk in colDisks
objFile.WriteLine ("Free space (in bytes): " & objDisk.FreeSpace)
objFile.WriteLine ("Total space (in bytes): " & objDisk.Size)
Next
objFile.Close
Een file openen
Je kan een tekstbestand openen met de method
OpenTextFile
Naast de bestandsnaam moet je echter een extra parameter meegeven, nl. of je
alleen maar wilt lezen (ForReading
), of je wilt
schrijven (ForWriting
) of dat je tekst aan het eind
van het bestand wilt toevoegen (ForAppending
).
Deze 3 parameters hebben resp. de waardes 1, 2 en 8.
Dus om een file te openen voor lezen:
Const ForReading = 1
Set objFile = objFSO.OpenTextFile(strFileName, ForReading)
Je kan OpenTextFile
ook gebruiken om een nog niet
bestaande file onmiddellijk te openen voor schrijven (dit is dus identiek
aan CreateTextFile
):
Set objFile = objFSO.OpenTextFile(strFileName, ForWriting, True)
Lezen uit een file
In het volgende script lees je 1 voor 1 de regels uit het bestand
Servers.txt
tot je aan het einde van de file bent,
en je drukt ze af (op het scherm).
De eigenschap AtEndOfStream
heeft de waarde
True
als je het einde van de file hebt bereikt.
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Servers.txt", ForReading)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
Wscript.Echo strLine
Loop
objFile.Close
ReadLine
leest regel voor regel uit een bestand.
Als je het hele bestand in 1 keer wil lezen gebruik je
ReadAll
Lezen en schrijven naar dezelfde file
Het volgende script leest een bestand, controleert of een regel bestaat uit het woord 'Apple', en verandert het dan door 'Samsung':
Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Scripts\Companies.txt", ForReading)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
If strLine = "Apple" Then
strLine = "Samsung"
End If
strContents = strContents & strLine & vbCrLf
Loop
objFile.Close
Set objFile = objFSO.OpenTextFile("C:\scripts\Companies.txt", ForWriting)
objFile.Write(strContents)
objFile.Close
De truc is dat het bestand eerst alleen voor lezen wordt geopend, en dat de
veranderde tekst in een string (strContents
) wordt
opgeslagen.
Daarna wordt het bestand gesloten en onmiddellijk weer geopend, maar nu voor
schrijven.
En de hele opgebouwde string wordt er met de
Write
method naartoe geschreven.
Je hebt in dit geval geen WriteLine
nodig, omdat
er bij het opbouwen van de string aan het eind al steeds een Carriage Return
(Cr) en LineFeed (Lf) zijn toegevoegd.
De string is dus al onderverdeeld in aparte regels.
Bestanden en mappen
Je kan op 2 manieren met files en folders werken, via het
FileSystemObject
object, en via
WMI
.
Het voordeel van WMI
is dat het
ook gebruikt kan worden voor remote computers.
Het voordeel van FileSystemObject
is dat het wat
makkelijker is om mee te werken, i.h.b. als het om datums gaat.
FileExists en FolderExists
Deze 2 methods controleren of een bestand of map bestaat.
Bv. als volgt voor een bestand:
If objFSO.FileExists("C:\scripts\test.txt") Then ...
GetFile
Deze method dient om een object te krijgen dat naar de file verwijst, als je weet dat hij bestaat.
Voorbeeld:
Set objFile = objFSO.GetFile("C:\scripts\test.txt")
Copy
Bestanden
Met deze method kan je een bestand copiëren, waarbij de standaard is dat
het doelbestand, als het al bestaat, wordt overschreven.
Door een 2e parameter, False
, op te geven kan je dat
verhinderen.
Dus met het volgende statement wordt de file alleen gecopiëerd als hij
nog niet bestaat:
objFile.Copy "C:\scripts\temp\", False
De backslash aan het eind is wel belangrijk, omdat je wilt dat de file in de
map temp
terecht komt.
CopyFile en CopyFolder
Je kan GetFile
of GetFolder
en Copy
ook combineren tot de method's uit de titel:
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.CopyFile "C:\scripts\test.txt","C:\scripts\temp\"
objFSO.CopyFolder "C:\scripts","C:\scriptstest"
Deze 2 methods kennen ook een extra (in dit geval 3e) parameter, die aangeeft of evt. bestaande files en folders overschreven moeten worden.
Maar ze kunnen ook iets wat de normale Copy
niet kan,
nl. meerdere bestanden of mappen copiëren.
Je moet dan met wildcards werken.
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.CopyFile "C:\scripts\*.txt","C:\scripts\temp\"
Bovenstaand script copiëert alle bestanden met extensie
txt
naar de doelmap.
In geval van mappen is het even oppassen geblazen.
De regel
objFSO.CopyFolder "C:\s*","C:\temp"
copiëert alle mappen die beginnen met 's' in zijn geheel *binnen* de map
c:\temp
Dus in dit geval wordt niet de inhoud van de mappen die met 's' beginnen gecopiëerd, maar de map als geheel. Anders zou het binnen de doelmap een ongeorganiseerde chaos worden.
Mappen
Met mappen werkt het vrijwel hetzelfde als met bestanden, alleen moet je nu geen backslash aan het einde van het doel zetten.
Verder is het belangrijk om te beseffen dat ook de inhoud van submappen e.d. wordt meegenomen.
Een voorbeeldscript:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("C:\scripts")
objFolder.Copy "C:\temp"
Move, MoveFile en MoveFolder
Alles werkt vrijwel identiek aan de copiëer-operaties die hierboven beschreven zijn, met 1 verschil.
De standaard is in dit geval dat een bestand niet overschreven wordt, en je kan ook geen extra parameter meegeven om dat wel te bewerkstelligen.
Delete, DeleteFile en DeleteFolder
Alles werkt weer gelijk aan de Copy
-methods,
met opnieuw 1 belangrijk verschil.
In dit geval is er wel een extra parameter.
Die heeft als standaardwaarde False
, en dat betekent
dat files die read-only zijn niet worden weggegooid.
Om dus een hele map gegarandeerd kwijt te raken moet je het volgende statement
uitvoeren:
objFolder.Delete True
Copiëren op basis van datum
Stel je hebt een file object, en je wilt afdrukken op welke datum het bestand
aangemaakt is.
Dat kan als volgt:
Wscript.Echo objFile.DateCreated
Je hebt ook nog 2 andere eigenschappen van een file object,
DateLastAccessed
(wanneer is de file voor het laatst
benaderd), en DateLastModified
(wanneer is de file
voor het laatst gewijzigd).
De bovenstaande 3 eigenschappen van het file object zie je ook als je
met rechts klikt op een bestand in Verkenner
en dan op
Eigenschappen (Properties)
Door nu gebruik te maken van de datum-functies kan je bv. alle files copiëren die meer dan een maand geleden zijn aangemaakt:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("C:\scripts")
Set colFiles = objFolder.Files
dtmMonthAgo = DateAdd("m", -1, Now)
For Each objFile in colFiles
If objFile.DateCreated < dtmMonthAgo Then
objFSO.CopyFile objFile.Path, "C:\scripts\old\"
End If
Next
In de 6e regel bepaal je het tijdstip dat een maand voor het huidige ligt.
En daarna ga je gewoon alle files bij langs om te kijken of
DateCreated
voor dat tijdstip ligt.
Bestanden en mappen via WMI
Misschien moet je eerst de introductie over WMI lezen.
Het verschil met werken met het FileSystemObject
is dat je nu met 2 classes te maken hebt, 1 voor files
(CIM_DataFile
) en 1 voor mappen
(Win32_Directory
).
Kijken of een file of map bestaat
Map
Gebruik het volgende script:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colFolders = _
objWMIService.ExecQuery("Select * From Win32_Directory Where Name = 'C:\\Scripts'")
If colFolders.Count < 1 Then
Wscript.Echo "Folder does not exist"
Else
Wscript.Echo "Folder does exist"
End If
Met het Select
-statement haal je alle bestanden uit
de map C:\Scripts
De reden voor de 2 backslashes is dat de '\' een zgn. escape-character is (om
aan te geven dat het volgende teken anders geinterpreteerd moet worden dan
normaal).
De eigenschap Count
geeft aan hoeveel objecten
(folders in dit geval) aan de voorwaarde voldoen, en omdat we om een specifieke
map gevraagd hebben zijn er maar 2 mogelijkheden: 0 of 1.
File
Voor bestanden werkt het eigenlijk net als met mappen, behalve, zoals ik in het
begin al zei, dat je nu een andere class gebruikt:
Set colFiles = _
objWMIService.ExecQuery("Select * From CIM_DataFile Where Name = 'C:\\Scripts\\Test.txt'")
Copy
Folder
Stel dat je de folder C:\Scripts
naar
C:\Temp
wilt copiëren.
Het script verandert niet veel t.o.v. dat in de vorige sectie (ik heb de 1e 5 regels weggelaten):
Set colFolders = _
objWMIService.ExecQuery("Select * From Win32_Directory Where Name = 'C:\\Scripts'")
For Each objFolder in colFolders
objFolder.Copy("C:\Temp")
Next
Belangrijk hier is dat als de map waar je naartoe copiëert al bestaat, er niets gebeurt, maar je ook geen foutmelding krijgt.
Je kan wel controleren op een foutmelding door het resultaat van de method
op te vragen:
errResult = objFolder.Copy("C:\Temp")
Foutcodes staan in de beschrijvingen van de
WMI classes (per method).
Verder heeft de Copy
method maar 1 parameter,
en worden eventuele submappen niet meegecopiëerd.
Als je dat wel wilt moet je de method CopyEx
gebruiken.
File
Als je een file wilt copiëren:
Set colFiles = _
objWMIService.ExecQuery("Select * From CIM_DataFile Where Name = 'C:\\Scripts\\Test.txt'")
For Each objFile in colFiles
objFile.Copy ("C:\Temp\NewTest.txt")
Next
Wat als je meerdere bestanden wilt copiëren? Dan gebruik je een volgend soort syntax:
Set colFiles = _
objWMIService.ExecQuery("Select * From CIM_DataFile Where Path = '\\Scripts\\' and Extension = 'txt'")
For Each objFile in colFiles
strNewFile = "C:\Temp\" & objFile.FileName & ".txt"
objFile.Copy strNewFile
Next
Als je zoekt op een andere schijf dan de huidige, moet je ook de
Drive
-property gebruiken:
Where Drive = 'C:' and Path = '\\Test\\' and Extension = 'txt'
Verder is het goed om te beseffen dat de
FileName
-property niet de extensie bevat.
Bestanden verhuizen (Move)
Er is geen Move
method in WMI.
Als je mappen of bestanden wilt verhuizen zal je ze eerst moeten copiëren en dan verwijderen van de plek waar ze vandaan komen.
Delete
Mappen
Voorbeeld:
Set colFolders = _
objWMIService.ExecQuery("Select * From Win32_Directory Where Name = 'C:\\Scripts'")
For Each objFolder in colFolders
' objFolder.Delete
Next
Read-only files in de map worden ook weggegooid!!
Het echte Delete
-statement is
uitgecommentariëerd, om te voorkomen dat je per ongeluk dit script uitvoert
en echt een map weggooit.
Bestanden
Voorbeeld:
Set colFiles = _
objWMIService.ExecQuery("Select * From CIM_DataFile Where Name = 'C:\\Scripts\\Test.txt'")
For Each objFile in colFiles
objFile.Delete
Next
Het weggooien van alle bestanden met extensie TXT
in een map:
Set colFiles = _
objWMIService.ExecQuery("Select * From CIM_DataFile Where Path = '\\Scripts\\' and Extension = 'txt'")
For Each objFile in colFiles
objFile.Delete
Next
Bestanden met deze extensie in submappen worden niet weggegooid.
Copiëren op basis van datum
Dit is een beetje ingewikkelder dan met het
FileSystemObject
-object.
Dat komt doordat WMI werkt met datums in UTC-formaat.
Je moet de datum in UTC-formaat dus eerst naar een "normaal" formaat omzetten:
Set colFiles = _
objWMIService.ExecQuery("Select * From CIM_DataFile Where Path = '\\Scripts\\' and Extension = 'txt'")
dtMonthAgo = DateAdd("m", -1, Now)
For Each objFile in colFiles
dtCreationDate = WMIDateStringToDate(objFile.CreationDate)
If dtCreationDate < dtMonthAgo then
strNewFile = "C:\Scripts\old\" & objFile.FileName & ".txt"
objFile.Copy strNewFile
End If
Next
Function WMIDateStringToDate(dtmInstallDate)
WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & _
Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4) _
& " " & Mid (dtmInstallDate, 9, 2) & ":" & _
Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, _
13, 2))
End Function
Register
Je kan zonder WMI werken (zie het vervolg) of met.
De Windows Scripting Host levert een class, WshShell
,
die je lokale toegang geeft tot het register.
Je maakt als volgt een object van de class aan:
Set objShell = WScript.CreateObject("WScript.Shell")
Je begint elke script (dat met het register werkt) met dit statement, dus die noem ik vanaf hier niet meer.
De class heeft 3 methods, RegRead
,
RegWrite
en RegDelete
Lezen uit het register
Simpel voorbeeld:
iWordWrap = objShell.RegRead _
("HKCU\Software\Microsoft\Notepad\fWrap")
If iWordWrap = 0 Then
Wscript.Echo "Word wrap is turned off"
Else
Wscript.Echo "Word wrap is turned on"
End If
Van de 5 hoofdkeys in het register moet je alleen
HKEY_USERS
en
HKEY_CURRENT_CONFIG
voluit schrijven, de andere 3
kan je afkorten tot 4 letters.
Schrijven naar het register
Het volgende script schrijft naar dezelfde waarde die ook al bij het
leescommando werd gebruikt:
objShell.RegWrite "HKCU\Software\Microsoft\Notepad\fWrap", 1,
"REG_DWORD"
Het meest opvallende hier is dat je als 3e parameter het data-type moet opgeven. De meest belangrijke types staan op mijn pagina over het register.
Om het schrijf-statement wat overzichtelijker te maken kan je het pad in het
register ook van tevoren in een variabele zetten.
Onderstaand script draait de waarde van de wrap-instelling in
Kladblok (Notepad)
om:
strPath = "HKCU\Software\Microsoft\Notepad\fWrap"
Set objShell = WScript.CreateObject("WScript.Shell")
iWordWrap = objShell.RegRead(strPath)
If iWordWrap = 0 Then
objShell.RegWrite strPath, 1, "REG_DWORD"
Else
objShell.RegWrite strPath, 0, "REG_DWORD"
End If
Stel dat je een compleet nieuwe waarde binnen een key wilt aanmaken, dan
zou je de volgende regel kunnen uitvoeren:
objShell.RegWrite "HKCU\Software\Microsoft\Notepad\NewValue", 1, "REG_DWORD"
Verwijderen uit het register
Met onderstaande statement verwijder je de nieuwe waarde weer die we hierboven
aangemaakt hebben:
objShell.RegDelete "HKCU\Software\Microsoft\Notepad\NewValue"
Registerbewerkingen m.b.v. WMI
Lezen
Het volgende script leest dezelfde waarde uit het register die we al in deze hele sectie (over het register) gebruiken:
Const HKEY_CURRENT_USER = &H80000001
strComputer = "."
strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "fWrap"
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
objReg.GetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue
Wscript.Echo strValue
In de 1e regel wordt 1 van de 5 keys in het register in een constante gezet.
Je kan hier niet de afkortingen van de keys gebruiken, zoals
HKCU
, maar moet een hexadecimale representatie ervan
gebruiken (HKLM
= &H80000002 en
HKCR
= &H80000000).
Als je de punt in de 3e regel vervangt door de naam van een remote computer, kan je (alleen met WMI) ook op die computer werken.
Op bijna deze hele pagina (waar het over WMI gaat) wordt vrijwel steeds gebruik
gemaakt van de \root\cimv2
namespace.
Hier is het \root\default
Met WMI moet je een verschillende method gebruiken, afhankelijk van het data-type dat je gaat lezen:
- GetBinaryValue
- GetDWordValue
- GetExpandedStringValue
- GetMultiStringValue
- GetStringValue
Schrijven
Dat is nauwelijks anders dan lezen, alleen moet je nu natuurlijk opgeven welke waarde je gaat schrijven. De enige 2 regels die dus anders zijn, zijn:
strValue = 1
...
objReg.SetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue
Verwijderen
Een nog niet bestaande waarde aanmaken, en die vervolgens verwijderen, is ook a piece of cake als het voorgaande duidelijk is:
Const HKEY_CURRENT_USER = &H80000001
strComputer = "."
strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "NewKey"
strValue = 10
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
objReg.SetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue
objReg.DeleteValue HKEY_CURRENT_USER, strKeyPath, strEntryName
Gebruik maken van voorgedefinieerde informatie (zoals WMI)
Aanroep
Om van WMI
gebruik te kunnen maken moet een regel
als de volgende in je script hebben staan:
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Maar het kan ook ingewikkelder:
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
En het kan simpeler als je met de lokale computer werkt:
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
Het object dat je terugkrijgt als je werkt met de naam
winmgmts
is van het type
SWbemServices
Meestal gebruik je de method ExecQuery
van dit
object, omdat je een bepaalde collectie gegevens wilt verzamelen (query).
Maar als je met events wilt werken gaat het anders.
Voorbeeld
Als je van bv. Verkenner
(het bijbehorende bestand
heet explorer.exe
) zou willen zien wanneer hij
gestart is, zou je het volgende (complete) script kunnen uitvoeren:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = 'explorer.exe'")
For Each objProcess in colProcessList
Wscript.Echo objProcess.CreationDate
Next
In mijn geval was de uitvoer (op 31 mei):
20130524165937.110020+120
Blijkbaar draaide mijn PC dus als sinds 24 mei onafgebroken.
Hoe vind je informatie over wat er in WMI beschikbaar is?
Je gebruikt hier de Win32_Process
-class en de property
Name
Hoe weet je dat die er zijn? Via de WMI Reference. Links daarnaar heb ik op mijn pagina over programmeren staan.
De bovengenoemde class ziet er als volgt uit (ik heb een groot stuk er uit
gesloopt, maar je ziet de properties Name
en
CreationDate
):
class Win32_Process : CIM_Process
{
datetime CreationDate;
string CSCreationClassName;
string CSName;
string Description;
string ExecutablePath;
uint16 ExecutionState;
uint32 MaximumWorkingSetSize;
uint32 MinimumWorkingSetSize;
string Name;
string OSCreationClassName;
string OSName;
};
Hier een script (compleet) om de service
SCardSvr
te starten (kan geen kwaad om uit te voeren),
en als uitvoer de statuscode af te drukken (0 = goed):
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='SCardSvr'")
For Each objService in colServiceList
errReturn = objService.StartService()
Wscript.Echo errReturn
Next
Events
Om WMI events te kunnen ontvangen gebruik je niet de method
ExecQuery
van het object
SWbemServices
, maar de method
ExecNotificationQuery
Dus bv.:
Set colMonitorProcess = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent " & _
"WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'")
Het getal achter 'within' (in dit geval 1) is het aantal seconden tussen de momenten dat er gekeken wordt naar nieuwe events (het 'polling interval').
De class __InstanceOperationEvent
is een ingebouwde
WMI event class, die elke wijziging, verwijdering of aanmaak van een object
van een WMI class registreert.
Er zijn 3 classes afgeleid van bovenstaande, nl.
__InstanceCreationEvent
,
__InstanceModificationEvent
en
__InstanceDeletionEvent
Als je, zoals in bovenstaande query, zoekt op de class
__InstanceOperationEvent
, dan krijg je ze alle 3.
Wanneer je een query als bovenstaande uitvoert krijg je als resultaat
een SWbemEventSource
-object.
Het object SWbemEventSource
heeft een method
NextEvent
, die informatie ophaalt over het
eerstvolgende event dat voldoet aan de query.
Het resultaat is een object, met de naam van de event class die opgetreden is
in de property Path_.Class
van dat object.
En als je een query doet die met processen te maken heeft (en dus de
class Win32_Process
), dan bevatten de eigenschappen
TargetInstance.Name
en
TargetInstance.ProcessId
van het object uit de vorige
paragraaf de naam en het proces ID van het proces.
Het volgende stukje code:
strComputer ="."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitorProcess = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent " _
& " WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'")
WScript.Echo "Waiting for process change event ..."
Set objLatestEvent = colMonitorProcess.NextEvent
WScript.Echo VbCrLf & objLatestEvent.Path_.Class
Wscript.Echo "Process Name: " & objLatestEvent.TargetInstance.Name
Wscript.Echo "Process ID: " & objLatestEvent.TargetInstance.ProcessId
WScript.Echo "Time: " & Now
zou dus de volgende uitvoer op kunnen leveren:
Waiting for process change event ...
__InstanceModificationEvent
Process Name: System Idle Process
Process ID: 0
Time: 25-11-2013 22:15:22
WMI Query Language
Select statement
Je kan zeggen
Select * from Win32_PnPEntity
wat betekent dat je alle (daar staat de '*' voor) eigenschappen van het
object Win32_PnPEntity
opvraagt.
Je kan ook 1 specifieke eigenschap opvragen:
Select Description from Win32_PnPEntity
Of meerdere eigenschappen:
Select Description, Manufacturer from Win32_PnPEntity
En als je wilt dat je de waarde van je eigenschap aan een bepaalde voorwaarde
voldoet, gebruik je de where
-clause:
Select * from Win32_PnPEntity Where Manufacturer = 'Microsoft'
Maar je kan natuurlijk ook meer voorwaarden opgeven:
Where Manufacturer = 'Microsoft' and Name = 'wan miniport (ip)'
En tenslotte kan je ook in de where
-clause
een wildcard-teken opgeven, de '%':
Select * from Win32_PnPEntity Where Manufacturer = 'Microsoft'
and Name Like 'wan miniport%'
betekent dus dat als de waarde van eigenschap Name
begint met wan miniport
, hij voldoet aan de voorwaarde.
In plaats van and
kan je ook or
gebruiken om 2 voorwaarden met elkaar te verbinden.
Foutzoeken en fouten voorkomen
Waar kan je fouten verwachten?
Veel voorkomende plekken waar fouten optreden:
- Als een script contact probeert te maken met een API (Application
Programming Interface), zoals WMI,
ADSI of een andere COM-bibliotheek.
Dat kan bv. met een commando als
Set oReg=GetObject("winmgmts:\\" & strComputer & "\root\cimV2:StdRegProv")
Hier meer over WMI-fouten. - Bij invoer en uitvoer naar een apparaat of bestand.
- Bij het benaderen van randapparatuur (zoals printers) die niet beschikbaar zijn.
- Bij het aanmaken van een object van een klasse die niet op dat systeem aanwezig is (kan variëren tussen Windows-versies).
- Bij het opvragen van eigenschappen (properties) of aanroepen van methods die niet op dat systeem aanwezig zijn (ook weer verschillen tussen Windows-versies).
Option explicit
Omdat VBScript loosely typed is, worden tikfouten in namen van variabelen niet gemerkt. Dat kan leiden tot moeilijk oplosbare fouten. Zie bv. het volgende script:
FirstNumber = 4
SecondNumber = 9
Wscript.Echo FirstNumber + SeconNumber
Het script drukt 4 af als antwoord, omdat er een 'd' mist in
SeconNumber
, en je krijgt geen foutmelding (een
niet gedeclareerde variabele krijgt standaard als waarde 0).
Als je aan het begin van het script
Option Explicit
zet, zou dit script wel een foutmelding geven.
Je moet de variabelen dan wel van tevoren declareren:
Option Explicit
Dim FirstNumber
Dim SecondNumber
FirstNumber = 4
SecondNumber = 9
Wscript.Echo FirstNumber + SeconNumber
Controleren op syntax-fouten
Een syntax-fout is wanneer je bv. een spelfout maakt in een keyword, zoals
Else
VBScript controleert de syntax van het hele script voordat het het uitvoert.
Een slimme manier om dus zelf te controleren of de syntax OK is, is het script
(tijdelijk) te laten beginnen met Wscript.Quit
Vooral als je script gevaarlijke dingen zou kunnen doen is dit een manier om er voor te zorgen dat je script niets kan beschadigen, want het stop per definitie na de 1e regel.
On Error Resume Next
Je kan alles over dit commando op de site van Microsoft vinden.
Met dit commando in je script doet het alsof fouten niet bestaan. Als een statement een fout oplevert slaat het dat statement gewoon over, en gaat verder met het volgende. En je zult het nooit te weten komen.
Tenzij je dit statement op zijn minst tijdelijk uitschakelt. En dat is dus ook wat je moet doen als je onverwachte resultaten krijgt.
Ook al staat dit commando in je hoofdscript, dan nog werkt het niet in functies of subroutines. Binnen elke functie of subroutine moet je het opnieuw uitvoeren.
Je kan het commando uitschakelen met
On Error GoTo 0
Err object
Je kan alles over dit object op de site van Microsoft vinden.
Number property
VBScript bevat standaard het object Err
, met de
property Number
Elke VBScript method zet een resultaat in deze property. En dat resultaat kan je bv. als volgt opvragen en er iets mee doen:
If Err.Number Then
...
Err.Clear
End If
Andere properties
Err
heeft ook nog de properties
Source
(bron) en
Description
(beschrijving), beide strings.
De properties HelpFile
en
HelpContext
zijn alleen van belang als de applicatie
eigen foutcodes heeft gedefiniëerd, en die aan helpbestanden heeft
gekoppeld.
Methods
Clear
Clear
is een zeer belangrijke method.
Als je waarde van bv. Err.Number
hebt gecontroleerd
moet je Err.Clear
uitvoeren.
Als je de waarde nl. later weer een keer controleert, en de commando's tot dan toe hebben geen fout opgeleverd, dan zal toch nog steeds de oude waarde er in zitten.
Raise
De andere method is
Raise(lngNumber, strSource, strDescription)
Hiermee kan je zelf een fout produceren als VBScript het niet doet.
Alleen de 1e parameter, een getal tussen 0 en 65536, is verplicht.
IsObject en Is Nothing
Deze 2 tests kan je gebruiken na een commando waarin je met objecten werkt,
zoals GetObject
en
CreateObject
Ze leveren geen specifieke foutinformatie op, alleen of je een geldig object hebt gekregen of niet.
Is Nothing
Nothing
staat gelijk aan Null
,
m.a.w. een pointer naar niets (en in elk geval geen object).
Je kan dus bv. het volgende script gebruiken om te testen of je een geldige referentie naar de WMI-provider hebt gekregen:
On Error Resume Next
strComputer = "fictional"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
If objWMIService Is Nothing Then
WScript.Echo "Unable to bind to WMI on " & strComputer
Else
WScript.Echo "Successfully bound to WMI on " & strComputer
End If
IsObject
Deze functie doet eigenlijk het omgekeerde van de vergelijking
Is Nothing
Als je een geldige referentie naar een object (maakt niet uit wat voor) aan
IsObject
geeft krijg je de waarde true terug, anders
false.
Het volgende script test of je succesvol een (printer) object hebt aangemaakt:
On Error Resume Next
strPrinter = "TestPrinter"
Set objPrinter = GetObject _
("winmgmts:root\cimv2:Win32_Printer.Name='" & strPrinter & "'")
If IsObject(objPrinter) Then
WScript.Echo "Connected to printer " & strPrinter
Else
WScript.Echo "Unable to connect to printer " & strPrinter
End If
Resultaten van methods
Methods geven altijd een code 0 terug als het goed is gegaan.
Als er iets mis gaat komt er een geheel positief getal terug, maar de waardes daarvan variëren per method.
Je zou bv. een functie kunnen schrijven die als parameter een object van het
type Win32_Process
meekrijgt, en vervolgens probeert
dat proces te beëindigen.
Afhankelijk van de code die het oplevert (in variable
intReturn
) kan de functie een andere actie ondernemen
(de onderstaande functie drukt steeds alleen maar de status af).
Function TerminateProcess(objProcess)
On Error Resume Next
intReturn = objProcess.Terminate
Select Case intReturn
Case 0 Wscript.Echo "Return code " & intReturn & " - Terminated"
Case 2 Wscript.Echo "Return code " & intReturn & " - Access denied"
Case 3 Wscript.Echo "Return code " & intReturn & " - Insufficient privilege"
Case 8 Wscript.Echo "Return code " & intReturn & " - Unknown failure"
Case 9 Wscript.Echo "Return code " & intReturn & " - Path not found"
Case 21 Wscript.Echo "Return code " & intReturn & " - Invalid parameter"
Case Else Wscript.Echo "Return code " & intReturn & _
" - Unable to terminate for undetermined reason"
End Select
TerminateProcess = intReturn
End Function
WMI-fouten
WbemErrorEnum
In geval van een WMI-fout komt er informatie terug in
WbemErrorEnum
Je moet echter waardes verwachten als
wbemErrInvalidFlavor
, en deze zelfde informatie zit
ook in de property Description
van het
Err
-object.
Bovendien is de waarde in WbemErrorEnum
moeilijk
te benaderen.
SWbemLastError
Door het object SWbemLastError
te creëren kunnen
we ook meer informatie over de laatste fout krijgen.
Dat doe je met het volgende commando:
Set WMI_Error = CreateObject("WbemScripting.SwbemLastError")
SWbemLastError
heeft een aantal parameters die
interessant zouden kunnen zijn in troubleshooting:
Operation
, ParameterInfo
en
ProviderName
Je moet het object pas aanmaken na het punt in het script waar een fout zou kunnen optreden.
De benodigde subroutine en een voorbeeld kan je hier vinden.
Fouten bij werken met het register
De klasse StdRegProv
die je nodig hebt om met het
register te werken, bevat alleen methods.
Deze kunnen een waarde 0 (succes) of iets anders teruggeven.
Aangezien dat 'iets anders' niet (goed) gedocumenteerd is, is het het beste gewoon te controleren op succes of niet.
In onderstaande code wordt eerst verbinding gemaakt met de registerklasse
op de lokale computer, en dan wordt de waarde van een niet bestaande
sleutel (hnetmonh
) in het register opgehaald.
On Error Resume Next
strComputer = "." 'Change to non-existent host to create binding error.
Const HKLM = &H80000002
strSubKeyName = "SOFTWARE\Microsoft\NetSh"
strEntryName = "hnetmonh"
'Connect to WMI and StdRegProv class.
Set objReg = GetObject("winmgmts:\\" & strComputer & _
"\root\default:StdRegProv")
If Err = 0 Then
WScript.Echo vbCrLf & "Bind success"
WScript.Echo vbCrLf & "Computer: " & strComputer
Else
WScript.Echo "ERROR: Unable to bind to WMI provider on " & strComputer & "."
WScript.Quit
End If
'Get string value from entry and check return value.
intRet = objReg.GetStringValue(HKLM, strSubKeyName, strEntryName, strValue)
If intRet = 0 Then
WScript.Echo vbCrLf & "Registry success"
WScript.Echo "Registry Path: HKLM\" & strSubKeyName & "\" & strEntryName
WScript.Echo "Entry Value: " & strValue
Else
WScript.Echo vbCrLf & "ERROR: Unable to retrieve value of registry " & _
"entry HKLM\" & strSubKeyName & "\" & strEntryName & vbCrLf & _
"Return value: " & intRet
End If
Gek genoeg, wanneer je de subroutine
gebruikt waarmee je foutinformatie kunt weergeven, dan geeft bovenstaand
script geen fout, omdat Err
kennelijk de waarde 0
heeft.
Maar wanneer je de waardes van strSubKeyName
en
strEntryName
uitcommentariëert, dan krijg je
ineens wel een fout:
ERROR: Unable to retrieve value of registry entry HKLM\\
Return value:
Number (dec) : -2147217400
Number (hex) : &H80041008
Description : Invalid parameter
Source : SWbemObjectEx
Operation : ExecMethod
ParameterInfo: StdRegProv
ProviderName : WinMgmt
ADSI-fouten
Deze sectie is voor de meeste thuisgebruikers niet van belang, want het gaat hier om Active Directory, en dat wordt bijna alleen in (grotere) bedrijven gebruikt.
Op de site van Microsoft is deze speciale pagina gewijd aan ADSI-fouten.
ADsGetLastError
Deze waarde, die vergelijkbaar is met SWbemLastError
voor WMI, is voor scripting-talen niet toegankelijk, dus vanuit VBScript
moet je andere methodes gebruiken.
4 soorten fouten
Generic COM-fouten
5 van de 6 zien eruit als 0xH8000400x
,
en de laatste is een soort doomsday-fout:
0xH8000FFFF
(catastophic failure).
Generic ADSI-fouten
3 zien eruit als 0xH000050xx
en de andere 18 als
0xH800050xx
Win32-foutcodes
Volgt later.
LDAP-foutcodes
Volgt later.
Verdere informatie
Op de site van Microsoft een serie artikelen ("To Err is VBScript") over geavanceerde foutzoektechnieken.
Links
- Learn Beginning Scripting
- Deze pagina bevat links naar een aantal columns, geschreven in de jaren 2005-2007, om de beginner te leren programmeren in VBScript. De linkerkolom is voor de *absolute* beginner, de rechter voor de beginner+. De artikelen zijn vaak heel humoristisch geschreven. Zeer de moeite waard, hoewel VBScript meer en meer zal worden vervangen door PowerShell.
- Tales from the Script
- Artikelen geschreven in de periode 2002-2005, bedoeld voor beginnende scripting gebruikers.
- Hey, Scripting Guy! Blog - Learn about Windows PowerShell
- 124 pagina's (mei 2013) met tientallen links naar blogs van de Scripting Guy waarin hij vragen van gebuikers beantwoordt. Deze link is naar de oudste pagina (op dit moment), en daar gaan de blogs nog over VBScript. Op de meest recente pagina's gaan de blogs over PowerShell.
- Doctor Scripto's Script Shop
- Vast en zeker interessante artikelen over scripting, maar ik heb er nog niet naar gekeken.
- Scripting Clinic
- Ik denk dat dit een verzameling wat oudere artikelen is (maar daarom niet noodzakelijk minder interessant).
- VBScript Language Reference
- Een complete beschrijving van de taal VBScript, onderverdeeld in secties als Constants, Functions, Keywords, enz.
- Functions (VBScript)
- Een overzicht van alle functies in VBScript.
- Windows Script Components Have a COM-ing Effect
- Een voorbeeld van het gebruik van Windows Script Components.
- Scripting
- Uitvoerige documentatie over scripting, i.h.b. over Windows Script Components.
- Separating lines from multi-line Excel cell
- Een script om regels in een Excel-cel op te splitsen.
Reageer via E-mail (dalmolen@xs4all.nl)
Deze pagina is voor het laatst gewijzigd op: 12-02-23 13:29:26