<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.iis.net/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Blog:\&amp;gt;_</title><subtitle type="html">Sergei Antonov&amp;#39;s blog</subtitle><id>http://blogs.iis.net/sergeia/atom.aspx</id><link rel="alternate" type="text/html" href="http://blogs.iis.net/sergeia/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.iis.net/sergeia/atom.aspx" /><generator uri="http://communityserver.org" version="3.0.20510.895">Community Server</generator><updated>2008-08-22T12:32:00Z</updated><entry><title>Simple way of extending PowerShell objects with custom methods</title><link rel="alternate" type="text/html" href="http://blogs.iis.net/sergeia/archive/2008/09/08/extending-powershell-objects-with-custom-methods.aspx" /><id>http://blogs.iis.net/sergeia/archive/2008/09/08/extending-powershell-objects-with-custom-methods.aspx</id><published>2008-09-08T07:45:00Z</published><updated>2008-09-08T07:45:00Z</updated><content type="html">&lt;P&gt;As you may know, IIS configuration is extensible. You could add new section, extend existing one by adding new schema file into folder containing schemas. All this was described in full details in the &lt;A href="http://learn.iis.net/page.aspx/241/configuration-extensibility/" mce_href="http://learn.iis.net/page.aspx/241/configuration-extensibility/"&gt;article&lt;/A&gt; of Tobin Titus. When we provide methods on configuration elements with COM extension, the only way to call it using configuration APIs is through creation of method instance, then creation of input parameters element on this instance, etc -- quite convoluted way. In PowerShell we expose it in more convenient way, like intrinsic methods on the object. User is able to call these methods exactly the same way as any other intrinsic methods of given object. Let's see how runtime methods work on site element:&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;gt;$site = get-webconfiguration '/system.applicationHost/sites/site[@name="mysite"]'&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;gt;$site.Stop()&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;gt;$site.State&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;Stopped&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;gt;$site.Start()&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;gt;$site.State&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=SourceCode&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;Started&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Methods that are coming from configuration extension could be called directly. Properties from extension are updated dynamically, like property State on web site object. In this post I will explain how it is done.&lt;/P&gt;
&lt;P&gt;PowerShell SDK provides number of ways to add new functionality to any object. You could add note property, script property or code property. You also could add script and code methods. When I started my implementation, my first attempt was to expose extended methods as PSCodeMethod, but this requires code reference to real code that will be executed when my exposed method is called. That was a problem. This real code has to be generated dynamically. It is simple enough code that will take input parameters and do all required actions to call configuration API. It could be implemented using type DynamicMethod, but it has to be done through emitting code into buffer, and this is quite tricky even for simple code. After spending couple of days with code generators and managed assembly language reference I started looking for alternative.&lt;/P&gt;
&lt;P&gt;PowerShell PSCodeMethod inherits from PSMethodInfo type. PSMethodInfo is an abstract class that PowerShell uses to work with extended methods: it has name, description and Invoke method. You could inherit your type from PSMethodInfo and it will be used exactly the same way as regular code method. Problem is that property Name is not virtual and there is no way to set it from inherited class. Fortunately, you could do it through reflection. After I realized that, coding took just couple of hours. PSMethodInfo is public class, therefore it has stay the same in future, and property Name shouldn't go away. Using reflection here is OK -- it is a workaround for mistake in type design.&lt;/P&gt;
&lt;P&gt;You will find implementation code at the end of this post. Two methods of CodeMethod class are specific to IIS 7 configuration: one is Invoke() -- that uses configuration APIs to call extension method, and another one is GetDefinition() that produces human readable signature for the methods using method definition from IIS configuration schema. You could use the same approach for any other type of method: defined in XML, or in WMI, or in ADSI, any time when you have programmatically accessible method definition and some generic way to invoke this method, for example passing its name and parameters. With direct implementation of extension method you don't need to bend your code to be compatible with PSCodeMethod -- you could access your native method directly.&lt;/P&gt;
&lt;P&gt;Class CodeProperty is implemented very similarly, the only difference is that it inherits from PSPropertyInfo and declares itself as type PSPropertyInfo.CodeProperty. You also have to do the same dirty hack with name. In CodeProperty methods get() and set() call native implementation, because of this property value is refreshing at every access. Let's see how this will looks like in PowerShell.&lt;/P&gt;
&lt;P class=style2&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;$s = get-webconfiguration "//sites/site[@name='test']"&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=style2&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;$s | gm Start&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#000080&gt;&amp;nbsp;&lt;SPAN class=style2&gt;TypeName: Microsoft.IIs.PowerShell.Framework.ConfigurationElement&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;BR class=style2&gt;&lt;SPAN class=style2&gt;Name&amp;nbsp; MemberType Definition&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;SPAN class=style2&gt;----&amp;nbsp; ---------- ----------&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;SPAN class=style2&gt;Start CodeMethod void Start()&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style2&gt;$s.bindings.Collection[0] | gm AddSslCertificate | fl *&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;BR class=style2&gt;&lt;SPAN class=style2&gt;TypeName : Microsoft.IIs.PowerShell.Framework.ConfigurationElement&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;SPAN class=style2&gt;Name : AddSslCertificate&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;SPAN class=style2&gt;MemberType : CodeMethod&lt;/SPAN&gt; &lt;BR class=style2&gt;&lt;SPAN class=style2&gt;Definition : void AddSslCertificate(System.String certificateHash, System.String certificateStoreName)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Method AddSslCertificate() is an extension, defined on each binding element of the site, and it has the following schema:&lt;/P&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style2&gt;&amp;lt;element name="bindings"&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;  &amp;lt;collection addElement="binding" clearElement="clear"&amp;gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style2&gt;  ...&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;  &amp;lt;method name="AddSslCertificate" extension="Microsoft.ApplicationHost.RscaExtension"&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;     &amp;lt;inputElement&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;        &amp;lt;attribute name="certificateHash" type="string" /&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;        &amp;lt;attribute name="certificateStoreName" type="string" defaultValue="MY" /&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;     &amp;lt;/inputElement&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=style2&gt;  &amp;lt;/method&amp;gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE class=style2&gt;&lt;FONT color=#000080&gt;   ... &lt;/FONT&gt;&lt;/PRE&gt;
&lt;P&gt;How to use CodeMethod? Every time you have to return your object into PowerShell, you will convert it into PSObject, right? If you not doing this, PowerShell will do it for you, and it don't know that you have extended methods that has to be exposed in some specific way. So, you have to add those methods manually.&lt;/P&gt;
&lt;P&gt;PSObject myObject = new PSObject()&lt;/P&gt;
&lt;P&gt;myObject.Methods.Add(new CodeMethod("methodName", configurationMethod));&lt;/P&gt;
&lt;P&gt;...send object to PowerShell&lt;/P&gt;
&lt;P&gt;In my case I am adding CodeMethod created from extended configuration method instance and name of the method. In your case&amp;nbsp;you could pass and store any other type that will be used to call native&amp;nbsp;method implementation.&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Enjoy,&lt;/P&gt;
&lt;P&gt;Sergei Antonov&lt;/P&gt;
&lt;P&gt;Here is CodeMethod implementation (provided as is without any support):&lt;/P&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;public class CodeMethod : PSMethodInfo&lt;/SPAN&gt;
{
&lt;SPAN class=style1&gt;   private ConfigurationMethod configMethod;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   string definition;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;   public CodeMethod(string name, ConfigurationMethod method)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      FieldInfo nameField = this.GetType().GetField("name", &lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          BindingFlags.NonPublic | BindingFlags.Instance);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      if (nameField != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          nameField.SetValue(this, name);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      configMethod = method;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      definition = GetDefinition(method);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;   public override PSMemberTypes MemberType&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      get {return PSMemberTypes.CodeMethod;}&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;   public override Collection&amp;lt;string&amp;gt; OverloadDefinitions&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      get&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          Collection&amp;lt;string&amp;gt; returnValue = new Collection&amp;lt;string&amp;gt;();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          returnValue.Add(this.definition);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          return returnValue;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;   public override string ToString()&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      StringBuilder returnValue = new StringBuilder();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      foreach (string overload in OverloadDefinitions)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;         returnValue.Append(overload);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;         returnValue.Append(", ");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      returnValue.Remove(returnValue.Length - 2, 2);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      return returnValue.ToString();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;   public override string TypeNameOfValue&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      get { return typeof(CodeMethod).FullName;}&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;    public override PSMemberInfo Copy()&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      return new CodeMethod(Name, configMethod);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE class=style1&gt;&lt;FONT color=#000080&gt;   // This code is specific to IIS 7 configuration, &lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE class=style1&gt;&lt;FONT color=#000080&gt;   // and I put it here for illustration&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;   public override object Invoke(params object[] arguments)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;   {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      if (arguments == null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          throw new ArgumentNullException("arguments");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      ConfigurationMethodInstance mi = configMethod.CreateInstance();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      ConfigurationElementSchema input &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;         = configMethod.Schema.InputSchema;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      if (arguments.Length &amp;gt; 0)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          if (input != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              int parametersCount = 0;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              if (input.AttributeSchemas != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  parametersCount += input.AttributeSchemas.Count;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              if (input.ChildElementSchemas != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  parametersCount += input.ChildElementSchemas.Count;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              if (arguments.Length != parametersCount)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  throw new ArgumentException();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              PSObject argObject = new PSObject();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              // We produced definition from attributes first, then &lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              // from child elements. &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;              // We expect the same order on input.&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              int index = 0;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              if (input.AttributeSchemas != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  foreach (ConfigurationAttributeSchema s &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                     in input.AttributeSchemas)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                     argObject.Properties.Add(&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                        new PSNoteProperty(s.Name, &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                        arguments[index++]));&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              if (input.ChildElementSchemas != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  foreach (ConfigurationElementSchema s &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                     in input.ChildElementSchemas)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                     argObject.Properties.Add(&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                        new PSNoteProperty(s.Name, &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                        arguments[index++]));&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              mi.Input.Update(argObject);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      try&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          mi.Execute();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      catch (COMException ex)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          if (ex.ErrorCode == unchecked((int)0x80070490))&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;             // This happens when there is no binding &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;             // for FTP on the site.&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          else&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;             throw;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      if (mi.Output != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          if (configMethod.Schema&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                 .OutputSchema.AttributeSchemas.Count == 1)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              return mi.Output.Attributes[0].ToPSObject();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          else&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              return mi.Output.ToPSObject(null);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      return null;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;  }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;  private static string GetDefinition(ConfigurationMethod method)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;  {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      ConfigurationMethodSchema ms = method.Schema;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      ConfigurationElementSchema input = ms.InputSchema;&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      ConfigurationElementSchema output = ms.OutputSchema;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;       StringBuilder builder = new StringBuilder();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      if (output != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          if (output.AttributeSchemas.Count == 1)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              // Configuration returns any result as element. &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;              // We could produce&lt;/SPAN&gt;&lt;SPAN class=style1&gt; more reasonable signature here&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              ConfigurationAttributeSchema a &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                 = output.AttributeSchemas[0];&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              builder.Append(a.ClrType.Name);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          else&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              builder.Append("object");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      else&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          builder.Append("void");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      builder.Append(" ");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      builder.Append(ms.Name);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      builder.Append("(");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      if (input != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;      {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          foreach (ConfigurationAttributeSchema a &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;             in input.AttributeSchemas)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              builder.Append(a.ClrType);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              builder.Append(" ");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              builder.Append(a.Name);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              builder.Append(", ");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;           if (input.ChildElementSchemas != null)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              foreach (ConfigurationElementSchema child &lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=style1&gt;                 in input.ChildElementSchemas)&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              {&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  builder.Append("object");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  builder.Append(" ");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  builder.Append(child.Name);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;                  builder.Append(", ");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;              }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;          builder.Remove(builder.Length - 2, 2);&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;       }&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;       builder.Append(")");&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;       return builder.ToString();&lt;/SPAN&gt;
&lt;SPAN class=style1&gt;    }&lt;/SPAN&gt;
}&lt;/FONT&gt;&lt;/PRE&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2606290" width="1" height="1"&gt;</content><author><name>sergeia</name><uri>http://blogs.iis.net/members/sergeia.aspx</uri></author><category term="PowerShell" scheme="http://blogs.iis.net/sergeia/archive/tags/PowerShell/default.aspx" /><category term="PSMethodInfo" scheme="http://blogs.iis.net/sergeia/archive/tags/PSMethodInfo/default.aspx" /><category term="Extended Types" scheme="http://blogs.iis.net/sergeia/archive/tags/Extended+Types/default.aspx" /></entry><entry><title>How to change output format in PowerShell</title><link rel="alternate" type="text/html" href="http://blogs.iis.net/sergeia/archive/2008/08/29/how-to-change-output-format-in-powershell.aspx" /><id>http://blogs.iis.net/sergeia/archive/2008/08/29/how-to-change-output-format-in-powershell.aspx</id><published>2008-08-29T09:03:00Z</published><updated>2008-08-29T09:03:00Z</updated><content type="html">&lt;P&gt;I was looking around the Net today and stumbled on &lt;A href="http://www.hanselman.com/blog/HowToSetAnIISApplicationOrAppPoolToUseASPNET35RatherThan20.aspx" mce_href="http://www.hanselman.com/blog/HowToSetAnIISApplicationOrAppPoolToUseASPNET35RatherThan20.aspx"&gt;the post in Scott Hanselman's blog&lt;/A&gt;, where he talks about technical and marketing aspects of product naming in Microsoft. There he shows display format for IIS application pools that may be relevant to servers, where admins keep multiple versions of CLR and run applications in various modes. This output includes managed runtime version for the pool and mode (integrated or classical) for the pool. By default IIS provider shows only name, state and list of applications, assigned to this pool. It is pretty easy to change this output to what Scott prefers.&lt;/P&gt;
&lt;P&gt;Open file iisprovider.format.ps1xml (name could be changed in next release) and find view, defined there for application pool. This will be piece of XML tagged by type name "Microsoft.IIs.PowerShell.Provider.NavigationNode#AppPool". This typename means that as soon as PowerShell will find object in the output stream, which has this type name in its typenames collection, it will use this view. View selected once for the first object in output stream -- this is pretty annoying shortcoming in PowerShell because in IIS configuration it is common to have objects of multiple types in output.&lt;/P&gt;
&lt;P&gt;OK, now you have to create new XML file with the name you like, and extension "format.ps1xml", say PoolModeView.format.ps1xml. Then add there header and footer:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN class=html&gt;xml&lt;/SPAN&gt; &lt;SPAN class=attr&gt;version&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="1.0"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;encoding&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="utf-8"&lt;/SPAN&gt;?&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Configuration&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;ViewDefinitions&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0px
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;ViewDefinitions&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Configuration&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;/P&gt;
&lt;P&gt;Select whole section with pool view in original file and copy it into your new file. We will modify this view to add new columns. We have to change name of the view first. Let's name it "appPoolModeView". Then add new column definitions after the State column:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnHeader&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;State&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;12&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Alignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;left&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Alignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnHeader&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnHeader&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;CLR Version&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;12&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Alignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;left&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Alignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnHeader&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnHeader&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;Mode&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Label&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;12&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Alignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;left&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Alignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnHeader&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;/P&gt;
&lt;P&gt;That will be our column headers. We have to define, what to show in these columns. After section TableColumnItem for State, add the following:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;PropertyName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;State&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;PropertyName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;PropertyName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;managedRuntimeVersion&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;PropertyName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;PropertyName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;managedPipelineMode&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;PropertyName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;/P&gt;
&lt;P&gt;We will display two properties that identify CLR runtime and mode. Now we could save our file. In PowerShell window run the following command:&lt;/P&gt;
&lt;P&gt;PS C:\ #&amp;gt; Update-FormatData -prependpath &amp;lt;path-to-your-file&amp;gt;&lt;/P&gt;
&lt;P&gt;Depending on your settings in PowerShell you may see an error, because new file is not signed. As a long term solution you will need &lt;A class="" href="http://www.hanselman.com/blog/SigningPowerShellScripts.aspx" mce_href="http://www.hanselman.com/blog/SigningPowerShellScripts.aspx"&gt;to sign this file&lt;/A&gt; the same way you are signing scripts, for now you could relax execution policy to RemoteSigned.&lt;/P&gt;
&lt;P&gt;Let's see what we get:&lt;/P&gt;
&lt;P&gt;PS C:\ #&amp;gt; cd iis:\apppools&lt;/P&gt;&lt;PRE class=csharpcode&gt;PS IIS:\AppPools &lt;SPAN class=rem&gt;#&amp;gt; dir&lt;/SPAN&gt;

