Posted on:
Categories: SharePoint
Description:
In this post my goal is to give an end to end configuration guide to deploying Remote BLOB storage for SharePoint 2010. I have found that there are many great blog posts available that describe different aspects of the configuration process, but I have found that there isn’t one single reference point for the entire configuration that includes the initial installation, configuration and maintenance of Remote BLOB Storage for SharePoint 2010. Prerequisites The user account that you use the configure RBS on your SharePoint servers must have the following group memberships Member of the Administrators group on the Web Servers and Application Servers SQL Server dbcreator and securityadmin fixed server roles on the computer that is running SQL Server Enable FILESTREAM on the database server On the Start menu, point to All Programs, point to Microsoft SQL Server 2008 R2, point to Configuration Tools, and then click SQL Server Configuration Manager. In the list of services, right-click SQL Server Services, and then click Open. In the SQL Server Configuration Manager snap-in, locate the instance of SQL Server on which you want to enable FILESTREAM. Right-click the instance and then click Properties. In the SQL Server Properties dialog box, click the FILESTREAM tab. Select the Enable FILESTREAM for Transact-SQL access check box. If you want to read and write FILESTREAM data from Windows, click Enable FILESTREAM for file I/O streaming access. Enter the name of the Windows share in the Windows Share Name box. If remote clients must access the FILESTREAM data that is stored on this share, select Allow remote clients to have streaming access to FILESTREAM data. Click Apply. See below In SQL Server Management Studio, click New Query to display the Query Editor. In Query Editor, enter the following Transact-SQL code EXEC sp_configure filestream_access_level, 2 RECONFIGURE Click Execute. Provision a BLOB store for each content database You will need to follow this procedure for each content database that you want to have configured to use Remote BLOB storage Click Start, click All Programs, click Microsoft SQL Server 2008 R2, and then click SQL Server Management Studio. Connect to the instance of SQL Server that hosts the content database. Expand Databases. Click the content database for which you want to create a BLOB store, and then click New Query. Paste the following SQL queries in Query pane, and then execute them in the sequence listed. use [WSS_Content] if not exists (select * from sys.symmetric_keys where name = N'##MS_DatabaseMasterKey##')create master key encryption by password = N'Admin Key Password !2#4' use [WSS_Content] if not exists (select groupname from sysfilegroups where groupname=N'RBSFilestreamProvider')alter database [WSS_Content] add filegroup RBSFilestreamProvider contains filestream use [WSS_Content] alter database [WSS_Content] add file (name = RBSFilestreamFile, filename = 'C\Blobstore') to filegroup RBSFilestreamProvider *Replace ‘WSS_Content’ with the name of your specific content database. By default this command will create a folder called ‘Blobstore’ in the root of the C\ on your SQL Server. You can change this location if desired. You must ensure that you will have enough space on the specified drive for your BLOBs. Also note that each content database will need to have its own folder on the file system (e.g. C\Blobstore2, C\Blobstore3 etc.). Install the RBS provider components on each server (SQL and Web Server) *First install RBS on your SQL server and then on the First Web server and then on additional Servers. Browse to http//www.microsoft.com/download/en/details.aspx?id=16978 find rbs.msi download X64 Package. *download the rbs_x64 link given in TechNet article http//technet.microsoft.com/en-us/library/ee663474.aspx Run cmd prompt as Administrator and then click OK. Change the directory to the place where rbs.msi is downloaded on the machine. Copy and paste the following command into the Command Prompt window. msiexec /qn /lvx* rbs_install_log.txt /i RBS.msi TRUSTSERVERCERTIFICATE=true FILEGROUP=PRIMARY DBNAME="WSS_Content" DBINSTANCE="DBInstance Name" FILESTREAMFILEGROUP=RBSFilestreamProvider FILESTREAMSTORENAME=FilestreamProvider_1 * Replace WSS_Content and DBInstance Name in the above command with the values that correspond to your own environment. **This command must be run on the SQL Server and on one of your SharePoint Web Front Ends. The command will look like it executed and succeeded right away; however, the RBS.msi file initiates a misexe.exe process that will take approximately 1 minute to complete. You will have to check the log to ensure that the process completed successfully. After running the command a file called ‘rbs_install_log.txt will be created in the same directory where you ran RBS.msi. To verify if the process was success you can look for the following line in the text file *if the process fails you will have to uninstall the ‘SQL Server 2008 R2 Remote Blob Store’ program from Add/Remove programs and then run the RBS.msi file again Once the RBS software is successfully installed you can verify the state of the configuration by looking for the following tables in the content database that you have configured to use RBS If you do not see these tables you will have to double check the values that you entered into the msiexec command that was executed earlier. Once you have verified the command syntax you will have to uninstall ‘SQL Server 2008 R2 Remote Blob Store’ from Add/Remove Programs and run the command again. *The SQL Server 2008 R2 Remote Blob Store software needs to be installed on all of your front-end SharePoint web servers. "You must install RBS client library on all Web servers in the SharePoint farm. The RBS client library is installed only once per Web server, but RBS is configured separately for each associated content database." http//technet.microsoft.com/en-us/library/ee748631.aspx? To install the RBS client software on all additional Web Servers ensure that you have a local copy of the RBS.msi file and then execute the following command msiexec /qn /lvx* rbs_install_log.txt /i RBS.msi DBNAME="WSS_Content" DBINSTANCE="DBInstanceName" ADDLOCAL=Client,Docs,Maintainer,ServerScript,FilestreamClient,FilestreamServer *Replace DBNAME with the name of your additional content database. Replace DBINSTANCE with the name of your SQL Server Instance. Enable RBS for Each Content Database After installing the RBS software you still have to enable RBS for each content database additional content database. When you are configuring an additional content database you need to execute the following command before enabling RBS via PowerShell msiexec /qn /i rbs.msi REMOTEBLOBENABLE=1 FILESTREAMPROVIDERENABLE=1 DBNAME=WSS_Content_RBSTest2 FILESTREAMSTORENAME=FilestreamProvider_1 ADDLOCAL=EnableRBS,FilestreamRunScript DBINSTANCE=localhost *This command is similar to the one that was run to install RBS on your SharePoint servers; however, this command is specifically designed for additional content databases. Replace DBNAME and DBINSTANCE to suit your own environment. Once RBS has been configured for your content databses you need to execute to following PowerShell commands to fully enable it Open the SharePoint 2010 Management Shell as Administrator and perform the steps below $cdb = Get-SPContentDatabase –DatabaseName <Database Name> $rbss = $cdb.RemoteBlobStorageSettings $rbss.Installed() $rbss.Enable() $rbss.SetActiveProviderName($rbss.GetProviderNames()[0]) *It is important to specify the Database Name when using the SPContentDatabase cmdlet. If a web application contains multiple content databases, and you use Get-SPContentDatabase - WebApplication parameter, the command will fail. After running the preceding commands you can verify if the configuration is successful by running the following command $rbss.Installed() If the preceding command returns ‘True’ then the content database for your web application has been successfully configured to use RBS. Test your RBS Installation In order to test that your RBS installation is working properly you can upload a file to your RBS enabled web application that is more than 60KB. If RBS is functioning correctly you should see a new file in your BLOB store that corresponds to your recently uploaded file. In the example below I uploaded a text file to a SharePoint document library. The text file was approximately 1.3MB. As you can see below the file was placed in the BLOB store on the SQL Server’s local C\. Remote BLOB Store Maintenance By default RBS will not clean up items that are deleted from SharePoint from the BLOB store. As a result, your BLOB store will grow increasingly large as new items are added to SharePoint. You need to setup an RBS maintenance job that will run periodically and perform ‘garbage collection’ on any items that have been deleted from SharePoint but are still in the BLOB store. Configuration parameters for RBS maintenance are governed by the settings that are specified in the mssqlrbs_resources.rbs_internal_config table in the database that is configured for BLOB storage. By default RBS will wait 30 days before deleting any BLOBs that have no reference in SharePoint but are still in the BLOB store. If you are testing your RBS configuration you can set this value to zero days so that you can verify that items are being properly deleted from the BLOB store. Once you have confirmed that garbage collection is working properly you can set the garbage_collection_time_window back to the default value of 30 days. garbage_collection_time_window specifies the minimum time that must pass between identifying a blob as having no references in the database and deleting the blob from the store. This guarantees the availability of BLOBs for the specified time in case a backup is restored. The default value is 30 days. You can change the default garbage collection window by executing a SQL query on the database that has BLOB storage enabled. The default value for each is 30 days exec mssqlrbs.rbs_sp_set_config_value 'garbage_collection_time_window', 'time 000000'; exec mssqlrbs.rbs_sp_set_config_value 'delete_scan_period', 'time 000000'; exec mssqlrbs.rbs_sp_set_config_value 'orphan_scan_period', 'time 000000'; Reference http//social.technet.microsoft.com/Forums/en-US/sharepoint2010setup/thread/e9bda580-b9e7-48c5-b18c-485e016677a1 *When you are testing BLOB file deletion ensure that you delete the files from the secondary recycle bin, otherwise they will stay in the Content Database even after running the RBS maintainer job. In Full Recovery mode you will need to perform the following to delete files from the BLOB store 1)Run your RBS Maintainer Scheduled Task 2)Run a Full Log Backup of your content database 3)run a SQL Checkpoint on your content database 4) run an additional log backup of your content database. At this point the BLOBs should be deleted from the BLOB store. For a good explanation of why this is necessary please refer to the following blog post http//www.sqlskills.com/BLOGS/PAUL/post/FILESTREAM-garbage-collection.aspx Delete the file from the secondary recycle bin Run your RBS Maintainance schedule task (see below for instructions on how to configure this scheduled task) Run a Transaction log backup of your content database Execute a manual CHECKPOINT on the content database Repeat this process once more and the file should be deleted from the BLOB Store. Run the RBS Maintainer In order to perform RBS maintenance on a regular basis it is recommended to setup a scheduled task that will run the RBS maintainer executable. Before we configure this scheduled task we have to edit the RBS configuration file and input the name of the content database that we have enabled for RBS. *You have to add an additional connection string for each database that is configured to use RBS. If you have only one content database configured for RBS then you do not need to perform this step because the configuration file will already have a reference to your RBS enabled content database. This step is only necessary for additional content databases that you want to enable for RBS. Rename the existing config file (Microsoft.Data.SqlRemoteBlobs.Maintainer.exe.config) to web.config using following command (located in %programfiles%\Microsoft SQL Remote Blob Storage 10.50\Maintainer ) cd /d %programfiles%\Microsoft SQL Remote Blob Storage 10.50\Maintainer ren Microsoft.Data.SqlRemoteBlobs.Maintainer.exe.config web.config *By default all connection strings in the Maintainer configuration file are encrypted. The following process will show you how to unencrypt the file so that you can add your additional connection strings. After you have made your additions you will re-encrypt the configuration file. Un-encrypt the connection strings from the config file by using following command (aspnet_regiis is located in %windir%\Microsoft.NET\Framework64\v2.0.50727 cd /d %windir%\Microsoft.NET\Framework64\v2.0.50727 aspnet_regiis.exe -pdf connectionStrings "%programfiles%\Microsoft SQL Remote Blob Storage 10.50\Maintainer" Add an additional connection string to the web.config file for each content database that is RBS enabled as follows. Change the name of the Data Source and Initial Catalog as needed. Data Source = YourSQL Server Instance Initial Catalog= the name of the content database that is configured for RBS “The RBS installer creates one connection string that is named RBSMaintainerConnection by using the connection information that was provided during setup. However, new connection strings must be added for every additional database.” http//technet.microsoft.com/it-it/library/ff943565 <configuration> <connectionStrings> <add name="RBSMaintainerConnection" connectionString="Data Source=localhost;Initial Catalog=WSS_Content_RBSTest;Integrated Security=True;Application Name=& quot;Remote Blob Storage Maintainer&quot;" providerName="System.Data.SqlClient" /> </connectionStrings> <RemoteBlobStorage> <Logging> <add key="ConsoleLog" value="0" /> </Logging> </RemoteBlobStorage> </configuration> *You must use a unique connectionString name for each content database specified in the config file. The connectionString name will be referenced in the scheduled task that you will setup for each content database, so each one needs to be unique. Encrypt the web.config file again by using following command. cd /d %windir%\Microsoft.NET\Framework64\v2.0.50727 aspnet_regiis -pef connectionStrings "%programfiles%\Microsoft SQL Remote Blob Storage 10.50\Maintainer" -prov DataProtectionConfigurationProvider Rename the file back to original cd /d %programfiles%\Microsoft SQL Remote Blob Storage 10.50\Maintainer ren web.config Microsoft.Data.SqlRemoteBlobs.Maintainer.exe.config Note 1) XML file is case sensitive; you need to use the exact string for 'connectionStrings' parameter above. RBS Scheduled Maintenance Task You need to create a scheduled task that will run periodically and cleanup files that have been deleted from SharePoint. The job will find files that have been deleted from SharePoint but are still in the BLOB store. *Each content database needs to have its own scheduled task for BLOB maintenance. Create a Maintenance Task using following steps (for each database). Click Start, point to Administrative Tools, and click Task Scheduler. Right-click Task Scheduler (Local) and click Create Task. Click the Actions tab and click New. On the New Action page, specify Action as Start a Program. For the Program/script, click Browse and navigate to the RBS Maintainer application; by default, the location is %programfiles%\Microsoft SQL Remote Blob Storage 10.50\Maintainer \Microsoft.Data.SqlRemoteBlobs.Maintainer.exe. In the Add Arguments (optional) field, enter the following parameter string (change the name of the connection string as specified in the config file earlier) -ConnectionStringName RBSMaintainerConnection -Operation GarbageCollection ConsistencyCheck ConsistencyCheckForStores -GarbageCollectionPhases rdo -ConsistencyCheckMode r -TimeLimit 120 *The ConnectionStringName parameter refers to the name that you specified in the config file that was unencrypted and then re-encrypted in an earlier step. The first default name that is configured when RBS is installed is ‘RBSMaintainerConnection’. When you add additional connectionStrings to the RBS maintainer configuration file each one must have its own unique connectionString so that multiple scheduled tasks can be setup. As seen below I have two content databases configured for RBS. Each content database needs to have its own connectionString name which will then be referenced in its associated scheduled task. Click OK Note XML file is case sensitive; you need to use the exact string for the connection string above. On the Triggers tab, click New. 6. In the New task dialog box, set Begin the task to on a schedule. The trigger schedule to be Weekly, Sunday, at 2am (or at another time when system usage is low.) Click OK. On the General tab, enter a name for the task, such as “<Database Name> RBS Maintainer”, where <Database Name> identifies the database associated with the task. In the Security settings section Make sure that the account under which the task is to be run has sufficient permissions to the database. Select the option to run whether user is logged on or not. Click OK. *Once you are finished testing don’t forget to set your garbage collection parameters back to their default settings exec mssqlrbs.rbs_sp_set_config_value 'garbage_collection_time_window', 'days 30'; exec mssqlrbs.rbs_sp_set_config_value 'delete_scan_period', 'days 30'; exec mssqlrbs.rbs_sp_set_config_value 'orphan_scan_period', 'days 30'; References http//blogs.technet.com/b/sharepointjoe/archive/2011/02/01/sp2010-configuring-remote-blob-storage-with-sharepoint-2010.aspx http//technet.microsoft.com/it-it/library/ff943565 http//blogs.msdn.com/b/sqlrbs/archive/2010/03/19/running-rbs-maintainer.aspx http//sharepoint.nauplius.net/2011/03/enabling-rbs-on-multiple-content.html http//reality-tech.com/2011/12/11/rbs-remote-blob-storage-part-3 http//ksmuraleedharan.blogspot.ca/2011/02/remote-blob-storage-in-sharepoint-2010.html http//www.sqlskills.com/BLOGS/PAUL/post/FILESTREAM-garbage-collection.aspx http//technet.microsoft.com/en-us/library/ee663474.aspx http//msdn.microsoft.com/en-us/library/gg316763(v=sql.105).aspx http//social.technet.microsoft.com/Forums/en-US/sharepoint2010setup/thread/e9bda580-b9e7-48c5-b18c-485e016677a1 http//blogs.msdn.com/b/sqlrbs/archive/2008/08/08/rbs-garbage-collection-settings-and-rationale.aspx?




