SharePoint Automation Gary Lapointe – Founding Partner, Aptillon, Inc.

18Dec/099

Creating a SharePoint 2010 Site Structure Using PowerShell

In a previous post I detailed how to use PowerShell to perform what would be otherwise done using PSConfig to create an initial SharePoint Farm. In this post I will continue the example and show how to create your web applications using a simple XML configuration file and a reusable script.

Like the previous example I have a very basic XML file that defines my web application structure. In this example I've included not only the web application and application pool but also the content databases and site collections, along with the SharePoint Designer settings. Consider the XML and corresponding PowerShell a starting place to extend further if needed by adding elements for managed paths, quota templates, sites and even lists. Here's the XML which I store in a file called WebAppConfigurations.xml:

<WebApplications>
<WebApplication Name="SharePoint Portal (80)"
DefaultTimeZone="12"
DefaultQuotaTemplate="Portal"
AllowAnonymous="false"
AuthenticationMethod="NTLM"
HostHeader="portal"
Path="c:\sharepoint\webs\portal"
Port="80"
LoadBalancedUrl="http://portal"
Ssl="false">
<ApplicationPool Name="SharePoint Portal App Pool"
Account="sp2010\spportalapppool" />
<SPDesigner AllowDesigner="true" AllowRevertFromTemplate="true"
AllowMasterPageEditing="true" ShowURLStructure="true" />
<ContentDatabases>
<ContentDatabase Server="spsql1"
Name="SharePoint_Content_Portal1"
MaxSiteCount="100" WarningSiteCount="80"
Default="true">
<SiteCollections>
<SiteCollection Name="Portal"
Description=""
Url="http://portal"
LCID="1033"
Template="SPSPORTAL#0"
OwnerLogin="sp2010\siteowner1"
OwnerEmail="siteowner1@sp2010.com"
SecondaryLogin="sp2010\spadmin"
SecondaryEmail="spadmin@sp2010.com">
</SiteCollection>
</SiteCollections>
</ContentDatabase>
</ContentDatabases>
</WebApplication>
</WebApplications>

Note that you could easily adapt the file by having the <WebApplications /> element be a child of the <Farm /> element shown in my previous post resulting in a single configuration file rather than multiple files. One thing to note is that I'm not storing the password for the application pool account which I assume exists - the password will be asked for when the script runs.

Let's take a look at the script that does all the work:

function Start-WebApplicationsBuild(
    [string]$settingsFile = "Configurations.xml") {
    [xml]$config = Get-Content $settingsFile

    #Creating individual web applications
    $config.WebApplications.WebApplication | ForEach-Object {
        $webAppConfig = $_
        $webApp = New-WebApplication $webAppConfig

        #Configuring SharePoint Designer Settings
        $spd = $webAppConfig.SPDesigner
        $allowRevert = ([bool]::Parse($spd.AllowRevertFromTemplate))
        $allowMasterEdit = ([bool]::Parse($spd.AllowMasterPageEditing))
        Write-Host "Setting SP Designer settings..."
        $webApp | Set-SPDesignerSettings `
            -AllowDesigner:([bool]::Parse($spd.AllowDesigner)) `
            -AllowRevertFromTemplate:$allowRevert `
            -AllowMasterPageEditing:$allowMasterEdit `
            -ShowURLStructure:([bool]::Parse($spd.ShowURLStructure))

        $webAppConfig.ContentDatabases.ContentDatabase | ForEach-Object {
            #Creating content database
            Write-Host "Creating content database $($_.Name)..."
            $db = New-SPContentDatabase -Name $_.Name `
                -WebApplication $webApp `
                -DatabaseServer $_.Server `
                -MaxSiteCount $_.MaxSiteCount `
                -WarningSiteCount $_.WarningSiteCount

            $_.SiteCollections.SiteCollection | ForEach-Object {
                #Creating site collection
                Write-Host "Creating site collection $($_.Url)..."
                $gc = Start-SPAssignment
                $site = $gc | New-SPSite `
                    -Url $_.Url `
                    -ContentDatabase $db `
                    -Description $_.Description `
                    -Language $_.LCID `
                    -Name $_.Name `
                    -Template $_.Template `
                    -OwnerAlias $_.OwnerLogin `
                    -OwnerEmail $_.OwnerEmail `
                    -SecondaryOwnerAlias $_.SecondaryLogin `
                    -SecondaryEmail $_.SecondaryEmail
                Stop-SPAssignment -SemiGlobal $gc
            }
        }
    }
}

