• No results found

Scripting MetaFrame

N/A
N/A
Protected

Academic year: 2020

Share "Scripting MetaFrame"

Copied!
82
0
0

Loading.... (view fulltext now)

Full text

(1)

Scripting MetaFrame

By Dr. SDK

© Copyright 2003

(2)

The information presented in this document is subject to change without notice.

THISPUBLICATIONISPROVIDED.ASIS.WITHOUTWARRANTIESOFANYKIND,EXPRESSOR

IMPLIED,INCLUDINGANYWARRANTIESOFMERCHANTABILITY,FITNESSFORAPARTICULAR

PURPOSEORNON-INFRINGEMENT.CITRIXSYSTEMS,INC.(“CITRIX”)SHALLNOTBELIABLEFOR

TECHNICALOREDITORIALERRORSOROMISSIONSCONTAINEDHEREIN,NORFORDIRECT,

INCIDENTAL,CONSQUENTIALORANYOTHERDAMAGESRESULTINGFROMTHEFURNISHING,

PERFORMANCE,ORUSEOFTHISPUBLICATION,EVENIFCITRIXHASBEENADVISEDOFTHE

POSSIBILITYOFSUCHDAMAGESINADVANCE.

Copyright and Trademark Notice

Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Citrix Systems, Inc.

Copyright © 2003 Citrix Systems, Inc. All rights reserved.

Citrix, ICA (Independent Computing Architecture), and WinFrame are registered trademarks, and MetaFrame, MetaFrame XP are trademarks of Citrix Systems, Inc. in the United States and other countries.

Trademark Acknowledgements

(3)

Table of Contents

1 INTRODUCTION...5

2 METAFRAME MANAGEMENT TOOLS...6

3 WHY IS SCRIPTING METAFRAME POSSIBLE...7

4 WHAT IS MFCOM ...8

4.1 PROGRAMMING INTERFACE FOR ADMINISTRATORS...8

4.2 INTERFACE FOR SOFTWARE INTEGRATION...8

4.3 AN NTSERVICE...9

4.4 ACOMINTERFACE FOR THE IMA...11

5 SIMPLIFY YOUR DAILY TASKS...13

6 MFCOMBASICS...14

6.1 DATA TYPES...14

6.2 OBJECTS...14

6.3 INTERFACES...15

6.4 COLLECTIONS...16

6.5 ARRAYS...17

6.6 TIME OBJECT...18

6.7 USER DEFINED COLLECTIONS...18

6.8 IDOBJECT...19

6.9 CREDENTIAL OBJECT...19

6.10 MULTI-STRING OBJECT...20

7 MANAGING FARM...20

8 MANAGING SERVERS...24

8.1 ENUMERATING SERVERS...24

8.2 LISTING HOTFIXES...27

9 MANAGING PUBLISHED APPLICATIONS...29

9.1 APPLICATION NAMES...30

9.2 APPLICATION-SERVER BINDING...33

9.3 BATCH PUBLISHING OF APPLICATIONS...35

9.4 PUBLISHING APPLICATIONS USING APSDK ...40

9.5 DISPLAYING APPLICATION PROPERTIES...42

9.6 MANAGING APPLICATION USERS...44

10 MANAGING SESSIONS AND USERS...46

11 MANAGING ADMINISTRATORS...46

12 MANAGING LICENSES...48

(4)

15 WEB INTERFACE...58

16 GATHERING AND REPORTING DATA...67

17 WORK AROUND BUGS...71

18 SCRIPTING METAFRAME 1.8 ...72

(5)

1

Introduction

It took me a while to come up with this title. Originally I was thinking along the line of the other existing MetaFrame documents to name this document something like MFCOM Advanced Concept Guide. It would be good enough to the extent that it clearly states the purpose of the document. Then I had a second thought. Because this document is intended to be read by many people inside and outside of Citrix, I thought a sexier name should be given to it to just attract people’s attention. So that they will at least flip through a few pages just to find out what this document is really about upon hearing the title.

If I were to write a store about a female scientist working on the hydrogen bomb1, a good title like The Bikini Woman would sound attractive enough. Although many readers would possibly be disappointed to find out that the subject never wore any bikini but rather were more in love with equations like

E=MC2, it would at least get a lot more people’s attention. Who knows if some of the readers would really be people who just love pictures of woman in bikini but also serious scientists who really enjoy reading stories about how the hydrogen bombs were made.

To our readers, Scripting MetaFrame sounds sexy enough, at least from my point of view. First of all, scripting is always something many Windows users find interesting and exciting. Scripting Unix would have been a poor title for any UNIX documents but scripting anything in Windows world would be something people look for.

The simple truth is that scripting management and other tasks in MetaFrame environment has not been considered a valid idea. Citrix includes some command line tools for certain tasks. But comparing to the highly integrated and graphical user interface Citrix Management Console (CMC), those tools are too few and too preliminary. Their existence is probably only known to the few administrators who really needed to perform those tasks and might have searched all through the CMC menus and then ended up with those command line tools.

There is no attempt to belittle CMC here. It’s one of the few very important reasons people say that MetaFrame XP is better than MetaFrame 1.8. Instead of some individually developed GUI tools, CMC is an integrated all-in-one tool that allows an administrator to do everything from one single

management console. Most administrators love this nicely designed and developed GUI interface. For hard core and seasoned MetaFrame administrators, they would also like the ability to perform routine tasks without having to click through many menus in the CMC. I would bet everyone would prefer a single command line to add a user to a published application over the CMC interface where you have to do quite a few mouse clicks.

I think most people would agree that scripting and command line tools are useful to system

administrators even for the ones who use Windows GUI tools all the time. This is a world in which efficiency and speed are often the utmost important things. So, if there’s anything that helps to get certain tasks done faster, then eventually people will like it (or at least be forced to like it, if not voluntarily).

1 I don’t know if I am making a valid assumption here. So far I don’t know there were any women scientists who actually

(6)

link the enormous power of the MetaFrame SDKs and with the real world problems MetaFrame users and administrators face everyday. People are intimidated when they hear the word SDK because the D stands for Development. This may turn many people off simply by thinking about learning new interfaces and writing code.

COM and VBScript have turned many users into developers. The short learning curve to write scripts and the tight integration of objects in VBScript have made it possible for people who don’t have extensive training and experience in C++ to be able to successfully write small but efficient and useful tools to make their software management tasks far easier.

We intend to tell people in this document that almost anything you can do through the CMC can be scripted. Although certain tasks may be more easily performed by using CMC, other tasks that should be scripted ought to be known by every MetaFrame administrator. We don’t want to call this

document Advanced Concept because the concepts presented in this documents are really not that advanced to require additional knowledge about programming. Any competent MetaFrame

administrator should have no problem understanding the concepts described in the next few sections. Although knowing programming in Visual Basic definitely gives a big advantage to the administrator who wants to do scripting, not everything about Visual Basic is required for someone to write decent VB scripts. Actually most people will find that by modifying some existing VB scripts, they can build a custom tool very quickly.

