## MS BackOffice Unleashed

- The SMS Database
  - The Machine Data Table
  - Views
  - Other Tables
- Interfacing Microsoft Access with SMS
  - Using ODBC
  - Access Options
  - Sample Access Interface to SMS: A Disk Usage Report
- Extending the SMS Database
  - Management Information Format Files
  - Adding Groups
  - Collecting User Documents Information
- Interfacing Microsoft Word with SMS
  - Mail Merging
  - Accessing SMS from Word Basic
  - Sample Word Interface to SMS
- Other SMS Programming Interfaces
  - SMS API
  - Packages
  - Extending the Network Monitor
- Summary

#
— 44 —

##
Interfacing Applications to and Extending SMS

Microsoft’s Systems Management Server (SMS) is a solution to one of the large general problems facing organizations today—managing large numbers of computers, especially personal computers. SMS is also an excellent architecture on which to build solutions to specific problems. Sometimes these solutions require extending SMS, and other times they involve using other applications interfaced to SMS. This chapter discusses a variety of approaches to programming such solutions with SMS.

SMS is composed of various elements, but central to most of them is the SMS database, stored by Microsoft’s SQL Server. This chapter starts by exploring this database and how a particularly appropriate tool for accessing the database, Microsoft Access, interfaces with SMS. You will then look at how you can extend the SMS database to include additional information that a typical organization might require. Microsoft Word will then be used to bridge the gap between all this technical data and the various worlds of your users. The chapter finishes by reviewing some less commonly used programming interfaces to SMS.

###
The SMS Database

SQL Server includes a variety of tools that prove very useful for exploring the databases it stores, presuming you have the privilege to do so. The most appropriate starting point for SQL Server version 6.5 is the SQL Enterprise Manager. You may need to register the server where your SMS database resides, by taking the Server menu’s Register Server item. Once you have your server listed in the Server Manager window, you can dig down to the databases on that server and look at the SMS database. For now you are particularly interested in the Objects, Tables subtree. You probably have over 50 tables listed, a rather intimidating prospect. However, you'll soon make sense of these tables.

> > If a list of all columns in the tables is desired, the SQL Enterprise Manager’s SQL Query Tool (under the Tools menu) can be used to execute the following SQL statement:
> > SELECT sysobjects.name Table_Name, syscolumns.name Column_Name from syscolumns, sysobjects where syscolumns.id=sysobjects.id and syscolumns.id>100

####
The Machine Data Table

Technical specialists looking to gain the greatest benefit from SMS will have two primary expectations for the SMS database. The first is to extract data, usually for reporting. The second is to store additional data, in order to serve needs specific to their organizations. From these points of view, the center of the SMS database design is the MachineDataTable table. This table contains pointers to all the data for every machine (computers and other devices you keep track of SMS with). Every machine has a unique identification number (dwMachineID) and is categorized as being part of an architecture. The architecture for our purposes will usually be 5, which the ArchitectureMap table refers to as "Personal Computer ". Every machine will have multiple records within the MachineDataTable, one for each pointer to data stored in other tables. You can tell which table these records point to by referring to the GroupKey column. The numeric GroupKey values can be used with the ArchitectureKey to look up a descriptive name for the group in the GroupMap table.

SMS’s machine data is stored in a series of tables appropriate to each group of machine characteristics. There are tables for disk, IRQ, network card, operating system, memory, and similar information. Most of these categories have two tables, one for common data and another for specific data. For instance, you may have many PCs that have NTFS-formatted SCSI Fixed Drives, CD Roms, FAT16-formatted DoubleSpace Drives, and so on. You will have only one, however, that has a drive with a serial number of A049-6B6D and 370M used of 532M. The former kind of data goes in the common tables, and the latter goes in the specific tables, thus maximizing the efficiency with which information is stored. In this case, the common data goes into a table called Disk_COMM and the specific data goes into a table called Disk_SPEC.

Going back to the MachineDataTable, you can use the GroupKey and ArchitectureKey to look in the GroupMap table and figure out the table names for the common and specific tables. You can then use MachineDataTable’s SpecificKey to find the data in the specific table and the CommonKey to find the data in the common table. In some cases, a machine may have several instances of a specific group, and the InstanceKey distinguishes between these. A good example, again, is disks—each PC will probably have a floppy drive, hard disk, and a CD-ROM, each of which is an instance of a disk.

You can see samples of the actual data contained in the tables by starting the SQL Enterprise Manager’s SQL Query Tool (under the Tools menu) and then entering a query of Select * From MachineDataTable, for example (note that case is not significant). Then click on the Execute Query button (the one with a green right arrowhead icon).

> > For many of the machine data groups (disk, operating system, and so forth), previous data is kept for each machine as new, changed data is recorded by SMS. The pointers to this information are kept in the MachineDataHistoryTable, which has an identical layout to the MachineDataTable and is used in the same way. In order to determine which groups have historical data, you can refer to the GroupMap table, HistoryFlag column.

####
Views

