Tuesday, January 06, 2009
Well, that's me well and truly back from my holidays, a nice relaxing couple of weeks spent at home with my family.
As a kind of New Years present, Microsoft has released a free learning initiative for those of you that are or will be using Visual Studio 2008. I am taking it myself as a way to make sure that I have not missed anything :)
Sign Up for the MSDN Ramp Up Program's Visual Studio 2008 Track
Monday, December 15, 2008
Up until now the only avenue for your average Vista user for support was to trawl the MSDN Forums, Technet Forums and the Support site for some elusive piece of information that is buried among all that technical BS that we teckies like to call help.
All that has now changed with the addition of the Answers forum!
This will be a no nonsense, non technical forum for real users to get real answers. The forum will follow the format that he user sees in the control panel of Vista so here are the topics:
Windows Vista Forums
Tap into the expertise and enthusiasm of Windows Vista customers and Microsoft support professionals.
Windows Update
Automatically keep software up-to-date
Hardware and Drivers
Add hardware, update drivers
Wireless, Internet, and Networking
Connect to a network
Security and Privacy
Adjust settings, manage user accounts
Improve Peformance
Run Windows Vista better, faster
Install, Upgrade, and Activate
Troubleshoot Windows Vista installation
Sound and Media
Work with music, pictures, video
Programs
Internet Explorer, Windows Mail & others
Gaming
Install, troubleshoot, set parental controls
Appearance and Personalization
Add gadgets, adjust screen resolution
Now, for those Blue badge holders and us MVP’s that have been asked to moderate there are strict rules around making sure that both the Questions and the Answers are non threatening and non technical.
These forums are specifically targeted at Vista, but if they are successful, there may be more forums added in the future. Maybe for things like Sharepoint and Office, and it may include many other products (deliberately vague).
Lets get Answering…but remember, no techno-babble!
If only I could be as eloquent as Scott. His recent post on “Does test-driven development speed up development?” really gets to the crux of an endemic problem in the Software Development industry, especially in companies for whom Software Development is not their core business.