This document is not intended to advocate learning VB scripting nor using the Citrix SDKs. Our purpose it to let people realize the power of the SDKs so that they can take advantage of the power to improve the efficiency of administrative tasks. So, instead of presenting all the details the SDKs (particularly MFCOM) can do, we want to look at the things from a typical MetaFrame administrator’s point of view and offer solutions to the tasks that are faced by most of the administrators everyday.

2

MetaFrame Management Tools

The tools used by MetaFrame administrators include the Citrix Management Console (CMC) and some command line utilities. The CMC is an integrated graphical user interface. It is written in Java. The CMC can run on a MetaFrame server but also has the ability to run on a standalone system. When it is running on a non-MetaFrame server, it remotely connects to a MetaFrame server. In this section, we describe some of the properties of CMC from the perspective of how performing the same tasks may be improved when they are scripted. Detailed descriptions of the CMC and its use are found in the MetaFrame XP administrator’s guide.

(7)

The CMC is designed to allow an administrator to perform almost all the common MetaFrame management tasks from one place. The CMC can be used to manage the following MetaFrame resources.

Farm. Properties and configurations that affect the entire farm.

Servers. Properties and configurations that are applicable to a single server.

Applications. Published applications and contents. Parameters and configurations. Sessions. Static and dynamic information about all the sessions on each server. Administrators. Properties and privileges of all farm administrators.

Policies. Properties and configurations.

Since it is a graphical user interface, objects are located using the mouse to point and click on them. A tree structure is a natural choice in presenting the objects in a hierarchical way. For example, servers and applications are displayed in folders, similar to directories for files.

3

Why Is Scripting MetaFrame Possible

The short answer is that we have MFCOM, which provides an API interface to CMC.

Ultimately the nature of the tasks determines if they are scriptable. A task can be scripted if it meets the following criteria:

No excessive graphical operation. Both the input and output do not contain or contain very little graphical data. Graphical operations definitely can’t be scripted easily. Visualization of these operations is a very important part of the task itself. We should not confuse this with the tasks that operate on graphical data files. Those tasks may be scriptable. Fortunately in MetaFrame XP we don’t need to worry much about this type of tasks.

No excessive amount of user input. This would simply translate into too many command line parameters for the scripts that process the tasks.

No excessive user interaction. Scripts can be written to take user inputs during the execution of the task. But if there are too many user interactions, a graphical user interface is a better

choice.

Single purposed. A simple algorithm can then be developed based on the requirements. If the task is too complicated to be accomplished using a few single steps, it should be programmed using other high level programming languages such as C++.

Yields well defined results. Output data will then be easy to present. At most the data may be dumped to a file but it should still be easy to organize.

Small and repetitive. These tasks are ideal candidates for scripting. These tasks would otherwise take more time to perform using a GUI tool because the items in the user interface need to be identified first. The identification process takes time because the task is small, which is often located in pages after some mouse clicks. The most common tasks (big tasks) are often presented more visibly in most GUI tools for quick access.

Operates on large amount of data in simple format. A typical script should solve these types of tasks by creating a loop that process each block of the data in the same format. These tasks are not suitable for GUI interfaces. Looping as a human action translates into boredom,

(8)

graphical data presented in CMC, except some Resource Manager (RM) data. Since MFCOM doesn’t have the equivalent calls for accessing RM tasks, they are not applicable in this discussion. Other CMC data are mostly text data. Many tasks are simple enough but may be repetitive, e.g., publishing and managing applications.

Although we have tried to be more scientific in the above analysis, in reality, people often have an intuition and inclination to script certain tasks. The best person who decides what can be scripted and should be scripted is the person who actually performs the tasks. This is why MFCOM should be made accessible and usable by not only well versed C++ programmers but also system administrators who are used to sending simple commands to the systems. Scripting offers a bridge between extensive programming and simple command controls.

In summary, MetaFrame administrative tasks are scriptable because of their own nature. MFCOM simply makes this type of scripting possible. People would have asked for such an interface if there was no MFCOM.

On the other hand, if something should be scripted is not being scripted, the efficiency is lost.

4

What Is MFCOM

It’s not hard to decipher the name MFCOM. As long as an interpretation puts MetaFrame and COM together, it suffices to be a short explanation of the word. So, MetaFrame COM, MetaFrame COM Object, and MetaFrame COM Interface are all valid long names of MFCOM.

4.1

Programming Interface for Administrators

MFCOM can be further explained from several different views. From the view of a MetaFrame developer, it is a programming interface for the administration of MetaFrame XP farms and servers. Since the CMC accomplishes basically the same purpose but is packaged as a graphical user interface tool, MFCOM can be described as a programming interface for the CMC. This is probably the most precise definition for MFCOM, although the role of MFCOM may be extended to tasks outside of the CMC. So far this definition is valid.

To a MetaFrame XP administrator, MFCOM provides a scripting interface, which allows him to create tools for tasks that are frequently performed but would otherwise take more mouse clicks if the same tasks are carried out in CMC.

4.2

Interface for Software Integration

To a developer, MFCOM provides the calls for him to integrate MetaFrame XP management functions into another software platform. The richness of the calls available from MFCOM makes this

(9)

To an end MetaFrame user, MFCOM’s effect is limited. This is largely due to the fact that MFCOM provides a management interface that is not accessible by an end user. Because this is an SDK, end users are not the targeted customers of MFCOM. But this situation may change as we are continuing to improve and enhance MFCOM. In future releases MFCOM may offer calls visible to end users.

4.3

An NT Service

Looking from inside, MFCOM runs on a MetaFrame XP server as an NT service. It can be controlled by an administrator using the Windows Control Panel or commands. The service is automatically started when the system boots. If the service has been stopped for any reason, the next connection request to MFCOM will cause the operating system to automatically start it.

The service’s process is mfcom.exe, which can be found in the Windows Task Manager’s window. The executable file, mfcom.exe, is typically installed under the %SystemRoot%\System32

directory.

A set of registry entries define MFCOM as an NT service to the operating system. The registry key

HKLM\SYSTEM\CurrentControlSet\Services\MFCOM has sub-keys and values that are required

to define MFCOM as an NT service as well as settings to control MFCOM. The following is a table of the keys and values, which are all under the previously mentioned key.

Key or value Data type Default setting

DebugOutput2 DWORD 0

DependOnGroup MULTI_SZ

DependOnService MULTI_SZ RPCSS WMI

Description SZ Provides access to MetaFrame farm DisplayName SZ MetaFrame COM server

ErrorControl DWORD 0

FlushTraceFile DWORD 0

ImagePath EXPAND_SZ C:\WINNT\System32\mfcom.exe

IMAWaitPause DWORD 30000

IMAWaitTimeout DWORD 600000

ObjectName SZ LocalSystem

Start DWORD 2

TraceBufferSize DWORD 0

TraceFile SZ

Type DWORD 16