Understanding the SMS database is important, enabling you to explore the database and find information you need. However, producing reports using the database as it is would be very tricky. Microsoft has addressed this issue by providing the SMSVIEW.EXE program, which can be found in the site’s executables directory, most commonly called \SMS\SITE.SRV\X86.BIN. If you execute this program, SQL Server is provided with views that will probably be more useful for producing reports. You have to provide logon information to access the database, but otherwise SMSVIEW will automatically execute without intervention, pausing only to announce success or failure. If you want, it can be run from the command line, by providing the logon information on switches. As an example, SMSVIEW /s:NT4_Server /l:sa /p: /d:SMS runs SMSVIEW on the SMS database on the NT4_Server, using the sa logon and no password.

Views are literally just views on the database—they do not contain data and thus do not consume any disk space. SMSView creates views that essentially flatten and amalgamate the machine detail tables. As an example of an SMSView view, for disks there is a view called vDisk, which contains both specific and common data on all disks for all machines. The only information missing is machine identification details, which are available in the Identification_SPEC table.

> > Microsoft reserves the right to change the layout of the SMS database. The views are likely to remain stable, but if you work with the tables then you should be prepared to adjust your code when new versions (especially major versions) appear.

####
Other Tables

Beyond the machine-related tables, the SMS database contains tables for the other architecture elements, the things that can be used or controlled by the SMS Administrator and Security programs, and the inevitable overhead details.

The tables for the other architecture elements are the following: Jobs and JobDetails for jobs; Packages, PackageLocations, PackageDistributions, Platforms, and WCLs for packages; SMSEvent for events; SNMP_Traps and SNMP_Varbinds for SNMP traps; and UserGroups for user groups.

The tables for other items that the SMS Administrator program can manipulate or use are the following: Alerts and AlertRecipients for alerts; MachineGroups and MachineGroupDetails for machine groups; ProgramGroups, ProgramGroupProgramItems, ProgramGroupUserGroups, and ProgramItems for program groups; Queries, QueryExpressions, QueryFormatDefaults, and QueryFormats for queries; and SiteGroups and SiteGroupDetails for site groups.

The tables for things that the SMS Security program can manipulate are stored in the SecurityObjAccessList, SecurityObjAssocation, SecurityObjects, and SecurityUserTemplates tables.

With any complex system there are various minor details and interior elements that the system must keep track of. For SMS, these are kept in the AttributeMap, DeletedMachines, Domains, DomainTypes, PropertyDisplayGroups, PropertyDisplayPanes, PropertyDisplayUsage, Requests, SchedulerSafeDelete, ServerShares, SetupInfo, SiteControl, SiteUses, SiteWork, SMSData, SqlStoreTable, SyncModification, and WorkstationStatus tables. The SMSData table is particularly central to many other tables in that it contains the next values for many keys, as well as other data.

###
Interfacing Microsoft Access with SMS

Microsoft Access is often thought of as a small database system (like SQL Server but less serious) that has some easy-to-use programming features included. This is true, but it don't forget that other databases can serve up the database functionality, and Access can be used to easily access that data (thus the name). In this case, the Access database is just used to store queries, reports, and so on. Using Access with SMS’s SQL Server database is a good example.

####
Using ODBC

When installing Access for Windows 95, the custom install should be chosen, and it should be ensured that the SQL Server ODBC driver was installed as part of the Data Access options. If so, using the 32-bit ODBC control panel, a data source can be added for the SMS database. It will use the SQL Server driver, of course. The Data Source Name can be anything, but let's call it SMS. The Server will be the computer name of the SMS SQL Server, and under Options you can specify the Database Name as SMS.

Using Access, a new blank Access database can be opened and the SMS database can be linked in, using the File, Get External Data, Link Tables… options. In the Link dialog box, the ODBC Databases option should be chosen from the Files of type drop-down listbox. The SQL Data Sources dialog box will appear, and the SMS database defined in the ODBC control panel can be selected. You will then be able to link in the tables you need (you may wish to link in all of them, for future needs). For most tables, you have to clarify for Access what the key is; this is usually fairly simple, because the column name will end in the word "key" and be appropriate for that table.

####
Access Options

At this point, Access knows where the data is and how to look it up, but it’s not clear to Access how the tables relate to each other. If information is needed from two tables, how does Access ensure that the same machine is referred to by the selected records in each table? This is where relationships come in, and these are defined using the Relationships menu item under the Tools menu. The relationships are specified by choosing the appropriate tables and then dragging the field that relates to a corresponding field in the other table onto it. The end result will be something like what we see in Figure 44.1.

FIGURE 44.1. Setting up the table relationships in Access.

Creating a query to collect the data needed for a report is fairly straightforward using Access. A new query based on the Simple Query Wizard can be created within minutes. The appropriate fields (columns) from the desired tables must be chosen with the wizard. Typically, these will be from the SMS view tables, such as dbo_vDisk, and dbo_Identification_SPEC. The wizard can then finish up and will present the basic query results. It may be necessary to use the Design View for the query and specify additional details—for example, if multiple tables are used then the relationship might involve the MachineDataTable. For each machine in the MachineDataTable, however, there are multiple records—at least one for each group for which the machine has data. Thus, it would be necessary to specify which record should be used to establish the relationship, based on the appropriate GroupKey value. The Design View can also be used to specify some formatting details, calculations, and so forth.

An even more attractive and powerful Access report can be created by generating a new report using the report wizard and choosing the query as the source of the data. All the fields could be selected and various formatting options chosen.

####
Sample Access Interface to SMS: A Disk Usage Report

A common use for the data collected by SMS is to report on who has what—for instance, who has what disks, and how full they are.

