MSM: The poor Mans System Management

Wim Verveen , e-mail: wim@win2kwereld.nl

In het vorige artikel over WMI hebben we ons bezig gehouden met het verzamelen van informatie uit machines. Dat is natuurlijk allemaal erg interessant maar op zich heeft dit nog slechts betrekkelijk nut. Interessant wordt het pas als we de door ons gewenste informatie kunnen opvragen bij heel veel machines tegelijk. Dit brengt ons gelijk bij het volgende probleem: Waar laten we al die informatie?  We kunnen het opslaan in een tekstbestand. Helaas leidt dit al snel tot een warboel van ongeordende gegevens. De Windows Script Host (WSH) is echter perfect in staat om ook informatie op andere wijze op te slaan, bijvoorbeeld in een Excel bestand.

Zo'n oplossing is echter weinig schaalbaar als we de informatie va veel machines voor langere tijd willen verzamelen. De oplossing is het gebruik van een database. Nu denkt u misschien: 'Een database, dat zal best ingewikkeld zijn'. Niets is minder waar, het benaderen van databases met de Windows Script Host is heel eenvoudig, je zou zelfs kunnen stellen dat het eenvoudiger is dan het gebruik van Excel. De voornaamste oorzaak daarvan wordt veroorzaakt doordat een database veel beter ingericht is op het bewaren van data dan een applicatie als Excel. Hierdoor is het opslaan en benaderen van gegevens veel eenvoudiger. Met Excel zullen uw scripts bijvoorbeeld op de hoogte moeten zijn van de locatie van een cel met gegevens. In een database kunt u gewoon de gewenste gegevens middels een SQL query opvragen en eenvoudig weer terugplaatsen. Wat voor databases kunnen we gebruiken? Dat kunnen diverse zijn, het meest makkelijk is om hiervoor gewoon het doodeenvoudige Access te gebruiken. Access mist wel veel zaken die een 'echte' database bezit zoals transacties en stored procedures maar kan voor scripting doeleinden vaak uitstekend voldoen. Wat we in dit artikel gaan doen is het combineren van de kracht van WMI met de flexibiliteit van een database.

Een stukje achtergrond

Databases worden door verschillende fabrikanten gemaakt. Men heeft voorzien dat dit niet zo handig is voor programmeurs die een applicatie schreven die meerdere database systemen moest kunnen benaderen. Een van de eerste standaardisaties die daar uit voorkwam was SQL, Stuctered Query Language. Hierdoor werd het makkelijker om gegevens uit een database te halen. Dit was echter nog niet genoeg. Een applicatie moet eerst contact kunnen maken met de database voordat de gegevens tevoorschijn komen. Hiervoor werd ODBC ( Open Database Connectivity ) ontwikkeld. Een ODBC driver zit tussen de applicatie en de database in waardoor de applicatie slechts met ODBC en SQL moet kunnen omgaan om de database te kunnen benaderen.  Omdat ODBC niet object georiënteerd is, werden interfaces ontwikkeld die bovenop ODBC zitten. Vandaag de dag is ADO (Active Data Objects) Microsofts standaard voor een database object model. ADO is een snel, efficiënt object georiënteerd model. ADO kan databases gebruiken die OLE DB ondersteunen. OLE DB is een standaard die ODBC vervangt. Microsoft voorziet in een ODBC driver voor OLE DB waardoor de meeste databases benaderbaar zijn.

Figuur 1: Het ADO object model

Het ADO object model is een relatief simpel model.  Meestal hoeft alleen het recordset object gebruikt te worden. De recordset geeft een resultset, bestaande uit records uit de database weer. Dit kan het resultaat zijn van een SQL query, een stored procedure of de inhoud van een tabel. Het recordset object kunnen we gebruiken om records uit de database toe te voegen, te wijzigen of te verwijderen.

Om de recordset te kunnen gebruiken hebben we als eerste een database verbinding nodig. Zo'n verbinding wordt opgebouwd middels een connection string. Een recordset kan die direct gebruiken of middels een Connection object. In de connection string staat alle informatie die nodig is om de database te kunnen benaderen. Een simpel voorbeeld van een connectionstring is bijvoorbeeld een database die als DSN gedefinieerd staat in de ODBC administrator : "DSN=MijnDB".

Aan de slag

