I've attached a couple custom tasks that allow manipulation of ADSI via NAnt.  Some 
examples of usage: 
  
   <!-- set the IIS root path to allow Anonymous access --> 
  <adsisetprop path="IIS://localhost/W3SVC/1/Root" propname="AuthAnonymous" 
propvalue="true"/> 
  <!-- retrieve the setting for NTLM and echo it. --> 
  <adsigetprop path="IIS://localhost/W3SVC/1/Root" propname="AuthAnonymous" 
storein="bar"/> 
   <echo message="${bar}"/> 
   
  <!-- multiple sets are possible using this syntax -->    
  <adsisetprop path="${iis.path}/Root/GWSSample"> 
   <properties> 
    <option name="AuthBasic" value="true"/> 
    <option name="AuthNTLM" value="false"/> 
   </properties> 
  </adsisetprop> 
   
If people think this is a useful task, I'm happy to have it be a part of NAntContrib. 
// NAnt - A .NET build tool
// Copyright (C) 2002 Galileo International
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Gordon Weakliem ([EMAIL PROTECTED])
// 
using System;
using System.DirectoryServices; 
using SourceForge.NAnt;
using SourceForge.NAnt.Tasks;
using SourceForge.NAnt.Attributes;

namespace Galileo.NAnt.Tasks
{
  /// <summary>
  /// Base NAnt task for working with ADSI.  This task contains only the path of the 
ADSI
  /// object that you want to work with.
  /// </summary>
  public abstract class ADSIBaseTask : Task
  {
    public ADSIBaseTask()
    {
      _path = null;
    }

    private string _path;
    /// <summary>
    /// The ADSI path of the location where we want to work with.
    /// </summary>
    [TaskAttribute("path", Required=true)]
    public String Path
    {
      get { return _path; }
      set { _path = value; }
    }

    // TODO: not at all tested at this point!
#if false
    private string _host = "LocalHost";
    /// <summary>
    /// The Host where the target object is located, default is LocalHost
    /// </summary>
    [TaskAttribute("host", Required=false)]
    public String Host
    {
      get { return _host; }
      set { _host = value; }
    }

    private string _username;
    /// <summary>
    /// The username to authenticate on the host with
    /// </summary>
    /// <remarks>
    /// When you connect using IIS Admin Objects (IIS ADSI provider)from a remote 
client, you can't 
    /// specify explicit credentials, the program must run with the credentials valid 
to manipulate 
    /// the metabase on the remote server.  That means that the user running this 
program must be 
    /// an account with "administrative" privileges on the IIS server (unless you 
changed the master 
    /// operators property settings of IIS), with the same password as this account on 
the remote 
    /// server.
    /// Say you have Server A running IIS, Server B running this program.  Say you 
have on A an 
    /// account named "IISADMIN" with pwd "IISPWD" and this account is member of the 
    /// administrators alias on A, and on serverB the same account named "IISADMIN" 
with pwd "IISPWD"
    /// When you run this program, in a logon session as "IISADMIN", 
password="IISPWD", the program 
    /// will succeed.  Anything else will fail with "Access Denied".
    /// </remarks>
    [TaskAttribute("username", Required=false)]
    public String Username
    {
      get { return _username; }
      set { _username = value; }
    }
    private string _password;
    /// <summary>
    /// The password to authenticate with.
    /// </summary>
    [TaskAttribute("password", Required=true)]
    public String Password
    {
      get { return _password; }
      set { _password = value; }
    }
#endif

  }
}
// NAnt - A .NET build tool
// Copyright (C) 2002 Galileo International
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Gordon Weakliem ([EMAIL PROTECTED])
// 
using System;
using System.DirectoryServices; 
using SourceForge.NAnt;
using SourceForge.NAnt.Tasks;
using SourceForge.NAnt.Attributes;

namespace Galileo.NAnt.Tasks
{
        /// <summary>
        /// Used to get the value of a property from an ADSI object.
        /// </summary>
        [TaskName("adsigetprop")]
        public class ADSIGetPropertyTask : ADSIBaseTask {
                public ADSIGetPropertyTask() {
                }