Name                  State     CLR Version  Mode         Applications
----                  -----     -----------  ----         ------------
DefaultAppPool        Started   v2.0         Integrated   Default Web Sit
                                                          e
                                                          mysite
                                                          /appDefault
                                                          /myapp
Classic .NET AppPool  Started   v2.0         Integrated
newPool               Started   v2.0         Integrated&lt;/PRE&gt;
&lt;P&gt;If you want to have this view, but don't like to use it by default, run update-formatdata without -prependpath. PowerShell will add your view to the internal tables, but still will use the old one. To enable new output format, add "format-table -view apppoolmodeview" to your output command, and you will get this view.&lt;/P&gt;
&lt;P&gt;PS IIS:\AppPools #&amp;gt; dir | ft -view appPoolModeView&lt;/P&gt;
&lt;H4&gt;XPath in output formatting&lt;/H4&gt;
&lt;P&gt;While we discussing output formatting, let me show how you could extend output for any object by adding pieces of script into the view. This script block could get any data and add it to your output. Look how I did it for application pool view. The last column shows applications, assigned to this pool. But pool structure doesn't include any indication about applications. To find which applications belong to the pool, we have to look through all applications and select those having property "applicationPool" set to the name of our pool. Let's take a look how we form column for applications (I inserted back ticks into long lines to fit them on screen):&lt;/P&gt;
&lt;DIV align=left&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;ScriptBlock&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    $pn = $_.Name
    $sites = get-webconfigurationproperty `
      "/system.applicationHost/sites/site/`&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      application[@applicationPool=`'$pn`'and `&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      @path='/']/parent::*" `
      machine/webroot/apphost -name name
    $apps = get-webconfigurationproperty `
      "/system.applicationHost/sites/site/`&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      application[@applicationPool=`'$pn`'and `&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;      @path!='/']" `
      machine/webroot/apphost -name path
    $out = ""
    foreach ($s in $sites + $apps) {$out = $out + $s + "`n"}
    $out = $out.Substring(0, $out.Length - 1)
    $out
  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;ScriptBlock&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TableColumnItem&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P align=left&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;/P&gt;
&lt;P&gt;In our namespace we are hiding root applications and root virtual directories, and moved their properties to sites. That's another XPath query, but in namespace definition for site. Because we need both sites and applications, scriptblock runs two queries. First it selects all root applications (with path'/') that are assigned to our pool (with name $pn). For each path query selects parent node for application, i.e. site, and returns name of this site. Second query selects names of all non-root applications with the same setting. Next line does the trick that shows all entries inside of column -- it appends each name from combined list to the string variable, and adds symbol &amp;lt;CR&amp;gt; after that. Then script removes the last &amp;lt;CR&amp;gt; and outputs the resulting string. When output module in PowerShell formats the view, it wraps strings inside of column, and inserted &amp;lt;CR&amp;gt; symbols point to end of each row.&lt;/P&gt;
&lt;P&gt;Certainly, one could write script block that doesn't use XPath, but this would be much longer code with multiple loops and conditions. XPath takes one query string and returns result with minimal overhead.&lt;/P&gt;
&lt;P&gt;Enjoy,&lt;/P&gt;
&lt;P&gt;Sergei Antonov&lt;/P&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2588273" width="1" height="1"&gt;</content><author><name>sergeia</name><uri>http://blogs.iis.net/members/sergeia.aspx</uri></author><category term="PowerShell" scheme="http://blogs.iis.net/sergeia/archive/tags/PowerShell/default.aspx" /><category term="XPath" scheme="http://blogs.iis.net/sergeia/archive/tags/XPath/default.aspx" /><category term="output views" scheme="http://blogs.iis.net/sergeia/archive/tags/output+views/default.aspx" /><category term="output formatting" scheme="http://blogs.iis.net/sergeia/archive/tags/output+formatting/default.aspx" /></entry><entry><title>How we use XPath in IIS PowerShell namespace</title><link rel="alternate" type="text/html" href="http://blogs.iis.net/sergeia/archive/2008/08/28/use-of-xpath-in-iis-powershell-namespace.aspx" /><id>http://blogs.iis.net/sergeia/archive/2008/08/28/use-of-xpath-in-iis-powershell-namespace.aspx</id><published>2008-08-28T07:18:00Z</published><updated>2008-08-28T07:18:00Z</updated><content type="html">&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;IIS 7 configuration API's were designed as DOM: you always have to start from top level data structure and work your way to the data you need, either collection element or child element attributes. It is quite annoying model when you are building generic tools, and soon we started looking for some way of cutting off amount of code required for access of internal collections and attributes. At some moment we realized that we could use System.Xml.XPath.XPathNavigator type to expose IIS configuration. This type could be used to represent any hierarchical data as tree for XPath queries, not necessarily originated in XML. That was a perfect fit: with XPath query we could access any entity inside of configuration in one step. First CTP of provider was based on this approach. It worked nice but was pretty slow. Keeping XPath engine in managed code introduced major performance bottleneck: configuration data are in non-managed code, and XPath engine should marshal across the border every piece of data during processing of query. To make it better, fearless IIS developer William Moy created XPath query processor in native code, following the same model as XPathNavigator, and second CTP of provider is based on this engine. It is so effective, that when we access internal data inside of configuration section using fully qualified path it takes in average only 10% longer than using straight code based on explicit configuration API's, when this code accesses the same data. Fully qualified here means that path points to the unique data inside of configuration, and query don't need to walk around big parts of tree.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;As you probably know, configuration system in IIS 7 is distributed, and is merged from multiple configuration files located in root folders of virtual directories and file system folders below them. Path that points to any of these containers for configuration files named &lt;EM&gt;commit path&lt;/EM&gt;.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;XPath engine works with the search tree built from IIS configuration sections, merged from files which were gathered along some commit path. The tree has root, represented by root section group, then it includes child groups and sections, then child elements and collection elements, so it is kind of like Object Viewer tree in Visual Studio, rather than file system tree. If written properly, XPath query could return just one unique piece of data from configuration, in that case we could use it as universal addressing format for configuration data. Or it could select set of nodes from the search tree, in that case it is good to describe groups of data, for example, all sites, or all applications of the site, etc. If we store these queries into some place, we could describe our own namespace, composed from data extracted from configuration by these stored queries. &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;XPath queries are the backbone of IIS 7 PowerShell namespace: if you open file NavigationTypes.xml, you will see that most of things in the namespace are described as XPath queries, for example,&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" New?;="New?;" ?Courier="?Courier" mso-bidi-font-family:="mso-bidi-font-family:" roman?,?serif?;="roman?,?serif?;" times="times"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" mso-bidi-font-family:="mso-bidi-font-family:" 12.0pt?="12.0pt?" mso-bidi-font-size:="mso-bidi-font-size:" Roman?;="Roman?;" new?;="new?;" courier="courier"&gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" mso-bidi-font-family:="mso-bidi-font-family:" 12.0pt?="12.0pt?" mso-bidi-font-size:="mso-bidi-font-size:" Roman?;="Roman?;" new?;="new?;" courier="courier"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" mso-bidi-font-family:="mso-bidi-font-family:" 12.0pt?="12.0pt?" mso-bidi-font-size:="mso-bidi-font-size:" Roman?;="Roman?;" new?;="new?;" courier="courier"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" mso-bidi-font-family:="mso-bidi-font-family:" 12.0pt?="12.0pt?" mso-bidi-font-size:="mso-bidi-font-size:" Roman?;="Roman?;" new?;="new?;" courier="courier"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" roman?,?serif?;="roman?,?serif?;" times="times"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" mso-bidi-font-family:="mso-bidi-font-family:" 12.0pt?="12.0pt?" mso-bidi-font-size:="mso-bidi-font-size:" Roman?;="Roman?;" new?;="new?;" courier="courier"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" roman?,?serif?;="roman?,?serif?;" times="times"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;FONT color=#000080&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;virtualDirectory&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp; ...&lt;BR&gt;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;InstanceXPath&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;%parent::InstanceXPath%/virtualDirectory[@path="%path%"]&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;InstanceXPath&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp; ...&lt;BR&gt;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;children&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;childInfo&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;childType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;fileDirectory&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;childType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;xPath&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;%InstanceXPath%/physicalPath&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;xPath&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;childInfo&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;childInfo&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;childType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;file&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;childType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;xPath&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;%InstanceXPath%/physicalPath&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;xPath&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;childInfo&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&amp;nbsp; &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;children&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;virtualDirectory&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;This description instructs code in provider how to list virtualDirectory namespace nodes, how to produce list of child nodes for this node. Names in %% are macros referring to namespace object properties, or its parent properties. When user wants to get object, provider resolves InstanceXPath using specific instance as parent and sends expanded query strings to XPath engine, then it uses resulting selection to build namespace object. This approach is very flexible: if I want to rearrange the tree, all I need to do is to modify this XML file; if I want to add new namespace type, based on configuration object from some section, in most cases I only add its description to this XML tree. After restart of PowerShell IIS provider will resolve it and new type will be exposed in the namespace. Format of namespace description was changed a bit after CTP2 to enable addition of new description files, so you could use this model to extend our namespace and include your objects.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;XPath queries directly accessible for user through base level commands: get-webconfiguration and set-webconfiguration. There are two more commands that work with properties, they also consume XPath queries to address object owning properties. Our XPath engine actually works with two trees, one combined from sections, elements and attributes, and another one -- from commit paths. This commit path engine is used, for example,&amp;nbsp; when we want to retrieve configuration recursively starting from some entry point on commit path tree, say, from some particular site. When you run command&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;get-webconfiguration /system.webServer/asp/limits/@requestQueueMax "iis:\sites\default web site" -recurse&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt; &lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;it will return all setting for asp section attribute requestQueueMax, existing down the tree from "Default Web Site". To direct query down the tree, provider internally resolves namespace path, and when -recurse is specified, converts it into "MACHINE/WEBROOT/APPHOST/Default Web Site/descendant-or-self::node()". This expression tells query engine that it should not limit search by one level, and should go down the tree. Another part, configuration XPath is also modified to "/system.webServer/asp/limits/@requestQueueMax[is-locally-defined()]". Function in square brackets is specific to IIS configuration navigator, it returns "true" if attribute was defined on some particular level, otherwise query will return all inherited values for this attribute. Our XPath engine defines several functions like this one, I will describe all of them later.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;This is an example of simplest XPath query. You could write much more complicated expressions and get more specific data from configuration. I recommend to learn a bit about XPath, if you want to use our "platform" level functionality to write you own scripts and functions in PowerShell, you will be surprised, how much you could achieve in just couple of line. You could find pretty good practical courses in XPath in many places in the Net, some sites offer visual XPath editor that shows result of your query applied to sample data file.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;Almost all helper commands that we released in CTP2 were built very quickly and are all based on base level commands. Each simplified cmdlet is nothing more but piece of code that declares parameters, then compiles low level command from user input and calls get-webconfiguration or other command. You could do the same for cmdlet specific to your needs. If you are using PowerShell v2.0, you could write script based cmdlets instead of compiled code. Let me show you one example of helper command.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;PS IIS:\#&amp;gt; get-command new-webbinding | select definition | fl * &lt;/SPAN&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;Definition : New-WebBinding [-Site] &amp;lt;String&amp;gt; [-Port &amp;lt;UInt32&amp;gt;] [-IPAddress &amp;lt;String&amp;gt;] [-HostHeader &amp;lt;String&amp;gt;] [-Ssl] [-Force] ...&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;For clarity I removed parameters inserted by PowerShell. This cmdlet defines all parameters that we need to create binding on some site: site name, port, ipaddress, host header and ssl switch, that tells us that we have to build binding for ssl. Internal code then compiles another command:&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;new-itemproperty IIS:\sites\&amp;lt;site_name&amp;gt; -name Bindings -value @{protocol="http";bindingInformation="&amp;lt;IPAddress&amp;gt;:&amp;lt;Port&amp;gt;:&amp;lt;Host_Header&amp;gt;"}&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;Here is the source code for ProcessRecord method of the cmdlet, it uses couple of utility functions to format error message and to invoke resulting script. I assume that you are familiar with details of PowerShell SDK and know how to write cmdlets. PowerShell v1.0 doesn't show errors happened in internally called script, therefore I have to check $error variable and if there is an error, print it in my utility function. In v2.0 that was already fixed.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;... &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;protected override void ProcessRecord() &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StringBuilder cmdLine = new StringBuilder("new-itemproperty "); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string protocol = "http"; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (sslBinding.IsPresent) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protocol = "https"; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append("\"IIS:\\sites\\" + siteName + "\" "); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(" -name Bindings -value @{protocol=\""); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(protocol); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append("\";bindingInformation=\""); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!ipAddress.Equals("*")) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IPAddress test = IPAddress.Any; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!IPAddress.TryParse(ipAddress, out test)) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentException(&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Utility.FormatResourceString( &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;"InvalidIPAddress", ipAddress)); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(ipAddress); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (sitePort == 0xFFFFFFFF) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sitePort = (uint)(sslBinding.IsPresent ? 443 : 80); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(":" + sitePort.ToString() + ":"); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!String.IsNullOrEmpty(hostHeader)) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(hostHeader); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (!sslBinding.IsPresent) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(siteName); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append("\"}"); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Force.IsPresent) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.Append(" -force"); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Utility.InvokeScriptShowError(this, &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" new?;="new?;" courier="courier"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmdLine.ToString()); &lt;BR&gt;} &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;... &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;That's all you need to make it work. It is a simple command, most of source code is required to declare and describe parameters, I spent half an hour to write it, and as a result user could avoid typing expression for PowerShell hastable @{...}, so unpopular in PowerShell MVP circles and could omit some parameters altogether.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;In my next post I will show you some less trivial queries that could produce more exciting results.&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;
&lt;P class=MsoNormal style="MARGIN: 6pt 0in; LINE-HEIGHT: normal"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 6pt 0in; LINE-HEIGHT: normal"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" arial?,?sans-serif?;="arial?,?sans-serif?;" roman??="Roman??"&gt;Sergei Antonov&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 8.5pt; FONT-FAMILY: " new="new" ?Times="?Times" mso-fareast-font-family:="mso-fareast-font-family:" roman??="Roman??" mso-bidi-font-family:="mso-bidi-font-family:" Roman?;="Roman?;" ms?,?sans-serif?;="ms?,?sans-serif?;" trebuchet="trebuchet"&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2585533" width="1" height="1"&gt;</content><author><name>sergeia</name><uri>http://blogs.iis.net/members/sergeia.aspx</uri></author><category term="PowerShell" scheme="http://blogs.iis.net/sergeia/archive/tags/PowerShell/default.aspx" /><category term="XPath" scheme="http://blogs.iis.net/sergeia/archive/tags/XPath/default.aspx" /></entry><entry><title>IIS7 PowerShell support -- details of our design</title><link rel="alternate" type="text/html" href="http://blogs.iis.net/sergeia/archive/2008/08/22/ProviderDesignConsiderations.aspx" /><id>http://blogs.iis.net/sergeia/archive/2008/08/22/ProviderDesignConsiderations.aspx</id><published>2008-08-22T19:35:00Z</published><updated>2008-08-22T19:35:00Z</updated><content type="html">&lt;P&gt;After IIS team released Technical Preview of our PowerShell provider and commands, we got a few rants and grumblings from our customers. Some people pointed to complexity of IIS PowerShell provider and command parameters. Other people denied the need of provider for IIS at all, telling that just a set of commandlets with simple parameters will be sufficient. I have to admit that we did a mistake shipping preview of provider without complete set of commands. This created an impression of incomprehensible complexity of our tool. &lt;/P&gt;
&lt;P&gt;In reality we had the following plan in mind: build base functionality first -- namespace, provider and generic cmdlets for configuration data handling, then add on top of it number of helper commands to cover most common and most convoluted tasks and actions. In our second preview release we included several dozens of commands that don’t require deep understanding of IIS configuration and structure of provider namespace. All these commands were implemented as “C# coded scripts”, i.e. they take parameters from user and generate script lines utilizing base functionality. We have to do it as compiled cmdlets, because for PowerShell v1.0 it is the only way to get full service from shell: help, parameters description, etc. In PowerShell v 2.0 these cmdlets could be implemented through pure readable script.&lt;/P&gt;
&lt;P&gt;For the beginning I would like to explain a bit of our reasoning behind design of our PowerShell provider and base level cmdlets.&lt;/P&gt;
&lt;P&gt;1. From my early days in IIS team I always had a feeling that we need interactive command tool that would work like shell on top of IIS configuration. I believe IIS administrators will use this tool more like a shell than like a script processor. Therefore navigation and other aspects of namespace were considered important. When Jeffrey Snover showed us the very first prototype of PowerShell, I saw what I always wanted: interactive composable shell with navigation.&lt;/P&gt;
&lt;P&gt;2. IIS configuration is rich and quite complicated. Let me illustrate it by numbers. On my development machine I could run the following command and find total number of configuration sections with schema (I will get back to details of these commands in my later posts):&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;$(get-webconfiguration “//*[is-section()=’true’]” MACHINE/WEBROOT/APPHOST).count&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This will produce 102 in my case. It means we have at least 102 data structures to manage. Now let’s run another command, which will show how many sections have default collections:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;$(get-webconfiguration "//*[is-section()='true']" MACHINE/WEBROOT/APPHOST | where {$_.Schema.CollectionSchema -ne $null}).count&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;That gives me 36. And finally, let’s take a look at the total number of collections on unique elements:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;$names = @{}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;$elements = get-webconfiguration //* MACHINE/WEBROOT/APPHOST | where {$_.Schema.CollectionSchema -ne $null}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;foreach ($el in $elements) {$names[$el.ElementTagName] += 1}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;$names.Count&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;I got 88 here. What these numbers tell us? Our tool have to handle many data collections, and most of them are nested either inside child elements of sections, or inside parent collections. &lt;/P&gt;
&lt;P&gt;Both considerations lead to namespace that should support navigation, operations on objects of this namespace and on properties of those objects. PowerShell naturally supports this functionality through providers. Historically IIS had hierarchy of objects that roughly follows URL path. Up to IIS 6 it was directly supported by metabase, in IIS 7 we placed all URL “related” objects into nested collections of one giant structure, configuration section ‘system.applicationHost/sites’. For PowerShell namespace I decided to abstract from details of configuration storage implementation and return back to familiar hierarchy “server/site/application/virtual directory/web directory/etc”. User could navigate along this hierarchy, change properties of objects, execute commands for them, copy objects, and current path will be used in most commands by default. This hierarchy roughly relates to commit path, as it used in configuration APIs, i. e. to concrete configuration files.&lt;/P&gt;
&lt;P&gt;Now, let’s consider why provider is important. Imagine that we want to have set of operations on configuration objects without navigation path. It would be like using file system provider from the root of the drive, you always have to type full path. Don’t like path at all? You still need to specify full set of parameters to address nested objects: applications inside of site element, virtual directories inside of application, etc. For example, command to set user name on virtual directory would be something like&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Set-username –site mysite –application myapp –virtualdirectory myvdir –value dude&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Set-property –site mysite –application myapp –virtualdirectory myvdir –name username –value dude&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Instead of &lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Set-itemproperty iis:\sites\mysite\myapp\myvdir –name user –value dude&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;I don’t think that provider command is more complicated than any of first two commands. Use of provider has additional benefits: you have to deal with the same commands as in other namespaces, or in other parts of IIS namespace. Do you want to change setting on the application pool? Use the same command:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Set-itemproperty iis:\apppools\mypool –name autoStart –value false&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;All you need is to remember how path is constructed in our namespace. This will happen naturally when you use it and navigate along it. Don’t remember property names? Use the same command, as you would do for other providers:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Get-item iis:\apppools\mypool | get-member&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Or, if you already navigated to this object and use standard command aliases,&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Gi . | gm&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;Sp . –n autostart –val true&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;In other words, if we want to use benefits of being one of PowerShell namespaces, we have to design namespace, path and provider. I tried to show you here, that we are not losing anything when we use set of standard commands instead of recreating them outside of namespace.&lt;/P&gt;
&lt;P&gt;Web objects are important, but main bulk of configuration data is stored outside of them – in configuration sections. In my next post I will discuss how we use XPath queries to provide flexible and user extensible namespace.&lt;/P&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2575350" width="1" height="1"&gt;</content><author><name>sergeia</name><uri>http://blogs.iis.net/members/sergeia.aspx</uri></author><category term="PowerShell" scheme="http://blogs.iis.net/sergeia/archive/tags/PowerShell/default.aspx" /></entry><entry><title>Hello, everyone!</title><link rel="alternate" type="text/html" href="http://blogs.iis.net/sergeia/archive/2008/08/22/hello-everyone.aspx" /><id>http://blogs.iis.net/sergeia/archive/2008/08/22/hello-everyone.aspx</id><published>2008-08-22T19:32:00Z</published><updated>2008-08-22T19:32:00Z</updated><content type="html">&lt;P&gt;Hi, I would like to introduce myself first. &lt;/P&gt;
&lt;P&gt;My name is Sergei Antonov, I am a developer and I spent with IIS team more than 10 years in various capacities, working on administration and configuration tools for IIS. During these years I worked on design and implementation of various GUI tools, programming APIs and configuration storage. Currently I own scripting and command line tools. You could send me your questions, comments&amp;nbsp;and complains regarding PowerShell support in IIS and about WMI provider.&lt;/P&gt;
&lt;P&gt;In my next blog posts I will concentrate on use of PowerShell with IIS, my main goal here is to engage community to start using our PowerShell platform in order to write custom tools that will solve your administration problems. When needed, I will discuss configuration features, our new XPath engine, scripting and whatever else you and I will find interesting.&lt;/P&gt;
&lt;P&gt;Sergei&lt;/P&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2575344" width="1" height="1"&gt;</content><author><name>sergeia</name><uri>http://blogs.iis.net/members/sergeia.aspx</uri></author></entry></feed>