function New-WebApplication([System.Xml.XmlElement]$webAppConfig) {
    $poolAccount = $null
    $tempAppPool = $null
    $poolName = $webAppConfig.ApplicationPool.Name
    if ([Microsoft.SharePoint.Administration.SPWebService]::ContentService.ApplicationPools.Count -gt 0) {
        $tempAppPool = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.ApplicationPools | ? {$_.Name -eq $poolName}
    }
    if ($tempAppPool -eq $null) {
        Write-Host "Getting $($webAppConfig.ApplicationPool.Account) account for application pool..."
        $accountCred = Get-Credential $webAppConfig.ApplicationPool.Account
        $poolAccount = (Get-SPManagedAccount -Identity $accountCred.Username -ErrorVariable err -ErrorAction SilentlyContinue)
        if ($err) {
            $poolAccount = New-SPManagedAccount -Credential $accountCred
        }
    }

    $allowAnon = [bool]::Parse($webAppConfig.AllowAnonymous.ToString())
    $ssl = [bool]::Parse($webAppConfig.Ssl.ToString())

    $db = $null
    if ($webAppConfig.ContentDatabases.ChildNodes.Count -gt 1) {
        $db = $webAppConfig.ContentDatabases.ContentDatabase | `
            where {$_.Default -eq "true"}
        if ($db -is [array]) {
            $db = $db[0]
        }
    } else {
        $db = $webAppConfig.ContentDatabases.ContentDatabase
    }

    #Create the web application
    Write-Host "Creating web application $($webAppConfig.Name)..."
    $webApp = New-SPWebApplication -SecureSocketsLayer:$ssl `
        -AllowAnonymousAccess:$allowAnon `
        -ApplicationPool $poolName `
        -ApplicationPoolAccount $poolAccount `
        -Name $webAppConfig.Name `
        -AuthenticationMethod $webAppConfig.AuthenticationMethod `
        -DatabaseServer $db.DatabaseServer `
        -DatabaseName $db.DatabaseName `
        -HostHeader $webAppConfig.HostHeader `
        -Path $webAppConfig.Path `
        -Port $webAppConfig.Port `
        -Url $webAppConfig.LoadBalancedUrl `
        -ErrorVariable err

    return $webApp
}

I've put the script in two different functions with Start-WebApplicationsBuild being the primary function that is called by the logged in user. The other function, New-WebApplication, is just there for readability (I wanted to separate out the code that created the application pool and web application itself). Note that, like in my previous post, I use a more complex version of this script which has the various elements broken out into many different shared helper functions and considerably more tracing and error handling added - this script is a fairly simplistic version which lets you focus on the core SharePoint 2010 PowerShell stuff without polluting the code with lots of plumbing.

With this script and XML file structure you can create as many web applications, content databases, and site collections as needed by only modifying the XML file - the script will support any number of each. One thing to be careful of - make sure you have only one <ContentDatabase /> element with a Default attribute set to "true" (this is the database that will be created when the web application is created - you may have as many <ContentDatabase /> elements as needed but you need at least one with a Default value of true).

Hopefully this script proves useful to anyone who needs to automatically create their SharePoint 2010 site structure. Stay tuned for the next piece of the scripts which will cover provisioning service applications.

19Jun/08106

Moving Databases, the Easy Way!

I've seen this come up a lot so I figured I'd write a short post about it.  A lot of people have been asking how to move their databases to a new server and to do this the way most people are prescribing you've got a lot of reading and a lot of steps to perform.  The following two post provide just a couple of examples of the numerous steps and issues to consider: http://techacid.spaces.live.com/blog/cns!6D62FC28E76BE4B!230.entry and http://blogs.technet.com/corybu/archive/2007/06/01/detaching-databases-in-moss-2007-environments.aspx.

But that's all just way too much work - who wants to deal with all those steps and what if something goes wrong and, oh, I have to rebuild my configuration database because you can't move it using the typical approaches.  Shouldn't there be an easier way?  Well, there is - use SQL Aliasing.  SQL Aliasing basically just involves installing the SQL Server Configuration Manager on each server and configuring an Alias to point to your SQL Server and the good news is that Microsoft now recognizes this as a supported configuration for SharePoint.

So say you have an existing farm with all the databases on a server called MOSSSQL1 and you want to move all the databases to MOSSSQL2.  To do this you can either install the SQL Server Configuration Manager on each server or if you have MDAC installed (which you should) then simply open up c:\windows\system32\cliconfg.exe (recommended over installing the SQL Configuration Manager).  Go to the Alias tab and click "Add".  In the dialog that appears you can then configure your alias (Alias Name=MOSSSQL1, Server=MOSSSQL2 if using Named Pipes or the IP address if using TCP/IP).  Then click "OK" to save the alias (be sure to do this during off hours as once you click OK SharePoint will now start looking to your new server for the databases).

Using cliconfg.exe

Using SQL Server Configuration Manager

Once you have the alias configured you can now simply detach all the databases from your old server and then copy and re-attach the databases to the new server.  If you're using Kerberos make sure you remember to create your SPNs for the new server.  Keep in mind though that using this approach will mean that all of your databases will need to be moved (even non-SharePoint databases if you are connecting to those databases from any of your SharePoint servers).  You can get around this if you use aliases prior to building your farm (keep reading).  One thing to watch out for is your permissions - make sure you take note of what permissions each database has as some may change with the re-attach.

That's it - your done!  Wasn't that easier than all the other crap you'd have to deal with otherwise?  But wait, there's more!  If you are in a position where you haven't yet built your farm then why not preemptively configure aliases?  So perhaps you have just one SQL Server today but you anticipate the need to eventually distribute the databases across servers in the future to address future performance needs or maybe you just want to isolate the SharePoint databases from other databases in a shared server situation?  Simply create the aliases that you anticipate needing and point them all to the same server for now - then when you need to move a database group you can just change the alias and move the databases in that group.  If you want ultimate flexibility (perhaps you just don't have a clue as to how you will need to distribute your databases in the future) then create an alias for each database (not sure I'd take it this far myself but it would give you the most flexibility in allowing you to very easily move any one or more databases to any other server with ease).

I've been using this approach for years with both 2003 and 2007 and it's always worked great for me and hopefully others will benefit as well.

31Jan/0834

Create Site in Database

So you've got a content database (perhaps you used the gl-createcontentdb command) and now you want to create a site collection in that database. Problem is that you can't do this easily via the browser and you definitely can't do it via stsadm. There is a createsiteinnewdb command and a createsite command but the first will create a new database and the second will put the site collection in the "best match" database. But you need it in a specific database. What I decided to do was to create a new command: gl-createsiteindb.

The code is pretty straight forward - the bulk of the code is just validation code:

   1: using System;
   2: using System.Collections.Specialized;
   3: using System.IO;
   4: using System.Text;
   5: using System.Web.Configuration;
   6: using Lapointe.SharePoint.STSADM.Commands.SPValidators;
   7: using Microsoft.SharePoint;
   8: using Microsoft.SharePoint.Administration;
   9: using Lapointe.SharePoint.STSADM.Commands.OperationHelpers;
  10:  
  11: namespace Lapointe.SharePoint.STSADM.Commands.SiteCollectionSettings
  12: {
  13:     public class CreateSiteInDB : SPOperation
  14:     {
  15:         protected SPWebApplication m_WebApplication;
  16:  
  17:         /// <summary>
  18:         /// Initializes a new instance of the <see cref="CreateSiteInDB"/> class.
  19:         /// </summary>
  20:         public CreateSiteInDB()
  21:         {
  22:             SPParamCollection parameters = new SPParamCollection();
  23:             parameters.Add(new SPParam("url", "url", true, null, new SPUrlValidator()));
  24:             parameters.Add(new SPParam("lcid", "lcid", false, "0", new SPRegexValidator("^[0-9]+$")));
  25:             parameters.Add(new SPParam("sitetemplate", "st", false, null, new SPNullOrNonEmptyValidator()));
  26:             parameters.Add(new SPParam("title", "t", false, null, null));
  27:             parameters.Add(new SPParam("description", "desc", false, null, null));
  28:             parameters.Add(new SPParam("ownerlogin", "ol", false, null, new SPNonEmptyValidator()));
  29:             parameters.Add(new SPParam("ownername", "on", false, null, null));
  30:             parameters.Add(new SPParam("owneremail", "oe", true, null, new SPRegexValidator(@"^[^ \r\t\n\f@]+@[^ \r\t\n\f@]+$")));
  31:             parameters.Add(new SPParam("quota", "quota", false, null, new SPNullOrNonEmptyValidator()));
  32:             parameters.Add(new SPParam("hostheaderwebapplicationurl", "hhurl", false, null, new SPUrlValidator()));
  33:             parameters.Add(new SPParam("secondarylogin", "sl", false, null, new SPNullOrNonEmptyValidator()));
  34:             parameters.Add(new SPParam("secondaryname", "sn", false, null, null));
  35:             parameters.Add(new SPParam("secondaryemail", "se", false, null, null));
  36:             parameters.Add(new SPParam("dbname", "db", true, null, new SPNonEmptyValidator(), "Please specify the database name."));
  37:  
  38:             StringBuilder sb = new StringBuilder();
  39:             sb.Append("\r\n\r\nCreates a new site collection in an existing content database.\r\n\r\nParameters:");
  40:             sb.Append("-url <url>");
  41:             sb.Append("\r\n\t-owneremail <someone@example.com>");
  42:             sb.Append("\r\n\t[-ownerlogin <DOMAIN\\name>]");
  43:             sb.Append("\r\n\t[-ownername <display name>]");
  44:             sb.Append("\r\n\t[-secondaryemail <someone@example.com>]");
  45:             sb.Append("\r\n\t[-secondarylogin <DOMAIN\\name>");
  46:             sb.Append("\r\n\t[-secondaryname <display name>]");
  47:             sb.Append("\r\n\t[-lcid <language>]");
  48:             sb.Append("\r\n\t[-sitetemplate <site template>]");
  49:             sb.Append("\r\n\t[-title <site title>]");
  50:             sb.Append("\r\n\t[-description <site description>]");
  51:             sb.Append("\r\n\t[-hostheaderwebapplicationurl <web application url>]");
  52:             sb.Append("\r\n\t[-quota <quota template>]");
  53:             sb.Append("\r\n\t-dbname <content database name>");
  54:             
  55:             Init(parameters, sb.ToString());
  56:         }
  57:  
  58:         #region ISPStsadmCommand Members
  59:  
  60:         /// <summary>
  61:         /// Gets the help message.
  62:         /// </summary>
  63:         /// <param name="command">The command.</param>
  64:         /// <returns></returns>
  65:         public override string GetHelpMessage(string command)
  66:         {
  67:             return HelpMessage;
  68:         }
  69:  
  70:         /// <summary>
  71:         /// Runs the specified command.
  72:         /// </summary>
  73:         /// <param name="command">The command.</param>
  74:         /// <param name="keyValues">The key values.</param>
  75:         /// <param name="output">The output.</param>
  76:         /// <returns></returns>
  77:         public override int Execute(string command, StringDictionary keyValues, out string output)
  78:         {
  79:             output = string.Empty;
  80:  
  81:             
  82:  
  83:             string dbname = Params["dbname"].Value;
  84:  
  85:             string uriString = Params["url"].Value;
  86:             string webTemplate = Params["sitetemplate"].Value;
  87:             string title = Params["title"].Value;
  88:             string description = Params["description"].Value;
  89:             string ownerName = Params["ownername"].Value;
  90:             string ownerEmail = Params["owneremail"].Value;
  91:             string quota = Params["quota"].Value;
  92:             string secondaryContactName = Params["secondaryname"].Value;
  93:             string secondaryContactEmail = Params["secondaryemail"].Value;
  94:             bool isHostHeaderWebAppUrlTypedIn = Params["hostheaderwebapplicationurl"].UserTypedIn;
  95:             uint nLCID = uint.Parse(Params["lcid"].Value);
  96:             Uri uri = new Uri(uriString);
  97:             SPUrlZone zone = SPUrlZone.Default;
  98:             bool createActiveDirectoryAccounts = m_WebApplication.WebService.CreateActiveDirectoryAccounts;
  99:             string ownerLogin = Utilities.TryGetNT4StyleAccountName(Params["ownerlogin"].Value, m_WebApplication);
 100:             string secondaryContactLogin = null;
 101:             if (!createActiveDirectoryAccounts || !Params["secondaryemail"].UserTypedIn)
 102:             {
 103:                 if (!createActiveDirectoryAccounts && Params["secondarylogin"].UserTypedIn)
 104:                 {
 105:                     secondaryContactLogin = Utilities.TryGetNT4StyleAccountName(Params["secondarylogin"].Value, m_WebApplication);
 106:                 }
 107:             }
 108:             else
 109:             {
 110:                 secondaryContactLogin = @"@\@";
 111:             }
 112:  
 113:             SPContentDatabase database = null;
 114:             foreach (SPContentDatabase tempDB in m_WebApplication.ContentDatabases)
 115:             {
 116:                 if (tempDB.Name.ToLower() == dbname.ToLower())
 117:                 {
 118:                     database = tempDB;
 119:                     break;
 120:                 }
 121:             }
 122:             if (database == null)
 123:                 throw new SPException("Content database not found.");
 124:  
 125:             if (database.MaximumSiteCount <= database.CurrentSiteCount)
 126:                 throw new SPException("The maximum site count for the specified database has been exceeded.  Increase the maximum site count or specify another database.");
 127:  
 128:             SPSite site = null;
 129:             try
 130:             {
 131:                 site = database.Sites.Add(uri.OriginalString, title, description, nLCID, webTemplate, ownerLogin,
 132:                     ownerName, ownerEmail, secondaryContactLogin, secondaryContactName, secondaryContactEmail,
 133:                     isHostHeaderWebAppUrlTypedIn);
 134:  
 135:  
 136:                 if (!string.IsNullOrEmpty(quota))
 137:                 {
 138:                     using (SPSiteAdministration administration = new SPSiteAdministration(site.Url))
 139:                     {
 140:                         SPFarm farm = SPFarm.Local;
 141:                         SPWebService webService = farm.Services.GetValue<SPWebService>("");
 142:  
 143:                         SPQuotaTemplateCollection quotaColl = webService.QuotaTemplates;
 144:                         administration.Quota = quotaColl[quota];
 145:                     }
 146:                 }
 147:                 if (!string.IsNullOrEmpty(webTemplate))
 148:                 {
 149:                     using (SPWeb web = site.RootWeb)
 150:                     {
 151:                         web.CreateDefaultAssociatedGroups(ownerLogin, secondaryContactLogin, string.Empty);
 152:                     }
 153:                 }
 154:                 if (isHostHeaderWebAppUrlTypedIn && !m_WebApplication.IisSettings[zone].DisableKerberos)
 155:                 {
 156:                     Console.WriteLine(SPResource.GetString("WarnNoDefaultNTLM", new object[0]));
 157:                     Console.WriteLine();
 158:                 }
 159:             }
 160:             finally
 161:             {
 162:                 if (site != null)
 163:                     site.Dispose();
 164:             }
 165:  
 166:             return OUTPUT_SUCCESS;
 167:         }
 168:  
 169:         /// <summary>
 170:         /// Validates the specified key values.
 171:         /// </summary>
 172:         /// <param name="keyValues">The key values.</param>
 173:         public override void Validate(StringDictionary keyValues)
 174:         {
 175:             base.Validate(keyValues);
 176:             string uriString = Params["url"].Value;
 177:  
 178:             if (Params["quota"].UserTypedIn)
 179:             {
 180:                 string quota = Params["quota"].Value;
 181:                 SPFarm farm = SPFarm.Local;
 182:                 SPWebService webService = farm.Services.GetValue<SPWebService>("");
 183:  
 184:                 SPQuotaTemplateCollection quotaColl = webService.QuotaTemplates;
 185:  
 186:                 if (quotaColl[quota] == null)
 187:                 {
 188:                     throw new ArgumentException(SPResource.GetString("InvalidQuotaTemplateName", new object[0]));
 189:                 }
 190:             }
 191:  
 192:             m_WebApplication = ValidateWebApplication(this);
 193:             if (m_WebApplication == null)
 194:             {
 195:                 throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[] { uriString }));
 196:             }
 197:             SPUrlZone zone = SPUrlZone.Default;
 198:             if (!m_WebApplication.WebService.CreateActiveDirectoryAccounts && !Params["ownerlogin"].UserTypedIn)
 199:             {
 200:                 throw new ArgumentException(SPResource.GetString("NoADCreateRequiresOwnerLogin", new object[0]));
 201:             }
 202:             if (m_WebApplication.GetIisSettingsWithFallback(zone).AuthenticationMode == AuthenticationMode.Windows)
 203:             {
 204:                 bool bIsUserAccount;
 205:                 if (Params["ownerlogin"].UserTypedIn)
 206:                 {
 207:                     string strLoginName = Utilities.TryGetNT4StyleAccountName(Params["ownerlogin"].Value, m_WebApplication);
 208:                     if (!Utilities.IsLoginValid(strLoginName, out bIsUserAccount))
 209:                     {
 210:                         throw new ArgumentException(SPResource.GetString("InvalidLoginAccount", new object[] { strLoginName }));
 211:                     }
 212:                     if (!bIsUserAccount)
 213:                     {
 214:                         throw new ArgumentException(SPResource.GetString("OwnerNotUserAccount", new object[0]));
 215:                     }
 216:                 }
 217:                 if (Params["secondarylogin"].UserTypedIn)
 218:                 {
 219:                     string strLoginName = Utilities.TryGetNT4StyleAccountName(Params["secondarylogin"].Value, m_WebApplication);
 220:                     if (!Utilities.IsLoginValid(strLoginName, out bIsUserAccount))
 221:                     {
 222:                         throw new ArgumentException(SPResource.GetString("InvalidLoginAccount", new object[] { strLoginName }));
 223:                     }
 224:                     if (!bIsUserAccount)
 225:                     {
 226:                         throw new ArgumentException(SPResource.GetString("OwnerNotUserAccount", new object[0]));
 227:                     }
 228:                 }
 229:             }
 230:         }
 231:  
 232:  
 233:  
 234:  
 235:         #endregion
 236:  
 237:         internal static SPWebApplication ValidateWebApplication(SPOperation operation)
 238:         {
 239:             if (SPFarm.Local == null)
 240:             {
 241:                 throw new SPException(SPResource.GetString("OperationInvalidInRemoteFarm", new object[0]));
 242:             }
 243:             SPWebApplication application;
 244:             string uriString = operation.Params["url"].Value;
 245:             bool isHostHeaderWebAppUrlTypedIn = operation.Params["hostheaderwebapplicationurl"].UserTypedIn;
 246:             Uri requestUri = new Uri(uriString);
 247:             if ((requestUri.Scheme != Uri.UriSchemeHttps) && (requestUri.Scheme != Uri.UriSchemeHttp))
 248:             {
 249:                 throw new ArgumentException(SPResource.GetString("InvalidSiteName", new object[] { uriString }));
 250:             }
 251:             if (isHostHeaderWebAppUrlTypedIn)
 252:             {
 253:                 Uri hostHeaderWebAppUrl = new Uri(operation.Params["hostheaderwebapplicationurl"].Value);
 254:                 application = SPWebApplication.Lookup(hostHeaderWebAppUrl);
 255:                 if (application == null)
 256:                 {
 257:                     return application;
 258:                 }
 259:                 bool portMatchFound = false;
 260:  
 261:                 foreach (SPIisSettings iisSettings in application.IisSettings.Values)
 262:                 {
 263:                     foreach (SPSecureBinding secureBinding in iisSettings.SecureBindings)
 264:                     {
 265:                         if (requestUri.Port == secureBinding.Port)
 266:                         {
 267:                             portMatchFound = true;
 268:                             break;
 269:                         }
 270:                     }
 271:  
 272:                     if (!portMatchFound)
 273:                     {
 274:                         foreach (SPServerBinding serverBinding in iisSettings.ServerBindings)
 275:                         {
 276:                             if (requestUri.Port == serverBinding.Port)
 277:                             {
 278:                                 portMatchFound = true;
 279:                                 break;
 280:                             }
 281:                         }
 282:                     }
 283:                     if (portMatchFound)
 284:                         return application;
 285:                 }
 286:                 Console.WriteLine(SPResource.GetString("HostHeaderDoesNotMatchWebAppPort", new object[0]));
 287:                 Console.WriteLine();
 288:             }
 289:             else
 290:                 return SPWebApplication.Lookup(requestUri);
 291:  
 292:             return application;
 293:         }
 294:  
 295:     }
 296: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-createsiteindb

stsadm -o gl-createsiteindb

Creates a new site collection in an existing content database.

Parameters:
        -url <url>        
        -owneremail <someone@example.com>        
        [-ownerlogin <DOMAIN\\name>]        
        [-ownername <display name>]        
        [-secondaryemail <someone@example.com>]        
        [-secondarylogin <DOMAIN\\name>        
        [-secondaryname <display name>]        
        [-lcid <language>]        
        [-sitetemplate <site template>]        
        [-title <site title>]        
        [-description <site description>]        
        [-hostheaderwebapplicationurl <web application url>]        
        [-quota <quota template>]        
        -dbname <content database name>

The following table summarizes the command and its various parameters:

Command Name Availability Build Date
gl-createsiteindb WSS 3, MOSS 2007 Released: 1/31/2008
Updated: 4/30/2009 

Parameter Name Short Form Required Description Example Usage
url   Yes The URL to the site collection to create. -url "http://portal/sites/NewSite"
owneremail oe Yes

The site owner's e-mail address.  Must be valid e-mail address, in the form someone@example.com.

-owneremail someone@example.com

-oe someone@example.com
ownerlogin ol

If your farm does not have Active Directory account creation mode enabled, then this parameter is required.

This parameter should not be provided if your farm has Active Directory account creation mode enabled, as Microsoft Office SharePoint Server 2007 will automatically create a site collection owner account in Active Directory based on the owner e-mail address.

The site owner's user account.  Must be a valid Windows user name, and must be qualified with a domain name, for example, domain\name

-ownerlogin domain\name

-ol domain\name
ownername on No

The site owner's display name.

-ownername "Gary Lapointe"

-on "Gary Lapointe"
secondaryemail se No

The secondary site owner's e-mail address.  Must be valid e-mail address, in the form someone@example.com.

-secondaryemail someone@example.com

-se someone@example.com
secondarylogin sl

If your farm does not have Active Directory account creation mode enabled, then this parameter is required.

This parameter should not be provided if your farm has Active Directory account creation mode enabled, as Microsoft Office SharePoint Server 2007 will automatically create a site collection owner account in Active Directory based on the owner e-mail address.

The secondary site owner's user account.  Must be a valid Windows user name, and must be qualified with a domain name, for example, domain\name

-secondarylogin domain\name

-sl domain\login
secondaryname sn No

The secondary site owner's display name.

-secondaryname "Pam Lapointe"

-sn "Pam Lapointe"
lcid   No

A valid locale ID, such as "1033" for English.  You must specify this parameter when using a non-English template.

-lcid 1033
sitetemplate st No

Specifies the type of template to be used by the newly created site.

The value must be in the form name#configuration. If you do not specify the configuration, configuration 0 is the default (for example, STS#0). The list of available templates can be customized to include templates you create.

-sitetemplate STS#0

-st STS#0
title t No

The title of the new site collection

-title "New Site"
description desc No

Description of the site collection.

-description "New Site Description"

-desc "New Site Description"
hostheaderwebapplicationurl hhurl No

A valid URL assigned to the Web application by using Alternate Access Mapping (AAM), such as "http://server_name".

When the hostheaderwebapplicationurl parameter is present, the value of the url parameter is the URL of the host-named site collection and value of the hostheaderwebapplicationurl parameter is the URL of the Web application that will hold the host-named site collection.

-hostheaderwebapplicationurl http://newsite

-hhurl http://newsite
quota   No

The quota template to apply to sites created on the virtual server.

-quota Portal
dbname db Yes

The name of the Microsoft SQL Server database or Microsoft SQL Server 2000 Desktop Engine (Windows) (WMSDE) database used for Windows SharePoint Services data.

-dbname SharePoint_Content1

-db SharePoint_Content1

Here's an example of how to create a site in an existing content database:

stsadm -o gl-createsiteindb -url "http://intranet/sites/testsite1" -owneremail "someone@domain.com" -ownerlogin "domain\someone" -ownername "Some User" -sitetemplate "BLANKINTERNET#2" -title "Test Site" -dbname "SharePoint_ContentDB1"

Update 4/30/2009: I’ve updated the code so that it now creates the default site groups for the site collection.

31Jan/082

Create Content Database

It's pretty easy to create a content database via the browser and you can create a new content database easily enough when creating a new site collection via stsadm, createsiteinnewdb, or directly using addcontentdb. But what if you need to script the creation of a new content database without creating a site collection and you need to set some of the properties found via the browser that addcontentdb doesn't provide? To do this I created a new command which basically does the same as addcontentdb but adds the additional properties found within central admin: gl-createcontentdb. To accomplish this I first do some checks to make sure that you're not trying to create a database using a name that already exists. I then use the SPWebApplication's ContentDatabases property to add the new database using the parameters provided. Once the database has been created we can set the search service settings:

   1: public override int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:  output = string.Empty;
   4:  
   5:  InitParameters(keyValues);
   6:  
   7:  string dbserver = Params["dbserver"].Value;
   8:  string dbname = Params["dbname"].Value;
   9:  
  10:  if (string.IsNullOrEmpty(dbserver))
  11:  {
  12:   dbserver = SPWebService.ContentService.DefaultDatabaseInstance.NormalizedDataSource;
  13:  }
  14:  
  15:  using (SPSite site = new SPSite(Params["webapp"].Value))
  16:  {
  17:   SPContentDatabase db = null;
  18:   foreach (SPContentDatabase tempDB in site.WebApplication.ContentDatabases)
  19:   {
  20:    if (tempDB.Name.ToLower() == dbname.ToLower())
  21:    {
  22:     db = tempDB;
  23:     break;
  24:    }
  25:   }
  26:   if (db != null)
  27:    throw new Exception("Content database already exists.");
  28:  
  29:   SPObjectStatus status = (SPObjectStatus)Enum.Parse(typeof(SPObjectStatus), Params["status"].Value, true);
  30:  
  31:   db = site.WebApplication.ContentDatabases.Add(dbserver, dbname, null, null, 
  32:    int.Parse(Params["warningsitecount"].Value),
  33:    int.Parse(Params["maxsites"].Value), (status == SPObjectStatus.Online?0:1));
  34:   
  35:   if (Params["searchserver"].UserTypedIn && !string.IsNullOrEmpty(Params["searchserver"].Value))
  36:   {
  37:    // If they specified a search server then we need to try and find a valid
  38:    // matching search server using the server address property.
  39:    SPSearchService service = SPFarm.Local.Services.GetValue<SPSearchService>("SPSearch");
  40:    SPServiceInstance searchServiceServer = null;
  41:    foreach (SPServiceInstance tempsvc in service.Instances)
  42:    {
  43:     if (!(tempsvc is SPSearchServiceInstance))
  44:      continue;
  45:  
  46:     if (tempsvc.Status != SPObjectStatus.Online)
  47:      continue;
  48:  
  49:     if (tempsvc.Server.Address.ToLowerInvariant() == Params["searchserver"].Value.ToLowerInvariant())
  50:     {
  51:      // We found a match so bug out of the loop.
  52:      searchServiceServer = tempsvc;
  53:      break;
  54:     }
  55:    }
  56:    if (searchServiceServer != null)
  57:    {
  58:     db.SearchServiceInstance = searchServiceServer;
  59:    }
  60:    else
  61:     throw new Exception("Search server not found.");
  62:   }
  63:   else if (Params["searchserver"].UserTypedIn)
  64:   {
  65:    // The user specified the searchserver switch with no value which is what we use to indicate
  66:    // clearing the value.
  67:    db.SearchServiceInstance = null;
  68:   }
  69:  
  70:   db.Update();
  71:  }
  72:  
  73:  return 1;
  74: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-createcontentdb

stsadm -o gl-createcontentdb

Creates a new content database.

Parameters:
        -dbname <content database name>
        -webapp <web application url>
        [-dbserver <content database server>]
        [-maxsites <<maximum number of sites allowed in the db (default is 15000)>]
        [-warningsitecount <number of sites before a warning event is generated (default is 9000)>]
        [-searchserver <search server (leave empty to clear the search server)>]
        [-dbuser <database username (if using SQL Authentication and not Windows Authentication)>]
        [-dbuser <database username (if using SQL Authentication and not Windows Authentication)>]
        [-dbpwd <database password (if using SQL Authentication and not Windows Authentication)>]
        [-status <online | disabled>]
Here's an example of how to create a new content database:
stsadm -o gl-createcontentdb -dbname "SharePoint_ContentDB1" -webapp "http://intranet" -maxsites 500 -warningsitecount 400