Scripting MetaFrame

Embed Size (px)

DESCRIPTION

Scripting for Citrix metaframe

Citation preview

  • Scripting MetaFrame

    By Dr. SDK

    Copyright 2003

    Citrix Systems, Inc.

  • Scripting MetaFrame

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

    THIS PUBLICATION IS PROVIDED .AS IS. WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. CITRIX SYSTEMS, INC. (CITRIX) SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED HEREIN, NOR FOR DIRECT, INCIDENTAL, CONSQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM THE FURNISHING, PERFORMANCE, OR USE OF THIS PUBLICATION, EVEN IF CITRIX HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES IN ADVANCE. 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 Microsoft, Windows, Windows 2000, Windows XP, and Win32 are either registered trademarks or trademarks of Microsoft Corp. in the United States and/or other countries.

    2

  • Scripting MetaFrame

    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 NT SERVICE ......................................................................................................................9 4.4 A COM INTERFACE FOR THE IMA..............................................................................................11

    5 SIMPLIFY YOUR DAILY TASKS..............................................................................................13 6 MFCOM BASICS..............................................................................................................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 ID OBJECT...........................................................................................................................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 13 DCOM CAVEATS .........................................................................................................50

    3

  • Scripting MetaFrame

    14 MFCOM SECURITY.......................................................................................................53 15 WEB INTERFACE ...........................................................................................................58 16 GATHERING AND REPORTING DATA ..................................................................................67 17 WORK AROUND BUGS....................................................................................................71 18 SCRIPTING METAFRAME 1.8 ...........................................................................................72 19 FREQUENTLY ASKED QUESTIONS ......................................................................................76

    4

  • 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 peoples 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 peoples 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. Its 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 theres 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 dont know if I am making a valid assumption here. So far I dont know there were any women scientists who actually worked on the hydrogen bomb. But I guess its ok to make such an assumption. After all, Im just trying to make a point about why I chose the current title for this document.

  • Scripting MetaFrame

    For the most part the idea of scripting MetaFrame tasks is unheard of. We havent done a good job to 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 dont 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 dont 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 administrators 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 administrators guide. There are also some command line utilities for some special tasks that are not supported by the CMC. Since these tools are already scriptable, they are not described in this document. Other ways of administering MetaFrame farm and servers are also available. For example, the CWC provides a web interface. These tools are either built based on MFCOM or infrequently used, they are not described in this documented.

    6

  • Scripting MetaFrame

    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 cant 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 dont 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, particularly when the amount of data is large.

    7

  • Scripting MetaFrame

    Most of the tasks performed through CMC meet some of the above criteria. There is very little graphical data presented in CMC, except some Resource Manager (RM) data. Since MFCOM doesnt 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 Its 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 integration task far easier since MFCOM offers a complete set of APIs for almost every manageable object in MetaFrame XP farm. Developers will not need to use other SDKs for the integration.

    8

  • Scripting MetaFrame

    To an end MetaFrame user, MFCOMs 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 services process is mfcom.exe, which can be found in the Windows Task Managers 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 dont create and recognize these entries. 3 This indicates the entry is a key, therefore it doesnt have a data type.

    94 This is not the actual data.

  • Scripting MetaFrame TraceLevel\AllLevels DWORD 0 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

    105 These trace flags are not honored by every MFCOM call. In fact most of the calls dont generate tracing information.

  • Scripting MetaFrame

    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 MFCOMs 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 clients 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. Creating the registry entries either directly or indirectly by calling some COM library functions is only part of the MFCOM registration process. The other part is to let itself known to the COM runtime.

    11

  • Scripting MetaFrame

    We dont need to go into details in describing the process. Essentially COM runtime maintains a 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 doesnt 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. From the above process we can see the importance of the type library. A type library does not have to be stored in the MFCOM binary image. A type library can exist independently as a .tlb file. In fact, we supply such a file in the SDK as mfcom.tlb. For convenience, the MFCOM type library is included in mfcom.exe and mfreg.exe as a resource.

    12

  • Scripting MetaFrame

    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 applications 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 administrators 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, its worth to offer a few general guidelines here regarding scripting. First of all, I dont 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. For someone who is new to MFCOM and familiar with Visual Basic, it is recommended that the VB environment is used to first create the equivalent VB code. Then convert the VB code to VBScript. Both are almost identical with some subtle differences, which we dont need to discuss for now. The advantage of using the Visual Basic development environment is that the properties and methods of objects declared of certain type are automatically displayed whenever the properties and methods are used.

    13

  • Scripting MetaFrame

    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, lets 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. 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. 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. Programmers would have to use the numerical values in places where the enum type literals are required.

    147 The correct term in HTML, which is used by Windows Scripting Host, is a reference element.

  • Scripting MetaFrame

    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 dont 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 laymans 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 doesnt 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 properties of the object if the properties and methods are browsed using an object browser, such as the ones available in the Visual Studio environment.

    15

  • Scripting MetaFrame

    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 its 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, well 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 Next

    16

  • Scripting MetaFrame

    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 its an object, its properties can be used, e.g., the ServerName property. After you have explored the MFCOM objects for a few minutes, youll 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 applications 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, its possible to navigate through all other objects. The SDK example CINCOM makes this claim possible and its 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

    178 Another example written in C#, CSCMC, is also organized this way.

  • Scripting MetaFrame

    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 dont usually have access to the Win32 calls for converting the time into different user-friendly formats. Even if these calls can be made available, its 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 dont 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., MetaFrameMyServers, MetaFrameMyAccounts, etc.

    18

  • Scripting MetaFrame

    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 objects 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 doesnt 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. To avoid confusion with the convention of using plural form of a word for collection objects, we use Credential, instead of Credentials as the name of the object although usually user information includes at least a user name and password, both consist the Credentials of the user. 19

  • Scripting MetaFrame

    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 users 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 doesnt 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 dont 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.

    20

    10 Dont worry if you dont know what we are talking about here. Im just trying to explain the reasons for defining an object that may seem to be unnecessary given that COM provides many pre-defined data types and objects.

  • Scripting MetaFrame

    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. File: Farm.wsf Description: A simple script displaying farm properties. Requirements: WSH 5.5 or higher. Copyright (c) 2002 Citrix Systems, Inc. A simple script displaying farm properties.

    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 dont need to explain much here11.

    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 doesnt 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 doesnt 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 dont know if this revelation will boost the confidence of the reader or lower the credibility of this document.

    2112 Again, no need to explain here. Just use as they are.

  • Scripting MetaFrame

    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 supports the IsCitrixAdministrator property. This property returns a Boolean, which indicates if the current user is a MetaFrame administrator or not. This call does not fail, it returns either TRUE or FALSE. 22

  • Scripting MetaFrame

    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)

    Finally we see how the objects 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, theres 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 wouldnt 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.

    2314 It appears as an exception (a.k.a trap) to such languages. In C++, the equivalent call returns a normal error code.

  • Scripting MetaFrame

    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 farms 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 farms property value should be used instead of that of the servers. 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. File: Servers.wsf Description: List servers in the farm. Requirements: WSH 5.5 or higher. Copyright (c) 2002 Citrix Systems, Inc. List servers in the farm. CScript //nologo Servers.wsf

    The usual stuff, still included here just to make the code complete.

    24

  • Scripting MetaFrame 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. Lets take a close look at what happens when the For Each aServer In theFarm.Servers statement is executed. Although it is a simple VB statement, a lot of things happen behind the scenes.

    25

  • Scripting MetaFrame

    The clause theFarm.Servers is first executed. Some MFCOM functions are invoked to return an 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 dont need to and should not be initialized. Further, here we assume that all the servers returned are Windows servers. We dont 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 Next returns another object, the pointer to the new object is stored in aServer and the execution goes 26

  • Scripting MetaFrame

    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)

    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 applications 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 administrators 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.

    27

    15 This would not work for MFCOM releases prior to Feature Release 3. The Count property was not initialized in the previous releases. The work around was to quit a For Each statement and then read the Count property.

  • Scripting MetaFrame File: Hotfixes.wsf Description: List hotfixes installed on a server. Requirements: WSH 5.5 or higher. Copyright (c) 2002 Citrix Systems, Inc. List hotfixes installed on a server. CScript //nologo hotfixes.wsf ServerName

    As usual, the header. 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

    The script needs a server name as the only required argument. We directly create a server object and initialize it using the server name. Note that the server name must be all in upper case. There is a bug in MFCOM that would cause some data unavailable if the server name is in lower case. This bug has been fixed in Feature Release 3.

    28

  • Scripting MetaFrame ' ' 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)

    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. The two most important parameters of a published application are its server list and user list. The server list defines the servers on which the application will be executed. The server list contains a subset of the servers in the entire farm. The user list defines the users who are allowed to access the application. The user list contains individual user accounts and user groups.

    29

  • Scripting MetaFrame

    Applications can be enumerated from many different objects. Similar to the server enumeration code 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. Well 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 Management Console. For example, My Notepad is a valid application name, as shown in the screen shot below.

    30

  • Scripting MetaFrame

    The distinguished name is used only in MFCOM. It is a string that consists of the parent folder name and the applications 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.

    3116 We actually tried to use the term pathname when we initially designed MFCOM.

  • Scripting MetaFrame

    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 doesnt 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 applications, the IMA creates a new browser name for the second My Notepad application, as shown in the following picture.

    32

  • Scripting MetaFrame

    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 objects AddServer method. The following is an example of adding a server to a published application. 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. Add a server to an app.

    33

  • Scripting MetaFrame

    34

    CScript //nologo AddServer.wsf Applications\calc SERVER1 Dim AppDN, ServerName, theApp, theAppSrvBind ' ' If no parameters specified, quit and ' show the usage of the script ' if WScript.Arguments.Count 2 Then WScript.Echo "USAGE: AddServer.wsf AppDN ServerName" WScript.Echo "" WScript.Echo "Example: AddServer.wsf Applications\cmd SRV1" WScript.Quit 0 Else AppDN = WScript.Arguments(0) ServerName = UCase(WScript.Arguments(1)) WScript.Echo "AddServer Application: " & AppDN & " Server: " & ServerName WScript.Echo "" End If ' ' Create App object ' Set theApp = CreateObject("MetaFrameCOM.MetaFrameApplication") if Err.Number 0 Then WScript.Echo "Can't create MetaFrameApplication object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo "" WScript.Quit Err.Number End if ' ' Initialize the app object. ' theApp.Initialize MetaFrameWinAppObject, AppDN if Err.Number 0 Then WScript.Echo "Can't Initialize Application object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo "" WScript.Quit Err.Number End if theApp.LoadData(1) ' ' Create AppServerBinding object ' Set theAppSrvBind = CreateObject("MetaFrameCOM.MetaFrameAppSrvBinding") if Err.Number 0 Then WScript.Echo "Can't create MetaFrameAppSrvBinding object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo "" WScript.Quit Err.Number End if ' ' Initialize the appsrvbind object. ' theAppSrvBind.Initialize MetaFrameWinSrvObject,ServerName,"" if Err.Number 0 Then WScript.Echo "Can't Initialize AppSrvBinding object" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo "" WScript.Quit Err.Number

  • Scripting MetaFrame End if ' ' Add the server. ' theApp.AddServer(theAppSrvBind) if Err.Number 0 Then WScript.Echo "Can't add server" WScript.Echo "(" & Err.Number & ") " & Err.Description WScript.Echo "" WScript.Quit Err.Number End if theApp.SaveData() WScript.Echo "Added Server to App successfully"

    9.3 Batch Publishing Of Applications The following is an example script to create a large number of published applications17. In the internal Citrix test environment, we often need to test scalability issues related to published applications. Publishing a large number of applications, even very simple ones, takes time using the CMC. By running the following script, one command line will create any number of applications you want. MoreApps.wsf This script requires Windows Scripting Host 5.5 or higher. Copyright (C) 2002, Citrix Systems Inc. To run this script, you must logon your MetaFrame server as a domain user account. This user account must also be a Citrix administrator. This simple script can be used to create a large number of published applications for testing purposes. It requires a root name of the published application, a total number of applications to be created, an the full pathname of the executable file. The applications created all have the same properties. The names of the applications are formed using the root name and a number. This script creates a large number of published applications. ADSI 2.5 or higher and Windows Scripting Host 5.5 or higher are required. Use the CScript.exe WSH engine to execute. Cscript MoreApps.wsf RootName AppCount ExePath

    3517 Jeff Reed, who is probably the best scripter at Citrix, wrote the code.

  • Scripting MetaFrame

    The header information describes pretty well about what this script does. It takes on the command line as arguments a root name of the application, a count of the applications to be published, and the path of the executable of the application. The root name is used to generate the names of the published application. For example, if the root name is app, the applications published will have name like app00, app01, etc. The total number of applications published is given by the count, which is the second command line argument. Option Explicit Dim myFarm, myApp, theWinApp, aFile, Args, SrvList Dim nApps, RootName, AppExe, Zeros, AppName, iApp, aServer Dim AppSrv, myNetwork, myDomain ' Parse the command line. Set Args = WScript.Arguments If Not Args.Count = 3 Then WScript.Echo "Usage: moreapps.wsf RootName AppCount Exe" WScript.Quit End If ' Make sure AppCount is a number. If Not IsNumeric(Args(1)) Then WScript.Echo Args(1) & " is not a number" WScript.Quit End If ' Make sure AppCount is at least 1. nApps = CInt(Args(1)) If nApps < 1 Then WScript.Echo Args(1) & " is not a positive number" WScript.Quit End If ' Make sure the executable exists. AppExe = Args(2) Set aFile = CreateObject("Scripting.FileSystemObject") If Not (aFile.FileExists(AppExe)) Then WScript.Echo Args(2) & " does not exist" WScript.Quit End If

    The command line arguments are parsed. Note that some built-in VB objects are used, such as WScript.Arguments and the Fi