Enum Key3

Enum\0 SZ Root\LEGACY_MFCOM\0000

Enum\Count DWORD 1

Enum\NextInstance DWORD 1

Security Key

Security\Security BINARY Binary data4

TraceLevel5 Key

2 These shaded entries (of this particular color) are only created by the debug version of MFCOM. Retail versions don’t

create and recognize these entries.

(10)

TraceLevel\Automation DWORD 0

TraceLevel\Collection DWORD 0

TraceLevel\Enumeration DWORD 0 TraceLevel\Initialization DWORD 0

TraceLevel\Method DWORD 0

TraceLevel\ObjectCount DWORD 0

TraceLevel\Property DWORD 0

TraceLevel\ReferenceCounting DWORD 0

TraceObject Key

TraceObject\AccountAuthority DWORD 0 TraceObject\Application DWORD 0 TraceObject\AppServerBinding DWORD 0

TraceObject\Channel DWORD 0

TraceObject\Event DWORD 0

TraceObject\Farm DWORD 0

TraceObject\Folder DWORD 0

TraceObject\Group DWORD 0

TraceObject\License DWORD 0

TraceObject\Process DWORD 0

TraceObject\Server DWORD 0

TraceObject\Session DWORD 0

TraceObject\User DWORD 0

TraceObject\Zone DWORD 0

The shaded entries are those created and used by MFCOM. Some people may argue that these entries should be placed under something like HKLM\Software\Citrix\MFCOM or

HKLM\SYSTEM\CurrentControlSet\Control\Citrix\MFCOM. We have created these entries

here because these are the only ones used by MFCOM as an NT service and a regular NT process. If we created more entries, we probably would have put them at more appropriate places.

The other reason is that for most users, most of the entries are not created and not visible. Most of the MFCOM entries are only created by the debug build of MFCOM. In fact only two entries,

IMAWaitPause and IMAWaitTimeout are created by the retail version of MFCOM. The debug entries are listed here as a reference for users who just happen to run the debug build. The debug registry entries will probably be phased out in the future since a new and better way of tracing all Citrix modules have been developed and the MFCOM code is gradually being migrated to using the new method.

MFCOM depends on the IMA service, which is not listed in the list for the entry DependOnService. This is to resolve some issues that could result during the start and stop of both services. The

dependency is implemented in another way in MFCOM. To make sure that IMA is running before it should access IMA, MFCOM uses polling to detect the availability of IMA.

The value of IMAWaitPause tells MFCOM how often it should poll for the status of IMA. This is the

amount of time MFCOM puts itself to sleep in between two polling calls. The time unit is in millisecond, so the default setting for this entry is 30 seconds. The value of IMAWaitTimeout

specifies the total amount of time MFCOM should wait for IMA to come up. It is also in millisecond, so the default setting for this entry is 10 minutes. For most configurations, this timeout value should

(11)

be more than sufficient as experiments have shown that for typical configurations IMA service starts up in less than 3 minutes.

If you receive error messages and event log messages about MFCOM cannot be started and everything else seems to be fine, try to increase the timeout value. If within that timeout value IMA should have been started and yet MFCOM still cannot be started after the timeout, something else may need to be checked to fix the problem.

The un-shaded entries are required by the operating system. They tell the system where the image of the service is and how the service should be started. Additional information, such as the service description, is also saved here for the NT service control manager (SCM) to use. Most of these entries are created and used by the SCM.

4.4

A COM Interface for the IMA

Finally, MFCOM is a COM server, which exports COM objects supported by interfaces, through which the objects’ properties and methods can be accessed by a COM client. To help understanding this description, we can look at the physical impact to the system and the effect to the COM runtime by running MFCOM. Then we can see how the COM clients, COM runtime, and MFCOM work

together.

MFCOM as a COM object lets itself known to the system by registering itself to the system. The registration basically consists of two parts. One is creating the necessary registry entries so that persistent information about the MFCOM’s objects and interfaces can be preserved. The other part is linking itself with the COM runtime.

A list of registry entries created by MFCOM attached at the end of the document in appendix A. The list is long because all the objects and interfaces must be described and MFCOM has many objects and interfaces.

The registry information is used by both the COM runtime and COM clients to find and connect to MFCOM. A couple of the registry entries are highlighted. They are

HKLM\SOFTWARE\Classes\TypeLib\{ED62F4E0-63C2-11D494D8-00C04FB0F326} and

HKLM\SOFTWARE\Classes\AppID\{ED62F4E0-63C2-11D494D8-00C04FB0F326}. The

Typelib entry tells COM runtime the ID of the type library, which contains everything about the

MFCOM objects and interfaces. Basically a type library is a binary form of the interface description (IDL) file. From the description stored in the type library, a COM client will be able to use the properties and methods with the correct data type information for the parameters.

The AppID entry is used when MFCOM acts as a DCOM server. A DCOM client uses this key to find the remote server on which MFCOM is running. This key is created on both the MFCOM server and the client’s machine. The values under this key are different on the server and the client. On the client machine, a remote server name is specified. This remote server name can also be specified using the

DCOMCNFG utility, which will be described in more detail in a later section on DCOM.

(12)

database of all the COM servers. We can imagine that there is a cross reference table stored in the COM runtime database. This table stores some pointers to the MFCOM functions for various tasks. Other things like security are also initialized during the MFCOM registration.

Now we should be ready to walk through a typical scenario when a COM client makes a request to connect to a COM server and create an object. For simplicity, we exclude DCOM in the discussion. Extra steps involving DCOM are discussed in more detail in the section on DCOM.

A COM client typically issues a call similar to the VBScript CreateObject method. An object identifier is given as the parameter to this method. This identifier looks something like

MetaFrameCOM.MetaFrameFarm. The COM runtime knows the process, in this case mfcom.exe, to which it should connect to make a RPC (Remote Procedure Call) call. The process may look like the following:

1. COM goes to the registry entry HKLM\SOFTWARE\Classes\MetaFrameCOM.MetaFrameFarm

to get the the GUID of this object, {ED62F4E2-63C2-11D494D8-00C04FB0F326}. 2. From the given GUID, COM uses the data in the registry entry

HKLM\SOFTWARE\Classes\CLSID\{ED62F4E2-63C2-11D494D8-00C04FB0F326} to get the process in which the object should be created as well as the type library, from which everything about the object can be found.

3. COM then calls the class factory exported by MFCOM to create an object. The class factory has been registered during the MFCOM registration. Now COM is using it. The created object resides in the MFCOM process and its pointer is returned to COM, which marshals it, if necessary, and then return the marshaled pointer to the COM client.

4. Then some QueryInterface calls may be made by the COM runtime to the newly created object. A series of such calls may be made for an automation client like VBScript. In particular, the IDispatch interface is queried.

5. Unless the client specifically queries for a particular version of the interface supported by the object, the default interface (specified in the type library) is used by the COM runtime to resolve calls made to the object.