Test-driven development decreases complexity, improves the incremental adaptability that software product development depends on, astronomically reduces the amount of rework that destabilizes schedules, and reduces the unrecognized design flaws that decrease productivity after the initial implementation phase.
…
Test-driven development supports flow. The software development industry at large is years away from recognizing that flow rather than efficiency is what creates giant leaps in productivity. Nonetheless, it works, and it's supported by the production physics used by industries that are well ahead of software development in product development and production maturity and optimization.
…
Scott Bellware on Does test-driven development speed up development?
This is a must read for any Software Professional… unless you are already using TDD :)
After making sending a “Call to Action” to my fellow Team System MVP’s I have added two managers to the VSTS Developers group I started on LinkedIn.
Thanks guys for giving up a little bit of your valuable time….
Hopefully, this will give members more information and a faster response time to requests…
Wednesday, December 10, 2008
With many people skipping off early for their holly bags, me included.. I thought I should send this out now…
Merry Christmas from the Hinshelwood family.
If you are having problems accessing or see a blank box, try (http://aka.zero.jibjab.com/client/zero/ClientZero_EmbedViewer.swf?external_make_id=cgijAPrn4DOVeeOU&service=sendables.jibjab.com&partnerID=ElfYourself). It is most likely a proxy problem…
If, like me, you tried to deploy a solution to Microsoft Office SharePoint Server 2007 and it ether failed or hung you will need to remove it somehow. But once the status has moved to “deploying”, if you receive an error like this:
Error: The web.config is invalid on this IIS Web Site: C:\Inetpub\wwwroot\wss\VirtualDirectories\search.xxx.xxx.biz80\web.config.
You will need to manually remove the job.
To do this, go to the Central Administration portal and under the “Global Configuration” section on the “Operations” tab select “Job Timer definitions”
This will take you to a massive list of all the scheduled and on demand jobs. Check down the list to find the job you want to kill, the Deployment operations will have “one-time” in the last column.

Click the title to bring up the job definition and status and you should have the kill switch readily available
Once killed you can check the deployments page and you will see that there is nothing trying to “deploy”.
Thursday, December 04, 2008
I have been getting very interested in the new Azure Services Platform and how I can use it to facilitate WPF development.
Imagine being able to launch a ClickOnce application from anywhere and for it to have exactly the same configuration and settings in all locations, or imagine being able to chat with other users of the application while you are using it.
This things have been relegated to large companies who can afford to support the infrastructure that you would need to run this. In fact, the only industry that I can think of that currently does this with applications is the Gaming industry. If you look at the capabilities of Xbox Live and think of all the cool things your users could achieve if the same communication and collaboration tools were available within even the simplest application.
For example, if I was to think of a couple of simple things that I would like the TFS Sticky Buddy to be able to do:
- Central storage for configuration (single setup across multiple computers)
- Chat with members of your team to be identified by linking your Team System login and email with you Live ID.
- Presence information on those team members, or anyone you might need to interact with.
Coool…..

Some of the new Windows Live Wave 3 services have gone live over the last couple of days. One of the best IMO is the SkyDrive services, updated to 25GB and with complete integration with other services like Photo Share, Connect to people…
You can connect to your Facebook and LinkedIn contacts as well :)
A nice feature is the ability to link your live accounts so you can easily switch from your clever [yourname]@[yourdomain].com to your nasty [yourname]@live.com address.
As you can see from the menu structure, all of your services are all in one place, although some of those other services, OneCare for example, have not yet been updated as you can’t get back into the same bits… I am sure it will come…
The SkyDrive service has had a major overall and has a nice new home page as well as the integration with Live Photo and a whopping 25gb of space…
Here is a comprehensive list of all Windows Live services currently available with the exception of the fantastic Live Mesh which is still in beta.
Windows Live
-
Home
Get a quick view of your world—e-mail, invitations, and what’s new with your network.
-
Profile
Share your world online–your activities, your photos, and the people you know.
-
People
Manage your contacts from Hotmail, Messenger, and Profile, all in one place.
-
Mail
Get fast, easy, reliable e-mail from Hotmail, with more spam protection and plenty of storage.
-
Photos
Post your favourite shots online in beautiful slideshows that only the people you choose can see.
-
Calendar
Check your schedule, share calendars with others, and get reminders when you need them.
-
Events
Plan your next event with customized invitations, a guest list, RSVPs, and a place to share online.
-
SkyDrive
Store the files you need online and share them with the people you choose.
-
Groups
Bring your team, club, or other group together with a webpage, calendar, and more.
-
Spaces
Express yourself with your own customized webpage—add a blog, photos, videos, and more.
-
Family Safety
Help protect your kids online, with customizable web filters and contact management.
-
Mobile
Stay in sync from the road, with Windows Live on your web-enabled mobile device.
-
Downloads
Download Windows Live Essentials—free programs for your PC, including Messenger, Mail, Photo Gallery, Movie Maker, Writer, Toolbar, and Family Safety.
-
Office Live
Store and share your business documents online—it’s quick, easy, and free.
Tuesday, December 02, 2008
Updated and improved for Team System 2008.
http://www.codeplex.com/TFSEventHandler
The TFS Event Handler makes it easier to notify users of changes to Work Items in Team Foundation Server. You will no longer need to add individual alerts to users.
It is developed in .NET 3.5 SP1 for Team Foundation Server 2008 and is deployed as a system service.
I have added support for groups. If you add a TFS group into the Assigned To drop down all members of that group will receive notifications!
You will need to allow groups in your Assigned to list. Below is a snippet from me Bug work item type as it stands at the moment.
1: <FIELD reportable="dimension" type="String" name="Assigned To" refname="System.AssignedTo">
2: <HELPTEXT>The person assigned to act on the bug, either to fix it or to verify the fix</HELPTEXT>
3: <ALLOWEXISTINGVALUE />
4: <ALLOWEDVALUES filteritems="excludegroups">
5: <LISTITEM value="[project]\Contributors" />
6: </ALLOWEDVALUES>
7: </FIELD>
You can see on line 4 that there is a filter for excluding the groups from the list. If you are using TFS Event Handler v1.0 or v1.1 then you will need this line. If you install the new TFS Event Handler v1.3 then you will be able to remove that and start assigning work items to Groups.
Note: Although they will now get an email, the work item will not appear in their “My Work items” query. You may want to consider creating a Query for each Group.
The Alerts that you no longer need users to individually setup are:
- A work item is assigned to you, or a group you are a member of.
- A work item that is assigned to you, or a group you are a member of is, reassigned to someone else.
- A work item that you created is assigned to someone else, or a group.
There is also a framework for creating and deploying your own event handlers that can do pretty much whatever you want. One of the shipped examples updates “Heat ITSM” whenever a work item that contains a Heat Id is changed.
Monday, December 01, 2008
This is a lot harder than it sounds. At first you think there will be a built in option with the Read Identities method on the IGroupSecurityService Interface, but you would be wrong!
When capturing an event from Team Foundation Server you have access to a lot of information about the change, including the Display Name of the fields for Assigned To and Changed By.
But what if you allow Work Items to be assigned to groups! First, lets achieve that. Create a group called “Program Management” on a project and add it into the “Contributors” list. We have a group for each of the advocacy groups in the CMMI process.
Edit your “Task” work item definition (you can use the power tools process editor or just edit the XML) and alter the Assigned To field to be the following:
1: <FIELD reportable="dimension" type="String" name="Assigned To" rename="System.AssignedTo">
2: <ALLOWEXISTINGVALUE />
3: <ALLOWEDVALUES>
4: <LISTITEM value="[project]\Contributors" />
5: </ALLOWEDVALUES>
6: </FIELD>
Once you have updated your project you should be able to see all of the users as well as this new group displayed. If you were to assign a task to this group, how would you email everyone in that group so that they know they have been assigned something at all?
Well this needs a wee tweak of the TFS Event Handler to handle this, I will be releasing the full in place code with the TFS Event Handler v1.3 drop, but you can download my little test app I used to get it all working.
[Download Project]
You can enter a display name of either a user or a group. And here is how it is done:
There is a little but of Active Directory lookup using a little method called GetUsername
1: '' <summary>
2: '' Retrieves a user's email address from Active Directory based on their display name
3: '' </summary>
4: Public Shared Function GetUsername(ByVal userDisplayName As String) As String
5: Dim ds As DirectoryServices.DirectorySearcher = New DirectoryServices.DirectorySearcher()
6: ds.PropertiesToLoad.Add("sAMAccountName")
7: ds.Filter = String.Format("(&(displayName={0})(objectCategory=person)((objectClass=user)))", userDisplayName)
8:
9: Dim results As DirectoryServices.SearchResultCollection = ds.FindAll()
10: If results.Count = 0 Then
11: Return String.Empty
12: End If
13: Dim values As DirectoryServices.ResultPropertyValueCollection = results(0).Properties("sAMAccountName")
14: If values.Count = 0 Then
15: Return String.Empty
16: End If
17: Return values(0).ToString()
18: End Function
This retrieves the users sAMAccountName (or username) from Active Directory. Easy enough, and I already had it kicking about…
But in order to retrieve an identity that you are not sure is a group or a user, you will need to try to get the Group Identity first. This is because it is faster to wade through a maximum of 20 groups than potentially hundreds of users mentioned on the MSDN Forum answer below.
1: Try
2: '----------------------------------------
3: Dim svr As New TeamFoundationServer(Me.uxTeamServer.Text)
4: Dim GroupSecurityService As IGroupSecurityService = CType(svr.GetService(GetType(IGroupSecurityService)), IGroupSecurityService)
5: '----------------------------------------
6: Dim CommonStructureService As ICommonStructureService = CType(svr.GetService(GetType(ICommonStructureService)), ICommonStructureService)
7: '----------------------------------------
8: ' Return App Group if you can
9: Dim pi As ProjectInfo = m_CommonStructureService.GetProjectFromName(Me.uxProject.Text)
10: Dim appGroup As Identity = (From i In m_GroupSecurityService.ListApplicationGroups(pi.Uri) Where i.DisplayName = Me.uxDisplayName.Text).SingleOrDefault
11: If Not appGroup Is Nothing Then
12: appGroup = m_GroupSecurityService.ReadIdentity(SearchFactor.Sid, appGroup.Sid, QueryMembership.Expanded)
13: WriteToLog(String.Format("Recieved identity for {0}", Me.uxDisplayName.Text))
14: WriteIdentity(appGroup)
15: Exit Try
16: End If
17: ' Not app group. Then return user is you can
18: Dim username As String = GetUsername(Me.uxDisplayName.Text)
19: Dim usrIdent As Identity = m_GroupSecurityService.ReadIdentity(SearchFactor.AccountName, username, QueryMembership.Expanded)
20: If Not usrIdent Is Nothing Then
21: WriteToLog(String.Format("Recieved identity for {0}", username))
22: WriteIdentity(usrIdent)
23: Exit Try
24: End If
25: '----------------------------------------
26: WriteToLog(String.Format("identity for {0} not found", Me.uxDisplayName.Text))
27:
28: '----------------------------------------
29: Catch ex As Exception
30: Me.uxResults.Items.Add(ex.ToString)
31: End Try
There is a lot going on here, but the first thing you need to do is retrieve the TFS objects that we will need to work with which include a TeamFoundationServer instance as well as an IGroupSecurityService and ICommonStructureService. You could use the WorkItemStore instead of the ICommonStructureService, but the WorkItemStore has a heavy performance hit for retrieving an instance.
1: Dim svr As New TeamFoundationServer(Me.uxTeamServer.Text)
2: Dim GroupSecurityService As IGroupSecurityService = CType(svr.GetService(GetType(IGroupSecurityService)), IGroupSecurityService)
3: Dim CommonStructureService As ICommonStructureService = CType(svr.GetService(GetType(ICommonStructureService)), ICommonStructureService)
Next we need to try and retrieve the Identity of the group, if it is one. The ICommonStructureService has a method for listing all of the Groups available within a project, but for that you need the project name which in the demo is just entered.
1: ' Return App Group if you can
2: Dim pi As ProjectInfo = m_CommonStructureService.GetProjectFromName(Me.uxProject.Text)
3: Dim appGroup As Identity = (From i In m_GroupSecurityService.ListApplicationGroups(pi.Uri) Where i.DisplayName = Me.uxDisplayName.Text).SingleOrDefault
4: If Not appGroup Is Nothing Then
5: appGroup = m_GroupSecurityService.ReadIdentity(SearchFactor.Sid, appGroup.Sid, QueryMembership.Expanded)
6: WriteToLog(String.Format("Recieved identity for {0}", Me.uxDisplayName.Text))
7: WriteIdentity(appGroup)
8: Exit Try
9: End If
What this does is use the project name entered (in the event it is under the element ProtfolioProject (yea, I don’t know why it is called that either) to search a list of Group’s within your project for the one of interest.
Then, as it does not by default load the “Members” and “MemberOf” arrays you need to call ReadIdentity with the Expand option is you want to list the Members, and I do.
If this does not return an identity, then we need to look at the display name being a user account.
1: ' Not app group. Then return user is you can
2: Dim username As String = GetUsername(Me.uxDisplayName.Text)
3: Dim usrIdent As Identity = m_GroupSecurityService.ReadIdentity(SearchFactor.AccountName, username, QueryMembership.Expanded)
4: If Not usrIdent Is Nothing Then
5: WriteToLog(String.Format("Recieved identity for {0}", username))
6: WriteIdentity(usrIdent)
7: Exit Try
8: End If
Actually quite easy, but it could be easier.
Example WorkItemChangedEvent:
1: <?xml version="1.0" encoding="utf-8"?>
2: <WorkItemChangedEvent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3: <PortfolioProject>TFS Sticky Buddy</PortfolioProject>
4: <ProjectNodeId>614c944e-7799-46a2-a519-30e68eea040b</ProjectNodeId>
5: <AreaPath>\TFS Sticky Buddy</AreaPath>
6: <Title>TFS Sticky Buddy Work Item Changed: Requirement 1267 - Visual Enhancement</Title>
7: <WorkItemTitle>Mobility Continental Exceptions Report</WorkItemTitle>
8: <Subscriber>HINSHDOM\svc_tfsservices</Subscriber>
9: <ChangerSid>S-1-5-21-1390067357-651377827-682003330-21716</ChangerSid>
10: <DisplayUrl>http://tfs01.hinshelwood.com:8080/workitemtracking/workitem.aspx?artifactmoniker=1267</DisplayUrl>
11: <TimeZone>GMT Standard Time</TimeZone>
12: <TimeZoneOffset>00:00:00</TimeZoneOffset>
13: <ChangeType>Change</ChangeType>
14: <CoreFields>
15: <IntegerFields>
16: <Field>
17: <Name>ID</Name>
18: <ReferenceName>System.Id</ReferenceName>
19: <OldValue>1267</OldValue>
20: <NewValue>1267</NewValue>
21: </Field>
22: <Field>
23: <Name>Rev</Name>
24: <ReferenceName>System.Rev</ReferenceName>
25: <OldValue>4</OldValue>
26: <NewValue>5</NewValue>
27: </Field>
28: <Field>
29: <Name>AreaID</Name