Transforming ServerManagerCmd query xml to input xml

 
Hello, my name is Travis Nielsen and I’m a developer on the Server Manager team. Among other things, I have worked on the ServerManagerCmd.exe tool for command line installation.
 
One of the most common requests I have heard from customers is that they want to detect what roles and features are installed on one machine and automate installing the same set of roles and features on another server. To make this work, users typically envision that something like the following would work:

1.       On the original server, query what roles and features are installed and save to xml format:

a.       ServerManagerCmd.exe –query Master.xml

2.       On the target server, use the xml file output by the previous query in order to install the same set of roles and features:

a.       ServerManagerCmd.exe –inputPath Master.xml

 
However, this approach will not work since the xml output by the -query option has a different schema than the -inputPath xml. While the differences in the xml look insignificant at first glance, there are enough differences that this will not work.  Identifying the differences is left as an exercise for the reader.
 
Luckily, all hope is not lost. There is a way to convert the xml from the query output into the xml input file used to install or remove the same set of roles and features. Below are instructions for using xslt (XML transforms) to convert the xml query output to the proper xml input format.
 

1)    Download the conversion tool

 
Download the command line transformation utility and save to a folder on your computer: msxsl.exe

2)    Save the transform files

 
An xsl transform will take an xml file and transform it into another format. There are three transforms provided that you may find useful: Install.xsl, Remove.xsl, and View.xsl.

·         Install: This transform will create an xml file to use with ServerManagerCmd.exe -inputPath for installing roles and features that were detected on a server. See Appendix A.

·         Remove: This transform will create an xml file to use with ServerManagerCmd.exe -inputPath for removing roles and features that were not detected on the master server.  See Appendix B.

·         View: This transform will create an html file that will display which roles and features are installed on the master server.  See Appendix C.

 
These three xsl files can be found at the end of this article in appendix A, B, and C. Using copy and paste with your favorite text editor (ie. Notepad), save these files to your machine. Note that you won’t want to use a fancier word processor that preserves html formatting tags.

3)    Query the “Master” Server

 
Given that you have the tools needed for the transform, you are ready to proceed. First, you will need to query a server for the roles and features that are installed. The server where this query is run will be referred to as the “master” server since it will essentially provide the list of roles and features that will potentially be installed on other servers. From an elevated command prompt on the master server, execute:
 
ServerManagerCmd.exe -query Master.xml
 

4)    Generate the Install xml input file

 
Now that we have the xml from the query of the master server, we will generate the xml that can be used to install all of the roles and features that were detected on the master server as installed. The xml generated will be a list of all the roles and features that should be installed, but will not contain a list of the roles and features that should be uninstalled to match the set exactly on the target server.
 
Run the xsl tool to generate the input xml that will install all the roles, role services, and features that are installed according to query.xml
 
msxsl.exe Master.xml install.xsl -o install.xml
 
If you view Install.xml in a text or xml editor, you will notice a couple of things:

·         There are a lot of blank lines in the file that can be ignored.

·         The set of roles and features that are listed in the xml are not exactly what you see installed on your master server. The difference is that roles, role services, and features that contain other role services and features are not listed. At install time, they will automatically be included by Server Manager with the install. It is not possible to install a role service or feature without its parent.

5)    Generate the Remove xml input file

 
Next, we generate the xml that can be applied to remove all the roles and features that were not detected as installed on the master server. This would not be necessary if you are mirroring the roles and features to a machine where there are not any roles or features installed yet. Neither will you need this if you only want to use the previously generated Install xml to add roles and features instead of removing as well.
 
Run the xsl tool to generate the input xml that will remove all the roles, role services, and features that are not installed according to Master.xml
 
msxsl.exe Master.xml remove.xsl -o remove.xml
 
As with the Install.xml, you may notice that Remove.xml does not contain an exact mapping of what to uninstall. The reason is that if you request to uninstall a root role or feature, all sub role services and subfeatures will also be installed. Therefore, root nodes are not included in the list unless they don’t have any children installed.

6)    Use the Install and Remove xml input files

 
Now you’re ready to perform the installation of desired roles and features on a target server. First, run the following command (from an elevated command prompt) to add the desired roles and features.
 
ServerManagerCmd.exe -inputPath Install.xml
 
If some of the roles or features are already installed on the target server, there is no need to remove them from the install xml. Requesting to install a role or feature that is already installed will not have any effect. An informational message will simply be displayed to indicate that the role or feature did not need to be installed.
 
Finally, if you desire to remove roles or features that should not be present according to the master server, run the following command (from an elevated command prompt) to remove the extraneous roles and features. Again, if they are already not detected as installed on the target server, this will have no effect on the server.
 
ServerManagerCmd.exe -inputPath Remove.xml
 
Note that neither of these commands will have any effect of installing or uninstalling when run on the master server where they were generated.