6. When the client uses the returned pointer to make a call to one of the methods, COM does the necessary marshalling of the parameters, finds the pointer to the function in MFCOM and makes the call. The marshalling information is available from the type library.

7. The result of the call is marshalled and returned to the COM client.

The above process is highly optimized by the COM runtime. COM doesn’t read the registry entries every time it creates an object. The QueryInterface calls are cached. And most importantly, behind the scenes object referencing counting is meticulously maintained by the COM library for the COM clients. For a C++ client, however, many things still need to be taken care of by the

programmer.

(13)

5

Simplify Your Daily Tasks

The previous sections are preparatory for the contents from hereon. We have discussed the reasons for scripting and looked at MFCOM from different perspectives in detail. In this section we will discuss the types of administrative tasks that may be good candidates for scripting. Then in the following sections we examine some commonly scriptable tasks and present and analyze some working scripts. The most common tasks include monitoring and control user sessions. Sessions contain the most dynamic data in MetaFrame environment. Administrators gather session information to gain

knowledge about the health of the farm and fix problems that may arise. Statistical information helps the system administrators to gauge the load of the farm with respect to certain applications and user count. Also, some firms may charge end users for resource usage. It is essential to be able to know everything about the sessions in the entire farm and on specific servers.

Managing published applications is another task that requires frequent attention. Although publishing applications seems to be a one time event that requires concentrated effort at the beginning of the MetaFrame XP deployment, application parameters often change. Users may be added or removed from a published application. Servers that go offline may be removed from the application’s server list.

The farm and the servers themselves need constant attention. Some parameters may need adjustment from time to time.

Printers and policies are two other things that may consume a large portion of an administrator’s time in certain environments.

The Resource Management (RM) component of CMC offers reporting capabilities. But what if people need to gather reports in finer granularities or real-time data?

All the above tasks are good candidates for MFCOM scripting. Few people probably would have thought that policy management may be scripted. Even fewer people would have thought that

MFCOM offers reporting capabilities that compliment the RM data. But all of the above are possible, as we will demonstrate in the next few sections.

Since in the examples we will use VB scripts extensively, it’s worth to offer a few general guidelines here regarding scripting.

First of all, I don’t know a good tool to assist writing VBScripts. So far all the scripts included in the document have been written using plain text editors. The good news about this fact is that the reader is not burdened to learn to use a new tool. The bad news is that many times the properties and methods of an object and interface are not easily remembered.

(14)

Another way is to pick some existing examples from the SDK and modify them. We have created many scripts using this method quite efficiently.

6

MFCOM Basics

Before we go deeper into specific topics, let’s spend some time looking at some of the basic MFCOM objects, interfaces, and data types so that we can have a good understanding of the mostly used concepts.

6.1

Data Types

MFCOM defines many data types. Most of them are defined to provide user-friendly names for the constants used by the various properties and methods. Without these friendly names, the values returned by the properties would be hard to describe and to remember. The enum types also make it

possible for certain compilers and programming tools to check the syntax for many calls so that run-time errors may be avoided.

To use the data types in scripting languages, a reference to the COM library must be made so that the type information included in the type library can be made available to the script statements6. In every

WSH script, the following line must be included in the script header.

<reference object="MetaFrameCOM.MetaFrameFarm"/>

Although the reference is about the farm object, any other MFCOM object may be referenced. An alternative is to specify the GUID of the MFCOM type library. But since this requires a GUID, which is not easily remembered as the object names, rarely this method is used. Below is an example of such a reference statement7.

<reference guid="ED62F4E0-63C2-11D4-94D8-00C04FB0F326"/>

With the reference for the type library included, the data types defined in MFCOM can be used directly in a WSH script. For example, the check the state of a session, the returned type by the

SessionState property of the session object is MetaFrameSessionState. If we want to see if a session is connected, we can use a statement similar to the following:

If aSession.SessionState = MFSessionStateConnected Then …

End If

6.2

Objects

The basic programming units in MFCOM are objects. Objects are defined to closely resemble the real world entities, e.g., session, application, and server. Objects have properties and methods for the users

6 This was not possible until Feature Release 2. Prior to this release, the data types were not included in the type library.

(15)

of the objects to access. Properties and methods are grouped in interfaces, which are attached to objects.

Some objects can be created independently by a COM client. These objects all have the names starting with MetaFrame, for example, MetaFrameSession is the name of the session object. In VB scripts,

many times we use the full name of such an object, MetaFrameCOM.MetaFrameSession. The string MetaFrameCOM defines a namespace. So when there is no ambiguity, the namespace string

MetaFrameCOM is not needed. For example, the following VBScript statement creates a farm object.

Set theFarm = CreateObject("MetaFrameCOM.MetaFrameFarm")

The pointer to the object is stored in the variable theFarm, which can be used later to access the calls of the interfaces supported by the farm object.

MFCOM also exposes objects that cannot be created using a COM library call such as

CreateObject. These objects can only be created by some other MFCOM calls. An example of

such an object is the MetaFrameTime object, which is returned by the properties that return a time. For example, if we have a session object pointed by a variable aSession, then the following statement gives us a time object.

aSession.ConnectTime(TRUE)

The Boolean is a required argument for the ConnectTime property. If it is TRUE, local time is

returned, otherwise the same time value in GMT is returned. For this particular example, the above statement is incomplete since at least one of the properties of the time object must be specified. In other words, there is no default property for the time object. In fact, all COM objects don’t support the default properties, which are disallowed by the latest releases of the Microsoft programming

languages.

6.3

Interfaces

There are many ways to define the concept of interface. Using a layman’s term, an interface is a bunch of calls put together. On the other hand, the calls constitute the properties of the objects that support the interfaces. Although COM defines some generic interfaces that every object must support, the MFCOM interfaces are rarely supported by more than one object. All MFCOM interface names start with a string IMetaFrame. An object is supported by usually more than one MFCOM interface, in addition to the standard COM interfaces such as IUnknown and IDispatch.

In MFCOM, interfaces are versioned. The later version of an interface is named using the root name plus a version number with the exception that the first version of the interface doesn’t end with the number 1. For example, the interface supported by the MetaFrameFarm object are defined as IMetaFrameFarm, IMetaFrameFarm2, and IMetaFrameFarm3, etc. The latest version of an

interface always supports all the calls defined in the previous versions of the same interface. Each object has a default interface, which is usually defined as the latest version of the interfaces supported by the object. The calls defined in the default interface are usually displayed as the

(16)

Although the interface names are usually associated with the object that supports the interfaces, some objects support interfaces named slightly differently since it may be a generic object for many different types of object. For example, a folder object is further classified as server, application, and account folder, therefore it may support interfaces like IMetaFrameFolder as well as

IMetaFrameAppFolder, IMetaFrameSrvFolder and IMetaFrameAcctFolder.

For most MFCOM users, although the concept of interface is important, rarely do they get in the way of coding explicitly. Most people can focus on the objects and the properties of the objects, which are exposed by the default interfaces of the objects.

