Archive

Archive for January, 2009

Creating an IIS Site through managed code (C#, .NET)

January 23rd, 2009 Michael Bell 3 comments

Another task I had in the past along with creating the DNS entries via managed code, was creating a new site in IIS. I had to nip various code from various places, but when I got done, it all worked nicely together. You will notice by the try catch block, that again, I was executing this chunk of code from a web based application. Needless to say, chances are you won’t have the permissions to do this unless you do. This code works on IIS 6.0 with Windows 2003 Server Std Edition . I’d imagine it’s more IIS specific than OS specific, but this is the only version of Windows I’ve tested it with.

public static string CreateWebSite(string NewSiteIP, string webSiteName, string pathToRoot, string DomainName)
{
    int siteID = 1;
    string sSiteID = “”;
    try
    {                

        CreatePhysicalDirectory(pathToRoot, webSiteName);

        ManagementScope _scope = new ManagementScope(@”\\WINDOWS\root\MicrosoftIISV2″, null);
        _scope.Connect();

        ManagementObject oW3SVC = new ManagementObject(_scope, new ManagementPath(@”IIsWebService=’W3SVC’”), null);
        DirectoryEntry root = new DirectoryEntry(”IIS://WINDOWS/W3SVC”);

        #region get a good site id
        foreach (DirectoryEntry e in root.Children)
        {
            if (e.SchemaClassName == “IIsWebServer”)
            {
                int ID = Convert.ToInt32(e.Name);
                if (ID >= siteID)
                    siteID = ID + 1;
            }
        }
        #endregion

        ManagementScope mScope = null;
        ManagementPath mPath = new ManagementPath();
        mPath.ClassName = “ServerBinding”;
        mPath.NamespacePath = “root\\MicrosoftIISv2″;
        mScope = new ManagementScope(mPath);
        mScope.Path.Server = “WINDOWS”;

        #region Create the new Site
        ManagementBaseObject[] serverBindings = new ManagementBaseObject[2];
        serverBindings[0] = CreateServerBinding(DomainName, NewSiteIP, “80″);
        serverBindings[1] = CreateServerBinding(”www.” + DomainName, NewSiteIP, “80″);

        ManagementBaseObject inputParameters = oW3SVC.GetMethodParameters(”CreateNewSite”);
        inputParameters["ServerComment"] = ConfigurationManager.AppSettings["SitePrefix"] + webSiteName;
        inputParameters["ServerBindings"] = serverBindings;
        inputParameters["PathOfRootVirtualDir"] = pathToRoot + webSiteName;
        inputParameters["ServerId"] = siteID;

        ManagementBaseObject outParameter = null;
        outParameter = oW3SVC.InvokeMethod(”CreateNewSite”, inputParameters, null);
        // return is like IIsWebServer=’W3SVC/2145288186′

        sSiteID = Convert.ToString(outParameter.Properties["ReturnValue"].Value).Replace(”IIsWebServer=’W3SVC/”,”").Replace(”‘”,”");

        ManagementObject site = new ManagementObject(_scope,
            new ManagementPath(Convert.ToString(outParameter.Properties["ReturnValue"].Value)),
            null);
        #endregion

        #region Remap ScriptMaps
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(@”root\MicrosoftIISv2″,
            “SELECT * FROM IIsWebVirtualDirSetting WHERE Path = ‘” + pathToRoot.Replace(@”\”,@”\\”) + webSiteName + “‘”) ;

        foreach(ManagementObject queryObj in searcher.Get())
        {
            if (queryObj.Properties["ScriptMaps"] != null)
            {
                Object[] arrScriptMaps = (Object[])(queryObj["ScriptMaps"]);
                foreach (Object arrValue in arrScriptMaps)
                {
                    foreach (PropertyData data in ((ManagementBaseObject)arrValue).Properties)
                    {
                        if(Convert.ToString(data.Value).ToLower()==@”c:\windows\microsoft.net\framework\v1.1.4322\aspnet_isapi.dll”)
                            if (data.Name == “ScriptProcessor”)
                                data.Value = @”c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll”;
                    }
                }
                queryObj.SetPropertyValue(”ScriptMaps”, arrScriptMaps);
                queryObj.Put();
            }
        }
        #endregion

        ManagementPath myPath = new ManagementPath();
        myPath.Path = @”IIsWebVirtualDirSetting.Name=’W3SVC/” + siteID.ToString() + “/root’”;
        ManagementObject oWebVDir = new ManagementObject(_scope, myPath, null);

        oWebVDir.Properties["AppFriendlyName"].Value = “mah new app”;
        oWebVDir.Properties["AccessRead"].Value = true;
        //oWebVDir.Properties["ServerAutoStart"].Value = true;
        oWebVDir.Properties["AuthFlags"].Value = 5; // Integrated Windows Auth.
        oWebVDir.Properties["AccessScript"].Value = true;
        oWebVDir.Properties["AuthAnonymous"].Value = true;
        oWebVDir.Properties["AppPoolId"].Value = “MyAppPoolName”;
        oWebVDir.Put();

        site.InvokeMethod(”Start”, null);
    }
    catch (Exception ex)
    {
        HttpContext.Current.Response.Write(ex.Message + “<BR>”);
        HttpContext.Current.Response.Write(ex.StackTrace);
        HttpContext.Current.Response.Write(ex.ToString());
        HttpContext.Current.Response.End();
    }

    return sSiteID;
}

private static void CreatePhysicalDirectory(string pathToRoot, string webSiteName)
{
    if (Directory.Exists(pathToRoot + webSiteName))
        throw new Exception(”Error creating new website: Customer root directory already exists at ” + pathToRoot + webSiteName);
    else
    {
        Directory.CreateDirectory(pathToRoot + webSiteName);
        //StreamWriter indexFile = new StreamWriter(pathToRoot + webSiteName + @”\index.htm”, false, System.Text.Encoding.ASCII);
        //indexFile.Write(”<html><body><br><br><br><br><center><h2><font name=’Verdana’>Welcome to <font color=’green’>&nbsp;” + webSiteName + “</font></font></h2></center></body></html>”);
        //indexFile.Close();
    }
}

/// <summary>
/// Adds a host header value to a specified website. WARNING: NO ERROR CHECKING IS PERFORMED IN THIS EXAMPLE.
/// YOU ARE RESPONSIBLE FOR THAT EVERY ENTRY IS UNIQUE
/// </summary>
/// <param name=”hostHeader”>The host header. Must be in the form IP:Port:Hostname </param>
/// <param name=”websiteID”>The ID of the website the host header should be added to </param>
private static void AddHostHeader(string hostHeader, string websiteID)
{
    DirectoryEntry site = new DirectoryEntry(”IIS://localhost/w3svc/” + websiteID);
    try
    {
        //Get everything currently in the serverbindings propery.
        PropertyValueCollection serverBindings = site.Properties["ServerBindings"];

        //Add the new binding
        serverBindings.Add(hostHeader);

        //Create an object array and copy the content to this array
        Object[] newList = new Object[serverBindings.Count];

        serverBindings.CopyTo(newList, 0);
        //Write to metabase

        site.Properties["ServerBindings"].Value = newList;

        //Commit the changes
        site.CommitChanges();
    }

    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}      

public static ManagementObject CreateServerBinding(string HostName, string IP, string Port)
{
    ManagementScope _scope = new ManagementScope(@”\\WINDOWS\root\MicrosoftIISV2″);
    _scope.Connect();

    ManagementClass classBinding = new ManagementClass(_scope, new ManagementPath(”ServerBinding”), null);
    ManagementObject serverBinding = classBinding.CreateInstance();
    serverBinding.Properties["Hostname"].Value = HostName;
    serverBinding.Properties["IP"].Value = IP;
    serverBinding.Properties["Port"].Value = Port;
    serverBinding.Put();
    return serverBinding;
}
Categories: ASP.NET, IIS, c# Tags:

Creating a DNS Entry in Windows 20003 Std Edition with c# .NET

January 23rd, 2009 Michael Bell No comments

One of the websites I did in the past required me to be able to register a domain, create the site in IIS, add the DNS entries, and add email entries into HMail server. Here is the DNS server half of it. Of course you have to have permissions, but this is the method I used to get from A to B entering a new domain name into the DNS Server in Windows 2003 Standard Edition. You can tell by my exception block that this piece of code was executed from an ASP.NET Web Application:

/// <summary>
/// Created an entry in DNS Server on a Windows 2003 Server
/// </summary>
/// <param name=”Domain”>Domain name and TLD Extension</param>
/// <param name=”AssignToIpAddr”>IP Address the site belongs to in IIS</param>
/// <param name=”PrimaryServerIP”>IP Address of the DNS Server itself</param>
/// <param name=”AdminEmailName”>Email of the administrator for this domain</param>
public void new_Zone(string Domain, string AssignToIpAddr, string PrimaryServerIP, string AdminEmailName)
{
    Domain = Domain.ToLower();
    try
    {
        string[] ipArray;
        ipArray = new string[1] { AssignToIpAddr };

        //Create Foward Lookup Zone.
        string sServerPath = “\\\\WINDOWS\\ROOT\\MicrosoftDNS”;
        ManagementScope oScope = new ManagementScope(sServerPath);
        oScope.Connect();
        ManagementPath Path = new ManagementPath(”MicrosoftDNS_Zone”);
        ManagementClass DnsZoneClass = new ManagementClass(oScope, Path, null);
        ManagementBaseObject InputParams =  DnsZoneClass.GetMethodParameters(”CreateZone”);

        InputParams["ZoneName"] = Domain;
        InputParams["ZoneType"] = 0;
        InputParams["AdminEmailName"] = AdminEmailName;
        InputParams["IpAddr"] = ipArray;
        ManagementBaseObject OutParams = DnsZoneClass.InvokeMethod(”CreateZone”, InputParams, null);

        #region A Records
        ManagementPath newPath = new ManagementPath(”MicrosoftDNS_ATYPE”);
        ManagementClass ARecordClass = new ManagementClass(oScope, newPath, null);
        ManagementBaseObject ARecord = ARecordClass.GetMethodParameters(”CreateInstanceFromPropertyData”);ARecord["DnsServerName"] = “WINDOWS”;

        ARecord["ContainerName"] = Domain;
        ARecord["OwnerName"] = Domain;
        ARecord["IPAddress"] = ipArray[0];

        OutParams = ARecordClass.InvokeMethod(”CreateInstanceFromPropertyData”, ARecord, null);

        ManagementClass dnsRRClass = new  ManagementClass(@”\\” + System.Environment.MachineName + @”\root\MicrosoftDNS”, “MicrosoftDNS_ResourceRecord”, null);
        ManagementBaseObject inParams =  dnsRRClass.GetMethodParameters(”CreateInstanceFromTextRepresentation”);

        inParams["DnsServerName"] = “.”;
        inParams["ContainerName"] = Domain;
        inParams["TextRepresentation"] = “www.” + Domain + ” IN A ” + ipArray[0];
        OutParams = dnsRRClass.InvokeMethod(”CreateInstanceFromTextRepresentation”, inParams, null);

        dnsRRClass = new ManagementClass(@”\\” + System.Environment.MachineName + @”\root\MicrosoftDNS”, “MicrosoftDNS_ResourceRecord”, null);
        inParams = dnsRRClass.GetMethodParameters(”CreateInstanceFromTextRepresentation”);

        inParams["DnsServerName"] = “.”;
        inParams["ContainerName"] = Domain;
        inParams["TextRepresentation"] = “mail.” + Domain + ” IN A ” + ipArray[0];
        OutParams = dnsRRClass.InvokeMethod(”CreateInstanceFromTextRepresentation”, inParams, null);

        #endregion
    }
    catch (Exception ex)
    {
        //throw;
        HttpContext.Current.Response.Write(ex.Message + “<BR>”);
        HttpContext.Current.Response.Write(ex.StackTrace);
        HttpContext.Current.Response.Write(ex.ToString());
        HttpContext.Current.Response.End();
    }
}
Categories: ASP.NET, DNS, IIS, c# Tags:

Tools for Sharepoint Deployment

January 22nd, 2009 Michael Bell No comments

I’ve tried WSPBuilder, the Extensions, and STSDev all. They were all very useful in starting out and in simple projects. I’ve found that at least for my projects, manually writing a DDF file and using the makecab myself turns out to be far, far easier. When you start doing something that’s a little out of the ordinary, the tools can really eat your time. You end up fighting the tools automated processes rather than the code you’re suppose to be writing.

To build your deployment package, you will need to build a DDF file, or Diamond Directive File. This tells makecab what to include in your WSP, and where it should extract to.
Here is an example of a simple DDF file:
;This file is for WSP CAB Generation
;A WSS or in this case MOSS solution file is essentially a .cab file,
;use the makecab.exe tool to create the solution package.
;The makecab.exe tool takes a pointer to a .ddf file,
;which describes the structure of the .cab file. 
;The format of a .ddf file is basically that
;you declare a standard header and
;then enumerate, one file per line, the set of files by where they live on disk,
;separated by where they should live in the .cab file

.OPTION EXPLICIT     ; Generate errors
.Set CabinetNameTemplate=”MyCoolTool.wsp”
.set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory
.Set CompressionType=MSZIP;** All files are compressed in cabinet files
.Set UniqueFiles=”ON”
.Set Cabinet=on
.Set DiskDirectory1=”..\..\Package”
;All file reference should be from the project root
;Files to place into the CAB Root

MyCoolTool.dll

..\..\Manifest.xml

.Set DestinationDir=MyCoolTool
..\..\Feature.xml

.Set DestinationDir=MyCoolTool\ContentPages
..\..\ContentPages\Module.xml
..\..\..\MyCoolToolWebApp\Tool.aspx
..\..\..\
MyCoolToolWebApp\Tool.aspx.cs

.Set DestinationDir=ControlTemplates\MyCoolTool
..\..\..\MyCoolToolWebApp\Controls\MyCoolToolControl.ascx           
..\..\..\
MyCoolToolWebApp\Controls\MyCoolToolControl.ascx.cs       
..\..\..\
MyCoolToolWebApp\Controls\MyCoolToolControl.ascx.designer.cs

.Set DestinationDir=IMAGES\MyCoolTool
..\..\IMAGES\MyCoolFeaturePicture.gif

And on your Project Properties, go to the “Build Events” tab, then the “Post build event command line:” area, and type in:
makecab /f “$(TargetDir)NameOfMy.ddf”

This should build your WSP file for you every time you compile. When you’re ready for a deploy, build some batch files to make it easy. I actually joined my retract and deploy script together so I wouldn’t have to wait on one to finish and then click to do the other. Might as well get them both overwith. My batch file:

IF [%1]==[] (
  set APPURL=”http://localhost/”
) else (
  set APPURL=”%1″
)
@set PATH=C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN;%PATH%

stsadm -o deactivatefeature -name MyCoolTool-url %APPURL% -force
stsadm -o retractsolution -name
MyCoolTool.wsp -immediate -url %APPURL%
stsadm -o execadmsvcjobs
stsadm -o deletesolution -name
MyCoolTool.wsp -override
stsadm -o execadmsvcjobs

stsadm -o addsolution -filename MyCoolTool.wsp
stsadm -o execadmsvcjobs
stsadm -o deploysolution -name
MyCoolTool.wsp -url %APPURL% -immediate -allowCasPolicies -allowgacdeployment
stsadm -o execadmsvcjobs
stsadm -o activatefeature -name
MyCoolTool-url %APPURL%

That’s it for deployment. Of course configuration is another issue (manifest, elements, feature xml files), but that’s another post!

Categories: MOSS, SharePoint 2007 Tags:

Adding a Lookup Column to a SharePoint List

January 20th, 2009 Michael Bell No comments

This took me a heckuva lot longer to get working right than I will ever admit. I thought the end result was nice and tidy. This example shows how to take a list from one web, and populate a column in another list based on the values from the first. Modifications to the first list will be reflected in any columns that reference that list via lookup.

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (SPSite website = new SPSite(SPContext.Current.Site.ID))
    {
        website.AllowUnsafeUpdates = true;                  

        SPWeb newWeb = website.OpenWeb(_newWeb.ID);
        newWeb.AllowUnsafeUpdates = true;

        #region Add Lookup Column to new doc lib
        SPDocumentLibrary newDocLib = (SPDocumentLibrary)newWeb.Lists["Documents"];

        // Grab list guid and the web container
        Guid customListGuid = ListManager.GetGuid(SPContext.Current.Web, “MyCustomWebList”);

        newCRFDocLib.Fields.AddLookup(”Some Descriptive Field Name”, customListGuid, SPContext.Current.Web.ID, false);

        // Add the new lookup field to the default view.
        SPField fld = newCRFDocLib.Fields["Some Descriptive Field Name"];
        SPView defaultView = newCRFDocLib.DefaultView;
        SPViewFieldCollection viewFields = defaultView.ViewFields;

        viewFields.Add(”Some Descriptive Field Name”);
        defaultView.Update();

        ListManager.ReorderField(newWeb.Lists["Documents"], fld, 0);
    }
}       

public static Guid GetGuid(SPWeb web, String listName)
{
    foreach (SPList list in web.Lists)
    {
        if (true == list.Title.Equals(listName, StringComparison.OrdinalIgnoreCase))
            return list.ID;
    }
    return Guid.Empty;
}
Categories: MOSS, SharePoint 2007, c# Tags: