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> /// <adsisetprop path='${iis.path}/Root' propname='AuthAnonymous' propvalue='true'/> /// /// <adsisetprop path='${iis.path}/Root/GWSSample'> /// <properties> /// <option name='AuthBasic' value='false'/> /// <option name='AuthNTLM' value='true'/> /// </properties> /// </adsisetprop> /// </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)); } } } }