6.4

Collections

MFCOM defines many collection objects and it’s safe to say that no code that does even the simplest job will be complete without using at least one MFCOM collection object. Throughout this document almost every example has a loop statement, which is the primary programming logic that uses

collection.

The Microsoft COM specification and the related reference available from MSDN have extensive information on how the collection objects should be created and used. In this document, we’ll describe only concepts and tips that MFCOM users should know to quickly use them.

A collection object is itself an object, but it is a collection of other objects. The collection is made possible by it supporting some predefined COM interfaces and calls that are required by the VBScript engine.

In MFCOM, all collection objects are named using the plural form of the name of the object contained in the collection. For example, the server collection object is named as MetaFrameServers, which apparently is a collection of MetaFrameServer objects.

Very few MFCOM collection objects can be created by the user. Most of them are returned as a property of another object, which is usually at a hierarchically higher layer of the object hierarchy in MFCOM. For example, the server collection object for the farm object is returned in the following statement:

theFarm.Servers

So it helps to think the collection object using names like MetaFrameServers. But rarely these object names are really used anywhere in code written based on MFCOM. Instead, the interfaces that support the collection objects can be seen in the type library, e.g., IMetaFrameServers.

One of the most common ways of using a collection object is to enumerate the object a collection contains. For example, the enumerate all the servers in the farm; the following code can be used.

For Each aServer In theFarm.Servers

WScript.Echo aServer.ServerName

(17)

The above code is valid because the theFarm.Servers clause returns an object that supports the pre-defined properties and methods required by the Visual Basic For Each statement. The aServer

variable is automatically assigned to a MetaFrameServer object fetched one by one by the VB run-time. Since it’s an object, its properties can be used, e.g., the ServerName property.

After you have explored the MFCOM objects for a few minutes, you’ll see many properties that return collection objects. In addition to the farm object, application, account authority, and even the license objects all have a Servers property defined.

So what are the differences for the collection objects returned by the different objects? The answer is that all these contain objects that make the common sense for the object, from which the enumeration is made. For example, the Servers property of a farm object returns a collection of servers in the farm. But the Servers property of an application object returns the servers in the application’s server

list.

MFCOM is so rich in supporting enumeration that almost any naturally sensible enumeration

relationship can be found. In other words, if it makes sense to enumerate other objects from an object, the enumeration is probably implemented. This makes navigating through the object hierarchy quite easy and from the top level farm object, it’s possible to navigate through all other objects. The SDK example CINCOM makes this claim possible and it’s not hard to see what the above statements in this paragraph mean if you have tried the CINCOM8.

6.5

Arrays

Some MFCOM collections are returned in arrays since the data are all of the elementary types. Even for objects, we sometimes use arrays since an array is easier to implement. Arrays are accessed differently than collections. For example, the hotfixes installed on a server is accessed using an array of objects. The For Each statement to access the hotfixes is different from such a statement to access

a collection object.

The following is an example script that lists the hotfixes installed on a server. Since the script will be analyzed in more detail later, only the part about the hotfix array is shown here.

hCount = theWinServer.HotfixCount Hotfixes = theWinServer.Hotfixes '

' Display hotfixes installed on the server. '

WScript.Echo CStr(hCount) & " hotfixes installed on server " & _ Args(0)

WScript.Echo "---" For I = 1 To (hCount - 1)

Set aHotfix = Hotfixes(I) Set Date = aHotfix.InstalledOn

WScript.Echo "Hotfix Name : " & aHotfix.Name

WScript.Echo "Installed by: " & aHotfix.InstalledBy WScript.Echo "Installed on: " & _

Date.Month & "/" & Date.Day & "/" & Date.Year Next

(18)

The above code displays the hotfixes. The For I = 1 To (hCount -1) statement is used instead

of the For Each statement. Each element of the array is accessed using the name of the array, e.g.,

Hotfixes, followed by the array index in a pair of parentheses.

6.6

Time Object

Whenever time is returned by a MFCOM property, a time object is actually returned. We took the pain to create an object for something as simple as time, which usually is stored in a 64-bit integer, because the scripting languages don’t usually have access to the Win32 calls for converting the time into different user-friendly formats. Even if these calls can be made available, it’s still too much for a system administrator, whose main job is to maintain a system, to bother with the syntaxes of using the Win32 calls.

All MFCOM properties that return a time take an additional parameter to allow the user to specify if the time should be converted to the local time or the GMT. For example, to query the logon time of a session, we can use the following statement.

aSession.LogonTime(TRUE).Day

The Boolean is necessary and it indicates that we want local time. More apparent for the necessity to specify the Boolean value is seen by the following property of the time object, Day, which can apparently be different from the local time if we specify FALSE to the LogonTime.

The following read-only properties are defined for the time object.

Year, Month, Day, DayOfWeek, Hour, Minute, Second, and Millisecond

Another property, IsLocalTime, which is read-write, can be used to query and set if the local time or the GMT time is currently or will be returned for the above properties.

The above properties make sense if the time represents a date or a specific moment. Since the time object is also used to return a duration, the above properties don’t make sense any more; most of the values will be zero for a duration. So instead, two other properties, LowPart and HighPart, should

be used to access the values of a duration. These two properties also form the 64-bit integer of the internal time value for a date. This value is the number of 100 nanoseconds past since January 1, 1601. The time object cannot be created by the user, it is only returned by one of the MFCOM object

properties that return time.

6.7

User Defined Collections

As mentioned before, most MFCOM collections cannot be changed by the user. There are, however, a few collection objects that support methods to allow the user to add items to or remove items from a collection. These collection objects usually are named as MetaFrameMyXxxs, e.g.,

(19)

We need to have these user changeable collections because some calls require a collection object as input parameter. For example, the policy object has calls to allow the user to specify the user accounts. Apparently these accounts can change from time to time.

The user defined collection objects support all the calls for a collection object. In addition, they support calls for editing the collection. These calls usually include Add and Remove. For each collection the names of the calls may be different.

Internally the collections are usually implemented using very simple data structures, mostly one dimensional arrays. We chose using the simple data structures because the collections are usually small.

6.8

ID Object

The MetaFrameID object is created with the similar purpose to the MetaFrameTime object. We define this object to allow languages such as VBScript to access the 64-bit integer ID, which is used internally by the IMA as the unique identifier for all the IMA objects. The scope of an object’s ID is the farm.

The ID object can be created by the user. When a call requires such an object, the caller can create an ID, initialize it, and give the ID object to the call as input parameter. Many MFCOM calls also return an ID. For these calls, an ID object is always returned.

The ID object has only three read-write properties, ID64, IDH32, and IDL32, which returns the entire 64 bits, the high 32 bits, and the low 32 bits of the ID. Since VBScript doesn’t support 64 bit data types, only IDH32 and IDL32 are available for scripting programs. This is the primary reason for offering such an object.

