Friday, November 19, 2010

Sharepoint 2010 Foundation - Create nested folders from workflows

Problem: Create a nested folder structure in response to an event without writing code in Sharepoint 2010 Foundation.

Why: We have a need for this functionality on a hosted Sharepoint site where we don't have the ability to write custom code other than what can be done in Sharepoint Designer.

Research Approach:
1 - Look through Sharepoint Doc
Nothing useful found
2 - Google it!
Very little useful found
3 - Beat head against wall until a solution manifests
YEAH!

Solution: Interrelated Workflows.

The user would like to track a set of "projects." A project is a collection of status' as well as documents in a nested folder structure. I decided to create several sharepoint artifacts to represent the structure.

1 - "Project Details" list which holds the Project and associated fields/columns.

2 - "Projects" Document Library which holds Project Folders, Project Sub Folders and Project Document

3 - "Project Folder"
This is a Folder object with additional columns and holds objects associated with the project

4 - "Project Sub Folder"
This is derived from Project Folder and is used to nest structure in a Project Folder

5 - "Project Document"
This is a Document object with extra, project specific columns

There are also several list workflows:
1 - Update Project Manager Name - Project Details List
Copies a lookup field's contents to a text field so it can be carried along with a site column

2 - Create Project Folder - Project Details List
Creates a Project Folder in the Projects Document Library when an item is created in the Project Details list.

3 - Update Project Folder Status - Projects List (Document Library)
Updates the status of the Project Folder so that the Create Project Sub Folders workflow knows to run

4 - Create Project Sub Folders - Projects List (Document Library)
Creates the Sub Folders for a new projects.

There were several problems that needed to be solved. The main one is how do I create objects in a new, arbitrary list?

My first approach was to attempt to create a workflow that fired when an item was added to the Project Details list that created the items in another list. This worked fine to create the folder in the Projects list, but I couldn't go any farther because creating objects in an arbitrary list isn't straight-forward.

I created another workflow that ran when a Project Folder was created to create a folder in the "current" list which worked to create a sibling of the new Project Folder, but not a child. BUT, after a lot of experimentation, I determined that I could create a sibling of the current item but code the name as follows: [%CurrentItem%]/NewFolderName
This worked to create a child of the current folder! After I got this working, I was able to run the workflow manually and life was good. However, as soon as I changed the workflow to run automatically at the creation of a Project Folder, Sharepoint Designer would no longer let me save the workflow. It complained about errors in the create-list-item operations. I was able to get around it by setting the workflow to fire on changing a Project Folder rather than creating it. Surprisingly, that worked.

Now my problem was: how to fire the workflow at object creation. I decided to create a status field on the Project Folder and have a workflow that fires at Project Folder create time to change the status so that the Project Sub Folder creation workflow would run. So, I created a "SubFolders" column in the Project Folder. When the first workflow creates the Project Folder, it sets this value to Waiting. The workflow that runs at Project Folder create time changes this value to Creating which triggers the Create Project Sub Folders workflow. This workflow creates the Sub Folders and then changes the SubFolders column to Created.

That's it!

I'll give some more details on the objects, workflows, and interactions soon.

Thursday, October 1, 2009

OpenVPN, Snow Leopard, and 64-bit

Since my MAC adventure began early this year, I discovered through a friend (thanks Jon) a tool called TunnelBlick which is a nice little GUI that sits on top of OpenVPN which is what one of my clients uses as their VPN. Anyhow, Snow Leopard's 64-bit kernel doesn't play nicely with TunnelBlick unless you also download the latest Tun/Tap driver which is available here:

http://tuntaposx.sourceforge.net/download.xhtml

I downloaded and installed it and TunnelBlick is back running like a champ.

This also brings up a point that by default Snow Leopard does NOT start using the 64-bit kernel extensions. You can force it by holding down the 6 and 4 keys during boot, or download this cute little tool which lets you select your startup mode and forget it. You can still override it by holding down the 3 and 2 keys or 6 and 4 keys during boot.

http://www.ahatfullofsky.comuv.com/English/Programs/SMS/SMS.html

Have fun all.

Monday, September 21, 2009

MacBook Pro upgrades

I purchased a 15" 2.53 GHz Unibody MacBook Pro with a 320GB drive and 4GB of RAM back in January of 2009 and recently upgraded the drive to a 7200RPM 500GB Seagate Momentus. The process was much more disruptive than I had expected it would be and took me about 2 days. My next few posts will document the adventure.

Thursday, June 12, 2008

WMI Association Classes

I've been trying for most of the day to determine how to create a WMI Association class using C#. Here's the ONLY reference I found, sheesh!

http://msdn.microsoft.com/en-us/library/system.management.instrumentation.managementreferenceattribute.aspx