In dit artikel gaan we niet gelijk met een grote database aan de slag. We houden het eenvoudig en gaan een Access database gebruiken om informatie in op te slaan. Acces mist veel van de functionaliteit die aanwezig is in een professioneel RDBMS maar is voldoende krachtig voor veel toepassingen die met WSH gebouwd kunnen worden. Daarnaast zijn de kosten verwaarloosbaar in vergelijking met een 'echte database'. In voorbeeld 1 wordt een illustratie gegeven hoe een en ander in zijn werk gaat. Om te zorgen dat het voorbeeld zal functioneren moeten we eerst zorgen dat de database die het script gebruikt aanwezig is en dat we in de ODBC instellingen een DSN hebben gemaakt naar deze database toe. In figuur 1 ziet u hoe dit in de ODBC administrator (Data sources in windows 2000) gedaan kan worden.

Figuur 2: Een DSN voor access definiëren

Wanneer we de database hebben gecreëerd en de DSN hebben aangemaakt hoeven we in Access alleen nog een tabel genaamd 'voorbeeld' te maken en 2 (tekst) velden te creëren met de namen 'a' en 'b'.

Als deze werkzaamheden zijn afgerond kunnen we het script starten. Dit stukje VBscript neemt 2 commandline argumenten mee en stopt deze in de tabel. Dit doet het script door een ADODB object te creëren en via ODBC een verbinding te maken met de Access database. Het aanmaken van de records in de database is dan relatief eenvoudig zoals het voorbeeld laat zien. Wijzigingen die we maken worden pas weggeschreven wanneer het commando 'rs.update' wordt gegeven.

Het maken van een SQL query lijkt u misschien wat complex, dit valt echter reuze mee. Wanneer u niet zo thuis bent op dit onderwerp maakt u gewoon eerst dezelfde query in Access en vraagt daarvan vervolgens de SQL code op, dit plakt u dan in uw script. Omdat in dit script alleen waarden worden toegevoegd, wordt een SQL query meegegeven die geen records teruggeeft maar er wel voor zorgt dat we de juiste verbinding opbouwen. Dit is een wat eenvoudige manier om gegevens in de database te krijgen, met SQL kunnen meer efficiënte statements worden gebruikt wanneer u hier wat meer in thuis bent.

Voorbeeld 1

      Dim rs,Args,sSelection

      Const connStr = "DSN=voorbeeldDB"


      sSelection = "SELECT Voorbeeld.* " _
         & "FROM Voorbeeld " _
       & "WHERE (((voorbeeld.a) Is Null));"


      Set Args = WScript.Arguments


      set rs = CreateObject("ADODB.recordset")
      rs.Open sSelection, connStr, 1, 3

      rs.AddNew
      rs.fields("a").value=Args(0)
      rs.fields("b").value=Args(1)
      rs.Update
      rs.close

Voorbeeld 2

      Dim rs,sSelection

      Const connStr = "DSN=voorbeeldDB"

      sSelection = "SELECT Voorbeeld.* " _
         & "FROM Voorbeeld ;"

      set rs = CreateObject("ADODB.recordset")
      rs.Open sSelection, connStr, 1, 3

      if not (rs.bof and rs.eof) then
         While not rs.EOF
           sMessage= sMessage & rs.fields("a") & " " & rs.fields("b") & vbCrlf
           rs.MoveNext
         Wend
         wscript.echo sMessage
      end if
      set rs=nothing

Voorbeeld 2 laat zien hoe je uit de door ons gevulde table weer gegevens kan inlezen. We vragen hier alle gegevens uit de database en wanneer de recordset die we krijgen niet leeg is (rs.BOF) dan plaatsen we alle record waarden in een string die we na het bereiken van het laatste record (rs.EOF) op het scherm plaatsen.

Het echte werk

Nu u een indruk heeft gekregen hoe het gebruik van een database met WSH ongeveer werkt gaan we een stapje verder en beginnen we een aan een daadwerkelijke toepassing: Het poor Mans System Management!

We gaan de kennis die we de vorige keer hebben opgedaan met WMI gebruiken om in Access een inventarisatie te maken van ons machine park. Als eerste maken we daarom een DSN die wijst naar de database die we gaan gebruiken, bijvoorbeeld de DSN 'MSMDB'. Vervolgens maken we in Access de tabellen hosts en services aan. Elke tabel krijgt de juiste velden, let op dat de velden voldoende groot zijn om alle gegevens te bevatten.