                private string _propName;
                private string _storeIn;

                /// <summary>
                /// The name of the property to get
                /// </summary>
                [TaskAttribute("propname",Required=true)]
                public String PropName
                {
                        get { return _propName; }
                        set { _propName = value; }
                }

                /// <summary>
                /// The system property to store the value in.
                /// </summary>
                [TaskAttribute("storein",Required=true)]
                public String StoreIn
                {
                        get { return _storeIn; }
                        set { _storeIn = value; }
                }

                /// <summary>
                /// Sets the specified property
                /// </summary>
                protected override void ExecuteTask() 
                {
                        try
                        {
                                // Get the directory entry for the specified path and 
set the 
                                // property.
                                using (DirectoryEntry pathRoot = new 
DirectoryEntry(Path))
                                {
                                        pathRoot.RefreshCache();
                                        if (Project.Properties[StoreIn] == null)
                                        {
                                                Project.Properties.Add(StoreIn,"");
                                        }
                                        if 
(pathRoot.Properties[PropName].Value.GetType().IsArray)
                                        {
                                                System.Text.StringBuilder sb = new 
System.Text.StringBuilder();
                                                foreach (object propValue in 
(Array)pathRoot.Properties[PropName].Value)
                                                {
                                                        sb.AppendFormat("{0}" + 
Environment.NewLine,propValue);
                                                }
                                                Project.Properties[StoreIn] = 
sb.ToString();
                                        }
                                        else
                                        {
                                                Project.Properties[StoreIn] = 
pathRoot.Properties[PropName].Value.ToString();
                                        }
                                        Log.WriteLine("{0}{3}: Property {1} = {2}", 
                                                LogPrefix, PropName, 
Project.Properties[StoreIn],Path);
                                }
                        }
                        catch (Exception e)
                        {
                                Log.WriteLine("{0}Error reading property {1}: {2}", 
                                        LogPrefix, PropName,e.Message);
                                throw new BuildException(String.Format("Error reading 
property {0}: {1}", 
                                        PropName,e.Message),e);
                        }
                }
        }
}
// NAnt - A .NET build tool
// Copyright (C) 2002 Galileo International
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Gordon Weakliem ([EMAIL PROTECTED])
// 
using System;
using System.DirectoryServices; 
using SourceForge.NAnt;
using SourceForge.NAnt.Tasks;
using SourceForge.NAnt.Attributes;

namespace Galileo.NAnt.Tasks
{
  /// <summary>
  /// Sets a property on an ADSI object.
  /// </summary>
  /// <remarks>
  /// This task uses a heuristic to determine the type of the property in ADSI.  The 
following cases are notable:
  /// <list type="bulleted">
  ///   <item>If the property does not exist on the item, it is inserted as a 
string.</item>
  ///   <item>If the property already exists, this method will attempt to preserve
  ///   the type of the property.  The types this method knows about are String,
  ///   Boolean, and Int32.</item>
  ///   <item>If the property exists and is an array, the value is added to 
  ///   the array, but only if it is not already present.</item>
  /// </list>
  /// </remarks>
  /// <example>
  /// &lt;adsisetprop path='${iis.path}/Root' propname='AuthAnonymous' 
propvalue='true'/&gt;
  /// 
  /// &lt;adsisetprop path='${iis.path}/Root/GWSSample'&gt;
  /// &lt;properties&gt;
  /// &lt;option name='AuthBasic' value='false'/&gt;
  /// &lt;option name='AuthNTLM' value='true'/&gt;
  /// &lt;/properties&gt;
  /// &lt;/adsisetprop&gt;
  /// </example>
  [TaskName("adsisetprop")]
  public class ADSISetPropertyTask : ADSIBaseTask
  {
    public ADSISetPropertyTask()
    {
      _propertyList = new OptionSet();
    }

    private string _propName;
    private string _propValue;

    /// <summary>
    /// The name of the property to set
    /// </summary>
    [TaskAttribute("propname",Required=false)]
    public String PropName
    {
      get { return _propName; }
      set { _propName = value; }
    }