Posted on:
Categories: SharePoint
Description:
The Problem Something that has come up a lot in the past with clients implementing SharePoint 2010 in tabbed content - specifically, tabbed web part zones. But those of you who have researched this before will know that this functionality is simply not available in SharePoint 2010 Out-Of-The-Box. I thought I would take a minute and show how we typically implement tabs for our clients. When I first starting looking at how to create tabs in SharePoint, I came across this blog post by Matthew Koon. It got me some of the way there, but I wanted a more generic method of creating web part tabs...which is when I found this blog post by Kyle Schaeffer. I took the javascript and html that he posted, made slight modifications, and then wrapped it up in an empty re-usable SharePoint Page Layout. Using this method, users can create a page using this page layout, add simply add web parts in edit mode just like they do for any other web part zone. Only when they hit save, we use the JQuery UI library to "tabify" the web parts into nice looking tabs that can be easily customized to fit the clients desired branding using CSS.The Implementation Start with a new or existing SharePoint 2010 project, and add a new Module called PageLayoutModule. Next, add a new Text File called TabbedPageLayout.txt, once once it's added to the project, rename the file to TabbedPageLayout.aspx, and move it into the PageLayoutModule. Now since we've just created a blank page layout, we need to modify the PageLayoutModule's Elements.xml to reflect this. So open Elements.xml, and inside the Elements tag, replace the existing Module with the following (you can delete the Sample.txt file from the module if you'd like)<Module Name="PageLayoutModule" Url="_catalogs/masterpage"> <File Path="PageLayoutModule\TabbedPageLayout.aspx" Url="TabbedPageLayout.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" > <Property Name="Title" Value="Tabbed Page Layout" /> <Property Name="MasterPageDescription" Value="Tabbed Page Layout"/> </File> </Module> Now since TabbedPageLayout.aspx is still a blank file, we need to insert the required SharePoint registrations/etc. So just paste the following<%@ Page Language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage, Microsoft.SharePoint.Publishing,Version=14.0.0.0, Culture=neutral,PublicKeyToken=71e9bce111e9429c" metaprogid="SharePoint.WebPartPage.Document" metawebpartpageexpansion="full" %> <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <aspContent ContentPlaceholderID="PlaceHolderAdditionalPageHead" runat="server"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"> </script> <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"> </script> <script type="text/javascript"> //PASTE TAB SCRIPTS HERE </script> </aspContent> <aspContent ContentPlaceholderID="PlaceHolderPageTitle" runat="server"> <SharePointWebControlsFieldValue id="PageTitle" FieldName="Title" runat="server"/> </aspContent> <aspContent ContentPlaceholderID="PlaceHolderPageTitleInTitleArea" runat="server"> <SharePointWebControlsFieldValue FieldName="Title" runat="server"/> </aspContent> <aspContent ContentPlaceholderID="PlaceHolderMain" runat="server"> <div class="my-web-part-tabs" style="displaynone;"> <WebPartPagesWebPartZone runat="server" Title="Tabs Web Part Zone" ID="CenterColumn" /> </div> </aspContent> And now we have an empty SharePoint 2010 Page Layout, with 1 web part zone. As you may have guessed by web part name, this is the web part zone that will be transformed into tabs. The next step is to add the supporting scripts that will transform the web part zone into tabs. You will notice that in the code you copied and pasted above, JQuery is already referenced and there is a blank script block. We will be adding our scripts within that script block. Note if your existing branding already references JQuery and/or JQuery UI, you don't have to reference them above.(function ($) $.fn.wpTabify = function () var toReturn = false; if ($('.ms-WPAddButton').size() == 0) toReturn = this.each(function (i) var idName = $(this).attr('id'); var tabList = $('<ul class="wpt-ui-tabs-nav"/>'); var panels = $('<div class="wpt-ui-tabs-wrapper"/>'); $(this).find('.s4-wpTopTable,td[id^="MSOZoneCell_"] > table'). each(function (j) $(tabList).append('<li><a href="#ui-tab-panel' + idName + i + j + '"><span>' + $(this).find('h3.ms-WPTitle').text() + '</span></a></li>'); var thisPanel = $('<div id="ui-tab-panel' + idName + i + j + '" class="wpt-ui-tabs-panel"/>'); var panelContents = $(this).detach(); $(thisPanel).append($(panelContents). find('.ms-wpContentDivSpace')​); $(panels).append(thisPanel); ); if ($(tabList).find('li').size() > 0) $(this).prepend(panels); $(this).prepend(tabList); $(this).tabs(); ); $(this).show(); return toReturn; ; )(jQuery); function TabifyFnWrapper() $('.my-web-part-tabs').wpTabify(); _spBodyOnLoadFunctionNames.push("TabifyFnWrapper"); Now deploy the solution, and create a new page on the site you deployed to. Make sure you change the page layout to our newly created page layout. Now in edit mode, add some web parts which you would like to appear in each tab. For example, I added two list view web parts And then Save & Close. You should now see something similar to this First thing you will likely notice is that, in fact, this looks nothing like tabs. But all that is missing is some CSS to transform the web part titles into Tabs, and hide/show the tab contents as appropriate. Typically you will want to write your own styles to accomodate your clients desired branding, but as an example, we will use the styles that Kyle Schaeffer provided in the blog post I mentioned earlier (I've made some tweaks as I was having some issues; your mileage may vary).ui-tabs-nav margin 0; padding 0; .ui-tabs-nav li list-style none; margin 0 1px 0 0; padding 0; float left; .ui-tabs-nav a position relative; top 1px; display block; padding 10px 8px; border solid #e1e0dc; border-width 1px 1px 0 1px; background #d6d6d6; color #999; text-decoration none; -webkit-border-top-left-radius 5px; -webkit-border-top-right-radius 5px; -moz-border-radius-topleft 5px; -moz-border-radius-topright 5px; border-top-left-radius 5px; border-top-right-radius 5px; .ui-tabs-nav li.ui-tabs-selected a color #c70d37; background #fff; .ui-tabs-panel clear both; padding 20px; background #fff; border 1px solid #e1e0dc; .ui-tabs-hide display none; Now re-deploy and take a look at your page...it now looks like tabs! (fyi - sometimes I find that I have to manually upload the updated page layout) And that's all that is involved with creating SharePoint 2010 Page Layouts with Tabbed Web Parts from scratch. Feel free to leave comments on this page if you have any issues/questions/comments. Cheers!