No attempt should be made to decipher the bits of an object ID. The bit definition of an object ID is strictly internal to the IMA and supplying an invalid object ID to a call may cause unpredictable problems to your system. Always use the valid IDs returned by the MFCOM calls.

The following is an example of accessing the application object ID. Assume that anApp is a MetaFrameApplication object, then the VBScript statement

WScript anApp.AppID.IDH32

prints out the high 32 bits of the ID.

6.9

Credential Object

The MetaFrameCredential object is designed to allow a user to supply user credentials when such information is needed by another MFCOM call. For example, user credentials are needed for the

ImportNetworkPrinters method of the farm object.

(20)

Different calls may require different user credential information, depending on the targeted system of the call. This should not be confused with the information about the user who is accessing MFCOM. The MFCOM user is usually the current logon user. Although it is possible to use another user’s credentials to access MFCOM9, it is totally a different scenario.

The call that takes a user credential object uses this information to access the targeted system, which may or may not be a MetaFrame server. The IMA call that is eventually used to implement the MFCOM call will try to become (impersonate) the given user specified in the credential object to access the target system. This is why the password is usually required.

For example, the farm object has an ImportNetworkPrinters call, which queries a remote network

print server about the printers it supports and imports the printers to the MetaFrame farm. Since the current MFCOM user may not be allowed to access the network print server, a credential object containing the credentials of a user who is allowed to access the remote network print server is required.

Many times a user credential object is also required to resolve some user accounts, which may be from different user account authorities, such as NT domain, Microsoft ADS, and Novell NDS. The current MFCOM user may not be allowed to access those account authorities. For these calls, a credential object containing the information for an allowed user account is needed.

For enhanced security, the Password property of the credential object is write-only. The password is stored in the memory encrypted and unencrypted only when it is passed to an IMA call.

6.10

Multi-String Object

An array of strings is sometimes required for some calls. Although the COM library provides such data types, they are not sufficient for our needs. Also, an array of strings is not supported by VBScript, which requires that all elements of an array are of type VARIANT10.

The MetaFrameMultiString object can be created by an end user and be given to a call that requires an array of strings, e.g., the ProcessList property of the

IMetaFrameSmartCardSetting interface. The strings in the multi-string object can be enumerated

and edited.

This object may be thought as a collection object. Its name may be an exception since it doesn’t end with an ‘s’.

7

Managing Farm

A farm is a group of servers working together to serve user sessions. In this section we discuss the daily routine management of a server farm. We don’t discuss the farm design issues here. We assume that a farm is already configured and working as designed. The scripts we will create for farm

9 The details are described in an answer in the FAQ section.

10 Don’t worry if you don’t know what we are talking about here. I’m just trying to explain the reasons for defining an

(21)

management are tasks that an administrator often performs to keep the farm operating under normal conditions. Like an automobile, we start and drive it. Starting the car needs certain procedures. But keep the car going to the intended destination needs constant attention. The tasks we will discuss regarding the management of a farm are of this nature.

A farm has many configurable parameters that can be adjusted. Most of these parameters can be adjusted using MFCOM by scripting. The following is a simple Windows Scripting Host script. It prints out the name of the farm and some properties. To make reading the script easier, comments and explanations are inserted in between the code. The code is in shaded boxes.

<package>

<job id="Farm"> <comment>

File: Farm.wsf

Description: A simple script displaying farm properties. Requirements: WSH 5.5 or higher.

Copyright (c) 2002 Citrix Systems, Inc. </comment>

<runtime>

<description>

A simple script displaying farm properties. </description>

</runtime>

This is the header of the script. For people who are familiar with HTML, the format is easy to understand. Since almost every script contains this type of header, we don’t need to explain much here11.

<reference object="MetaFrameCOM.MetaFrameFarm"/> <script language="VBScript">

These two lines appear to be important. The first line tells the scripting engine that MFCOM is the object to be used. Even if the actual objects used may be different from the farm object, this particular reference line works for all other scripts12.

Dim theFarm, theWinFarm

'

' Create MetaFrameFarm object '

Set theFarm = CreateObject("MetaFrameCOM.MetaFrameFarm")

if Err.Number <> 0 Then

WScript.Echo "Can't create MetaFrameFarm object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

11 The author has to confess here that he doesn’t know the precise definition of the format of a WSH script file. The script

was written by another engineer whom the author considers the real scripting expert. Since the topic is not about learning WSH nor scripting but about using MFCOM and scripting is just a simple and most popular way to explain the usage, the author doesn’t feel shameful to claim that he knows some scripting. Even to the extent to pretend that all the WSH statements are well understood. Although this may be a problem to an orthodox programmer, the author has managed to write many scripts like this one that have worked pretty well. I don’t know if this revelation will boost the confidence of the reader or lower the credibility of this document.

(22)

Like Visual Basic, two variables are declared and then one of them, theFarm is set to the created farm

object.

'

' Initialize the farm object. '

theFarm.Initialize(MetaFrameWinFarmObject) if Err.Number <> 0 Then

WScript.Echo "Can't Initialize MetaFrameFarm object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

Almost every MFCOM object has an Initialize method that must be called immediately after the

object is created and before any other methods and properties of the object can be used. For a farm object, the only parameter to its initialization method is MetaFrameWinFarmObject, which is the only possible value.

If you think more about this the initialization makes sense. All objects created by CreateObject do not represent any particular entity in the farm. Initializing the object simply connects an object prototype with the entity that really exists.

'

' Get MetaFrameWinFarm2 object '

Set theWinFarm = theFarm.WinFarmObject2 if Err.Number <> 0 Then

WScript.Echo "Can't receive MetaFrameWinFarm2 object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

This is a typical way of getting a new version of the interface pointer. Since type casting and

QueryInterface are not available in VBScript, using the properties that provide the new version of

the interface is the only possible way to get a pointer to an interface that supports calls not available to the given interface, e.g., theFarm. Many MFCOM objects use this method to support new interfaces of an existing object.

'

' Are you a Citrix Administrator? '

if theWinFarm.IsCitrixAdministrator = 0 then

WScript.Echo "You must be a Citrix admin to run this script" WScript.Echo ""

WScript.Quit 0 End If

This is the reason that we need to get the pointer to the IMetaFrameWinFarm2 interface, which

(23)

Because currently MFCOM is an API interface for the CMC13, only Citrix administrators are allowed to access MFCOM. There are very few calls that work for non-administrators. This call is one of the few. It is a good idea to use this call to ensure that the user has the proper authorization. If the user is not properly authorized, calls to other methods may fail, which may look nasty in languages such as VBScript14.

'

' Print out the farm name. '

WScript.Echo "MetaFrame Farm Name: " & theFarm.FarmName

'

' Print out some of the MetaFrameWinFarm2 object properties. '

WScript.Echo "MetaFrame WinFarm object properties"

WScript.Echo "DegradationBias : " & theWinFarm.DegradationBias WScript.Echo "UseClientLocalTime: " & theWinFarm.UseClientLocalTime WScript.Echo "Press ENTER to exit..."