7)    Generate the View html file

 
The last transform will convert the query xml into a friendly html file to view the available roles, role services, and features, with installed roles/features highlighted in green.
 
msxsl.exe Master.xml View.xsl -o View.html
 
Now open the View.html in your favorite web browser.
 

Appendix A: Install.xsl

 
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1"
version="1.0">
 
  <!-- Transform to xml that can be used to install all roles, role services, and features that were discovered as installed in the output query. -->
 
  <xsl:output indent="no" />
 
  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>
 
  <xsl:template match="sm:ServerManagerConfigurationQuery">
    <xsl:element name="ServerManagerConfiguration" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
      <xsl:attribute name="Action">Install</xsl:attribute>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
 
  <xsl:template match="sm:Role">
    <xsl:if test="@Id and @Installed='true' and count(sm:RoleService) = 0">
      <xsl:element name="Role" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
        <xsl:attribute name="Id">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:apply-templates/>
  </xsl:template>
 
  <xsl:template match="sm:RoleService">
    <xsl:if test="@Id and @Installed='true' and count(sm:RoleService) = 0">
      <xsl:element name="RoleService" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
        <xsl:attribute name="Id">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:apply-templates/>
  </xsl:template>
 
  <xsl:template match="sm:Feature">
    <xsl:if test="@Id and @Installed='true' and count(sm:Feature) = 0">     
      <xsl:element name="Feature" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
        <xsl:attribute name="Id">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:apply-templates/>
  </xsl:template>
 
</xsl:stylesheet>
 

Appendix B: Remove.xsl

 
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1"
version="1.0">
 
  <!-- Transform to xml that can be used to uninstall all roles, role services, and features that were not discovered as installed in the output query. -->
  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>
 
  <xsl:template match="sm:ServerManagerConfigurationQuery">
    <xsl:element name="ServerManagerConfiguration" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
      <xsl:attribute name="Action">Remove</xsl:attribute>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
 
  <xsl:template match="sm:Role">
    <xsl:if test="@Id and @Installed='false'">
      <xsl:element name="Role" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
        <xsl:attribute name="Id">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:if test="not(@Id) or @Installed='true'">
      <xsl:apply-templates/>
    </xsl:if>
  </xsl:template>
 
  <xsl:template match="sm:RoleService">
    <xsl:if test="@Id and @Installed='false'">
      <xsl:element name="RoleService" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
        <xsl:attribute name="Id">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:if test="not(@Id) or @Installed='true'">
      <xsl:apply-templates/>
    </xsl:if>
  </xsl:template>
 
  <xsl:template match="sm:Feature">
    <xsl:if test="@Id and @Installed='false'">
      <xsl:element name="Feature" namespace="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1">
        <xsl:attribute name="Id">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:if>
    <xsl:if test="not(@Id) or @Installed='true'">
      <xsl:apply-templates/>
    </xsl:if>
  </xsl:template>
 
</xsl:stylesheet>
 

Appendix C: View.xsl

 
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://schemas.microsoft.com/sdm/Windows/ServerManager/Configuration/2007/1"
xmlns:html="html"
version="1.0">
 
  <!-- Display the roles, role services, and features that are available for install.
  Default role services and subfeatures will be in bold. -->
 
  <xsl:output method="html"/>
 
  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>
 
  <xsl:template match="sm:ServerManagerConfigurationQuery">
    <html:html>
      <body>
        <h2>Server Roles and Features</h2>
        <xsl:apply-templates/>
      </body>
    </html:html>
  </xsl:template>
 
  <xsl:template match="sm:Role">
    <xsl:if test="@Installed='true'">
      <B>
        <Font color="#00AA00">
          <xsl:value-of select="@DisplayName"/>
        </Font>
      </B>
    </xsl:if>
    <xsl:if test="@Installed='false'">
      <xsl:value-of select="@DisplayName"/>
    </xsl:if>
    <UL>
      <xsl:apply-templates/>
    </UL>
  </xsl:template>
 
  <xsl:template match="sm:RoleService">
    <xsl:if test="@Installed='true'">
      <B>
        <Font color="#00AA00">
          <xsl:value-of select="@DisplayName"/>
        </Font>
      </B>
    </xsl:if>
    <xsl:if test="@Installed='false'">
      <xsl:value-of select="@DisplayName"/>
    </xsl:if>
    <BR/>
    <UL>
      <xsl:apply-templates/>
    </UL>
  </xsl:template>
 
  <xsl:template match="sm:Feature">
    <xsl:if test="@Installed='true'">
      <B>
        <Font color="#00AA00">
          <xsl:value-of select="@DisplayName"/>
        </Font>
      </B>
    </xsl:if>
    <xsl:if test="@Installed='false'">
      <xsl:value-of select="@DisplayName"/>
    </xsl:if>
    <BR/>
    <UL>
      <xsl:apply-templates />
    </UL>
  </xsl:template>
 
</xsl:stylesheet>