This example demonstrates how to use the ManagementReferenceAttribute attribute together with the ManagementQualifierAttribute to create an association WMI class that links two other WMI classes. The example is a decoupled provider that exposes three WMI classes in the root/assoc namespace. The first two classes, NumberPhonetic and NumberLetter, are linked by the last class, LetterPhonetic.
To compile the example, you will need to include references to both System.Management.Instrumentation and System.Configuration.Install. You must run installutil.exe against the resulting executable and ensure that the program is running in order to use the implemented WMI classes.
Copy Codeusing System;
using System.Collections;
using System.Management.Instrumentation;
[assembly: WmiConfiguration("root/assoc", HostingModel = ManagementHostingModel.Decoupled)]
[System.ComponentModel.RunInstaller(true)]
public class TheInstaller : DefaultManagementInstaller
{ }
namespace AssocExample
{
class Program
{
static void Main(string[] args)
{
InstrumentationManager.RegisterType(typeof(NumberPhonetic));
InstrumentationManager.RegisterType(typeof(NumberLetter));
InstrumentationManager.RegisterType(typeof(LetterPhonetic));
Console.WriteLine("Press enter to exit");
Console.ReadLine();
InstrumentationManager.UnregisterType(typeof(NumberPhonetic));
InstrumentationManager.UnregisterType(typeof(NumberLetter));
InstrumentationManager.UnregisterType(typeof(LetterPhonetic));

}
}
[ManagementEntity]
public class NumberPhonetic
{
[ManagementKey]
public int Number;
[ManagementProbe]
public string Name;
[ManagementBind]
public NumberPhonetic(int Number)
{
this.Number = Number;
if(Number == 1)
{
Name = "alpha";
}
else if(Number == 2)
{
Name = "bravo";
}
else
{
throw new InstanceNotFoundException();
}
}
[ManagementEnumerator]
static public IEnumerable EnumerateInstances()
{
for (int i = 1; i < 3; i++)
{
yield return new NumberPhonetic(i);
}
}

}
[ManagementEntity]
public class NumberLetter
{
[ManagementKey]
public int Number;
[ManagementProbe]
public string Letter;
[ManagementBind]
public NumberLetter(int Number)
{
this.Number = Number;
if(Number == 1)
{
Letter = "A";
}
else if(Number == 2)
{
Letter = "B";
}
else
{
throw new InstanceNotFoundException();
}
}
[ManagementEnumerator]
static public IEnumerable EnumerateInstances()
{
for (int i = 1; i < 3; i++)
{
yield return new NumberLetter(i);
}
}
}
[ManagementEntity]
[ManagementQualifier("Association", Flavor = ManagementQualifierFlavors.DisableOverride)]
public class LetterPhonetic
{
[ManagementReference(Type = "NumberLetter")]
[ManagementKey]
public string LetterNumber;
[ManagementReference(Type = "NumberPhonetic")]
[ManagementKey]
public string PhoneticNumber;
[ManagementEnumerator]
static public IEnumerable EnumerateInstances()
{
ArrayList insts = new ArrayList();
for (int i = 1; i < 3; i++)
{
LetterPhonetic inst = new LetterPhonetic();
inst.LetterNumber = "Letter = " + i;
inst.PhoneticNumber = "Phonetic = " + i;
insts.Add(inst);
}
return insts;
}
}
}

Wednesday, April 9, 2008

Windows Computer Management Services SnapIn

I can't believe that I need to write my own MMC Snap-In to simply filter out certain services that the standard Services SnapIn displays. Why should I have to duplicate all of that existing functionality? It would be nice to be able to inherit that whole SnapIn and override the WMI query that it uses to retrieve the list of services.

If anybody knows another way to do this please comment.

Monday, April 7, 2008

Learning to Juggle 5

I've been trying to learn to juggle 5 balls for several months now. I only practice Thursday nights for a few hours at our (TurksHeadJugglers) club meetings, so it is definitely my fault that I'm not progressing faster then I should.

I'm finding that using tetrahedral felt bags filled with shot seems easier then my Dube balls.

I've gotten to the point where I can flash 5 fairly consistently, 6 once in a while, and 7 once in a GREAT while.

My biggest issue is accuracy. I juggle facing a wall and with a large pile of gym mats in front of me so I don't have to bend over to the floor every 15 seconds or so to pick up the bags. When I'm tossing 3 or 4, my accuracy isn't bad, but as I throw higher and faster, it goes to pot. Tosses from my Right hand inevitably go forward, so if the wall wasn't there, I'd be walking forward, and tosses from my left go much higher then they're supposed to. Every so often I just back down to 1 or 2 balls to improve my aim. It is going much slower then I'd hoped though.

Friday, April 4, 2008

First Entry

Ok, so I blog therefore, I am, right?

I'm putting this up so that I can save my random thoughts and ramblings on things I'm interested in which includes juggling, motorcycles, origami, flying and software development. Everything that appears here will be my thoughts and feelings only unless attributed to someone else.

Enjoy reading.