WScript.StdIn.Read(1)

</script> </job>

</package>

Finally we see how the object’s properties and methods are used. The farm name is printed. Then additional properties available only to the Windows farm are printed.

Based on this script, many farm properties can be viewed or set quite easily. For example, if the ICA keep-alive time out value needs to be changed, instead of using CMC, we can write a simple script. If the user is known to be always a MetaFrame administrator, the above administrator check may not be necessary. Only thing needed in the script would be something like the following:

theWinFarm.ICAKeepAliveTimeout = 100

With this, there’s no need to open the CMC, right click on the farm property and they change the value of this setting.

This may be an extreme example since very few people would change some farm level setting so frequently. As such, using the CMC to change farm settings may seem to be not a big problem. Many people wouldn’t bother to spend the extra time to write and debug a script when the payoff for doing so may not be so great.

Our purpose of giving this example, however, is to show that it is very easy to write a script. Once you are familiar with some basic scripting techniques and MFCOM objects properties and methods. It only takes a few minutes to create a simple tool.

13 This may change in future releases. MFCOM may be extended to support calls made by regular users.

(24)

8

Managing Servers

If managing farms seems to be an ill-fitted task for MFCOM, managing servers and other lower level entities in the farm architecture will yield real benefits if scripting is used effectively. Generally the lower the level of an object in the farm hierarchy, the more frequently the objects’ properties change. Monitoring and setting the properties of these low level objects is more routine for an administrator. On the other hand, more mouse clicks will be needed to navigate the CMC trees to reach a low level object.

A server object itself has many properties. Many of them bear the same name as the farm’s properties but changes to these properties only apply to the server itself. In addition, for these properties that have a farm equivalent, another Boolean flag is also available to indicate if the farm’s property value should be used instead of that of the server’s. So, essentially for a server we can create tools similar to the one illustrated in the previous section to read or set the properties of a server. Since that type of scripting has been demonstrated, we will focus on tasks that are a little more complex than dealing with only one object.

8.1

Enumerating Servers

Since there can be more than one server in a farm, enumerating servers is a common task. Apparently servers can be enumerated from a farm object. The following is a script that performs this task.

<package>

<job id="Servers"> <comment>

File: Servers.wsf

Description: List servers in the farm. Requirements: WSH 5.5 or higher.

Copyright (c) 2002 Citrix Systems, Inc. </comment>

<runtime>

<description>

List servers in the farm. </description>

<example>

CScript //nologo Servers.wsf </example>

</runtime>

<reference object="MetaFrameCOM.MetaFrameFarm"/>

(25)

<script language="VBScript">

Dim theFarm, aServer, aWinServer

'

' Create MetaFrameFarm object '

Set theFarm = CreateObject("MetaFrameCOM.MetaFrameFarm") if Err.Number <> 0 Then

WScript.Echo "Can't create MetaFrameFarm object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

'

' Initialize the farm object. '

theFarm.Initialize(MetaFrameWinFarmObject) if Err.Number <> 0 Then

WScript.Echo "Can't Initialize MetaFrameFarm object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

'

' Are you a MetaFrame Administrator? '

if theFarm.WinFarmObject.IsCitrixAdministrator = 0 then

WScript.Echo "You must be a Citrix admin to run this script" WScript.Echo ""

WScript.Quit 0 End If

'

' Print out the farm name. '

WScript.Echo "MetaFrame Farm Name: " & theFarm.FarmName WScript.Echo ""

Since we are going to enumerate servers for the entire farm, the farm object must be created. The object is initialized and the farm name is printed.

'

' Display all servers in the farm. '

WScript.Echo "All servers in the farm (" & Now & ")"

WScript.Echo "---"

For Each aServer In theFarm.Servers

This statement is the core of the code. The farm object supports a method that returns a collection object, which contains the server objects. A collection object is a COM concept. Basically a predefined set of properties and methods must be supported by a collection object. Except those required properties and methods, a collection object is just a normal COM object. The required properties and methods of a collection object enable some Visual Basic statements such as the one used here, For Each.

Let’s take a close look at what happens when the For Each aServer In theFarm.Servers

(26)

object to the caller. The object supports the required properties and methods and therefore is recognized as a collection object.

The interface supported by the collection object is IMetaFrameServers. There are many such

collection interfaces defined in MFCOM. Their names are easy to recognize because it is the plural form of the object interface for which the collection is created. MFCOM has collection objects defined for almost all the objects except the farm object, which is the top level object.

One of the required methods for a collection object is the __NewEnum method, which is hidden to VB and many other languages but visible to C++. The actual enumeration is executed when this method is called. The For Each statement quietly calls this method after the theFarm.Servers clause returns

successfully.

If __NewEnum returns successfully, the Next property, which is required for a collection object, is called to get the first object in the collection since this is the first time Next is called. The pointer to

this object is stored in the variable aServer, which is available to the statements in the body of the loop.

if Err.Number <> 0 Then

WScript.Echo "Can't enumerate servers"

WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

WScript.Echo "Name : " & aServer.ServerName WScript.Echo "IPAddress : " & aServer.IPAddress

‘ MetaFrameWinServer object. ‘

Set aWinServer = aServer.WinServerObject

Wscript.Echo “Product Code : “ & aWinServer.MFWinProductCode Wscript.Echo “Windows Name : “ & aWinServer.MFWinName

Wscript.Echo “”

This is the loop body. The variable aServer points to the current server object in the collection. Here we just print out the MetaFrame product code and name. Many other server properties can be changed or displayed.

Note that unlike the objects created using the CreateObject or other equivalent object instantiation methods, the objects in a collection are all fully initialized. They don’t need to and should not be initialized. Further, here we assume that all the servers returned are Windows servers. We don’t check the object type before executing the statement Set aWinServer = aServer.WinServerObject. The reason for using another variable aWinServer is because the product code and name properties are only available through the IMetaFrameWinServer interface. The

aServer.WinServerObject statement returns a pointer that supports this interface.

Next

This statement closes the loop. Upon execution, it calls the Next method of the collection object. If

(27)

back to the first statement of the loop body. If Next indicates that there are no more objects in the collection, the loop ends.

The scope of aServer ends outside of the For Each … Next loop. In other words, aServer

should not be used outside of the loop. VB automatically calls the Release method (of aServer) to decrement the references to aServer during the execution of the Next statement.

WScript.Echo "Press ENTER to exit..." WScript.StdIn.Read(1)

</script> </job>

</package>

So VBScript has made things a lot easier by doing a lot of the leg work behind the scenes. This is why many people like using scripting.

Since the collection object is just a regular object, its pointer can be stored in another variable that can be used later. The following statements print out the number of servers in the farm15.

Dim Servers

Set Servers = theFarm.Servers

Wscript.Echo “Number of servers in the farm: “ & Servers.Count