In voorbeeld 3 kunt u zien hoe we nu de database gaan vullen. Het script leest eerst uit de database de benodigde hostnamen uit. Hierna wordt met WMI query's zoals we in het vorige artikel hebben geleerd de gewenste informatie opgehaald waarna deze met de eerdergenoemde ADO instructies in de database worden geplaatst. Een aantal interessante punten in het script is de manier waarop door de hosts tabel wordt bewogen om elke host af te vragen. Daarnaast wordt voor services en process informatie eerst de oude gegevens weggegooid, dit om te voorkomen dat oude informatie blijft staan.

Voorbeeld 3

      Const connStr = "DSN=MSMDB"

      sSelection = "SELECT hosts.* " _
         & "FROM hosts ;"

      Set hrs = CreateObject("ADODB.recordset")
      hrs.Open sSelection, connStr, 1, 3

      if not (hrs.bof and hrs.eof) then
         While not hrs.EOF
           Hostname=hrs.fields("host")
           Set ServiceSet = GetObject("winmgmts:{impersonationLevel=impersonate}!//" & HostName).InstancesOf("Win32_ComputerSystemProduct")
           For each Object in ServiceSet
            hrs.fields("product")= Object.Name
            hrs.fields("Manufacturer")= Object.Vendor
           next

           Set serviceset = Nothing
           Set SystemSet = GetObject("winmgmts:{impersonationLevel=impersonate}!//" &  HostName).InstancesOf ("Win32_OperatingSystem")

           for each System in SystemSet
            hrs.fields("version")=System.Version
           'Het volgende veld moet in de database groot genoeg zijn
            hrs.fields("versionname")=System.Name
           next
           Set systemset =Nothing
           hrs.update
           getinfo Hostname
           hrs.MoveNext
         Wend
      end if
      set hrs=nothing


      Sub Getinfo(hostname)
        sSelection = "SELECT services.* " _
           & "FROM services " _
         & "WHERE (services.host = '" & HostName & "' );"
        Set rs = CreateObject("ADODB.recordset")
        rs.Open sSelection, connStr, 1, 3
        ClearOldRecords rs

        for each Service in GetObject("winmgmts:").InstancesOf ("win32_service")
         rs.addnew
         'Description en path velden moeten groot genoeg zijn
         rs.fields("host")=HostName
         rs.fields("Description")=Service.Description
         rs.fields("Path")=Service.PathName
         rs.fields("State")=Service.State
        next
        rs.update
        rs.close
      End Sub

      Sub Clearoldrecords (rs)
      ' Deze functie verijdert eerst de oude gegevens
      If Not(rs.BOF And rs.EOF)Then
        While Not rs.EOF
          rs.delete
          rs.movenext
        wend
        rs.updatebatch
      end if
      End Sub

Conclusie

Hoewel het op het eerste gezicht ingewikkeld lijkt om een database te benaderen met scripting blijkt het echter een relatief eenvoudige zaak. Wanneer we dit vermogen combineren met andere functionaliteit van scripting blijken we ineens een krachtige toepassing te kunnen bouwen, bedenk dat het niet hoeft te stoppen met dit eenvoudige voorbeeld. We kunnen door steeds meer informatie in deze database te verzamelen een heus management systeem creëren zonder dat we hier een duur pakket voor hoeven aan te schaffen.  Daarnaast zijn er natuurlijk nog tal van andere toepassingen beschikbaar, om u tot slot wat ideeën mee te geven: gebruikersdesktop configuratie vanuit een database, koppeling Active directory met een personeels of leerlingen systeem of tal van andere beheerstoepassingen.

Links/extra info

Databases en de scripts : http://www.win2kwereld.nl/downloads/ado.zip
SQL informatie http://www.sql.org/
ADO http://msdn.microsoft.com/library/psdk/dasdk/ados4piv.htm

 

W. Verveen is verbonden aan de Ormer groep als Consultant, daarnaast beheert hij Win2K Wereld
E-mail: w.verveen@ormer.nl
Web:
http://www.ormer.nl en http://www.win2kwereld.nl

 


privacy policy