Wednesday, November 22, 2006

Clean install or migrating SharePoint Portal Server 2003 to SQL Server 2005

Currently, we have a SharePoint Portal Server 2003 (SPS) with no service packs installed and Windows SharePoint Services 2.0 with SP2 (WSS-SP2) connecting to SQL Server 2000 with I believe the latest Service Pack. All this running on one dual processor server running Windows Server 2003 SP1.

I am moving it to a Quad Processor with dual cores, so that is 8 virtual processors. It will still be running Windows Server 2003 SP1. Windows SharePoint Services with SP2 (WSS-SP2) is already up to date.

We will be doing the following upgrades:

  • SQL 2000 -> SQL 2005
  • SPS -> SPS Service Pack 2 (SPS-SP2)

There are serveral reasons for this migration.

  • We need a faster server
  • We need to be able to have .Net 2.0 Framework installed on the server and this requires SPS-SP2.
  • We need a server to test the upgrade on without affecting production.
  • Probable speed increases due to SQL 2005 over SQL 2000.
  • Increased stability and bug fixes that come with the SPS-SP2

OK, now that we know where we are coming from and where we are going to, let's get started. The overview of what we need to do is to get new server running like old server with a new installation of SharePoint but with new SQL 2005, then restore SharePoint. This is easier said than done because SPS and WSS don't run properly if .Net 2.0 framework is installed on server and SQL 2005 requires .Net 2.0 framework. SPS-SP2 and WSS-SP2 will run with .Net 2.0 framework installed. Following the below instructions we should be able to do this just fine.

  1. Format the drive where SQL Server Data files will be kept. For optimal performance it is suggested that you use 64K blocks. Be sure to use NTFS as well.
  2. Install SQL 2005. While installing choose Mixed authentication since we have SQL users for each of our apps. Also, be sure to click Advanced on the step that says where SQL Server will be installed. Here you can specify that just the datafiles for SQL Server be stored on a particular drive. Specify the drive you formatted in step 1. If you have more than one physical disk it would be good to put tempdb on a different disk from the other database files. Also put index files on different physical drive. If you don't have that many disks, keep the installation simple, often it is just as good as a more complex one that doesn't have all the right disks. Having the data partition formatted as 64K even if same physical disk should help, but it is not known how much.
  3. Add the domain user you want to use for SharePoint to the Power Users group in Windows Server 2003.
  4. Install SPS (original installation). Choose Install without database engine. Default paths are ok. Click the Finish button in the Windows based installation wizard. The web based page will appear called "Configuration Server Farm Account Settings." Important! Fill in this page only! Click OK. STOP. Close Window. Do not fill in the next page. STOP when you reach the point at which you create a configuration database. i.e. Do NOT create a configuration db or portal site (you can do this after installed SPS-SP2). NOTE: You can use the user you added to the Power Users group. However, you may need to either add that user to any site you want to index using SharePoint indexing or add that user to the Administrator group so that it implicitly has access to all sites. We are not using built in search. We are using Google Mini to perform our searches as we have less trouble with it. NOTE: The reason this installation works is that we have not accessed SQL 2005 yet. Again, the reason we don't want to is that SPS does not support SQL 2005. If we were to create a configuration db, we would be access SQL 2005 and thus it would break.
  5. Add the user you specified in previous step to SQL Server 2005. The one that was used for the Application Pool. Add the user to the dbcreator, securityadmin, and sysadmin Server roles in SQL Server 2005. (I don't know exactly what is needed, but that should be good. You can try reducing permissions later if you are adventurous).
  6. Install WSS-SP2. You may get an error in your browser. I ignored it and have not seen any issues. Restart IIS (using iisreset from a command prompt is easiest). Close Your browser. Do NOT Set the configuration database yet! You can do this after SPS-SP2 is installed.
  7. Install SPS-SP2.
  8. Create WebSite in IIS. Open IIS and create a new WebSite or virtual directory if you prefer. Besure to set the application pool to appropriate pool.
  9. Setup Configuration Database. Open SharePoint Central Administration. You will be prompted to specify the configuration database. Finally, you can do this. Create a configuration database. Use default name for configuration database name or specify different one if you had done so in your other installation.
  10. Setup Typology. Click "Change Components" button at the bottom of the "Cofigure Server Topology" page. Specify Web only in my scenario since we are using Google. No job server for me either. You will probably need to specify them as appropriate.
  11. Specify Email Server. On "Configure Server Topology" page click the link next to "Global e-mail server" that is located under the "Database Server Settings" header.
  12. Create a portal site. The easiest way to do this is to go to the SharePoint Portal Server Central Administration. Then click the "Create a portal site" link under the "Portal site and Virtual Server Configuration" section. You should be able to see the standard SharePoint Portal Server 2003 site using the website you setup in IIS 6.
  13. Create a Windows SharePoint Services (WSS) site by clicking on the Sites link in the menu bar of the SharePoint Portal Server 2003 portal that you created. On the left side click the "Create Site" link. Follow the steps.
  14. Verify that SQL Server 2005 has the databases. Open MS SQL Server Management Studio and connect to the SQL Server 2005 server where you installed SPS-SP2 and WSS-SP2. You should 4 new databases. The example below assumes that the default configuration database name was used, and the portal we created is called Test Portal. SharePoint by default uses the first 8 characters and then "1_" to designate the database name.
    • SPS01_Config_db -- this is the configuration database and will be recreated when we restore later.
    • TestPort1_PROF
    • TestPort1_SERV
    • TestPort1_SITE

At this point you have successfully configured SPS-SP2 and WSS-SP2 and proved that it works.

  1. Install any customizations, Site Definitions, etc at this point. Test changes.

Thursday, November 2, 2006

Check parameters of methods the Microsoft way

Microsoft makes heavy use of some common internal methods in .Net 2.0 that check parameters to methods. They are internal, so they can't be used directly. However, using Reflector, we can implement our own version of it. The class is System.Web.Util.SecUtility and is static internal. Below is the source generated by Reflector for the class. namespace System.Web.Util { using System; using System.Collections; using System.Collections.Specialized; using System.Configuration.Provider; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Globalization; using System.Web; using System.Web.Hosting; internal static class SecUtility { internal static void CheckArrayParameter(ref string[] param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize, string paramName) { if (param == null) { throw new ArgumentNullException(paramName); } if (param.Length < 1) { throw new ArgumentException(SR.GetString("Parameter_array_empty", new object[] { paramName }), paramName); } Hashtable hashtable1 = new Hashtable(param.Length); for (int num1 = param.Length - 1; num1 >= 0; num1--) { SecUtility.CheckParameter(ref param[num1], checkForNull, checkIfEmpty, checkForCommas, maxSize, paramName + "[ " + num1.ToString(CultureInfo.InvariantCulture) + " ]"); if (hashtable1.Contains(param[num1])) { throw new ArgumentException(SR.GetString("Parameter_duplicate_array_element", new object[] { paramName }), paramName); } hashtable1.Add(param[num1], param[num1]); } } internal static void CheckParameter(ref string param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize, string paramName) { if (param == null) { if (checkForNull) { throw new ArgumentNullException(paramName); } } else { param = param.Trim(); if (checkIfEmpty && (param.Length < 1)) { throw new ArgumentException(SR.GetString("Parameter_can_not_be_empty", new object[] { paramName }), paramName); } if ((maxSize > 0) && (param.Length > maxSize)) { throw new ArgumentException(SR.GetString("Parameter_too_long", new object[] { paramName, maxSize.ToString(CultureInfo.InvariantCulture) }), paramName); } if (checkForCommas && param.Contains(",")) { throw new ArgumentException(SR.GetString("Parameter_can_not_contain_comma", new object[] { paramName }), paramName); } } } internal static void CheckPasswordParameter(ref string param, int maxSize, string paramName) { if (param == null) { throw new ArgumentNullException(paramName); } if (param.Length < 1) { throw new ArgumentException(SR.GetString("Parameter_can_not_be_empty", new object[] { paramName }), paramName); } if ((maxSize > 0) && (param.Length > maxSize)) { throw new ArgumentException(SR.GetString("Parameter_too_long", new object[] { paramName, maxSize.ToString(CultureInfo.InvariantCulture) }), paramName); } } internal static void CheckSchemaVersion(ProviderBase provider, SqlConnection connection, string[] features, string version, ref int schemaVersionCheck) { if (connection == null) { throw new ArgumentNullException("connection"); } if (features == null) { throw new ArgumentNullException("features"); } if (version == null) { throw new ArgumentNullException("version"); } if (schemaVersionCheck == -1) { throw new ProviderException(SR.GetString("Provider_Schema_Version_Not_Match", new object[] { provider.ToString(), version })); } if (schemaVersionCheck == 0) { lock (provider) { if (schemaVersionCheck == -1) { throw new ProviderException(SR.GetString("Provider_Schema_Version_Not_Match", new object[] { provider.ToString(), version })); } if (schemaVersionCheck == 0) { SqlCommand command1 = null; SqlParameter parameter1 = null; foreach (string text1 in features) { command1 = new SqlCommand("dbo.aspnet_CheckSchemaVersion", connection); command1.CommandType = CommandType.StoredProcedure; parameter1 = new SqlParameter("@Feature", text1); command1.Parameters.Add(parameter1); parameter1 = new SqlParameter("@CompatibleSchemaVersion", version); command1.Parameters.Add(parameter1); parameter1 = new SqlParameter("@ReturnValue", SqlDbType.Int); parameter1.Direction = ParameterDirection.ReturnValue; command1.Parameters.Add(parameter1); command1.ExecuteNonQuery(); if (((parameter1.Value != null) ? ((int) parameter1.Value) : -1) != 0) { schemaVersionCheck = -1; throw new ProviderException(SR.GetString("Provider_Schema_Version_Not_Match", new object[] { provider.ToString(), version })); } } schemaVersionCheck = 1; } } } } internal static bool GetBooleanValue(NameValueCollection config, string valueName, bool defaultValue) { bool flag1; string text1 = config[valueName]; if (text1 == null) { return defaultValue; } if (!bool.TryParse(text1, out flag1)) { throw new ProviderException(SR.GetString("Value_must_be_boolean", new object[] { valueName })); } return flag1; } internal static string GetDefaultAppName() { try { string text1 = HostingEnvironment.ApplicationVirtualPath; if (string.IsNullOrEmpty(text1)) { text1 = Process.GetCurrentProcess().MainModule.ModuleName; int num1 = text1.IndexOf('.'); if (num1 != -1) { text1 = text1.Remove(num1); } } if (string.IsNullOrEmpty(text1)) { return "/"; } return text1; } catch { return "/"; } } internal static int GetIntValue(NameValueCollection config, string valueName, int defaultValue, bool zeroAllowed, int maxValueAllowed) { int num1; string text1 = config[valueName]; if (text1 == null) { return defaultValue; } if (!int.TryParse(text1, out num1)) { if (zeroAllowed) { throw new ProviderException(SR.GetString("Value_must_be_non_negative_integer", new object[] { valueName })); } throw new ProviderException(SR.GetString("Value_must_be_positive_integer", new object[] { valueName })); } if (zeroAllowed && (num1 < 0)) { throw new ProviderException(SR.GetString("Value_must_be_non_negative_integer", new object[] { valueName })); } if (!zeroAllowed && (num1 <= 0)) { throw new ProviderException(SR.GetString("Value_must_be_positive_integer", new object[] { valueName })); } if ((maxValueAllowed > 0) && (num1 > maxValueAllowed)) { throw new ProviderException(SR.GetString("Value_too_big", new object[] { valueName, maxValueAllowed.ToString(CultureInfo.InvariantCulture) })); } return num1; } internal static bool ValidateParameter(ref string param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize) { if (param == null) { return !checkForNull; } param = param.Trim(); if (((!checkIfEmpty || (param.Length >= 1)) && ((maxSize <= 0) || (param.Length <= maxSize))) && (!checkForCommas || !param.Contains(","))) { return true; } return false; } internal static bool ValidatePasswordParameter(ref string param, int maxSize) { if (param == null) { return false; } if (param.Length < 1) { return false; } if ((maxSize > 0) && (param.Length > maxSize)) { return false; } return true; } } }