As per the discussion, Access must be set up to link in the SMS data via ODBC, with the appropriate relationships among tables. Then a query can be created using the Simple Query Wizard. The Disk_Index0, File_System0, Storage_Type0, Free_Storage__Mbyte_0, and Storage_Size__Mbyte_0 fields from the dbo_vDisk table will be selected, along with GroupKey from the dbo_MachineDataTable and Name0 from dbo_Identification_Spec. This will be a detail query, called Disk Query, and it will be necessary to modify the query design after you finish with the wizard.

In the design view, you can specify that you don’t want to show the GroupKey, but you want it to have a value of 1 as the criteria so that you select the Identification table record when making the relationship between the vDisk and Identification_SPEC tables (via the MachineDataTable). You also specify that you don’t want to see records where the Disk_Index0 is equal to A, because you presume every machine has a diskette drive (whose characteristics you already know). With inserting columns, cutting, and pasting, the fields can be moved into a reasonable order. You can also specify that the query results should be sorted by the Name0 and then Disk_Index0 fields. More descriptive names can be given by right-clicking on each column and giving it a description in its Properties dialog box. A percentage of disk space free column can be added with the Expression Builder, which can be invoked by right mouse-clicking on the Field row of a new column and taking the Build… option (and yes, there is a percent free column in the vDisk table already, but for the purposes of demonstration, let's create our own expression). The expression can be given a format property of percent to make it more readable. The design view should look like Figure 44.2.

FIGURE 44.2. Design view of a query in Access.

The SQL view will be much like the following:

    SELECT DISTINCT dbo_Identification_SPEC.Name0, dbo_vDisk.Disk_Index0, dbo_vDisk.Storage_Type0,

    dbo_vDisk.File_System0, dbo_vDisk.Storage_Size__MByte_0, dbo_vDisk.Free_Storage__MByte_0,

    [Free_Storage__MByte_0]/[Storage_Size__MByte_0] AS Expr1

    FROM (dbo_vDisk INNER JOIN dbo_MachineDataTable ON dbo_vDisk.dwMachineID = dbo_MachineDataTable.dwMachineID)

    INNER JOIN dbo_Identification_SPEC ON dbo_MachineDataTable.SpecificKey = dbo_Identification_SPEC.datakey

    WHERE (((dbo_vDisk.Disk_Index0)<>"A") AND ((dbo_MachineDataTable.GroupKey)=1))

    ORDER BY dbo_Identification_SPEC.Name0, dbo_vDisk.Disk_Index0;

The query in the end will be in the form of Table 44.1—columns widths may need adjustment, and the data will vary, of course.

Table 44.1. The start of the output from the sample query.

Computer Name | Disk | Disk Type | Type | Size | Free | % Free
ABOYD | C | Fixed Disk, CMOS Type 65 | FAT16 | 602 | 365 | 60.63%
AFULTON | C | Fixed Disk, CMOS Type 0 | FAT16 | 1215 | 469 | 38.60%
AHALVERSON | B | Floppy Drive, 5.25 1.2M |  |  |  |

A report preview based on this query (but with different data) can look like Figure 44.3.

FIGURE 44.3. Report based on the sample Access query.

###
Extending the SMS Database

As we have seen, the SMS database is a wealth of information, but nonetheless it’s not omniscient—it doesn’t know everything about everything. Additional details that may be required can be collected and stored in the SMS database, and they can then be reported on or manipulated along with all the other information. The data that becomes the machine details in the SMS database starts out at the clients, where it is collected by the software and hardware inventories. The inventories write their findings to Management Information Format (MIF) files, in the \MS\SMS\NOIDMIF’s directory. This data is then collected and eventually stored in the SMS database. Every SMS Administrator should be comfortable with this process, which is well detailed in Appendix C, SMS System Flow, of the SMS v1.1 Administrator’s Guide. Other programs can also write MIF files to this directory, enabling collection of additional needed data.

####
Management Information Format Files

Management Information Format files are ASCII text files with a fairly straightforward format. Listing 44.1 is a typical MIF.

Listing 44.1. A representative Management Information Format (MIF) file.

    Start Component

     Name = "Data"

     Start Group

     Name = "Data Information"

     ID = 1

     Class = "Your Organization Name|Data Information|1.0"

     Start Attribute

     Name = "Files"

     ID = 1

     Type = String(5)

     Storage = Specific

     Value = "23"

     End Attribute

     Start Attribute

     Name = "Word Documents"

     ID = 2

     Type = String(5)

     Storage = Specific

     Value = "15"

     End Attribute

     End Group

    End Component

The formatting of this MIF should be fairly intuitive. The Name just after Start Group is the group name, as it will appear in the Personal Computer Properties window of the SMS Administrator program. This will also become the table name in the SMS database, except that spaces will be replaced with underscores, and _COMM and _SPEC will be suffixed to the common and specific tables, respectively. The attributes are then the columns of the table. The Name after Start Attribute is the column name. The IDs must be unique and increment appropriately. The Type can either be Counter or String, and if it’s a string, the maximum field length must be specified in parentheses and must not exceed 255. Counters are 32-bit integers. Storage specifies whether the value ends up in the common or specific tables. Value is the data to be recorded; strings must be within quotation marks.

Other parts of the syntax may be less intuitive. Class is the source of the data, as in who provided it, from which process, and which version. This is useful for analysis down the line if MIFs are found at a stage where the source is not obvious. In addition to ID, groups can also have a Key. This is necessary in those situations where there may be multiple instances of the group for a machine (disk drives being the example discussed earlier in this chapter).

An unsupported tool is provided by Microsoft to check for MIF file syntax validity. It can be found in the \PSSTools directory tree of the SMS CD-ROM and is called MIFCHECK.EXE. If there are any doubts about the syntax of a MIF, this tool should be used to check for problems.

> > MIFs can include many other details, useful in only the most advanced situations, which space does not allow discussion of here (see the BackOffice SDK discussion at the end of this chapter). In particular, MIFs can include details about architectures other than PCs, including completely new architectures. In these cases, the MIFs have to go in the IDMIFS directory of the client PCs. With no-ID MIFs, the architecture defaults to the current architecture. With ID MIFs, the architecture must be specified. If it is a new architecture, that architecture is automatically added in the SMS database.

####
Adding Groups

Adding groups to the inventory for an architecture is very simple. When the first MIF for that group is collected, the Inventory Data Loader will create the appropriate data structures to support that group—namely, specific and/or common tables and an entry in the GroupMap table. Once the group is added, any further MIFs for that group must be compatible with the first MIF’s definition. For instance, if the first MIF defines the datatype as a string of 10 characters, all further MIFs must also provide strings. If they’re longer than 10 characters, they will be trimmed to 10 characters.

Once the group is added, it will be displayed with the default icon. This may be acceptable, but if you want to use a more appropriate icon, one must be provided in a Dynamic Link Library (DLL), with appropriate changes to ensure it can be found by the SMS Administrator program when it is started. The icon can be created as a 32-pixel-by-32-pixel icon using an appropriate program, such as Visual C++’s Microsoft Developer Studio, or Visual Basic’s IMAGEDIT.EXE. Then a stub C program (see Listing 44.2) and resource definition files (see Listing 44.3) must be created and compiled to produce the DLL. Finally, the appropriate registry keys must be adjusted so that the DLL can be found.

Listing 44.2. A stub DLL source program for the resource DLL.

    // resdll.c - defines the minimal DLL entry point

    #include <windows.h>

    // stub resource DLL entry point

    BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReser_

    {

     // Nothing to initialize.

     return TRUE;

    }

Listing 44.3. The resource compiler source file for a resource DLL.

    // resdll.rc - defines a resource for an SMS resource DLL.

    #include <windows.h>

    // a Program Display Group icon (as seen in Machine Property windows)

    PDG_Personal_Computer_Disk ICON test.ico

The files are then compiled with the following commands, presuming Microsoft’s Visual C++ is appropriately installed:

    cl -DLL -c resdll.c

    rc docs.rc

    link -DLL resdll.obj docs.res

It’s necessary to run REGEDT32 to set up the registry so that the SMS Administrator will find this resource DLL—that is, on Windows NT 3.x. Use REGEDIT on Windows 95. You can use either REGEDT32 or REGEDIT on Windows NT 4.x. Then, under the HKEY_LOCAL_MACHINE hive, find SOFTWARE\Microsoft\SMS and add a new key (use Edit, Add Key) with a keyname of ResDLLs, no class name. With this new key selected, add a value with a value name of Installed and data type of REG_MULTI_SZ. With the Multi-String Editor dialog box, you can enter as many lines as there are DLLs to register. Each one must be given a unique name, such as ResDLL1. Then it will be necessary to add keys for each of the DLL names, spelled exactly the same as per the Multi-String Editor dialog box, and with no class. Finally, with each key selected in turn, these keys must have values added with the value name of PathName and Data Type of REG_SZ. The string for each will be the full path where the resource DLL file exists, such as C:\SMSADMIN\RESDLL.DLL.

> > If you want this special icon loaded only for yourself, when registering the key be sure to do it under the HKEY_CURRENT_USER hive while you’re logged in.

####
Collecting User Documents Information

Organizations spend a lot of money providing their staffs with computers, trusting that they are providing a useful tool to the workers. The computers may be used for a variety of tasks, such as client-server applications, but one of the primary uses will probably be office systems, as provided by Microsoft Office. The organization may want to collect information on how many documents users are producing with Office—not to monitor productivity necessarily, but to see how valuable Office is to the organization. This information could be critical to making decisions relating to training, upgrades, standardization, and so on.

With the popularity of Microsoft Office within large organizations, it is reasonable to expect that users will keep their documents within the My Documents directory tree, as recommended by Microsoft. If so, the batch procedure in Listing 44.4 quickly provides totals of the various kinds of directories.

Listing 44.4. Batch file to do the directory listings for the sample program.

    @ECHO OFF

    rem Get lists of the appropriate files, in all subdirectories, wide format

    rem (thus quicker to read), don't stop after each set of 24 lines, and

    rem don't include commas in the totals (easier to parse)

    DIR "C:\MY DOCUMENTS\*.DO?" /S /W /-P /-C > WORD_DIR.TXT

    DIR "C:\MY DOCUMENTS\*.XL?" /S /W /-P /-C > EXCL_DIR.TXT

    DIR "C:\MY DOCUMENTS\*.*" /S /W /-P /-C > ALLD_DIR.TXT

    rem turn the lists into a MIF

    SMS_DOCS

    rem erase the temporary files

    ERASE WORD_DIR.TXT

    ERASE EXCL_DIR.TXT

    ERASE ALLD_DIR.TXT

Listing 44.5 is a program that analyzes the directory listings and produces a MIF file. The program can be compiled with the command CL SMS_DOCS.C.

Listing 44.5. C program to analyze directory listings and create a MIF file.

    /* SMS_DOCS.c - Office document count .MIF file creation program (for use on SMS PC clients)

     - Paul Thomsen, August 20th, 1996

     - the idea is that we want to collect a count of all Word, Excel and similar

     documents under the C:\My Documents directory tree. Then we

     also want to store this info in SMS, with all the similar data

    */

    #include <stdio.h>

    #include <string.h>

    #include <time.h>

    FILE *mif; // the mif file (the output)

    FILE *tempnes; // the directory listing file (the input)

    char input_buffer[100];

    void get_numbers( char filename[40] );

    void create_mif();

    void read_line();

    void write_line();

    int files, sizes;

    void main()

    {

     mif = fopen( "C:\\MS\\SMS\\NOIDMIFS\\SMS_DOCS.MIF", "w" );

     create_mif();

     fclose( mif );

     }

    void create_mif()

    {

     int total_files=0, total_sizes=0;

     char temp_buffer[100];

     // start the file

     write_line( "Start Component\n" );

     write_line( " Name = \"MS Office Documents\"\n" );

     write_line( " Start Group\n" );

     write_line( " Name = \"MS Office Documents\"\n" );

     write_line( " ID = 1\n" );

     write_line( " Class = \"your organization|MS Office Documents|1.0\"\n" );

     write_line( " Start Attribute\n" );

     write_line( " Name = \"Word Files\"\n" );

     write_line( " ID = 1\n" );

     write_line( " Type = Counter\n" );

     write_line( " Storage = Specific\n" );

     get_numbers( "WORD_DIR.TXT" );

     sprintf( temp_buffer, " Value = %i\n", files );

     write_line( temp_buffer );

     total_files += files;

     // finish this value and start the next one

     write_line( " End Attribute\n" );

     write_line( " Start Attribute\n" );

     write_line( " Name = \"Word File Sizes\"\n" );

     write_line( " ID = 2\n" );

     write_line( " Type = Counter\n" );

     write_line( " Storage = Specific\n" );

     sprintf( temp_buffer, " Value = %i\n", sizes );

     write_line( temp_buffer );

     total_sizes += sizes;

     // finish this value and start the next one

     write_line( " End Attribute\n" );

     write_line( " Start Attribute\n" );

     write_line( " Name = \"Excel Files\"\n" );

     write_line( " ID = 3\n" );

     write_line( " Type = Counter\n" );

     write_line( " Storage = Specific\n" );

     get_numbers( "EXCL_DIR.TXT" );

     sprintf( temp_buffer, " Value = %i\n", files );

     write_line( temp_buffer );

     total_files += files;

     // finish this value and start the next one

     write_line( " End Attribute\n" );

     write_line( " Start Attribute\n" );

     write_line( " Name = \"Excel File Sizes\"\n" );

     write_line( " ID = 4\n" );

     write_line( " Type = Counter\n" );

     write_line( " Storage = Specific\n" );

     sprintf( temp_buffer, " Value = %i\n", sizes );

     write_line( temp_buffer );

     total_sizes += sizes;

     // finish this value and start the next one

     write_line( " End Attribute\n" );

     write_line( " Start Attribute\n" );

     write_line( " Name = \"Other Files\"\n" );

     write_line( " ID = 5\n" );

     write_line( " Type = Counter\n" );

     write_line( " Storage = Specific\n" );

     get_numbers( "ALLD_DIR.TXT" );

     sprintf( temp_buffer, " Value = %i\n", files - total_files );

     write_line( temp_buffer );

     // finish this value and start the next one

     write_line( " End Attribute\n" );

     write_line( " Start Attribute\n" );

     write_line( " Name = \"Other File Sizes\"\n" );

     write_line( " ID = 6\n" );

     write_line( " Type = Counter\n" );

     write_line( " Storage = Specific\n" );

     sprintf( temp_buffer, " Value = %i\n", sizes - total_sizes );

     write_line( temp_buffer );

     // finish this value and the file

     write_line( " End Attribute\n" );

     write_line( " End Group\n" );

     write_line( "End Component\n" );

    }

    void get_numbers( char filename[40] )

    {

     char number[15];

     files = 0;

     sizes = 0;

     if ( ( tempnes = fopen( filename, "r" ) ) == NULL )

     printf( "Couldn't open the %s directory listing\n", filename );

     // and if successful then do what we need to and close the file

     else {

     // get to the grand totals - while string not found and not end of file

     while ( ( strncmp( " Total Files Listed:", input_buffer, 24 )!=0 )

       && ( feof( tempnes )==0 ) )

     read_line();

     // get the actual totals file

     if ( feof( tempnes )==0 ) {

     read_line();

     strncpy( number, input_buffer+6, 10 );

     number[11]=0;

     // printf( "number: %s\n", number );

     files = atoi( number );

     strncpy( number, input_buffer+29, 10 );

     number[11]=0;

     // printf( "number: %s\n", number );

     sizes = atoi( number );

     }

     fclose( tempnes );

     }

     }

    void read_line()

    {

     char character=0;

     int i=0;

     // make sure the buffer is a null string before we start

     input_buffer[0]=0;

     // fill the buffer until end of file or end of line

     while ( !feof( tempnes ) && ( character != 10 ) ) {

     character = fgetc( tempnes );

     input_buffer[ i++ ] = character;

     }

     // make sure we know where the end of this line was

     input_buffer[i]=0;

     // for testing

     // printf( "reading: %s", input_buffer );

    }

    void write_line( char buffer[100] )

    {

     int i=0;

     while ( buffer[i] != 0 )

     fputc( buffer[ i++ ], mif );

     // for testing

     // printf( "writing: %s", buffer );

    }

A typical MIF file produced by the SMS_DOCS program is provided in Listing 44.6.

Listing 44.6. Output from the SMS_DOCS program.

    Start Component

     Name = "MS Office Documents"

     Start Group

     Name = "MS Office Documents"

     ID = 1

     Class = "your organization|MS Office Documents|1.0"

     Start Attribute

     Name = "Word Files"

     ID = 1

     Type = Counter

     Storage = Specific

     Value = 31

     End Attribute

     Start Attribute

     Name = "Word File Sizes"

     ID = 2

     Type = Counter

     Storage = Specific

     Value = 803804

     End Attribute

     Start Attribute

     Name = "Excel Files"

     ID = 3

     Type = Counter

     Storage = Specific

     Value = 29

     End Attribute

     Start Attribute

     Name = "Excel File Sizes"

     ID = 4

     Type = Counter

     Storage = Specific

     Value = 295332

     End Attribute

     Start Attribute

     Name = "Other Files"

     ID = 5

     Type = Counter

     Storage = Specific

     Value = 129

     End Attribute

     Start Attribute

     Name = "Other File Sizes"

     ID = 6

     Type = Counter

     Storage = Specific

     Value = 4555055

     End Attribute

     End Group

    End Component

A resource icon is also supplied with the sample program, in the ICON subdirectory (details the same as in the previous discussion). Figure 44.4 shows the data collected by SMS_DOCS program when viewed with the SMS administrator (once it has had a chance to go through the inventory collection system).

FIGURE 44.4. Information about Office documents, as collected by the SMS_DOCS program.

###
Interfacing Microsoft Word with SMS

Intuitively, one might think that word processing has little to do with managing PCs. Traditionally, this may have been true, but with a little imagination, SMS administrators can get Word to do a lot of their legwork for them. The most significant Word feature is mail merging, which can automatically produce paper or electronic mail based on data that SMS has collected, notifying users of various things SMS administrators think are important. If SMS administrators also have the Office Development Kit (ODK), they can write programs in Word Basic to further enhance their SMS reporting.

SMS administrators might use Microsoft Word with SMS to notify users that have certain software packages that training is soon going to be available. They might advise users that have more than 90 percent of their disks full that their disks are getting full, and thus it would be advisable to review their disk usage. SMS administrators might also include various common solutions to the problem. If users are found that are using nonstandard (or banned) software, administrators can send a stern message to them. By using Word, such tasks can be accomplished with a minimum of coding, and the message can include formatting, graphics, and effects to communicate the message and intent most effectively.

####
Mail Merging

The important aspect of Word mail merging for the SMS Administrator is that it can use SQL statements to collect the data to be merged with the document. The Word mail merge feature is based on the Microsoft Query engine, so the SQL syntax must be legal for Microsoft Query. Microsoft Query should be used to generate the SQL commands to collect the data and to test it to ensure that the correct data is collected.

Programming a mail merge-based report should start with creating a new template. A new document can then be created, based on this template, that contains the message to be sent to the users, complete with whatever formatting may be desired. Some of the text will vary from user to user, such as user name, software used, disk capacity, or whatever else the requirement may be. The points where the variable text (fields) will go should be left blank and bookmarks must be placed there. This is done by selecting the Bookmark item under the Edit menu. A bookmark can be added wherever the cursor is currently sitting. The Go To button of this dialog box can also be used to find the bookmarks later and to ensure they exist in the correct places.

Programming in Microsoft Word is done with Word Basic in routines called macros. The macros can be created by selecting Tools, Macro from the menu. For simplicity, the program should be split into two routines—one to ask the user where the database is and how to log into it, and another to actually do the work.

The first routine should probably be automatically executed when the master document is opened, and thus must be called AutoOpen. It should display a dialog box asking for the ODBC data source, the SQL Server user identification, and the corresponding password. See the Using ODBC section earlier in this chapter for a discussion of setting up an ODBC data source.

The code that actually does the work should start with a MailMergeMainDocumentType 0 statement in order to tell the mail merge to activate the loaded (and currently visible) document. The collection of the data is done with a MailMergeOpenDataSource command, with the significant switch being .SQLStatement, which is the SQL command generated and tested in Microsoft Query. It is then necessary to ensure that the main document is ready for mail merging, with a MailMergeEditMainDocument command. Associating the collected data with the bookmarks previously set up can be done by first going to the bookmarks with an EditBookmark .name="name of bookmark", .SortBy=-1, .Goto command, and then inserting the field name with InsertMergeField .MergeField="column name", .WordField=-1. Finally, the merging of data and document is done and printed by executing MailMergeToPrinter.

> > One common problem is that SQL statements can be very lengthy, but Word Basic has limits on how long strings (which contain the SQL statements) can be. This is solved by using additional .SQLStatement switches on the MailMergeOpenDataSource command, such as .SQLStatement1. The strings in the .SQLStatement switches must still be a valid SQL command when they are concatenated.

Mail merging can also send the generated documents to the user via MAPI-based mail, such as Microsoft Exchange or Microsoft Mail. The SQL statement used to collect the data in the MailMergeOpenDataSource command should be extended to include fields from the SMS database that contain the e-mail address of the users. The MailMerge command can be used to send the documents via e-mail, and it has additional switches to associate the appropriate column with the e-mail address. Check out the ODK for details on this and other mail merge features.

With the template (and its macros) and the main document saved, the program is ready to run. The simplest way is to open the main document, which will activate the initial routine, prompting the administrator for login details. With these entered, the link will be made, the data collected, and the print initiated. This process may take a minute or so, depending on the data being collected and the size of the database being scanned. For development and testing purposes, it may not be desirable to repeatedly close and open the document in order to initiate the program, so the Run button from the Macro dialog box (Tools, Macro) or from the macro toolbar can be used.

####
Accessing SMS from Word Basic

Word Basic, which is much like Visual Basic, is a powerful, easy-to-program language. With the powerful benefits of mail merging and word processing, as just discussed, SMS Administrators may want to do significant programming using it. The only significant problem they will discover is accessing the SQL Server database where the SMS data resides. Word Basic doesn’t have commands (other than mail merging) to do this. This problem is rectified with a dynamic link library (DLL) called WBODBC.WLL (WLLs are Word DLLs).

WBODBC.WLL is an unsupported library distributed with the Office Development Kit, and is documented in an appendix of the ODK’s documentation. There is also a copy of this program included with the BackOffice SDK; however, that version is a 16-bit version, and thus only works with Word for Windows, in the Windows 3.x environment.

WBODBC.WLL provides functions to do various things with ODBC databases, such as open and close links, submit queries, retrieve the associated data, figure out how much data is available, and so forth. With Word Basic, the programmer can then list data collected in dialog boxes, allowing the user to review it or make selections.

####
Sample Word Interface to SMS

This program will demonstrate how to use Microsoft Word’s mail merging feature to prepare documents to advise users who are running low on disk space. As an example main document we’ll use the following letter:

    Dear ,

     A review of records finds that your personal computer’s C: disk

    drive is % full. This could soon lead to problems when your disk does

    fill up. You may not be able to create or save documents that you are

    working on, or you may not be able to install new programs that you

    may require.

     We would like to suggest, when you get a few minutes, that you

    review what is on your hard disk to see whether anything can be

    removed. Common possibilities are old programs or old documents. If

    you are uncertain as to which files to remove then please don’t

    hesitate to contact the helpdesk.

     Thank you for your attention to this matter.

Notice that there is no word after Dear, and the percent sign has no number before it. These are where the SMS data will be substituted, so there are bookmarks at each of these points, called Username and Percent, respectively.

The AutoOpen macro prompts the user for login information (see Listing 44.7):

Listing 44.7. AutoOpen macro for sample Word interface.

    'mail merging using SMS dat

    Sub MAIN

     UID$ = "sa"

     PWD$ = ""

     DSN$ = "SMS"

     Begin Dialog UserDialog 660, 216, "Connection Information"

     Text 12, 46, 196, 13, "ODBC Connection Name: ", .Text5

     TextBox 218, 44, 160, 18, .DSN$

     Text 14, 9, 447, 13, "Fill in the following information and press OK when finished", .Text6

     Text 14, 76, 113, 13, "SQL Logon ID:", .Text7

     TextBox 217, 75, 160, 18, .UID$

     Text 14, 106, 73, 13, "Password", .Text8

     TextBox 217, 106, 160, 18, .PWD$

     OKButton 529, 23, 88, 21

     CancelButton 529, 47, 88, 21

     End Dialog

    Dim GetUserInfo As UserDialog

     GetUserInfo.UID$ = UID$

     GetUserInfo.PWD$ = PWD$

     GetUserInfo.DSN$ = DSN$

     If Dialog(GetUserInfo, - 1) = 0 Then

     MsgBox("Operation Canceled")

     Else

     UID$ = GetUserInfo.UID$

     PWD$ = GetUserInfo.PWD$

     DSN$ = GetUserInfo.DSN$

     ODBCstr$ = "DSN=" + DSN$ + ";UID=" + UID$ + ";PWD=" + PWD$ + ";DATABASE=SMS"

     Call SMS.MAIN(ODBCstr$)

     End If

    End Sub

Listing 44.8 is the SMS macro, called at the end of AutoOpen.

Listing 44.7. The SMS macro.

    Sub MAIN(ODBCstr$)

    MailMergeMainDocumentType 0

    'the Microsoft Query style SQL statement to get the data

    statement$ = "SELECT Name0,__Disk_Full0 FROM Disk_COMM,Disk_SPEC,MachineDataTable,vIdentification WHERE SpecificKey=Disk_SPEC.datakey AND CommonKey=Disk_COMM.datakey AND MachineDataTable.dwMachineID=vIdentification.dwMachineID"

    'continuation of statement$

    statement1$ = " And Disk_Index0='C' AND __Disk_Full0>90 AND GroupKey=8"

    'get the data for the mail merge

    MailMergeOpenDataSource .Name = "", .ConfirmConversions = 0, .ReadOnly = 0, .LinkToSource = 0, .AddToMru = 0, .PasswordDoc = "", .PasswordDot = "", .Revert = 0, .WritePasswordDoc = "", .WritePasswordDot =
    "", .Connection = ODBCstr$ + ";APP=Microsoft Query", .SQLStatement = statement$, .SQLStatement1 = statement1$

    'indicate where the data should go in the document

    MailMergeEditMainDocument

    EditBookmark .Name = "Username", .SortBy = 0, .Goto

    InsertMergeField .MergeField = "Name0", .WordField = - 1

    EditBookmark .Name = "Percent", .SortBy = 0, .Goto

    InsertMergeField .MergeField = "__Disk_Full0", .WordField = - 1

    'do it!

    MailMergeToPrinter

    End Sub

The attentive reader will notice the use of MachineDataTable in addition to the SMSVIEW views in the SQL statement. This was done because the SMSVIEWS use double outer joins, which Microsoft Query does not have good facilities to handle (the HAVING clause does help in many cases). It is tricky to ensure that records are not collected that are not appropriate. Partially bypassing the views can avoid this problem. Microsoft Access has a more sophisticated SQL syntax and thus doesn’t have this problem.

When the main document is opened, AutoOpen gets the login information from the user, and then calls the SMS macro, producing letters such as the following for all the users that have more than 90 percent of their C: drives full:.

    Dear JGilbert,

     A review of records finds that your personal computer’s C: disk

    drive is 95% full. This could soon lead to problems when your disk

    does fill up. You may not be able to create or save documents that you

    are working on, or you may not be able to install new programs that

    you may require.

     We would like to suggest, when you get a few minutes, that you

    review what is on your hard disk to see whether anything can be

    removed. Common possibilities are old programs or old documents. If

    you are uncertain as to which files to remove then please don’t

    hesitate to contact the helpdesk.

     Thank you for your attention to this matter.

###
Other SMS Programming Interfaces

SMS offers several other programming interfaces that may be of interest to you. They provide some powerful options; however, they are much more complicated to implement than those you have looked at so far. They also rely upon the BackOffice Software Development Kit (discussed in the Summary of this chapter) due to the requirement for headers, libraries, and so forth. The BackOffice SDK includes fairly good documentation on these programming interfaces. Given these factors, you should check this out if you require these options. Only a brief description is provided here.

####
SMS API

There is a powerful application programming interface for SMS that provides the opportunity to view and manipulate data objects in much the way that SMS itself manipulates them. The programmer can manipulate jobs and packages, as well as work with architectures, security details, and all the other data objects of SMS.

The SMS API requires learning the terminology of SMS’s internals and how they relate to each other. Programs can be developed in C or Visual Basic. Approximately eight sample programs are supplied, many of which are potentially useful or interesting in themselves. You may want to explore this area of SMS programming even if no particular applications are currently in mind.

####
Packages

Preparing packages to install programs is usually fairly straightforward, as any experienced SMS administrator will know. The SMS Administrator provides a nice facility to create packages and set appropriate options. There are also additional package options available—you may have observed this from more advanced packages provided by Microsoft or other vendors.

The BackOffice SDK does include a discussion of creating packages to do installations. This mostly involves details relating to package definition files and the considerations under which these files are used.

####
Extending the Network Monitor

The network monitor is a powerful utility, useful for resolving some kinds of computer management problems, but it is not strongly related to SMS. The SMS Administrator can be used to initiate the network monitor for a particular computer, but otherwise the two are separate products. Recognizing these factors, Microsoft has now made the network monitor available with Windows NT 4.0.

The BackOffice SDK provides the resources necessary to extend the Network Monitor, regardless of whether it is used with SMS. The extensions enable the Network Monitor to understand protocols that Microsoft has not yet provided parsers for (an example of which is DECnet). A new parser can be used by creating and registering a DLL, which is called at predefined functions and which should use various functions and data structures that Network Monitor provides. Note that DLLs are normally created in the C programming language.

###
Summary

This chapter provided you with many details on programming solutions with SMS. With a good understanding of the SMS database, interfacing SMS with Word or Access provides the programmer powerful yet easy-to-use facilities to use the data collected by SMS. The SMS administrator can also readily extend the SMS database to collect other data that may be required. Other programming options enable the programmer to extend the network monitor, use packages more effectively, or manipulate SMS objects.

Combined with reviewing the sample code provided on this book’s CD-ROM, you should be able to work out any details needed to implement your own solutions. Microsoft’s BackOffice Software Development Kit (SDK) is an excellent source for a more in-depth discussion of these topics. The BackOffice SDK (at least the SMS-related materials) are good for reference purposes, but often presume details that may not be obvious to the novice SMS programmer. BackOffice Unleashed is a good source to start on this advanced topic, and the BackOffice SDK can be used to build on that knowledge. The BackOffice SDK has been included with the Microsoft Developers Network subscriptions on occasion and is also an important part of the Microsoft Solutions Development Kit. See http://www.microsoft.com/catalog/products/msdk/default.htm for more details.