Posted on:
Categories: Hyper-V
Description:
Windows Server 2012 introduces a new type of live migration called ‘Shared Nothing Live Migration”. Shared Nothing Live Migration allows IT administrators to migrate virtual machines to other Server 2012 Hyper-V hosts without the necessity of having to use shared storage. In this tutorial I will walk you through configuring Hyper-V 2012 Shared Nothing Live Migration. My test environment consists of two hosts running Windows Server 2012. Each host has its own local storage and is connected to a local area network via an Ethernet connection to an unmanaged switch. Each host has a 10Gbps connection to the LAN. First we have to enable Live Migrations on each of the hosts. On one of the Hyper-V hosts go to Hyper-V settings and then select ‘Live Migrations’ In this tutorial we will select the option to use Kerberos. CredSSP doesn't allow credentials to be delegated, so you can only initiate a live migration from the source server. With CredSSP you would not be able to initiate a live migration from your desktop Hyper-V client. Configure Kerberos delegation for Live Migration In order to use Kerberos for Live Migrations we have to configure Kerberos delegation so that Windows can delegate credentials between Hyper-V hosts during Live Migrations. In accordance with best practices, we have configured constrained delegation. In Active Directory Users and Computers select the ‘Delegation’ tab for one of the Hyper-V hosts and then select ‘ trust this computer for delegation to specified services only’. Click ‘Add’ and then select ‘cifs’ and ‘Microsoft Virtual System Migration Service’. In this example I have configured Xamot to delegate credentials to Tomax for the two specified services. This will allow credentials to be passed through for Live Migrations. Make sure that you configure delegation for the other server as well. In our case, we would configure the exact same delegation properties for Tamox, except that we would specify Xamot as the computer that we would like to delegate credentials to. That’s it. We’re now ready to perform a live migration. On one of the Hyper-V hosts select a virtual machine, right click and select ‘Move’ Select the option to ‘Move the virtual machine’ In our example we are going to select the option to move the virtual machine data to a single location Select a location on the destination computer for the virtual machine data **When you attempt to perform the live migration with the Release Candidate version of Server 2012 you will get the following error 'Virtual Machine Migration Operation Failed at Migration Source' This is a bug and will be fixed with the RTM version of Server 2012 ( http//www.jamesbannanit.com/2012/03/windows-8-server-hyper-v-live-migration-without-shared-storage ) Important Links http//www.windowsitpro.com/article/clustering/sharednothing-failover-clustering-windows-server-2012-143168 http//technet.microsoft.com/en-us/library/jj134199.aspx http//www.jamesbannanit.com/2012/03/windows-8-server-hyper-v-live-migration-without-shared-storage




