<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Adam Singer : Coding Practices</title><link>http://blogs.msdn.com/adamsinger/archive/tags/Coding+Practices/default.aspx</link><description>Tags: Coding Practices</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Ventriloquism: TFS Style</title><link>http://blogs.msdn.com/adamsinger/archive/2008/07/28/ventriloquism-tfs-style.aspx</link><pubDate>Mon, 28 Jul 2008 18:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8784613</guid><dc:creator>Adam Singer</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/adamsinger/comments/8784613.aspx</comments><wfw:commentRss>http://blogs.msdn.com/adamsinger/commentrss.aspx?PostID=8784613</wfw:commentRss><wfw:comment>http://blogs.msdn.com/adamsinger/rsscomments.aspx?PostID=8784613</wfw:comment><description>&lt;P&gt;Quite a long time back, Buck posted about how to recover from the situation where one TFS machine is created as a clone from another. This can lead to clients still showing the project list for one server when the connect to the second. Based on a recent &lt;a href="http://forums.microsoft.com/MSDN/default.aspx?ForumGroupID=5&amp;SiteID=1"&gt;Visual Studio Team System forums&lt;/a&gt; question (they certainly seem to be inspirational to me these days), I decided to code up a very simple tool that connects to one or more TFS instances and spits out their GUIDs so you can check whether they were cloned from each other. The actual interesting block of code is as follows:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&lt;FONT color=#2b91af&gt;TeamFoundationServer&lt;/FONT&gt; tfs = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#2b91af&gt;TeamFoundationServer&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;(arg);&lt;BR&gt;&lt;FONT color=#2b91af&gt;Console&lt;/FONT&gt;.WriteLine(&lt;FONT color=#a31515&gt;"The GUID for server '{0}' is:{1} {2}"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; arg, &lt;FONT color=#2b91af&gt;Environment&lt;/FONT&gt;.NewLine, tfs.InstanceId);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;As you can see, there isn't much to finding out the GUID of a server. I've attached the project in case you want to play around with it yourself. Nothing fancy- I even attempted to manually hack it back to a Visual Studio 2008 capable csproj file since I'm using a recent internal version of the next release. Enjoy!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8784613" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/adamsinger/attachment/8784613.ashx" length="3568" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Team+Foundation+General/default.aspx">Team Foundation General</category><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Team+Foundation+Setup+Admin+_2600_amp_3B00_+Ops/default.aspx">Team Foundation Setup Admin &amp;amp; Ops</category><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Coding+Practices/default.aspx">Coding Practices</category></item><item><title>Random Acts of Group-ness</title><link>http://blogs.msdn.com/adamsinger/archive/2007/02/28/random-acts-of-group-ness.aspx</link><pubDate>Wed, 28 Feb 2007 22:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1775203</guid><dc:creator>Adam Singer</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/adamsinger/comments/1775203.aspx</comments><wfw:commentRss>http://blogs.msdn.com/adamsinger/commentrss.aspx?PostID=1775203</wfw:commentRss><wfw:comment>http://blogs.msdn.com/adamsinger/rsscomments.aspx?PostID=1775203</wfw:comment><description>&lt;P&gt;Following up from my last post "&lt;A class="" href="http://blogs.msdn.com/adamsinger/archive/2007/02/09/grep-ing-groups.aspx" mce_href="http://blogs.msdn.com/adamsinger/archive/2007/02/09/grep-ing-groups.aspx"&gt;'Grep'ing Groups&lt;/A&gt;"&amp;nbsp;and &lt;A class="" href="http://forums.microsoft.com/MSDN/showpost.aspx?postid=1284508&amp;amp;siteid=1" mce_href="http://forums.microsoft.com/MSDN/showpost.aspx?postid=1284508&amp;amp;siteid=1"&gt;this&lt;/A&gt; question on the forums, here's a bit of code that will help you add a user to multiple groups across all projects on your server. Say you want to add someone with the&amp;nbsp;domain account&amp;nbsp;"CORPNET\JoeBlogs"&amp;nbsp;to the "Readers" group for all your projects on your Team Foundation Server "atlantis". Simply download, build, and&amp;nbsp;run the attached code with the arguments&amp;nbsp;"atlantis CORPNET\JoeBlogs&amp;nbsp;Readers" as a Team Foundation Adminstrator.&lt;/P&gt;
&lt;P&gt;A few of the more salient points in the code are as follows:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&lt;FONT color=#009999&gt;NTAccount&lt;/FONT&gt; userAccount = &lt;FONT color=#3333ff&gt;new&lt;/FONT&gt; &lt;FONT color=#009999&gt;NTAccount&lt;/FONT&gt;(username);&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;...&lt;BR&gt;&lt;FONT color=#009999&gt;SecurityIdentifier&lt;/FONT&gt; userSid = (&lt;FONT color=#009999&gt;SecurityIdentifier&lt;/FONT&gt;)userAccount.Translate(&lt;FONT color=#3333ff&gt;typeof&lt;/FONT&gt;(&lt;FONT color=#009999&gt;SecurityIdentifier&lt;/FONT&gt;));&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Here, I'm using some of the System.Security.Principal .NET helpers to conver our user to a SID. While I could also use the IGroupSecurityService's "ReadIdentityFromSource" call, that includes a round-trip to the server and includes a bit more information than we need in this helper code.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&lt;FONT color=#009999&gt;ProjectInfo&lt;/FONT&gt;[] projects = css.ListProjects();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Here, I chose to use "ListProjects()" rather than "ListAllProjects()". The former only includes well formed projects while the latter will list all projects that are in the process of being created, being deleted, etc. as well. In this case, I think we only want to try to update projects that have been completely constructed.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&lt;FONT color=#009999&gt;Identity&lt;/FONT&gt; projectGroup = gss.ReadIdentity(&lt;FONT color=#009999&gt;SearchFactor&lt;/FONT&gt;.AccountName, &lt;FONT color=#009999&gt;String&lt;/FONT&gt;.Format(&lt;FONT color=#990033&gt;"[{0}]\\{1}"&lt;/FONT&gt;, project.Name, groupToUpdate), &lt;FONT color=#009999&gt;QueryMembership&lt;/FONT&gt;.Expanded);&lt;BR&gt;...&lt;BR&gt;&lt;FONT color=#009999&gt;List&lt;/FONT&gt;&amp;lt;&lt;FONT color=#3333ff&gt;string&lt;/FONT&gt;&amp;gt; members = &lt;FONT color=#3333ff&gt;new&lt;/FONT&gt; &lt;FONT color=#009999&gt;List&lt;/FONT&gt;&amp;lt;&lt;FONT color=#3333ff&gt;string&lt;/FONT&gt;&amp;gt;(projectGroup.Members);&lt;BR&gt;&lt;FONT color=#3333ff&gt;if&lt;/FONT&gt; (!members.Contains(userSid.ToString())) {...}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Before attempting to add the user to the group, I want to make sure it's not already a member. I chose to query the extended membership rather than just direct as it wouldn't make a difference in terms of user permissions whether the user is a direct member or a member under a nested group. However, if you want to make sure that the user is a direct member of the specified groups, you could change the "QueryMemberhip" value to Direct. Changing the query to Direct will also speed up the ReadIdentity call, particularly if your groups have many members.&lt;/P&gt;
&lt;P&gt;Happy coding!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1775203" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/adamsinger/attachment/1775203.ashx" length="3714" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Team+Foundation+Setup+Admin+_2600_amp_3B00_+Ops/default.aspx">Team Foundation Setup Admin &amp;amp; Ops</category><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Coding+Practices/default.aspx">Coding Practices</category></item><item><title>'Grep'ing Groups</title><link>http://blogs.msdn.com/adamsinger/archive/2007/02/09/grep-ing-groups.aspx</link><pubDate>Fri, 09 Feb 2007 20:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1636033</guid><dc:creator>Adam Singer</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/adamsinger/comments/1636033.aspx</comments><wfw:commentRss>http://blogs.msdn.com/adamsinger/commentrss.aspx?PostID=1636033</wfw:commentRss><wfw:comment>http://blogs.msdn.com/adamsinger/rsscomments.aspx?PostID=1636033</wfw:comment><description>&lt;P&gt;Man have I been busy. What have I been busy doing? Well, see there's.... actually, I'll let &lt;A class="" title="Brian Harry" href="http://blogs.msdn.com/bharry/" mce_href="http://blogs.msdn.com/bharry/"&gt;Brian&lt;/A&gt; explan as he's &lt;A class="" title="Automated Testing" href="http://blogs.msdn.com/bharry/archive/2007/02/04/managing-quality-part-2-automated-testing.aspx" mce_href="http://blogs.msdn.com/bharry/archive/2007/02/04/managing-quality-part-2-automated-testing.aspx"&gt;already done&lt;/A&gt; such an eloquent job at it, with&amp;nbsp;some neat charts and graphs, too.&lt;/P&gt;
&lt;P&gt;I mentioned in my last post that I have some code that will help you find built-in groups. It's actually pretty simple, and build upon code that &lt;A class="" title="James Manning" href="http://blogs.msdn.com/jmanning/" mce_href="http://blogs.msdn.com/jmanning/"&gt;James&lt;/A&gt; already provided &lt;A class="" title="Listing users and groups" href="http://blogs.msdn.com/jmanning/archive/2006/05/02/588648.aspx" mce_href="http://blogs.msdn.com/jmanning/archive/2006/05/02/588648.aspx"&gt;last year&lt;/A&gt;. Say you want to find the Team Foundation&amp;nbsp;Administrators group, the Valid Users group, or the Service Accounts group. These three groups are always created when TFS installs, so we added a neat flag to help you access them without knowing anything else than the server name. Try using the attached file as the main file in a new C# console application and then add dll references to Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll, and Microsoft.TeamFoundation.Common.dll. Many thanks to Matt Hoover for the code review on my sample code here.&lt;/P&gt;
&lt;P&gt;The key piece of code is the following method. &lt;/P&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;///&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;lt;summary&amp;gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;///&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt; Prints out the membership of the three built-in groups&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;///&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;&amp;lt;/summary&amp;gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;public&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;void&lt;/FONT&gt;&lt;FONT size=2&gt; DisplayBuiltinGroupMembers()&lt;BR&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT color=#008000 size=2&gt;// Find all the Administrative users&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Identity&lt;/FONT&gt;&lt;FONT size=2&gt; adminUserSids = m_gss.ReadIdentity(&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;SearchFactor&lt;/FONT&gt;&lt;FONT size=2&gt;.AdministrativeApplicationGroup, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;null&lt;/FONT&gt;&lt;FONT size=2&gt;, &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;QueryMembership&lt;/FONT&gt;&lt;FONT size=2&gt;.Expanded);&lt;BR&gt;PrintSubUsers(adminUserSids);&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;// Find all the Service accounts&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Identity&lt;/FONT&gt;&lt;FONT size=2&gt; serviceSids = m_gss.ReadIdentity(&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;SearchFactor&lt;/FONT&gt;&lt;FONT size=2&gt;.ServiceApplicationGroup, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;null&lt;/FONT&gt;&lt;FONT size=2&gt;, &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;QueryMembership&lt;/FONT&gt;&lt;FONT size=2&gt;.Expanded);&lt;BR&gt;PrintSubUsers(serviceSids);&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;// Find all the valid users&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Identity&lt;/FONT&gt;&lt;FONT size=2&gt; allUserSids = m_gss.ReadIdentity(&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;SearchFactor&lt;/FONT&gt;&lt;FONT size=2&gt;.EveryoneApplicationGroup, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;null&lt;/FONT&gt;&lt;FONT size=2&gt;, &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;QueryMembership&lt;/FONT&gt;&lt;FONT size=2&gt;.Expanded);&lt;BR&gt;PrintSubUsers(allUserSids);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;We can also read the project administatrative groups in a similar way. The only thing you need to know is the project URI. Note that if you have the project name you can find its URI the ICommonStructureService's "GetProjectFromName" method.&lt;/P&gt;&lt;FONT size=2&gt;
&lt;BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;&lt;FONT color=#2b91af size=2&gt;
&lt;P&gt;ProjectInfo&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; project = m_css.GetProjectFromName(&lt;/FONT&gt;&lt;FONT color=#a31515 size=2&gt;"My Project"&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt;);&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;Identity&lt;/FONT&gt;&lt;FONT size=2&gt; adminGroup = m_gss.ReadIdentity(&lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;SearchFactor&lt;/FONT&gt;&lt;FONT size=2&gt;.AdministrativeApplicationGroup, project.Uri, &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;QueryMembership&lt;/FONT&gt;&lt;FONT size=2&gt;.Expanded);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;
&lt;P&gt;Disclaimers: The most efficient means of reading identity information is by using the SearchFactor.Sid. If you plan to do a tremendous number of queries like the ones in my sample app and want to get the best perf, this may not be the right method for you. Instead, use the members of the Microsoft.TeamFoundation.GroupWellKnownSidConstants class in Microsoft.TeamFoundation.Common.dll (this will also allow you to access the Licensed Users Group which only exists in the Team Foundation Server Workgroup Edition). Even so, the extra SearchFactors can make your code&amp;nbsp;look a bit prettier.&lt;FONT size=2&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1636033" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/adamsinger/attachment/1636033.ashx" length="7249" type="text/plain" /><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Team+Foundation+Setup+Admin+_2600_amp_3B00_+Ops/default.aspx">Team Foundation Setup Admin &amp;amp; Ops</category><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Coding+Practices/default.aspx">Coding Practices</category></item><item><title>New and Improved</title><link>http://blogs.msdn.com/adamsinger/archive/2006/12/14/new-and-improved.aspx</link><pubDate>Thu, 14 Dec 2006 18:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1093733</guid><dc:creator>Adam Singer</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/adamsinger/comments/1093733.aspx</comments><wfw:commentRss>http://blogs.msdn.com/adamsinger/commentrss.aspx?PostID=1093733</wfw:commentRss><wfw:comment>http://blogs.msdn.com/adamsinger/rsscomments.aspx?PostID=1093733</wfw:comment><description>&lt;P&gt;I always wondered about that phrase- "New and Improved". Either it's 'new', which means it never existed before, or it's 'improved' which means that it's better than the previous version(s) and, therefore, existed before. Finally I can stop wondering because I think I've come up with a situation where it can actually be logically applied.&lt;/P&gt;
&lt;P&gt;Now that the first version of TFS (&lt;a href="http://msdn.microsoft.com/vstudio/products/vsts/tfs/default.aspx"&gt;Team Foundation Server&lt;/a&gt;)&amp;nbsp;is out in the wild doing its wild thing and we're well on the way in our hunt for version 2 we have a new issue to contend with. This issue is something that never came up in the last product cycle- Legacy Code. I'm talking about both product code and automated test code (of which we have a great deal).&lt;/P&gt;
&lt;P&gt;The issue of course is that as we work, we learn. We come up with smarter, better, faster, stronger ways of doing whatever needs to be done. The old way still works, certainly, it's just not correct according to new preferred practices. In an ideal world, we'd like to refactor all of the code any time a new method comes into the shuffle. However, we only have so many hands and would like to release the next version some time this decade.&lt;/P&gt;
&lt;P&gt;Given that, you have to make some tradeoffs and costing decisions. How bad does old code have to be before you update it? Certainly you'll update anything that gets broken, but do you apply all new practices, or just the critical ones? If it's bad enough, do you scrap it and start again?&lt;/P&gt;
&lt;P&gt;In this sense, our automated test code is both new &lt;I&gt;and&lt;/I&gt; improved. Some portions of it never existed before since the features tested didn't exist previously. Some portions of it have been upgraded to the new standards. And the third, unspoken, category is all that testcode from V1 that still does something useful, whether or not it's written the way we'd do it today.&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;I'd like to finish by posing a question to all you code writers out there- When what made your code tick just doesn't click, do you give it a kick, or just let it stick?&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1093733" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Team+Foundation+General/default.aspx">Team Foundation General</category><category domain="http://blogs.msdn.com/adamsinger/archive/tags/Coding+Practices/default.aspx">Coding Practices</category></item></channel></rss>