10/25/12

SharePoint, Office 2013 RTM - MSDN

Microsoft has just added SharePoint 2013, Office 2013, Visio 2013, Project 2013 and Exchange 2013 to MSDN for subscribers to download.


8/23/12

Microsoft MSDN .img file



Microsoft seems to have switched file formats from .iso to .img for some of the software available on MSDN.

What is an .img file? At first I thought I had to use Nero to burn the image to a disk and then install, but I noticed that in Windows 8 you can natively mount .iso and .img formats.

Since I don't plan on installing these .img files on Windows 8 or Server 2012 yet, you can simply rename the file from .img to .iso and then use the file as you would normally use an .iso


8/22/12

Sharepoint 2013 Preview


Sharepoint 2013 is just around the corner, full of new features to take the platform to the next level




Here are some of the new features


  • Visual Experience
    • Metro Interface
    • To brand a SharePoint site, designers just create a site design as they typically would, by implementing HTML, CSS, and JavaScript. Designers can create these files by using their design tool of choice, whether that is Adobe Dreamweaver, Microsoft Expression Web, or some other HTML editor. You don't have to use SharePoint Designer or Visual Studio 2013 to brand a SharePoint site
  • App Store
    • Everything in Sharepoint 2013 is an App, lists, workflow, site pages, remote web apps, etc.
    • Make your apps available to everyone to try and buy through the public Store or only available to your employees through the corporate catalog
  • Social Networking
    • The introduction of Community Sites offers a forum experience to categorize discussions around subject areas, and connect users who have knowledge or seek knowledge about subject areas
    • My Sites for micro-blogging, allows likes, hash tags and news feed functionality following content, people and sites.
  • Integration
    • Organize all your projects and tasks to get visibility into upcoming deliverables across SharePoint, Outlook and Microsoft Project
    • Sync your content in SharePoint to your desktop with SkyDrive Pro
  • Development
    • Based on common web standards like HTML, CSS, and JavaScript. Furthermore, implementation relies on established protocols like the Open Data protocol (OData), and OAuth
    • Support for the newly developed web-based tool "Napa" Office 365 Development Tools for developing apps
    • Visual Studio 2012 now includes a new app project template in the Apps folder named Apps for SharePoint 2013
    •  In addition to the use of Representational State Transfer (REST) endpoints for web services, there is a broad new API for both server and client development. Remote event receivers and now supported in addition to client-side rendering
  • Cloud
    •  Improved and enhanced to support the new cloud-based architecture and app-driven development framework
    • Full support for development against the Windows Azure Workflow platform
  • Content
    • Many new features for videos and using videos on pages. A new video content type is added, and the video upload process is improved for content authors
    • Content authors can insert an iframe element into an HTML field on a page. This lets content authors embed dynamic content from other sites, such as videos or map directions
    •  Support for image renditions. Image renditions let you display different sized versions of an image on different pages
    • Cross-site publishing lets you store and maintain content in one or more authoring site collections, and display this content in one or more publishing site collections
    • Designate any library or list as a catalog. After the Cross-Site Collection Publishing feature is enabled for a site collection, you can designate any library or list within that site collection as a catalog so that content can be reused on publishing site collections
  • Localization
    • Built in integrated translation service that lets content authors select content for export for human translation or specify content for machine translation.



These are only a subset of all of the new and improved features and functionality in the Sharepoint 2013 Preview, for more information check out Microsoft's official Sharepoint 2013 sites at

http://technet.microsoft.com/en-us/library/cc303422(v=office.15)
http://msdn.microsoft.com/en-us/library/jj162979(v=office.15)


Download the preview at:
http://technet.microsoft.com/en-US/evalcenter/hh973397

8/15/12

Microsoft System Center Service Manager 2012 Gotchas


I have attempted to install SCSM 2012 unsuccessfully multiple times and learned a few things that I'll share that will hopefully save someone hours of time hunting down solutions for these issues.

The first issue I ran into was during the SCSM Data warehouse management server installation, during this install you will be asked for multiple database names, rather than selecting the default names, I chose to append '2012' to all the database names. The install will fail with 2012 in the database names, I tried this in three separate environments and it failed in all three.

The next issue was the SQL instance name, if you create a new instance besides the default MSSQL and include 'MSSQL' in the name of the new instance, the installation will fail. Tried this in a couple of different environments and always a failed installation.