    /// <summary>
    /// The new value of the property
    /// </summary>
    [TaskAttribute("propvalue",Required=false)]
    public String PropValue
    {
      get { return _propValue; }
      set { _propValue = value; }
    }

    /// <summary>
    /// A group of properties to set with this task.
    /// </summary>
    private OptionSet _propertyList;
    [OptionSet("properties",Required=false)]
    public OptionSet PropertyList
    {
      get { return _propertyList; }
    }

    /// <summary>
    /// Sets the specified property
    /// </summary>
    protected override void ExecuteTask() 
    {
          if ( (this.PropName == null || this.PropValue == null) && 
this.PropertyList.Count == 0 )
          {
          throw new BuildException("propname and propvalue attributes or <properties> 
option set is required");
          }
          try
      {
        // Get the directory entry for the specified path and set the 
        // property.
        using (DirectoryEntry pathRoot = new DirectoryEntry(Path))
        {
          pathRoot.RefreshCache();
          
          // if there was a property named in the attributes, set it.
          if (PropName != null)
          {
            SetProperty(pathRoot, PropName, PropValue);
          }
          // set the properties named in the child property list.
          foreach (OptionValue ov in PropertyList)
          {
            SetProperty(pathRoot, ov.Name, ov.Value);
          }

          pathRoot.CommitChanges();
        }
      }
      catch (BuildException)
      {
        // rethrow any BuildExceptions from farther down.
        throw;
      }
      catch (Exception e)
      {
        // log any other exception and wrap it in a BuildException.
        Log.WriteLine(LogPrefix + "Error setting property {0}: {1}", 
          PropName,e.Message);
        throw new SourceForge.NAnt.BuildException(String.Format("Unable to set 
property {0} to value {1}: {2}",PropName,PropValue,e.Message),e);
      }
    }

    /// <summary>
    /// Sets the named property on the DirectoryEntry passed to the method to the 
given value.
    /// </summary>
    /// <param name="entry">The DirectoryEntry we're modifying</param>
    /// <param name="propName">The name of the property to set</param>
    /// <param name="propValue">The value to set the property to.</param>
    /// <remarks>
    /// The following cases are notable:
    /// <list type="bulleted">
    ///   <item>If the property does not exist on the item, it is inserted as a 
string.</item>
    ///   <item>If the property already exists, this method will attempt to preserve
    ///   the type of the property.  The types this method knows about are String,
    ///   Boolean, and Int32.</item>
    ///   <item>If the property exists and is an array, the value is added to 
    ///   the array, but only if it is not already present.</item>
    /// </list>
    /// </remarks>
    private void SetProperty(DirectoryEntry entry, String propName, String propValue)
    {
      if (!entry.Properties.Contains(propName))
      {
        entry.Properties[propName].Insert(0,propValue);
      }
      // TODO: can I find out the property type from the entry's schema?
      if (entry.Properties[propName].Value.GetType().IsArray)
      {
        // with arrays, don't add the value if it's already there.
        object objToSet = Convert(entry.Properties[propName][0],propValue);
        if (!entry.Properties[propName].Contains(objToSet))
        {
          entry.Properties[propName].Add(objToSet);
        }
      }
      else
      {
        //entry.Properties[propName].Clear();
        object originalValue = entry.Properties[propName].Value;
        object newValue= Convert(originalValue,propValue);
        entry.Properties[propName][0] = newValue;
      }
      Log.WriteLine(LogPrefix + "{2}: Property {0} set to {1}", 
        propName, propValue, Path);
    }
    
    private object Convert(object existingValue, String newValue)
    {
      if (existingValue is String)
      {
        return newValue.ToString();
      }
      else if (existingValue is Boolean)
      {
        return Boolean.Parse(newValue);
      }
      else if (existingValue is Int32)
      {
        return Int32.Parse(newValue);
      }
      else
      {
        throw new BuildException(String.Format("Don't know how to set property type 
{0}",existingValue.GetType().FullName));
      }
    }
  }
}

Reply via email to