Servers can be enumerated from a zone, application, and other objects in addition to the farm object. All those objects have a Servers property that returns a collection object of servers, which are included in the collection with respect to the specific logical meaning of the collection. For example, the servers enumerated by a zone are those defined in the zone. Servers enumerated from an

application object are those in the application’s server list. Regardless how a server is enumerated, all the objects created for the same physical server contain the same information.

8.2

Listing Hotfixes

Although every software company in the world claims that they make great software, none of them can say that their software is defect free. Unlike any other products, customers of software products are willingly purchasing and using software that surely contains bugs. The only good thing is that many companies promise to fix any problems that may be found. Most of the time the fixes are free, but after some time, even managing the fixes becomes part of the administrator’s job.

Citrix releases fixes as hotfix. Each hotfix has a name and MetaFrame hotfixes can also been seen using the CMC. Like many other things, the hotfix information is also available from MFCOM. So, instead of clicking through servers to find the hotfixes installed on a server, the following script can be used.

(28)

<job id="Hotfixes"> <comment>

File: Hotfixes.wsf

Description: List hotfixes installed on a server. Requirements: WSH 5.5 or higher.

Copyright (c) 2002 Citrix Systems, Inc. </comment>

<runtime>

<description>

List hotfixes installed on a server. </description>

<example>

CScript //nologo hotfixes.wsf ServerName </example>

</runtime>

<reference object="MetaFrameCOM.MetaFrameFarm"/>

As usual, the header.

<script language="VBScript">

Dim theServer, theWinServer, Args, hCount, aHotfix, I, Hotfixes Dim Date

'

' Parse the command line. '

Set Args = WScript.Arguments If Not Args.Count = 1 Then

WScript.Echo "Usage: hotfixes.wsf ServerName" WScript.Quit

End If

'

' Create MetaFrameServer object '

Set theServer = CreateObject("MetaFrameCOM.MetaFrameServer") if Err.Number <> 0 Then

WScript.Echo "Can't create MetaFrameServer object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

'

' Initialize the server object. '

theServer.Initialize MetaFrameWinSrvObject, UCase(Args(0)) if Err.Number <> 0 Then

WScript.Echo "Can't Initialize MetaFrameServer object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo ""

WScript.Quit Err.Number End if

(29)

'

' Get the WinServer interface. '

Set theWinServer = theServer.WinServerObject2

hCount = theWinServer.HotfixCount Hotfixes = theWinServer.Hotfixes

'

' Display hotfixes installed on the server. '

WScript.Echo CStr(hCount) & " hotfixes installed on server " & _ Args(0)

WScript.Echo "---"

For I = 1 To (hCount - 1) Set aHotfix = Hotfixes(I) Set Date = aHotfix.InstalledOn

WScript.Echo "Hotfix Name : " & aHotfix.Name

WScript.Echo "Installed by: " & aHotfix.InstalledBy WScript.Echo "Installed on: " & _

Date.Month & "/" & Date.Day & "/" & Date.Year Next

WScript.Echo "Press ENTER to exit..." WScript.StdIn.Read(1)

</script> </job>

</package>

The WinServerObject2 interface is obtained because it supports IMetaFrameWinServer2, which supports calls to get the hotfixes. The hotfix information is stored in a one dimensional array. Each array element is an object that supports the IMetaFrameHotfix interface, which supports hotfix properties such as name and installation date. The hotfix installation date is returned in an object that supports the IMetaFrameTime interface, which has the usual time/date properties like month, day, and year.

The script can be easily modified to loop on all the servers in the farm. It can also be modified to be a query utility to check if a specific hotfix is installed on a particular server.

9

Managing Published Applications

Published applications are objects that are most suitable for scripting. Customers of MFCOM from both inside and outside of Citrix have used MFCOM to create and manage published applications. Probably more scripts have been written on published applications than any other objects.

A typical server farm hosts many published applications. Each application is accessed by many users. A published application has many parameters that can be adjusted for different needs.

(30)

described in the previous section, code to enumerate applications for the farm and for a particular server can be created. Note that the published applications enumerated from a server are those that have the server in their server list.

Enumerating and displaying properties of an application are only the easy part of managing published applications. First, published applications can be created. Second, published applications relate to many other objects, e.g., servers, users, and sessions. In fact there is so much to do with published applications we have created a separate SDK just for the purpose of managing published applications. We’ll use one of the tools based on the application publishing SDK (APSDK) to complement the examples in this section.

9.1

Application Names

Managing published applications is probably the number one job of many MFCOM users and I would bet nine out of ten of these users have had some degree of confusion over the different names of the a published application. Hopefully, after reading this section, the reader will have a clear understanding of the application names.

Three different names are used in MFCOM for the MetaFrameApplication object. They are the display name, distinguished name, and the browser name. The maximum length for all these names is 256 characters, including the ending NULL character.

The display name, a.k.a. friendly name, is a string visible to the end user in the MetaFrame

(31)

The distinguished name is used only in MFCOM. It is a string that consists of the parent folder name and the application’s display name. Since applications are organized in folders, which resembles directories, the distinguished name is very similar to the directory path name for a file16. For example if the application My Notepad is published in folder /Applications/App Folder1, the

distinguished name for this published application is /Applications/App Folder1/My Notepad. Distinguished names are so called because they uniquely identify an application in the entire farm. All MFCOM calls that require an application name take only the distinguished name of an application.

The root folder for published applications is always /Applications, which cannot be renamed. All published application distinguished names start with /Applications. Although we are using the

forward slash / in all examples, the backward slash \ is also accepted as a valid string separator in an application distinguished name. Both slashes can mix in one distinguished name. In the next picture, there are two published application with the same display name but they are in different folders.

(32)

Since the display name, which can be changed, is included in the distinguished name, when it is necessary to track the application object even when its name changes, the application ID returned by the AppID property can be used. This ID doesn’t change for the life time of the application.

Another name is the browser name, which was not available from MFCOM until Feature Release 2. The browser name is read-only and internally generated by the IMA. This name is unique across the entire farm. It is instead not like the distinguished name, which is structured. The browser name is a simple string and is mainly used by older releases of MetaFrame as well as the Web Interface of MetaFrame XP.

The browser name is called Application Name in the CMC. For the above two published

(33)

9.2

Application-Server Binding

The MetaFrameAppSrvBinding object is used to add a server to the server list of a published application. Since for each server, the working directory and the initial command, a.k.a. initial

program, can be different, it takes more than a server name when a server is to be added to a published application.

The binding object can be created by the user. Then it can be initialized by setting the

InitialCommandLine and WorkingDirectory properties, in addition to the server name and application name. Then the binding object can be given as the input parameter for the application object’s

AddServer method. The following is an example of adding a server to a published application.

<package>

<job id="AddServer"> <comment>

File: AddServer.wsf

Description: Exanmple of how to add a server to an app. Requirements: WSH 5.5 or higher.

Copyright (c) 2002 Citrix Systems, Inc. </comment>

<runtime>

<description>

References

Related documents