The last issue is during an upgrade from SCSM 2010 to SCSM 2012, about three quarters of the way through the installation it will attempt to make changes to the SSRS server, if there is a web folder on the site with the name 'Data Sources' the installation will fail. This failure will be a catastrophic failure and require a disaster recovery scenario to rebuild/reinstall. The horrible thing about this issue is that if you have been creating reporting solutions using the SQL Business Intelligence Development Studio, when you publish your projects to the SSRS server I believe it will automatically create the Data Sources Folder. For the upgrade, rename this folder, run the upgrade and the change the name back after it succeeds.


SQL 2008 Native Client Installation Error





I recently worked on a Microsoft System Center Service Manager 2012 upgrade project and on both of the management servers during the prerequisite installation the SQL Server 2008 Native Client installation would fail. After searching around through what seemed like hundreds of sites, I found a solution that works consistently.

Error Message - An error occurred during the installation of assembly 'Microsoft.VC80.CRT...




Export and delete the following registry keys...

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Winners\x86_policy.8.0.microsoft.vc80 & vc90 entries…

[HKEY_LOCAL_MACHINE\COMPONENTS\DerivedData\Components\x86_policy.8.0.microsoft.vc80 & vc90 entries

[HKEY_LOCAL_MACHINE\COMPONENTS\WINNER\Components\x86_policy.8.0.microsoft.vc80 & vc90 entries.


Note: On my 2008 R2 Server the third set of keys was not present

Then run services.msc and set the "Windows Module Installer" to automatic and Reboot.
The installation will now complete successfully.

6/18/12

Cannot resolve the collation conflict between “SQL_Latin1_General_CP1_CI_AS” and “Latin1_General_100_CI_AS” in the equal to operation

Working in a Microsoft System Center Service Manager 2010 database I had added a couple of new tables for doing Business Hour Calculations ( see SQL Calculate Business Hours post). I added the tables calendar and holiday for the business hour calculations and when I attempted to execute my SQL function for doing the business hour calculation between date ranges I received the error.

After searching and searching I found a simple solution. First a useful query to determine what the collation is for a columns in a table. In my case I performed the query on the calendar table and day_name and day_number were both set incorrectly.


SELECT
    col.name, col.collation_name
FROM 
    sys.columns col
WHERE
    object_id = OBJECT_ID('YourTableName')




This query will return the collation for each column specified, for me it instantly helped my identify the collation conflict and I was able to execute the following query to correct the issue.


ALTER TABLE YourTableName
  ALTER COLUMN OffendingColumn
    VARCHAR(100) COLLATE Latin1_General_CI_AS NOT NULL


After I ran the alter statement, I tried the business hour function again and sure enough it worked perfectly.



5/31/12

SQL Server 2008 - No Administrator Access



In the past I've experienced issues with SQL Server where the domain account or group that I designated for administrator access loses the ability to perform any administrative actions. Strange behavior because it will let the accounts log in to the server but anytime a domain user attempts an action that requires elevated permissions an error is thrown.

One quick solution is to logon to the machine as the local administrator rather than any domain account and use this account to re-add any domain user or group permissions. By default this account is given administrative access on the SQL server.


5/23/12

SQL - Calculate Business Hours Minus Holidays


Calculating Business Hours 


I was recently tasked with generating SSRS reports against a Microsoft System Center Service Manager data warehouse. The reports require that only business hours be used to extract things like how long a service management ticket was worked etc. In my case the service desk is open M-F from 7:30 to 4:30 and no weekends or Federal Holidays. I expected to find a number of good examples with a few searches but nothing came up that fit my needs exactly.

Here's a quick rundown of how I was able to satisfy the reporting requirements.

First - create a new table to store the work week hours including Saturday and Sunday, this table will be used whenever a query is generated to determine how many hours fall within the "open" hours of the service desk.

I started the process with some examples I gathered here - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=74645 I then extended the examples to include Holidays and fix the queries when the start date and end date were on the same day.

Open SQL Management Studio and attach to the database you wish to add this new table to, paste the following SQL code into the query and execute.

CREATE TABLE [dbo].[ttr_calendar] (
[day_number] [varchar] (50) NOT NULL ,
[day_name] [varchar] (50) NULL ,
[begin_time] [datetime] NULL ,
[end_time] [datetime] NULL ,
[duration] [real] NULL 
) ON [PRIMARY]

Next I'll populate the table with the hours of the service desk. Execute the following statement

insert into ttr_calendar
select 1,             'Monday',      '7:30:00 AM',    '4:30:00 PM',   32400 union all
select 2,             'Tuesday',     '7:30:00 AM',    '4:30:00 PM',   32400 union all
select 3,             'Wednesday',   '7:30:00 AM',    '4:30:00 PM',   32400 union all
select 4,             'Thursday',    '7:30:00 AM',    '4:30:00 PM',   32400 union all
select 5,             'Friday',      '7:30:00 AM',    '4:30:00 PM',   32400 union all
select 6,             'Saturday',    '7:30:00 AM',    '4:30:00 PM',   0 union all
select 7,             'Sunday',      '7:30:00 AM',    '4:30:00 PM',   0

For brevity I'll just link the F_Table_Date function that I used in conjunction with the other tables, this code will need to be copied and executed on our SQL instance, this will generate a function that is used in the query.


Function F_TABLE_DATE is a multistatement table-valued function that returns a table containing a variety of attributes of all dates from @FIRST_DATE through @LAST_DATE. In short, it’s a calendar table function.

Next I need to create a table to store the Holiday information - Note: This table will have to be manually populated with your holiday information, simply add a title i.e. Christmas, New Years, etc. and the date in the following format 12/25/2012.


USE [DWDataMart] /* <--Your Database Name */
GO

/****** Object:  Table [dbo].[ttr_Holiday]    Script Date: 05/22/2012 14:37:53 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[ttr_Holiday](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Date] [date] NOT NULL,
 CONSTRAINT [PK_ttr_Holiday] PRIMARY KEY CLUSTERED 
(
[ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

Now that all the pieces are in place I can generate the actual query that will return my business hours minus Holidays.

declare @start_date datetime,
@end_date datetime,
@temp int

select @start_date = '24 May 2012 07:30:00 AM',
@end_date = '29 May 2012 04:30:00 PM'
Select @temp = COUNT(ttr_holiday.date)*9 from ttr_holiday where ttr_holiday.date Between @start_date and @end_date 
select @temp, total_hours = sum(case
when dateadd(day, datediff(day, 0, @start_date), 0) = dateadd(day, datediff(day, 0, @end_date), 0) then
CASE
WHEN CONVERT(VARCHAR(8),@start_date,108) < '07:30:00 AM' and CONVERT(VARCHAR(8),@end_date,108) > '16:30:00'
THEN  
datediff(second, [DATE] + begin_time, [DATE] + end_time)
WHEN CONVERT(VARCHAR(8),@start_date,108) < '07:30:00 AM' and CONVERT(VARCHAR(8),@end_date,108) < '16:30:00'
THEN  
datediff(second, [DATE] + begin_time, @end_date)
WHEN CONVERT(VARCHAR(8),@start_date,108) > '07:30:00 AM' and CONVERT(VARCHAR(8),@end_date,108) < '16:30:00'
THEN  
datediff(second, @start_date, @end_date)
WHEN CONVERT(VARCHAR(8),@start_date,108) > '07:30:00 AM' and CONVERT(VARCHAR(8),@end_date,108) > '16:30:00'
THEN  
datediff(second, @start_date, [DATE] + end_time)
END
when [DATE] = dateadd(day, datediff(day, 0, @start_date), 0) then
case
when @start_date > [DATE] + begin_time then datediff(second, @start_date, [DATE] + end_time)
else duration
end
when [DATE] = dateadd(day, datediff(day, 0, @end_date), 0) then
case
when @end_date <  [DATE] + end_time then datediff(second, [DATE] + begin_time, @end_date)
else duration
end
else duration
end
 ) 
 
/ 60.0 / 60.0 - @temp
from F_TABLE_DATE(@start_date, @end_date) d inner join ttr_calendar c
on d.WEEKDAY_NAME_LONG = c.day_name

This query will also take into account the start date and end date being on the same day, in several examples that I looked at this part would not return the correct results.

I hope this post helps with calculating business hours.



5/17/12

Programmatically Change Sharepoint Web Application IP Address


Recently I was asked about changing a Sharepoint Web Application IP Addresses programatically, is this possible and how will it affect the Sharepoint sites?

I did some testing and it turns out that it is indeed possible to change the IIS Website IP Address without impacting the Sharepoint Web Application(s). For the most part Sharepoint does not care about the IP Address that are assigned to it's Web Application(s), what it cares about is how the IIS sites are mapped to it's Site Collections. The mapping is done via host header in IIS and Alternate Access Mappings in Sharepoint.

Hopefully there are no Sharepoint sites that are accessed using IP Addresses, if so when the IP Address changes, things will break.

Using  Host Headers and Alternate Access Mappings allow access via friendly names, these names are only bound by DNS so as

To create a friendly name like 'Portal' first I'll create a host header in IIS to my Sharepoint site, host headers allow me to have several IIS sites and only require one IP address.

In IIS select the Sharepoint site and click Bindings from the Actions menu, enter a friendly name, in my case 'Portal'



 Next Ill create a new A record on my DNS server so that the name Portal resolves to my Sharepoint Web Applications IP Address.

Next I'll create a Sharepoint Alternate Access Mapping so that Sharepoint knows what to do when it receives a request for this friendly name 'Portal'

Open Sharepoint Central Administration, select Application Management and under Web Applications select configure alternate access mappings.

Select the alternate access mapping collection for your site and select edit public URLs


Next add the url for your friendly name in one of the zone text boxes


After this configuration is complete Sharepoint can be accessed by typing http://portal. Next I want to programmatically change the IP address of my Sharepoint Web Application.

I found a Powershell script to perform this exact task.


$oldIp = "172.16.3.214"
$newIp = "172.16.3.215"


# Get all objects at IIS://Localhost/W3SVC
$iisObjects = new-object `
    System.DirectoryServices.DirectoryEntry("IIS://Localhost/W3SVC")


foreach($site in $iisObjects.psbase.Children)
{
    # Is object a website?
    if($site.psbase.SchemaClassName -eq "IIsWebServer")
    {
    $siteID = $site.psbase.Name


    # Grab bindings and cast to array
    $bindings = [array]$site.psbase.Properties["ServerBindings"].Value


    $hasChanged = $false
    $c = 0


    foreach($binding in $bindings)
    {
    # Only change if IP address is one we're interested in
    if($binding.IndexOf($oldIp) -gt -1)
    {
    $newBinding = $binding.Replace($oldIp, $newIp)
    Write-Output "$siteID: $binding -> $newBinding"


    $bindings[$c] = $newBinding
    $hasChanged = $true
    }
    $c++
    }


    if($hasChanged)
    {
    # Only update if something changed
    $site.psbase.Properties["ServerBindings"].Value = $bindings


    # Comment out this line to simulate updates.
    $site.psbase.CommitChanges()


    Write-Output "Committed change for $siteID"
    Write-Output "========================="
    }
    }
}

Note: Remember DNS will have to be changed first to accommodate the IP Address change.

Provided there are multiple IP Addresses available on the Sharepoint server, this script will look for an old IP Address and update the IIS website to the new IP Address. Again Sharepoint does not care about the IP Address but it only cares about the request coming to it via IIS and matching the name with a Site Collection.

Hopefully this is helpful, it can be useful in fail over scenarios where re-iping at the fail over site is required.

2/24/12

Passed VCP 510 (VMWare Certified Professional)

I recently passed the VCP 510 exam renewing my VCP again before the deadline of February 28th 2012. If I wouldnt have taken the exam before this date I would have had to enroll in the week long training class prior to taking the exam.

The exam was very much like what I have been used to as far as the previous VMWare VCP exams have been, it did seem like there were more select multiple answer type questions than usual.

Here is a great study site that currently has 927 test questions posted, I can say that these questions are right inline with what you can expect to see on the test. If you can get comfortable with these test questions you will surely pass the test with no issues.

Check out the test questions here

2/23/12

SharePoint 2010 101 Code Samples



Microsoft has released 101 code samples for Sharepoint 2010. The samples include HTML 5, AJAX, JQuery, WCF, REST and a lot more.

Check them out Here

Some of the projects include...




Each code sample is part of the SharePoint 2010 101 code samples project. These samples are provided so that you can incorporate them directly in your code. Each code sample consists of a standalone project created in Microsoft Visual Studio 2010

2/10/12

SoftArtisans OfficeWriter - Sharepoint 2010 - Word 2010


I recently had the opportunity to check out SoftArtisans OfficeWriter product. The OfficeWriter product exposes an API that allows information from custom ASP.NET applications to be consumed and used to dynamically and programmatically build Microsoft Word documents and Microsoft Excel spreadsheets.

The OfficeWriter API is a .NET library that allows you to read, manipulate and generate Microsoft Word and Microsoft Excel documents from your own applications. The OfficeWriter product can integrate with Sharepoint 2010 allowing you to export Sharepoint list data into Microsoft Word and Excel documents.

SoftArtisans provides easy to understand sample code, videos and pre-built Sharepoint solutions that make getting started with the product very trivial.

For this tutorial I'll demonstrate deploying, configuring and testing Word Export Plus in a Sharepoint 2010 environment. Word Export Plus is a SharePoint solution that demonstrates the usage of the OfficeWriter API in SharePoint 2010. This solution adds a new context menu (custom action) button to list items, allowing you to export the list data to a pre-formatted Word template that can be designed yourself in Word, or automatically generated by Word Export Plus.

Requirements for this tutorial

  1. SoftArtisans OfficeWriter -  Installed and properly licensed, download the trial from Here
  2. SoftArtisans Word Export Plus - Download the Sharepoint solution installer from Here
  3. Sharepoint 2010  - A site in place that will be used to test the Sharepoint integration features
  4. Microsoft Word 2010 - Installed on the Sharepoint 2010 server

Installation


Launch the WordExportPlus.msi executable, this will install the Sharepoint solution into the Sharepoint Farm.



After the Sharepoint solution has been installed it can be deployed

Open Sharepoint Central Administration
Navigate to System Settings |  Farm Management  | Manage Farm Solutions
Select Word Export Plus.wsp
Select Deploy Solution
Specify a deployment time
Select OK


After the solution has been deployed it can be enabled through the site features on the site where the tool is going to be used.













After Word Export Plus has been activated I'll configure it for use.

First I'll create a contacts list that will be the data source for my exports, select Site Actions | View All Site Content | Create and select Contacts



I'll name the list People and select OK.

After the list is created I'll create a couple of test contacts in the list.



Next I'll configure Word Export Plus by selecting Site Actions | Site Settings | OfficeWriter Solution: Word Export Plus



First I'll choose the list that I just created (People) in the Sharepoint List dialog, in the Word Template dialog select Create a new template file. In the Template File Location select the Shared Documents library of the current site. Enter a name for the Template File (Word Template). Enter a name for the Action (Word)


This completes the configuration, 

select Create New Action

To test the new custom action browse to the People list created previously, from one of the contacts select the dropdown next to the last name column and select the action name created previously (Word)


A dialog will open asking if I would like to open or save the WordWriter.Doc file, select Save and after the file is downloaded select Open

This is how the auto-generated template will render the Sharepoint list data, I could have created my own Word template and selected that during the configuration steps. This provides a flexible solution to allow users to get the list data out quickly and formatted nicely into Microsoft Word.




2/1/12

InfoPath 2010 - Sharepoint 2010 Custom Workflow Part 3


Add Custom Code

Next I'll add some custom code to define the logic for the workflow by expanding the InfoPathWorkflow folder and double clicking the InfoPathWorkflow.cs class. This will bring up the design workflow design view. In the design view click the whileActivity1 red exclamation | Choose the property 'Condition' is not set option. 




In the properties window select from the Condition property dropdown: Code Condition




Next expand the Condition property and type into the child Condition property: notDone and press enter



The logic in the code will allow the workflow to run until our condition is met and we change a variable to indicate the workflow is complete.

First I'll create a method to indicate the workflow is not complete. Right click on the workflow design surface and select View Code. Find the auto-generated notDone method and replace the code with the following code snippet.

bool done = default(bool);
private void notDone(object sender, ConditionalEventArgs e)
{
     e.Result = !done;
}

The while activity looks at the e.Result value to determine if the loop will continue or not. The onWorkflowItemChanged event will await the event that the workflows list item has changed ( is the site name provided? ) when that happens the after event (invoked) of the onWorkflowItemChanged activity will fire providing the opportunity to change the done variable to true. The while loop will then run the notDone method to check the e.Result which will always return the opposite of done (!done) the while loop will exit when done is set to true.

Double click the onWorkflowItemChanged1 shape in the designer view to generate the onWorkflowChanged1_Invoked method. Replace the auto-generated method with the following code snippet

private void onWorkflowItemChanged1_Invoked(object sender, ExternalDataEventArgs e)
{
     isSiteNameProvided();
}

private void isSiteNameProvided()
{
     if(!string.IsNullOrEmpty(workflowProperties.Item["SiteName"] as string))
     {
          done=true;
     }
}

Double click on the onWorkflowActivated1 shape to generate the onWorkflowActivated1_Invoked method. Replace the auto-generated method with the following code snippet.

private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
{
     isSiteNameProvided();
}

From the workflow designer surface click on the onWorkflowItemChanged1 red exclamation and choose the activity 'onWorkflowItemChanged1' does not have a Correlation Token property set option




Note: A Correlation Token is just an unique identifier for the workflow, it's used to keep all of the individual workflow activities together. 

From the properties window select the CorrelationToken property dropdown: workflowToken.

Back to the design surface and choose the codeActivity1 red exclamation, select the property 'ExecuteCode' is not set. Double click the codeActivity1 shape to generate the ExecuteCode method

Add Exception Handling to the Workflow

Next I'll add some error handling so if an exception occurs we'll write the text of the exception to the History List and set the column status to error logged and allow the workflow to exit and complete.

Next ensure the toolbox is open and the Windows Workflow V3 node is expanded. Drag and drop a FaultHandler activity onto the Drop FaultHandlerActivity Here text. 



In the Workflow Exceptions window select the faultHandlerActivity1 red exclamation, choose the Property 'FaultType' is not set or its value cannot be resolved to an actual type option. 



In the properties window select the FaultType property ellipses, in the Browse and Select a .NET type window Select Referenced Assemblies | mscorlib on the Type tab. Select the System type, locate Exception in the type name column (scroll the right pane down) Select the Exception type name (System.Exception) and select OK.



In the Visual Studio Toolbox expand the Sharepoint Workflow node, Drag and drop a LogToHistoryListActivity activity into the Drop Activities Here text. Drag and drop a SetState activity on the line below the logToHistoryListActivity1 shape

Next I'll configure the Log to History List Activity to write the exception details to the Workflow History List and the Set State Activity to end the Workflow with a custom status called Error Logged. 

On the InfoPathWorkflow design surface right click the logToHistoryListActivity1 shape and select the properties option. Select the HistoryDescription property and click the ellipsis. 

In the Bind History Description dialog expand faultHandlersActivity1 | faultHandlerActivity1 | Fault | Message and select OK


In the properties window select the HistoryOutcome property and click the ellipsis. In the bind History Outcome to an activity dialog expand faultHandlersActivity1 | faultHandlerActivity1 | Fault - Select the StackTrace option and select OK


In the Visual Studio Solution Explorer double click the elements.xml file

Replace the metadata node and its contents with the following code 

<MetaData>
  <ExtendedStatusColumnValues>
         <StatusColumnValue>Error Logged</StatusColumnValue>
  </ExtendedStatusColumnValues>
</MetaData>


Back to the design surface for the Infopath workflow, double click the setState1 Activity, replace the setState1_MethodInvoking with the following code

private void setState1_MethodInvoking(object sender, EventArgs e)
        {
            setState1.State = (int)SPWorkflowStatus.Max;
        }


This code will set the workflow state to the custom StatusColumnValue defined in the elements.xml file


Back to the workflow design surface, select the red exclamation next to setState1 activity



Choose the Activity setState1 does not have CorrelationToken property set, select the correlationtoken property dropdow: workflowToken

Now when an exception occurs it will be handled and logged as shown below



Create a New Site Collection and Add Quicklaunch Link to Site

The next part of this tutorial will involve programmatically creating a new site collection if the site name condition is met on the list we are attaching this custom workflow to. 

Right click on the InfoPath workflow design surface and select view code. In the top area of the InfoPathWorkflow.cs file add the following import directive

using Microsoft.SharePoint.Navigation;

Next replace the method codeActivity1_ExecuteCode with the following code.

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            //Get the Site Name
            string SiteName =
              workflowProperties.Item[SITE_NAME_COLUMN].ToString();
         
            // Get the system token, instantiate new site and web objects
            // in order to have permissions to create the new Site Collection 

            SPUserToken _sysToken = default(SPUserToken);
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(workflowProperties.Site.Url))
                {
                    _sysToken = site.SystemAccount.UserToken;
                }
            });

            using (SPSite siteCollection = new SPSite(workflowProperties.Site.Url, _sysToken))
            {
                using (SPWeb web = siteCollection.OpenWeb(workflowProperties.Web.ServerRelativeUrl))
                {
                    //Gather user information
                    SPUser user = web.SiteAdministrators[0];
                    string adminLogin = getLoginName(user);
                    string adminEmail = user.Email;
                    string adminDisplayName = user.Name;

                    SPSite newSiteCollection = default(SPSite);

                    Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(
                      () =>
                      {
                         //Set the new site collection properties
                          newSiteCollection =
                            web.Site.WebApplication.Sites.Add(
                            "/sites/" + SiteName,  // Url
                            SiteName,
                            "Site Created by Submitting InfoPath Form",
                            1033,  // locale identifier - US English
                            "SGS#0",  // Basic Group Work Site Template
                            adminLogin,
                            adminDisplayName,
                            adminEmail);
                      });

                    if (default(SPSite) != newSiteCollection)
                    {
                        // Add Site Collection Administrators
                        addSiteCollectionAdministrators(web.SiteAdministrators,
                          newSiteCollection.RootWeb.SiteAdministrators);

                        string newSiteCollectionUrl =
                          newSiteCollection.MakeFullUrl(newSiteCollection.ServerRelativeUrl);

                        // Add Site collection link to Quick Launch
                        SPNavigationNode projectSiteNode =
                          new SPNavigationNode(SiteName, newSiteCollectionUrl, true);

                        // Create or retrieve the Site Collections node
                        SPNavigationNode siteCollectionsNode =
                          ensureHeadingNode("Site Collections", web.Navigation.QuickLaunch);
                      
                        siteCollectionsNode.Children.AddAsLast(projectSiteNode);
                    }
                }
            }
        }
      
        //Extract a readable username
        private string getLoginName(SPUser user)
        {
            string loginName = default(string);

            int pipePosition = user.LoginName.IndexOf("|");

            if (0 >= pipePosition)
            {
                loginName = user.LoginName.Substring(pipePosition + 1);
            }
            else
            {
                loginName = user.LoginName;
            }

            return loginName;
        }

        // Add the Site Collection Administrators from
        // the current Site Collection to the new Site Collection

        private static void addSiteCollectionAdministrators(
          SPUserCollection existingSiteAdmins, SPUserCollection newSiteAdmins)
        {
            // Add the Workflow's Site Collection Administrators
            // to the new Site Collection
            foreach (SPUser admin in existingSiteAdmins)
            {
                newSiteAdmins.Add(
                  admin.LoginName, admin.Email, admin.Name, admin.Notes);
            }
        }

        // Add a custom SPQuickLaunchHeading NavNode
        // if it doesn't already exist
        private static SPNavigationNode ensureHeadingNode(
          string nodeHeading, SPNavigationNodeCollection quickLaunch)
        {
            // Get the first NavNode in the Web's Quick Launch
            SPNavigationNode projectSitesNode = quickLaunch[0];

            if (nodeHeading != projectSitesNode.Title)
            {
                // Quick Launch Heading NavNode called nodeHeading
                // linked to the Web's Home Page (empty string)
                projectSitesNode =
                  new SPNavigationNode(nodeHeading, string.Empty);
                quickLaunch.AddAsFirst(projectSitesNode);
            }
            return projectSitesNode;
        }

Deploy and Test



The last part of this tutorial will involve deploying the Visual Studio Solution and testing.
From Visual Studio right click on the project name and select Deploy, ensure there are no errors in the build and wait for the process to complete.


Next, well visit the site that we deployed the workflow to, in my case it is at  http://w2k8r2_2010dev/sites/apps/

Select the list that we created in step 1 - Issues


From the Ribbon select the List tab and Click the Workflow Settings dropdown | Add Workflow

Select the InfoPath Workflow from the available Workflows, enter a name for the workflow and select the Start this workflow when a new item is created checkbox


From the Issues List create a new item

Note: If your URL has an underscore (_) in it you will receive the following message: The form cannot be displayed in the browser because the use of session cookies has been disabled in the current browser settings


In my case and can simply change the machine name in the URL with Localhost after adding an alternate access mapping and everything works.


Next Add the new item - MyIssue, I'll intentionally leave the SiteName field blank to demonstrate the workflow functionality




Immediately after we submit the new item the status will change to Starting




Then the workflow status will quickly change to In Progress


The workflow status will remain at In Progress until we edit the item we submitted and add a SiteName

Note: If a SiteName is added initially the workflow will complete quickly on its own

Next I'll edit the entry and add the SiteName (MyIssues Site) and in a minute or two I will see the Quicklaunch area under Site Collections will be updated with the new SiteName. If this is the first entry then the Site Collections heading will be added and a link to the new site will be listed below.


This completes this tutorial. If you would like to download the Visual Studio Solution Click Here