Posted on:
Categories: SharePoint
Description:
Issue SharePoint Search displays “Error from SharePoint site *** Index was outside the bounds of the array.” in the crawl logs and the users are not able to find the affect file in search. This issue is caused by improperly mapped Managed Metadata Column fields. The issue itself can be triggered a number of different ways. One of them which is prevalent in my environment is the Data Sheet View when used with Custom Libraries. I know what you’re thinking, the datasheet view does not support MMS columns and they are set to read-only. This is correct if the MMS field has already been populated. However, if the MMS field is blank, we are able to enter data into it. In my case the users were using the Data Sheet View as a bulk edit tool for MMS. They would map one item correctly, then copy the data (ie. “180;#Test24 MECHANICAL”) and then paste it in the subsequent fields. From the SharePoint end everything would look fine. However, when search crawls the document, it would error out with “ The SharePoint item being crawled returned an error when requesting data from the web service. ( Error from SharePoint site *** Index was outside the bounds of the array. )”. This would cause the document not to appear in the search results as the document is ignored once an error occurs. The issue is clearly visible when looking at the SPListItem.Xml Property . I have posted a script on the Script Center which will get the data quickly. Get Crawled Property Names Below are screenshots of two files in the same library. As you can see in the bad file, TaxHTField field begins with |Guid while it should be Term|Guid. Solution The solution to this problem begins at finding the reason that MMS fields are not mapped properly. This could be caused by Entering MMS Fields using Data Sheet View Improperly setting the field data programmatically Backup/Restore Once the cause has been found it needs to be resolved. In my case I have set Default Values for the MMS Fields, this disallows the users from entering the data using the Data Sheet View. The next step is to deal with all of the items which have this issue. If the count is small simply edit each file and reselect the MMS Fields using the picker and save the items. If you’re unlucky like myself, you will have more than 500 items with this issue. I was able to script the full repair process. Get-SPSearchCrawlLogs http//gallery.technet.microsoft.com/scriptcenter/Get-SharePoint-Search-a55da58b Repair-SPMMSMappings http//gallery.technet.microsoft.com/scriptcenter/Repair-Orphaned-Managed-824159e3 Run Get-SPSearchCrawlLogs on the Farm containing the Search Service It will display all the Document URLs which are experiencing this issue Run Repair-SPMMSMappings with the Document URLs from above on the Farm containing the associated Web Application If you have any questions/comments you can leaven them blow. Enjoy!




Posted on:
Categories: SharePoint;CodePlex
Description:
Previously I wrote a blog posting where I showed how to easily inject client-side code via delegates in SharePoint 2010. Now, I'd like to show how I extended that idea to allow authors in a SharePoint 2010 site to insert Code (i.e. C#, JavaScript, Powershell, etc) through the Content Editor interface, and automatically apply Syntax Highlighting. The Problem Recently we've been working on updating Softlanding's own internet site, including our Blog. When I started writing the article, I started copying in some code snip-its, and realized it didn't look so great using out-of-the-box SharePoint styles. So, I started reading some blog posts online, which show how to utilize the SyntaxHighlighter code from Alex Gorbatchev from within SharePoint. At first, I thought great!...until I realized that this involved lots of manual insertion of Javascript into pages, and requiring users to edit the html markup in order to make use of the syntax highlighting. And so my next thought was, how can we integrate this into the SharePoint UI so that our users can easily include nicely-formatted code and scripts into their blog posts? The Idea My answer was to combine client-side code injection, with a custom SharePoint Ribbon button. This way, users would be able to just select their code, pick the language, save their post, and Voila! Syntax Highlighting in a SharePoint Blog! I'll briefly highlight the steps to implement this below, and if you'd like to see the final product on CodePlex, click here...And although this post is targeting only the SharePoint blog, with some simple xml changes you should be able to use this code for any Enhanced Rich Text field anywhere in SharePoint 2010! The Solution First, start a new SharePoint 2010 Project, and add in the class and module mentioned in my previous post. Now you should have the project all set up for script injection. All we need to do here is change what we're injecting into the page, so just modify the CreateChildControls() method as follows base.CreateChildControls(); if (SPContext.Current.FormContext.FormMode != SPControlMode.Edit && SPContext.Current.FormContext.FormMode != SPControlMode.New) CssLink coreCss = new CssLink(); coreCss.DefaultUrl = "http//alexgorbatchev.com/pub/sh/current/styles/shCore.css"; this.Controls.Add(coreCss); CssLink coreDefaultCss = new CssLink(); coreDefaultCss.DefaultUrl = "http//alexgorbatchev.com/pub/sh/current/styles/shCoreDefault.css"; this.Controls.Add(coreDefaultCss); //TODO can we use ScriptLink objects instead using external urls? this.Page.ClientScript.RegisterClientScriptInclude("shCore", "http//alexgorbatchev.com/pub/sh/current/scripts/shCore.js"); this.Page.ClientScript.RegisterClientScriptInclude("shAutoloader", "http//alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js"); //Load all brushes for languages that have been // added to the SharePoint ribbon UI this.Page.ClientScript.RegisterClientScriptInclude("shBrushCSharp", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushJScript", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushCpp", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushCss", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushJava", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushPerl", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushPhp", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushPlain", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushPowerShell", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushPowerShell.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushPython", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushSql", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushVb", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js"); this.Page.ClientScript.RegisterClientScriptInclude("shBrushXml", "http//alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js"); //lastly, load our file that contains any of our own // javascript related to rendering syntax highlighting this.Page.ClientScript.RegisterClientScriptInclude( "slsyntaxrenderonly", @"/_layouts/Softlanding.SyntaxHighlighter/ SLSyntaxHighlightRenderOnly.js"); else ScriptLink editOnlyScript = new ScriptLink(); editOnlyScript.Name = "/_layouts/Softlanding.SyntaxHighlighter/SLSyntaxHighlightEditOnly.js"; editOnlyScript.Language = "javascript"; editOnlyScript.Localizable = false; this.Controls.Add(editOnlyScript); Next, we need to add the Ribbon button, so that users can make use of all this Javascript and CSS that we've just injected. To do that, open up the module that was added in my previous blog post (I called it ClientSideDelegateCtlElement), and inside the Elements tag above the Control tag, insert a CustomAction that declaratively creates the ribbon button while editing blog posts only. Note I've only included the option to highlight C# for the sake of brevity, but you can add additional language options as desired. <CustomAction Id="SplitButtonRibbonControl" RegistrationType="ContentType" RegistrationId="0x0110" Location="CommandUI.Ribbon"> <CommandUIExtension> <CommandUIDefinitions> <CommandUIDefinition Location="Ribbon.EditingTools.CPEditTab.Styles.Controls._children"> <SplitButton Id="Ribbon.SplitButton" Sequence="0" Alt="Ribbon.SplitButton.Controls.CPFlyout_ALT" LabelText="Code Syntax" PopulateDynamically="false" PopulateOnlyOnce="true" TemplateAlias="o1" Image16by16= "/_layouts/Softlanding.SyntaxHighlighter/objectscript_16.png" Image32by32= "/_layouts/Softlanding.SyntaxHighlighter/objectscript_32.png" ToolTipTitle="Code Syntax" ToolTipDescription="Apply Code Block Style" Command="ApplyDefault"> <Menu Id="Ribbon.SplitButton.Menu"> <MenuSection Id="Ribbon.SplitButton.Menu.MenuSection"> <Controls Id="Ribbon.SplitButton.Menu.MenuSection.Controls"> <Button Id="Ribbon.SplitButton.Menu.MenuSection.Controls.Button1" Alt="" Sequence="0" Command="ApplyCSharp" ToolTipTitle="" ToolTipDescription="" LabelText="C#" TemplateAlias="o1"/> </Controls> </MenuSection> </Menu> </SplitButton> </CommandUIDefinition> </CommandUIDefinitions> <CommandUIHandlers> <CommandUIHandler Command="ApplyDefault" CommandAction="javascriptApplyCodeBlock('defaultbutton');" /> <CommandUIHandler Command="ApplyCSharp" CommandAction="javascriptApplyCodeBlock('csharp');" /> </CommandUIHandlers> </CommandUIExtension> </CustomAction> And lastly, you will need to add the javascript which ties everything together! You may have noticed above that in the server side code, I was injecting 2 JavaScript files from my /_layouts/ folder - called SLSyntaxHighlightRenderOnly.js and SLSyntaxHighlightEditOnly.js. As their names imply, each file contains the client side code necessary to handle user actions in edit mode, and the rendering of the syntax highlighting when the user is not editing the blog article. The Catch I noticed that the first time I tried to inject all of the SyntaxHighlighter JavaScript and CSS to every page, it broke some SharePoint content editing functionality, mainly the ribbon - so you have to be careful what javascript you inject when. I found that if I only injected the shCore.js, the brush js, and your rendering js in Display & Invalid mode, it behaved nicely. So then in Edit & New mode, you inject only the javascript you require for handling the ribbon actions (in my case, the ApplyCodeBlock() function and its helper methods). So, now that I've explained my reasoning for these 2 files, here they are SLSyntaxHighlightEditOnly.js //NOTE this has been tested in IE only; cross browser support // may require some extra cases to find selection text. function ApplyCodeBlock(langName) if (langName == "defaultbutton") return; var selectedText = (document.all) ? document.selection.createRange() document.getSelection(); if (selectedText != null && selectedText.text != null && selectedText.text.length > 0) wrapSelectionWithPreTags(langName, selectedText.text); // This function sets the current selection to the selected text, // wrapped inside of a pre-tag that Syntax Highlighting // javascript will read and re-format function wrapSelectionWithPreTags(langName, selectedTextStr) var sel, range, node; var html = "<pre class='brush " + langName + "'>" + selectedTextStr + "</pre>"; if (typeof window.getSelection != "undefined") // IE 9 and other non-IE browsers sel = window.getSelection(); // Test that the Selection object contains at least one Range if (sel.getRangeAt && sel.rangeCount) // Get the first Range (only Firefox supports more than one) range = window.getSelection().getRangeAt(0); range.deleteContents(); // Create a DocumentFragment to insert and populate it with HTML // Need to test for the existence of range.createContextualFragment // because it's non-standard and IE 9 does not support it if (range.createContextualFragment) node = range.createContextualFragment(html); else // In IE 9 we need to use innerHTML of a temporary element var div = document.createElement("div"), child; div.innerHTML = html; node = document.createDocumentFragment(); while ((child = div.firstChild)) //while (child == div.firstChild) node.appendChild(child); range.insertNode(node); else if (document.selection && document.selection.type != "Control") // IE 8 and below range = document.selection.createRange(); range.pasteHTML(html); SLSyntaxHighlightRenderOnly.js //this just performs any required syntax highlighting on SP load. SyntaxHighlighter.all(); So now, deploy to your Blog site, and start editing a new or existing Blog article. You should notice a new ribbon button that looks something like this (but with only C# in the drop down menu) So paste in your plain text code, select it, click the new ribbon button, chose your language, and save your blog - and now view it....you should now have some amazing looking syntax highlighting, just like all the example text I've included in this blog entry! And that should be it! And if you missed it, click here to view the full source on CodePlex. If you encounter any issues or have any questions/comments, feel free to leave a comment on this page and I'll try and respond.




Posted on:
Categories: SharePoint
Description:
I've run into situations in the past where I needed to insert client-side code (such as javascript) into a page dynamically from server-side code. For example, on some custom pages it is useful to add javascript to be called on page load, but many times the client side code needs data that is easily accessible server-side. In the most recent case, I was deploying a custom solution into an environment that I had no control over, and I needed to include JQuery and some custom javascript functions in the header, so that I could run some custom client-side code on certain pages. Since I did not have access or control over the master pages or application pages in the clients environment, this was a nice alternative. To do this, I use a Delegate Control class, and using that control I target the AdditionalPageHead placeholder. In the server side code within that class, I inject the required client-side code. The Setup First, add an empty class to your SharePoint 2010 project in Visual Studio by selecting Class under the Code Templates in the Add New Item dialog. I named my user control ClientSideDelegateClass (I'll be using C# in this blog entry) Now we need to specify where to insert the new user control in the SharePoint master page. To do this, simply add another new item - this time, select Empty Element (again, under the SharePoint 2010 Templates in the Add New Item dialog). I called my element ClientSideDelegateCtlElement You may optionally may also want to add some javascript files to a mapped layouts folder in your project, if you have large(r) functions you need to call. If a feature was automatically created, ensure that it contains ClientSideDelegateCtlElement, and that it is web-scoped. If a feature was not automatically created, then add a new feature and make sure it's configured correctly (you can change the feature name and description as desired) The Code Next we have to tell SharePoint where to put our newly created web control class (ClientSideDelegateClass). To do this, open up the empty element you created, and insert the following Control element inside the empty Elements tag. However, you will need to change the ControlAssembly and the ControlClass (both lines are highlighted in the below code snip-it) to correspond with your project. And, if you're like me, you'll want an easy way of finding out your assembly's PublicKeyToken...so if you haven't seen this already, check this msdn blog article out. <Control Id="AdditionalPageHead" ControlAssembly="ClientSideSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0f1ad6f8348c61d0" ControlClass="ClientSideSample.ClientSideDelegateClass"/> The last thing you need to do with the element (and I always forget to do this) is register the control as a safe control. You can do this by selecting the element, and adding the control to the Safe Control Entries property collection in the properties window NOTE You may have to modify the Namespace, as I noticed in my environment by default the namespace was not correct. Ok, now we just have to add the code to our class to inject the client-side code! Open ClientSideDelegateClass.cs, and you will need to add some code (see below) public class ClientSideDelegateClass System.Web.UI.WebControls.WebControl protected override void OnLoad(EventArgs e) base.OnLoad(e); protected override void CreateChildControls() base.CreateChildControls(); //inject required client side code here this.Page.ClientScript.RegisterClientScriptInclude( "jquery181", "//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"); this.Page.ClientScript.RegisterClientScriptBlock( this.GetType(), "CustomPageLoadFn", @" function OnCustomPageLoad() alert('hello world!'); $('body').css('background-color', 'aqua'); ", true); this.Page.ClientScript.RegisterClientScriptBlock( this.GetType(), "HelloWorldStartup", " _spBodyOnLoadFunctionNames.push('OnCustomPageLoad'); ", true); Now deploy the solution to any SharePoint site, and you should see a "Hello World!" messagebox, followed by the background colour changing. And notice that the background color was changed using JQuery, so if the background colour changed, then JQuery has been successfully included as well! If you have any comments/questions/issues, please feel free to leave a comment on this page and I'll try and respond.