<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BUGBUG: poor title &#187; TFS</title>
	<atom:link href="http://richardberg.net/blog/category/tech/tfs/feed/" rel="self" type="application/rss+xml" />
	<link>http://richardberg.net/blog</link>
	<description>...the same thing we do every night, Pinky...</description>
	<lastBuildDate>Mon, 27 Apr 2009 15:54:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Get-TfsItemProperty is the bridge between server and local objects</title>
		<link>http://richardberg.net/blog/2009/03/27/get-tfsitemproperty-is-the-bridge-between-server-and-local-objects/</link>
		<comments>http://richardberg.net/blog/2009/03/27/get-tfsitemproperty-is-the-bridge-between-server-and-local-objects/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 02:59:34 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=67</guid>
		<description><![CDATA[Most of the real-world examples of the TFS powershell tool revolve around querying (and possibly updating) the state of the server.&#160; My first public demo, by way of Brian Harry’s blog Keith Hill’s early explorations And rightfully so: most of the operations you want to do locally are already possible without any special tools.&#160; The [...]]]></description>
			<content:encoded><![CDATA[<p>Most of the real-world examples of the TFS powershell tool revolve around querying (and possibly updating) the state of the server.&#160; </p>
<ul>
<li><a href="http://blogs.msdn.com/bharry/archive/2008/10/01/preview-of-the-next-tfs-power-tools-release.aspx">My first public demo</a>, by way of Brian Harry’s blog</li>
<li><a href="http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6691.entry">Keith Hill’s early explorations</a></li>
</ul>
<p>And rightfully so: most of the operations you want to do locally are already possible without any special tools.&#160; The “Powershell snap-in system” we know and love today was created to help IT admins manage their servers – even today, only a brave few developers have completely replaced cmd.exe at their daily workstation.</p>
<p>Nevertheless, we shouldn’t be satisfied to have our TFS cmdlets live in their own little world.&#160; Luckily, all the info we could ever want about a TFS version controlled item – including its local state – comes packaged in the <a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.extendeditem.aspx">ExtendedItem</a> object.&#160; Even more fortuitously, if you revisit the <a href="http://richardberg.net/blog/?p=30">exploration of QualifiedItemSpec</a> with an eye for detail, you’ll notice that one overload of ToQualifiedItem() is not like the others.*&#160; In the constructor where ExtendedItem decays into QualifiedItem, the properties saved into the resulting tuple include LocalItem and VersionLocal instead of more familiar ones like ServerItem.&#160; This is not a coincidence :)&#160; </p>
<p>Let’s sum up what we know so far.&#160; Native TFS objects are funneled down the pipeline by stripping them to bare essentials about the items they represent (QIs); these serve as a common interface between cmdlets.&#160; When an ExtendedItem is stripped down, the next cmdlet will use the <em>local</em> filename &amp; <em>local </em>version info as its parameters.&#160; Get-TfsItemProperty is the cmdlet that returns ExtendedItems.&#160; Capiche?</p>
<p>Time to put our newfound knowledge into action.&#160; If you’ve also been following the last several posts on file manipulation in powershell, these examples will hopefully inspire an “aha!” moment.</p>
<div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; padding-left: 5px; width: 750px; padding-right: 5px; font-family: consolas,lucida console; font-size: 10pt; overflow: auto; border-top: black 1px solid; border-right: black 1px solid; padding-top: 5px">
<table border="0" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td valign="top">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #cecece; font-size: 10pt; padding-top: 5px">001             <br />002              <br />003              <br />004              <br />005              </div>
</td>
<td valign="top" nowrap="nowrap">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #fcfcfc; font-size: 10pt; padding-top: 5px"><span style="color: #006400"># find all C# makefiles with HintPath elements, check them out, and open them in my text editor</span>              <br /><span style="color: #0000ff">tfprop</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">$/project/*csproj</span><span style="color: #000000">&#160;</span><span style="color: #000080">-r</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">get-fullpath</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">ss</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">hintpath</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">tfedit</span><span style="color: #000000">&#160;</span><span style="color: #000080">-passthru</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">ue</span>              </p>
<p><span style="color: #006400"># find my shelvesets related to powershell, unshelve them, and open every file in the ISE</span>              <br /><span style="color: #0000ff">get-tfsshelveset</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">?</span><span style="color: #000000">&#160;</span><span style="color: #000000">{</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$_</span><span style="color: #a9a9a9">.</span><span style="color: #000000">name</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">-like</span><span style="color: #000000">&#160;</span><span style="color: #8b0000">&quot;*powershell*&quot;</span><span style="color: #000000">&#160;</span><span style="color: #000000">}</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">tfunshelve</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">tfprop</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">ise</span> </div>
</td>
</tr>
</tbody>
</table></div>
<p>[Note that I have get-tfsitemproperty aliased to ‘tfprop’ rather than ‘tfproperties’ as it appears in a default install of the Power Tools.]</p>
<p>Are we having fun yet?!</p>
<p>So far we’ve only really exercised the filename part of the QI.&#160; Equally interesting things happen when you take advantage of the special ability that Get-TfsItemProperty offers to manipulate the local version.</p>
<div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; padding-left: 5px; width: 750px; padding-right: 5px; font-family: consolas,lucida console; font-size: 10pt; overflow: auto; border-top: black 1px solid; border-right: black 1px solid; padding-top: 5px">
<table border="0" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td valign="top">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #cecece; font-size: 10pt; padding-top: 5px">001             <br />002              <br />003              <br />004              <br />005              <br />006              <br />007              <br />008              <br />009              <br />010              <br />011              <br />012              <br />013              <br />014              <br />015              <br />016              <br />017              <br />018              <br />019              <br />020              <br />021              </div>
</td>
<td valign="top" nowrap="nowrap">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #fcfcfc; font-size: 10pt; padding-top: 5px"><span style="color: #006400"># Force unshelve to pend changes against your current workspace (&quot;have&quot;) version. Ordinarily,</span>              <br /><span style="color: #006400"># unshelve rolls the affected files back to the version you had at the time you shelved the </span>              <br /><span style="color: #006400"># changes.</span>              <br /><span style="color: #006400"># Pro: this ensures your workspace stays in a consistent, buildable state</span>              <br /><span style="color: #006400"># Con: you may need to resolve content and/or namespace conflicts</span>              <br /><span style="color: #00008b">function</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">unpack</span>              <br /><span style="color: #000000">{</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">CmdletBinding</span><span style="color: #000000">(</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">param</span><span style="color: #000000">&#160;</span><span style="color: #000000">(</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">parameter</span><span style="color: #000000">(</span><span style="color: #000000">Mandatory</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$True</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">Position</span><span style="color: #a9a9a9">=</span><span style="color: #800080">0</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">ValueFromPipeline</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$True</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #008080">[Microsoft.TeamFoundation.PowerTools.Powershell.ShelvesetSpec]</span><span style="color: #ff4500">$ss</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">)</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">process</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">{</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #ff4500">$currentWorkspaceVersions</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">=</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">tfstatus</span><span style="color: #000000">&#160;</span><span style="color: #000080">-shelveset</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$ss</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">tfprop</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #0000ff">restore-tfsshelveset</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$ss</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">out-null</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #ff4500">$currentWorkspaceVersions</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">tfget</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #0000ff">tf</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">resolve</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">/prompt</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">}</span>              <br /><span style="color: #000000">}</span> </div>
</td>
</tr>
</tbody>
</table></div>
<p>[Microsofties: think bbpack / jjpack]</p>
<p>Opens up a whole new world of TFVC scripting mania, wouldn’t ya say?</p>
<p>*I’ll admit the one for GettingEventArgs is a little funky as well.&#160; Here, the choice of properties to expose came down to UX / gut feel.&#160; TargetLocalItem is usually what you want to see; it tends to be the “final result” of mainline operations, surviving things like Rename and Undo fairly well.&#160; But it’s not always the best choice.&#160; Obviously when it’s null we need a backup; good old ServerItem will do.&#160; It’s [almost always] guaranteed to be present, but it’s&#160; not always perfect either – now you have the occasional strange appearance of server paths in your list of local files being touched by the Update.&#160; Finding the right info gets really tricky really fast: was TargetLocalItem null because of a pending Delete, because it’s cloaked or otherwise excluded from our workspace, or because we’re undoing a pending Branch or Merge?&#160; That’s just one example.&#160; The logic behind which name tf.exe displays in which scenario is actually one of the more complex pieces of the app.&#160; With powershell we can accept “good enough” since the object model lets you manipulate things to your heart’s content.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/03/27/get-tfsitemproperty-is-the-bridge-between-server-and-local-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fixing consistency issues with Powershell&#8217;s filename properties</title>
		<link>http://richardberg.net/blog/2009/03/27/fixing-consistency-issues-with-powershells-filename-properties/</link>
		<comments>http://richardberg.net/blog/2009/03/27/fixing-consistency-issues-with-powershells-filename-properties/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 21:06:55 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=57</guid>
		<description><![CDATA[When I decided to bitch about select-object, I used “dir” in my examples for a reason: passing filesystem objects around the pipeline is simultaneously one of the most common yet one of the most annoying things you can do in Powershell.&#160; Let’s review some built-in cmdlets from the POV of getting the full path to [...]]]></description>
			<content:encoded><![CDATA[<p>When I decided to <a href="http://richardberg.net/blog/?p=55">bitch about select-object</a>, I used “dir” in my examples for a reason: passing filesystem objects around the pipeline is simultaneously one of the most common yet one of the most annoying things you can do in Powershell.&#160; Let’s review some built-in cmdlets from the POV of getting the full path to a given file or folder:</p>
<table border="0" cellspacing="0" cellpadding="2" width="545">
<tbody>
<tr>
<td valign="top" width="247"><strong>Cmdlet</strong></td>
<td valign="top" width="129"><em>Input property name accepted on pipeline</em></td>
<td valign="top" width="167"><em>Output property name on object sent to pipeline</em></td>
</tr>
<tr>
<td valign="top" width="247">Get-Item, Get-ChildItem, Set-Item</td>
<td valign="top" width="129">Path</td>
<td valign="top" width="167">FullName</td>
</tr>
<tr>
<td valign="top" width="247">Join-Path, Split-Path, Test-Path</td>
<td valign="top" width="129">Path</td>
<td valign="top" width="167">n/a</td>
</tr>
<tr>
<td valign="top" width="247">Resolve-Path, Select-String</td>
<td valign="top" width="129">Path</td>
<td valign="top" width="167">Path*</td>
</tr>
<tr>
<td valign="top" width="247">New-Item</td>
<td valign="top" width="129">Name</td>
<td valign="top" width="167">FullName</td>
</tr>
</tbody>
</table>
<p><em>* note that the built-in documentation for Resolve-Path is wrong!&#160; as of CTP3, it’s claiming the output is a string</em></p>
<p>Plus, you may be working with 3rd party tools that obey <em>none </em>of the above conventions.&#160; </p>
<p>For example, with the TFS Power Tools, Hyung had the foresight to add string[] to the list of types we can <a href="http://richardberg.net/blog/?p=30">convert to <strong>QualifiedItems</strong> behind the scenes</a> using extra constructors, but we still don’t support the <a href="http://msdn.microsoft.com/en-us/library/system.management.automation.parameterattribute.valuefrompipelinebypropertyname(VS.85).aspx">ValueFromPipelineByPropertyName</a> idiom that’s needed to make non-trivial filesystem objects flow.&#160; Furthermore, the objects we output are native TFS types, which were never designed with Powershell in mind.&#160; Most of the time there’s little overlap between these objects and non-TFS cmdlets, but a big exception is the LocalItem property of the <strong>ExtendedItem </strong>object returned by “tfprop.”&#160; In hindsight, we should have added a NoteProperty that aliased it to Path.&#160; (…or FullName, or Name, depending on whether the PS guys make up their mind :) )</p>
<p>Then there are tools that have nothing at all to do with Powershell.&#160; Some sort of wrapper script is going to be required regardless, but without consistency in the kind of input your wrapper can expect, it can get needlessly complex.</p>
<p>My solution to all of the above is outlined below.&#160; Time to let the code do the talking:</p>
<div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; padding-left: 5px; width: 886px; padding-right: 5px; font-family: consolas,lucida console; height: 468px; font-size: 10pt; overflow: auto; border-top: black 1px solid; border-right: black 1px solid; padding-top: 5px">
<table border="0" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td valign="top">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #cecece; font-size: 10pt; padding-top: 5px">001              <br />002               <br />003               <br />004               <br />005               <br />006               <br />007               <br />008               <br />009               <br />010               <br />011               <br />012               <br />013               <br />014               <br />015               <br />016               <br />017               <br />018               <br />019               <br />020               <br />021               <br />022               <br />023               <br />024               <br />025               </div>
</td>
<td valign="top" nowrap="nowrap">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #fcfcfc; font-size: 10pt; padding-top: 5px"><span style="color: #00008b">function</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">get-fullpath</span>               <br /><span style="color: #000000">{</span>               <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">CmdletBinding</span><span style="color: #000000">(</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>               <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">Param</span><span style="color: #000000">(</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Parameter</span><span style="color: #000000">(</span><span style="color: #000000">ParameterSetName</span><span style="color: #a9a9a9">=</span><span style="color: #8b0000">&quot;ByPropertyName&quot;</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">Position</span><span style="color: #a9a9a9">=</span><span style="color: #800080">0</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">Mandatory</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$true</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">ValueFromPipelineByPropertyName</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$true</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">ValueFromPipeline</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$true</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Alias</span><span style="color: #000000">(</span><span style="color: #8b0000">&quot;FullName&quot;</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Alias</span><span style="color: #000000">(</span><span style="color: #8b0000">&quot;FullPath&quot;</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #006400"># [Alias(&quot;Name&quot;)] - too many false positives</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Alias</span><span style="color: #000000">(</span><span style="color: #8b0000">&quot;Path&quot;</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Alias</span><span style="color: #000000">(</span><span style="color: #8b0000">&quot;LocalItem&quot;</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #008080">[string]</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$file</span>               <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">)</span>               <br /><span style="color: #000000">&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">Process</span>               <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">{</span><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #006400"># eliminate nonexistent files, obviously, but also random objects that were coerced from the pipeline by calling their ToString() method</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #00008b">if</span><span style="color: #000000">&#160;</span><span style="color: #000000">(</span><span style="color: #a9a9a9">!</span><span style="color: #000000">(</span><span style="color: #0000ff">test-path</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$file</span><span style="color: #000000">)</span><span style="color: #000000">)</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #000000">{</span><span style="color: #000000">&#160;</span><span style="color: #00008b">break</span><span style="color: #000000">&#160;</span><span style="color: #000000">}</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #006400"># expand relative paths (in case the immediate window's workingdir != the workingdir of powershell_ise.exe) </span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #0000ff">resolve-path</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$file</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #006400"># and also make sure UNC paths are in normal format, not Powershell format</span>               <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #0000ff">convert-path</span><span style="color: #000000">&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">}</span>               <br /><span style="color: #000000">}</span> </div>
</td>
</tr>
</tbody>
</table></div>
<p>Who knew that ValueFromPipelineByPropertyName worked on aliases?&#160; I didn’t.&#160; I thought it would be nice, but since I didn’t see it documented anywhere, my initial sketch for this function used a ton of ugly ParameterSets as a workaround.&#160; Somewhere in there I decided to try Aliases; lo and behold, it works!&#160; Yay.</p>
<p>This function is useful on its own – if nothing else I use it as a wholesale replacement for resolve-path, whose behavior on UNC paths is bizarre in my opinion – but its real value is as a helper.&#160; For example, a couple snippets from my $profile:</p>
<div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; padding-left: 5px; width: 750px; padding-right: 5px; font-family: consolas,lucida console; font-size: 10pt; overflow: auto; border-top: black 1px solid; border-right: black 1px solid; padding-top: 5px">
<table border="0" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td valign="top">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #cecece; font-size: 10pt; padding-top: 5px">001             <br />002              <br />003              <br />004              <br />005              <br />006              <br />007              <br />008              <br />009              <br />010              <br />011              <br />012              <br />013              <br />014              <br />015              <br />016              <br />017              </div>
</td>
<td valign="top" nowrap="nowrap">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #fcfcfc; font-size: 10pt; padding-top: 5px"><span style="color: #00008b">function</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">tfedit</span><span style="color: #000000">&#160;</span>              <br /><span style="color: #000000">{</span>              <br /><span style="color: #000000"></span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">CmdletBinding</span><span style="color: #000000">(</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">Param</span><span style="color: #000000">(</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Parameter</span><span style="color: #000000">(</span><span style="color: #000000">Position</span><span style="color: #a9a9a9">=</span><span style="color: #800080">0</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">Mandatory</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$true</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">ValueFromPipeline</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$true</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #008080">[psobject]</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$file</span><span style="color: #a9a9a9">,</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Parameter</span><span style="color: #000000">(</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #008080">[switch]</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$PassThru</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">=</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$false</span><span style="color: #000000">&#160;</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">)</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">Process</span><span style="color: #000000">&#160;</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">{</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #00008b">if</span><span style="color: #000000">&#160;</span><span style="color: #000000">(</span><span style="color: #ff4500">$PassThru</span><span style="color: #000000">)</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #000000">{</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$file</span><span style="color: #000000">&#160;</span><span style="color: #000000">}</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #0000ff">tfpend</span><span style="color: #000000">&#160;</span><span style="color: #000080">-edit</span><span style="color: #000000">&#160;</span><span style="color: #000000">(</span><span style="color: #ff4500">$file</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">get-fullpath</span><span style="color: #000000">)</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">}</span>              <br /><span style="color: #000000">}</span> </div>
</td>
</tr>
</tbody>
</table></div>
<p>&#160;</p>
<div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; padding-left: 5px; width: 750px; padding-right: 5px; font-family: consolas,lucida console; font-size: 10pt; overflow: auto; border-top: black 1px solid; border-right: black 1px solid; padding-top: 5px">
<table border="0" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td valign="top">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #cecece; font-size: 10pt; padding-top: 5px">001             <br />002              <br />003              <br />004              <br />005              <br />006              <br />007              <br />008              <br />009              <br />010              <br />011              <br />012              <br />013              <br />014              <br />015              <br />016              </div>
</td>
<td valign="top" nowrap="nowrap">
<div style="padding-bottom: 5px; padding-left: 5px; padding-right: 5px; font-family: consolas,lucida console; background: #fcfcfc; font-size: 10pt; padding-top: 5px"><span style="color: #00008b">function</span><span style="color: #000000">&#160;</span><span style="color: #8a2be2">ise</span><span style="color: #000000">&#160;</span>              <br /><span style="color: #000000">{</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">CmdletBinding</span><span style="color: #000000">(</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">param</span><span style="color: #000000">&#160;</span><span style="color: #000000">(</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">parameter</span><span style="color: #000000">(</span><span style="color: #000000">Mandatory</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$True</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">Position</span><span style="color: #a9a9a9">=</span><span style="color: #800080">0</span><span style="color: #a9a9a9">,</span><span style="color: #000000">&#160;</span><span style="color: #000000">ValueFromPipeline</span><span style="color: #a9a9a9">=</span><span style="color: #ff4500">$True</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #008080">[psobject]</span><span style="color: #ff4500">$file</span><span style="color: #a9a9a9">,</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #a9a9a9">[</span><span style="color: #add8e6">Parameter</span><span style="color: #000000">(</span><span style="color: #000000">)</span><span style="color: #a9a9a9">]</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #008080">[switch]</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$PassThru</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">=</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$false</span><span style="color: #000000">&#160;</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">)</span><span style="color: #000000">&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #00008b">process</span><span style="color: #000000">&#160;</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">{</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #00008b">if</span><span style="color: #000000">&#160;</span><span style="color: #000000">(</span><span style="color: #ff4500">$PassThru</span><span style="color: #000000">)</span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #000000">{</span><span style="color: #000000">&#160;</span><span style="color: #ff4500">$file</span><span style="color: #000000">&#160;</span><span style="color: #000000">}</span><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span>              <br /><span style="color: #000000">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #ff4500">$psise</span><span style="color: #a9a9a9">.</span><span style="color: #000000">CurrentOpenedRunspace</span><span style="color: #a9a9a9">.</span><span style="color: #000000">OpenedFiles</span><span style="color: #a9a9a9">.</span><span style="color: #000000">Add</span><span style="color: #000000">(</span><span style="color: #000000">(</span><span style="color: #ff4500">$file</span><span style="color: #000000">&#160;</span><span style="color: #a9a9a9">|</span><span style="color: #000000">&#160;</span><span style="color: #0000ff">get-fullpath</span><span style="color: #000000">)</span><span style="color: #000000">)</span>              <br /><span style="color: #000000">&#160;&#160;&#160; </span><span style="color: #000000">}</span>              <br /><span style="color: #000000">}</span> </div>
</td>
</tr>
</tbody>
</table></div>
<p>I think the PS parser should be smart enough that double-parens are not required in the second example, but oh well.&#160; Pretty simple overall, and super convenient.&#160; Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/03/27/fixing-consistency-issues-with-powershells-filename-properties/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>TFS Powershell cmdlets default to -noprompt</title>
		<link>http://richardberg.net/blog/2009/03/16/tfs-powershell-cmdlets-default-to-noprompt-2/</link>
		<comments>http://richardberg.net/blog/2009/03/16/tfs-powershell-cmdlets-default-to-noprompt-2/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 15:35:12 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=53</guid>
		<description><![CDATA[The title kinda says it all.&#160; But as usual, there’s a backstory to tell and some ramifications to warn you about. First, let’s look back at the legacy tf.exe command line.&#160; In the effort to be both user friendly and flexible, its behavior has actually become quite complicated.&#160; As of TFS 2008, the logic appears [...]]]></description>
			<content:encoded><![CDATA[<p>The title kinda says it all.&#160; But as usual, there’s a backstory to tell and some ramifications to warn you about.</p>
<p>First, let’s look back at the legacy tf.exe command line.&#160; In the effort to be both user friendly and flexible, its behavior has actually become quite complicated.&#160; As of TFS 2008, the logic appears to be evaluated in this order of precedence:</p>
<ol>
<li>If the <font face="Courier New">/prompt</font> flag is present for this command, always use Prompt mode, otherwise</li>
<li>If the <font face="Courier New">/noprompt</font> flag is present for this command, always use Noprompt mode, otherwise</li>
<li>If the tf.exe process’ stdout stream is redirected, use Noprompt mode (unless the environment variable TFS_IGNORESTDOUTREDIRECT is set), otherwise</li>
<li>If executing in <a href="http://msdn.microsoft.com/en-us/library/56f7w6be.aspx">script mode</a> with a @command file, use Noprompt mode (unless the most recent invocation of the setnoprompt command was “setnoprompt false”), otherwise</li>
<li>Default to Prompt mode</li>
</ol>
<p>Yikes.&#160; I’d actually forgotten just how many variables there were until I started running tests for this blog post.&#160; Suffice to say, the Powershell cmdlets approach things in a much simpler way:</p>
<ol>
<li>If the <font face="Courier New">–prompt</font> switch is present for this cmdlet, always use Prompt mode, otherwise</li>
<li>Default to Noprompt mode</li>
</ol>
<p>Simple enough.&#160; I know a lot of power users will rejoice at this, having long since resigned themselves to <font face="Courier New">/i</font> muscle memory lest random WinForms interrupt their console workflow.&#160; However, there are ramifications to this behavior that you should be aware of.&#160; “Prompt mode” means more than simply popping up dialogs.&#160; First of all, there are some UI features that are still not accessible in Prompt mode without additional parameters, such as <font face="Courier New">tf diff /configure</font>.&#160; More importantly, leaving Prompt mode turns off a number of safeguards:</p>
<ul>
<li>Undo will <strong>permanently</strong> discard your local changes.&#160; (I think TFS should use the Recycle Bin, but that’s another show…)</li>
<li>Shelve /delete will <strong>permanently</strong> delete shelvesets.&#160; (The server used to keep them around until a cleanup job ran, but again that’s the way things work now.)</li>
<li>Destroy, well, destroys.</li>
</ul>
<p>These aren’t the only examples; you get the idea.&#160; None of this behavior is new to TFS in general, but with the default settings of the Powershell tool, it’s a lot easier to shoot yourself in the foot.&#160; Even good old Checkin is likely to surprise you the first time you see it simply <strong><em>go</em> </strong>without any further interaction.&#160; <em>[a “no blank comments” checkin policy might help here, nudge nudge]</em>&#160; </p>
<p>So have fun, just be careful.&#160; If you’re using the power tools then you are ready to be a power user, right? :)</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/03/16/tfs-powershell-cmdlets-default-to-noprompt-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why is the TFS Powershell snapin marked 32-bit only?</title>
		<link>http://richardberg.net/blog/2009/03/13/why-is-the-tfs-powershell-snapin-marked-32-bit-only/</link>
		<comments>http://richardberg.net/blog/2009/03/13/why-is-the-tfs-powershell-snapin-marked-32-bit-only/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 17:46:27 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=51</guid>
		<description><![CDATA[Short answer: because the TFS core assemblies are marked 32-bit only. Like everyone else, I wish the TFS team had supported x64 much earlier on.&#160; You can see in Microsoft.TeamFoundation.Common.dll that while there are a decent number of routines under the NativeMethods static class that need to be ported, it’s not an enormous task.&#160; Turns [...]]]></description>
			<content:encoded><![CDATA[<p>Short answer: because the TFS core assemblies are marked 32-bit only.</p>
<p>Like everyone else, I wish the TFS team had supported x64 much earlier on.&#160; You can see in Microsoft.TeamFoundation.Common.dll that while there are a decent number of routines under the NativeMethods static class that need to be ported, it’s not an enormous task.&#160; Turns out that supporting setup and deployment on x64 servers (with all the requisite expansion of the test matrix, etc.) is by far the higher cost.&#160; Good news is that x64 is supposed to be on the Rosario feature list.</p>
<p>In the meantime, I can’t have <a href="http://www.wintellect.com/CS/blogs/jrobbins/archive/2008/12/31/powershell-one-year-later.aspx">John Robbins’ impression of our power tool</a> be negative!&#160; I consider my trip to attend his “Native Windows Debugging” class one of the highlights of my MS career.&#160; As a TFS power user I frequently live in x86 shells, so here’s a tidbit from my $profile that helps keep me sane:</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:41cfae52-9136-4e9f-91bd-498b946f9c19" class="wlWriterEditableSmartContent">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">$isX86Process </span><span style="color: #000000;">=</span><span style="color: #000000;"> ( $env:Processor_Architecture </span><span style="color: #000000;">-</span><span style="color: #000000;">eq </span><span style="color: #800000;">&quot;</span><span style="color: #800000;">x86</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> )

...

$Global:PscxHostTitlePreference </span><span style="color: #000000;">=</span><span style="color: #000000;"> { $(</span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ($IsAdmin) { </span><span style="color: #800000;">&quot;</span><span style="color: #800000;">Admin: </span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> }) </span><span style="color: #000000;">+</span><span style="color: #000000;">
                                    $PscxWindowTitlePrefix </span><span style="color: #000000;">+</span><span style="color: #000000;">
                                    $(get</span><span style="color: #000000;">-</span><span style="color: #000000;">location).Path </span><span style="color: #000000;">+</span><span style="color: #000000;">
                                    $(</span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ($IsX86Process) {</span><span style="color: #800000;">&quot;</span><span style="color: #800000;"> (x86)</span><span style="color: #800000;">&quot;</span><span style="color: #000000;">})
                                  }</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>Naturally, I like Vivek’s auto-Fork example too – may need to incorporate somewhere into my library of stuff…</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/03/13/why-is-the-tfs-powershell-snapin-marked-32-bit-only/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to diff a file that&#8217;s not in your workspace?</title>
		<link>http://richardberg.net/blog/2009/03/11/how-to-diff-a-file-thats-not-in-your-workspace/</link>
		<comments>http://richardberg.net/blog/2009/03/11/how-to-diff-a-file-thats-not-in-your-workspace/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 19:05:53 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=49</guid>
		<description><![CDATA[The documentation for “tf diff” indicates that it should be possible to do things like tf diff /server:myserver.com c:\file.txt $/project/file.txt Unfortunately, this syntax is not supported.&#160; (Neither is the /workspace parameter, in case you were wondering.)&#160; It’s an oversight I hope will be corrected in the future.&#160; Until then, here’s a quick fix: tf view [...]]]></description>
			<content:encoded><![CDATA[<p>The documentation for “tf diff” indicates that it should be possible to do things like    <br /><font face="Courier New">tf diff /server:myserver.com c:\file.txt $/project/file.txt</font></p>
<p><a href="http://social.msdn.microsoft.com/Forums/en-US/tfsversioncontrol/thread/369b1a36-9126-4627-be42-bf60a59604fe/">Unfortunately, this syntax is not supported</a>.&#160; (Neither is the /workspace parameter, in case you were wondering.)&#160; It’s an oversight I hope will be corrected in the future.&#160; Until then, here’s a quick fix:</p>
<p><font face="Courier New">tf view $/project/file.txt &gt; temp.txt      <br />tf diff c:\file.txt temp.txt       <br />del temp.txt</font></p>
<p>This technique should be easy to put into your scripting language of choice.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/03/11/how-to-diff-a-file-thats-not-in-your-workspace/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More on ConvertTo-FixedByte vs Powershell Community Extensions</title>
		<link>http://richardberg.net/blog/2009/02/25/more-on-convertto-fixedbyte-vs-powershell-community-extensions/</link>
		<comments>http://richardberg.net/blog/2009/02/25/more-on-convertto-fixedbyte-vs-powershell-community-extensions/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 02:00:42 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=47</guid>
		<description><![CDATA[Last time we introduced two undocumented cmdlets that shipped with the TFS Fall ‘08 power tools.&#160; The idea behind ConvertTo-FixedByte is probably familiar to anyone who’s used Format-Byte from PSCX.&#160; Take a number and make it pretty.&#160; That’s it -- even the dirt simple conversion from “0” to “&#60;DIR&#62;” is handled in the formatter XML, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://richardberg.net/blog/?p=46">Last time</a> we introduced two undocumented cmdlets that shipped with the TFS Fall ‘08 power tools.&#160; The idea behind ConvertTo-FixedByte is probably familiar to anyone who’s used Format-Byte from <a href="www.codeplex.com/PowerShellCX">PSCX</a>.&#160; Take a number and make it pretty.&#160; That’s it -- even the dirt simple conversion from “0” to “&lt;DIR&gt;” is handled in the formatter XML, not the cmdlet.</p>
<p>However, there are some key differences: </p>
<ul>
<li>ConvertTo-FixedByte lets you specify any width between 6 and 22, while Format-Byte is fixed at 10 characters.</li>
<li>ConvertTo-FixedByte allows the entire UInt64 range (~10^20), while Format-Byte only goes up to TB (~10^15).</li>
<li>ConvertTo-FixedByte does not allow pipeline input, while Format-Byte does.</li>
<li>ConvertTo-FixedByte uses the <a href="http://en.wikipedia.org/wiki/SI_prefix">SI standard prefixes</a>, as <a href="http://en.wikipedia.org/wiki/Megabyte#Definition">recommended by IEC, IEEE, EU, and NIST</a>.&#160; Format-Byte uses binary-based prefixes (although it does not display them as KiB, MiB, etc).       <br /><font face="Courier New">PS&gt; convertto-fixedbyte 2000 -width 10        <br />&#160;&#160;&#160;&#160;&#160; 2 KB         <br />PS&gt; format-byte 2000         <br />&#160; 1.953 KB</font> </li>
<li>ConvertTo-FixedByte uses the biggest possible unit so long as the value is at least one unit.&#160; Format-Byte waits until you’ve exceeded 2^n to use the next biggest unit.     <br /><font face="Courier New">PS&gt; convertto-fixedbyte 1000 -width 10       <br />&#160;&#160;&#160;&#160;&#160; 1 KB        <br />PS&gt; format-byte 1024        <br />&#160;&#160; 1024 B</font></li>
<li>Both cmdlets attempt to output a fixed width by rounding, but Format-Byte’s approach fails to handle some edge cases correctly:      <br /><font face="Courier New">PS&gt; convertto-fixedbyte (1000*999) -width 10       <br />&#160;&#160;&#160; 999 KB        <br />PS&gt; convertto-fixedbyte (1000*999+1) -width 10        <br />999.001 KB        <br /></font><font face="Courier New">PS&gt; convertto-fixedbyte (1000*999+499) -width 10       <br />999.499 KB        <br /></font><font face="Courier New">PS&gt; convertto-fixedbyte (1000*999+500) -width 10       <br />&#160;&#160;&#160;&#160;&#160; 1 MB        <br /></font><font face="Courier New">PS&gt; convertto-fixedbyte (1000*999+501) -width 10       <br />&#160;&#160;&#160;&#160;&#160; 1 MB        <br /></font><font face="Courier New">PS&gt; convertto-fixedbyte (1000*1000-1) -width 10       <br />&#160;&#160;&#160;&#160;&#160; 1 MB        <br /></font><font face="Courier New">PS&gt; convertto-fixedbyte (1000*1000) -width 10       <br />&#160;&#160;&#160;&#160;&#160; 1 MB        <br /></font><font face="Courier New">PS&gt; convertto-fixedbyte (1000*1000+1) -width 10       <br />&#160;&#160;&#160;&#160;&#160; 1 MB        <br /></font><font face="Courier New">PS&gt; format-byte (1024*1023)       <br />&#160;&#160; 1023 KB        <br />PS&gt; format-byte (1024*1023+1)        <br />1023.001 KB        <br />PS&gt; format-byte (1024*1023+511)        <br />1023.499 KB        <br />PS&gt; format-byte (1024*1023+512)        <br /> 1023.5 KB        <br />PS&gt; format-byte (1024*1023+513)        <br />1023.501 KB        <br />PS&gt; format-byte (1024*1024-1)        <br />1023.999 KB        <br />PS&gt; format-byte (1024*1024)        <br />&#160;&#160; 1024 KB        <br />PS&gt; format-byte (1024*1024+1)        <br />&#160;&#160;&#160;&#160;&#160; 1 MB</font></li>
<li>Both cmdlets omit trailing 0’s, instead padding the front with extra spaces.&#160; [thought there was a slight difference here, but now I can’t repro it!]</li>
<li>And of course: PSCX is open-source, while the Power Tools are not.&#160; So I can’t read the PSCX source and Keith can’t read mine.&#160; Even so, I hope some of the ideas can cross-pollinate :)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/25/more-on-convertto-fixedbyte-vs-powershell-community-extensions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How does the TFS snap-in handle formatting?</title>
		<link>http://richardberg.net/blog/2009/02/25/how-does-the-tfs-snap-in-handle-formatting/</link>
		<comments>http://richardberg.net/blog/2009/02/25/how-does-the-tfs-snap-in-handle-formatting/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 01:31:42 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=46</guid>
		<description><![CDATA[Powershell formatting is pretty flexible, as long as you know how it works.&#160; So how do the version control cmdlets work?&#160; Open up %programfiles(x86)%\Microsoft Team Foundation Server 2008 Power Tools\PowerShell\Microsoft.TeamFoundation.PowerTools.PowerShell.format.ps1xml and have a look for yourself.&#160; Let’s consider the ubiquitous Item class for now: &#60;View&#62; &#60;Name&#62;Item&#60;/Name&#62; &#60;ViewSelectedBy&#62; &#60;TypeName&#62;Microsoft.TeamFoundation.VersionControl.Client.Item&#60;/TypeName&#62; &#60;/ViewSelectedBy&#62; &#60;TableControl&#62; &#60;TableHeaders&#62; &#60;TableColumnHeader&#62; &#60;Width&#62;7&#60;/Width&#62; &#60;Alignment&#62;Right&#60;/Alignment&#62; &#60;/TableColumnHeader&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Powershell formatting is pretty flexible, as long as <a href="http://blogs.msdn.com/powershell/archive/2006/06/21/more-how-does-powershell-formatting-really-work.aspx">you know how it works</a>.&#160; So how do the version control cmdlets work?&#160; Open up <strong>%programfiles(x86)%\Microsoft Team Foundation Server 2008 Power Tools\PowerShell\Microsoft.TeamFoundation.PowerTools.PowerShell.format.ps1xml</strong> and have a look for yourself.&#160; Let’s consider the ubiquitous Item class for now:</p>
<p> <!-- code formatted by http://manoli.net/csharpformat/ -->
</p>
</p>
<p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:43f46727-777b-4b16-bb8a-88028d0b7507" class="wlWriterEditableSmartContent">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">&lt;</span><span style="color: #000000;">View</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Name</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Item</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Name</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ViewSelectedBy</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TypeName</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Microsoft.TeamFoundation.VersionControl.Client.Item</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TypeName</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">ViewSelectedBy</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableControl</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableHeaders</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Width</span><span style="color: #000000;">&gt;</span><span style="color: #800080;">7</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Width</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Right</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Label</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">CheckinDate</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Label</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Width</span><span style="color: #000000;">&gt;</span><span style="color: #800080;">10</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Width</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Right</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Label</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">ContentLength</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Label</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Width</span><span style="color: #000000;">&gt;</span><span style="color: #800080;">7</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Width</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Right</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Label</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">ServerItem</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Label</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Left</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">Alignment</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnHeader</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableHeaders</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableRowEntries</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableRowEntry</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnItems</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">PropertyName</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">ChangesetId</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">PropertyName</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ScriptBlock</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">$_.CheckinDate.ToString(</span><span style="color: #800000;">'</span><span style="color: #800000;">d</span><span style="color: #800000;">'</span><span style="color: #000000;">)</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">ScriptBlock</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ScriptBlock</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
              </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ($_.ItemType </span><span style="color: #000000;">-</span><span style="color: #000000;">eq [Microsoft.TeamFoundation.VersionControl.Client.ItemType]::Folder)
              { </span><span style="color: #800000;">'</span><span style="color: #800000;">&amp;lt;DIR&amp;gt;</span><span style="color: #800000;">'</span><span style="color: #000000;"> }
              </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
              { ConvertTo</span><span style="color: #000000;">-</span><span style="color: #000000;">FixedByte $_.ContentLength </span><span style="color: #800080;">7</span><span style="color: #000000;"> }
            </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">ScriptBlock</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ScriptBlock</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
              ConvertTo</span><span style="color: #000000;">-</span><span style="color: #000000;">FixedPath $_.ServerItem </span><span style="color: #800080;">7</span><span style="color: #000000;">,</span><span style="color: #800080;">10</span><span style="color: #000000;">,</span><span style="color: #800080;">6</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">ScriptBlock</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnItem</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableColumnItems</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableRowEntry</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableRowEntries</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TableControl</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">View</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>And a few examples of what it looks like, taken from an 80- and a 112-character-wide console: </p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:8d8a7402-0dbc-4775-b1e9-084356bb8873" class="wlWriterEditableSmartContent">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">PS</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> tfdir 

Changes CheckinDat Content ServerItem
   etId          e  Length
</span><span style="color: #000000;">-------</span><span style="color: #000000;"> </span><span style="color: #000000;">----------</span><span style="color: #000000;"> </span><span style="color: #000000;">-------</span><span style="color: #000000;"> </span><span style="color: #000000;">----------</span><span style="color: #000000;">
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">   </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">DIR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">u...g</span><span style="color: #000000;">/</span><span style="color: #000000;">directorynamefromhell
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">   </span><span style="color: #800080;">11</span><span style="color: #000000;"> KB $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">u...efromhell</span><span style="color: #000000;">/</span><span style="color: #000000;">devilsurf.jpg
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">   </span><span style="color: #800080;">12</span><span style="color: #000000;"> B  $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">u...orynamefromhell</span><span style="color: #000000;">/</span><span style="color: #000000;">foo.txt
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">    </span><span style="color: #800080;">5</span><span style="color: #000000;"> MB $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">u...</span><span style="color: #000000;">/</span><span style="color: #000000;">PowerGUI.</span><span style="color: #800080;">1.6</span><span style="color: #000000;">.</span><span style="color: #800080;">1.639</span><span style="color: #000000;">.msi

PS</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> tfdir 

Changes CheckinDat Content ServerItem
   etId          e  Length
</span><span style="color: #000000;">-------</span><span style="color: #000000;"> </span><span style="color: #000000;">----------</span><span style="color: #000000;"> </span><span style="color: #000000;">-------</span><span style="color: #000000;"> </span><span style="color: #000000;">----------</span><span style="color: #000000;">
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">   </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">DIR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">ultra</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">mega</span><span style="color: #000000;">/</span><span style="color: #0000FF;">long</span><span style="color: #000000;">/</span><span style="color: #000000;">directorynamefromhell
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">   </span><span style="color: #800080;">11</span><span style="color: #000000;"> KB $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">ultra</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">m...ong</span><span style="color: #000000;">/</span><span style="color: #000000;">directorynamefromhell</span><span style="color: #000000;">/</span><span style="color: #000000;">devilsurf.jpg
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">   </span><span style="color: #800080;">12</span><span style="color: #000000;"> B  $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">ultra</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">mega</span><span style="color: #000000;">/</span><span style="color: #0000FF;">long</span><span style="color: #000000;">/</span><span style="color: #000000;">directorynamefromhell</span><span style="color: #000000;">/</span><span style="color: #000000;">foo.txt
   </span><span style="color: #800080;">8224</span><span style="color: #000000;">  </span><span style="color: #800080;">2</span><span style="color: #000000;">/</span><span style="color: #800080;">25</span><span style="color: #000000;">/</span><span style="color: #800080;">2009</span><span style="color: #000000;">    </span><span style="color: #800080;">5</span><span style="color: #000000;"> MB $</span><span style="color: #000000;">/</span><span style="color: #000000;">Test</span><span style="color: #000000;">-</span><span style="color: #000000;">ConchangoV2</span><span style="color: #000000;">/</span><span style="color: #000000;">super</span><span style="color: #000000;">/</span><span style="color: #000000;">ultra</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">very</span><span style="color: #000000;">/</span><span style="color: #000000;">m...torynamefromhell</span><span style="color: #000000;">/</span><span style="color: #000000;">PowerGUI.</span><span style="color: #800080;">1.6</span><span style="color: #000000;">.</span><span style="color: #800080;">1.639</span><span style="color: #000000;">.msi
</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>You can see that the Powershell team’s “expand toward the right to minimize visual variance” concept is used to great effect.&#160; However, we violated their “never provide a label” maxim in 3 out of 4 columns.&#160; Oops!&#160; Seriously though, I don’t think anyone would want to use a ScriptProperty with the exact parameters found in the formatter XML.&#160; What we provided instead is far more useful: a couple of fully generic cmdlets named <strong>ConvertTo-FixedByte</strong> and <strong>ConvertTo-FixedPath</strong>.&#160; I’ll cover the former in another post; there’s a fair amount of detail to dig into, but its use here is rather mundane.&#160; </p>
<p>ConvertTo-FixedPath is what really makes this example shine.&#160; If you’re like me, you <em>hate </em>managing long paths in shell environments.&#160; Wrapping onto multiple lines, truncating the front, and (especially) truncating the end of the path are all unacceptable.&#160; Cmdlets to the rescue!&#160; This one has two modes (“parameter sets” in PS-speak).&#160; The first is obvious enough:</p>
<p><font face="Courier New">PS&gt; convertto-fixedpath 12345678901234567890 -width 16<br />
    <br />12345678...67890</font></p>
<p>The 20-character input string is truncated to 16, but only by omitting things <em>in the middle</em>.&#160; (Note that this mode has an off-by-one bug.&#160; Hint: odd numbers.)&#160; This allows you to answer the important questions: what is the file name? what branch/workspace are they located in?&#160; Usually we don’t care as much about the intermediate directories.&#160; Maybe the same is true for other kinds of strings too – let me know if you find it useful!</p>
<p>The other mode is designed explicitly for use in a ps1xml formatter.&#160; Consider:</p>
<p><font face="Courier New">PS&gt; convertto-fixedpath 12345678901234567890 -otherwidths 30, 20, 10<br />
    <br />12345678...67890</font></p>
<p>Same output, but what the heck are the “other widths”?&#160; Imagine this string were going into a variable-length field.&#160; We want the string to expand dynamically, showing us as much of the filename as possible.&#160; Yet if it does need to be cropped, we want it done intelligently, as if we’d known the width in advance and passed it as a –width parameter.</p>
<p>As it turns out, we <em>can </em>know the final width, given a little hackery.&#160; The Powershell API lets you access the raw console host details, <a href="http://msdn.microsoft.com/en-us/library/system.management.automation.host.pshostrawuserinterface.buffersize(VS.85).aspx">including its BufferSize</a>.&#160; All you need to do is subtract the widths of the other columns, plus room for the separator character PS places between each column.&#160; So imagine the code above is used in a four-column formatter: 80 - 30 - 20 - 10 - (4*1) = 16.&#160; Sure enough, if you scroll back up to the XML, you’ll see the values passed to –otherwidths are no coincidence.&#160; We hand-tweaked every column width so it fit the data type as closely as possible without wrapping*, then plugged in those widths to the convertto-fixedpath cmdlet driving the final variable-length column.</p>
<p>This hack may not always work as Powershell migrates away from the ancient CSRSS hosting environment.&#160; But in theory, anyone who implements <a href="http://msdn.microsoft.com/en-us/library/system.management.automation.host.pshostrawuserinterface(VS.85).aspx">PSHostRawUserInterface</a> should be compatible.&#160; It works in the Powershell v2 ISE environment that ships with Win7, for instance.&#160; Custom-PS-tool-lovers, let me know how it goes. </p>
<p>*Except for column titles, obviously.&#160; They were a necessary casualty of two higher-priority design considerations (a) keeping labels identical to the underlying property name (b) supporting the default 80-character console width without squishing average-sized paths.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/25/how-does-the-tfs-snap-in-handle-formatting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to enforce a rule on Area/Iteration Path</title>
		<link>http://richardberg.net/blog/2009/02/17/how-to-enforce-a-rule-on-areaiteration-path/</link>
		<comments>http://richardberg.net/blog/2009/02/17/how-to-enforce-a-rule-on-areaiteration-path/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 16:59:46 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Work Item Tracking]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=39</guid>
		<description><![CDATA[Another pitfall I encountered while setting up our new team project was how to make sure people didn’t cop out and leave them at the default (root, aka useless) value.  With Areas I may have been able to set up some weird non-inheriting permission scheme, but I needed to solve this problem for Iterations anyway, [...]]]></description>
			<content:encoded><![CDATA[<p>Another pitfall I encountered while setting up our new team project was how to make sure people didn’t cop out and leave them at the default (root, aka useless) value.  With Areas I may have been able to set up some weird non-inheriting permission scheme, but I needed to solve this problem for Iterations anyway, so I turned to the web. </p>
<p>Unfortunately, the <a href="http://blogs.msdn.com/teams_wit_tools/archive/2008/01/30/faq-2-how-do-i-enforce-a-rule-on-area-path-or-iteration-path.aspx">standard answer from the product team</a> didn’t work for me. </p>
<div id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:44a893be-96ad-4c62-96b9-d3f7de71b4f2" class="wlWriterEditableSmartContent" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD type</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Integer</span><span style="color: #800000;">"</span><span style="color: #000000;"> name</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">AreaID</span><span style="color: #800000;">"</span><span style="color: #000000;"> refname</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">System.AreaId</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">AreaID</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD type</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Integer</span><span style="color: #800000;">"</span><span style="color: #000000;"> name</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">IterationID</span><span style="color: #800000;">"</span><span style="color: #000000;"> refname</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">System.IterationId</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">IterationID</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD type</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">String</span><span style="color: #800000;">"</span><span style="color: #000000;"> name</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Product Area - Validation</span><span style="color: #800000;">"</span><span style="color: #000000;"> refname</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Coatue.ProductAreaValidation</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Hidden field used to validate Product Area</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">WHEN field</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">System.AreaId</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">84</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">COPY from</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">value</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Restricted</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">WHEN</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">PROHIBITEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">LISTITEM value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Restricted</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">PROHIBITEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD type</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">String</span><span style="color: #800000;">"</span><span style="color: #000000;"> name</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Sprint or Release - Validation</span><span style="color: #800000;">"</span><span style="color: #000000;"> refname</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Coatue.SprintPathValidation</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Hidden field used to validate Sprint or Release</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">WHEN field</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">System.IterationId</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">84</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">COPY from</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">value</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Restricted</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">WHEN</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">PROHIBITEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">LISTITEM value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Restricted</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">PROHIBITEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>It successfully blocked work items that had Area/Iteration paths I didn’t want, but I’d continue to get validation errors after I changed the paths in the form to something else.</p>
<p>At this point I started to wonder whether the AreaId and AreaPath fields were as intricately tied as I thought they were.  After all, I didn’t have any rules saying to update one when the other changed.  (<a href="http://msdn.microsoft.com/en-us/library/ms194971.aspx">The documentation</a> kinda implies this but doesn’t spell out the mechanism.)  So I decided to test at the object model level: <a href="http://richardberg.net/blog/?p=38">Get-TfsServer OM wrapper</a> to the rescue!</p>
<p><span style="FONT-FAMILY: Courier New">PS C:\Users\rberg&gt; $tfs = get-tfsserver njtfs –all<br />
</span><span style="FONT-FAMILY: Courier New">PS C:\Users\rberg&gt; $bug = $tfs.wit.GetWorkItem(1333)<br />
</span><span style="FONT-FAMILY: Courier New">PS C:\Users\rberg&gt; $bug.AreaId; $bug.IterationId<br />
84<br />
</span><span style="FONT-FAMILY: Courier New">84 </span> </p>
<p> </p>
<p><span style="FONT-FAMILY: Courier New">PS C:\workspaces\ws1&gt; $bug.AreaPath; $bug.IterationPath<br />
Test-ConchangoV2\test<br />
</span><span style="FONT-FAMILY: Courier New">Test-ConchangoV2\Release 1\Sprint 4</p>
<p></span><span style="FONT-FAMILY: Courier New">PS C:\Users\rberg&gt; $bug.fields | where { $_.name.contains("Validation") } | select value<br />
Value<br />
-----<br />
</span><span style="FONT-FAMILY: Courier New">Restricted Restricted                                                                                                                      </span> </p>
<p><span style="FONT-FAMILY: Courier New">PS C:\Users\rberg&gt; $bug.AreaId = 104; $bug.IterationId = 91<br />
</span><span style="FONT-FAMILY: Courier New">PS C:\workspaces\ws1&gt; $bug.AreaPath; $bug.IterationPath<br />
Test-ConchangoV2\test<br />
</span><span style="FONT-FAMILY: Courier New">Test-ConchangoV2\Release 1\Sprint 4</span> </p>
<p><span style="FONT-FAMILY: Courier New">PS C:\Users\rberg&gt; $bug.fields | where { $_.name.contains("Validation") } | select value<br />
</span><span style="FONT-FAMILY: Courier New">Value<br />
-----<br />
</span><span style="FONT-FAMILY: Courier New">Restricted<br />
Restricted</span></p>
<p>Nope, not a synchronization issue between path on the form &lt;–&gt; underlying ID.  Looks like I really do need to tweak Gregg’s advice.  All you need is a corresponding WHENNOT rule to cancel out each WHEN rule as it’s no longer needed.  Here’s what the hidden validator for Area looks like now:</p>
<div id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:d8046de1-8093-4b80-9d4e-3fd32f093d17" class="wlWriterEditableSmartContent" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD type</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">String</span><span style="color: #800000;">"</span><span style="color: #000000;"> name</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Product Area - Validation</span><span style="color: #800000;">"</span><span style="color: #000000;"> refname</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Coatue.ProductAreaValidation</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Hidden field used to validate Product Area</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">HELPTEXT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">WHEN field</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">System.AreaId</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">84</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">COPY from</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">value</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Restricted</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">WHEN</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">WHENNOT field</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">System.AreaId</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">84</span><span style="color: #800000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">COPY from</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">value</span><span style="color: #800000;">"</span><span style="color: #000000;"> value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Ok</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">WHENNOT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">PROHIBITEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">LISTITEM value</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">Restricted</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">PROHIBITEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></p>
<p>Make the same change for Iteration and you’re golden.</p></div>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/17/how-to-enforce-a-rule-on-areaiteration-path/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What does Get-TfsServer –All do, exactly?</title>
		<link>http://richardberg.net/blog/2009/02/17/what-does-get-tfsserver-all-do-exactly/</link>
		<comments>http://richardberg.net/blog/2009/02/17/what-does-get-tfsserver-all-do-exactly/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 16:59:32 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=38</guid>
		<description><![CDATA[PS C:\workspaces\ws1&#62; help tfserver –full SYNTAX     Get-TfsServer [-Name] &#60;String&#62; [-Credential &#60;PSCredential&#62;] [-All] [&#60;Common     Parameters&#62;]        Get-TfsServer -Path &#60;String&#62; [-Credential &#60;PSCredential&#62;] [-All] [&#60;CommonPa     rameters&#62;] ...   -All     Get Team Foundation Server object with the extended properties   Required?                    false     Position?                    named     Default value     Accept pipeline input?       false     Accept wildcard [...]]]></description>
			<content:encoded><![CDATA[<p><span style="FONT-FAMILY: Courier New">PS C:\workspaces\ws1&gt; help tfserver –full</p>
<p><span style="font-family: Courier New;">SYNTAX<br />
    Get-TfsServer [-Name] &lt;String&gt; [-Credential &lt;PSCredential&gt;] [-All] [&lt;Common<br />
    Parameters&gt;] </span></span>  </p>
<p><span style="FONT-FAMILY: Courier New">    Get-TfsServer -Path &lt;String&gt; [-Credential &lt;PSCredential&gt;] [-All] [&lt;CommonPa<br />
    rameters&gt;]</p>
<p><span style="font-family: Courier New;">...</p>
<p></span></span>  <span style="FONT-FAMILY: Courier New">-All<br />
    Get Team Foundation Server object with the extended properties</p>
<p></span><span style="FONT-FAMILY: Courier New">  Required?                    false<br />
    Position?                    named<br />
    Default value<br />
    Accept pipeline input?       false<br />
    Accept wildcard characters?  false</p>
<p><span style="font-family: Courier New;">...</span></span> </p>
<p>Not the greatest help text ever written, I know.  Oh well, there’s a lot more room on this blog anyway :)</p>
<p>First the basics: Get-TfsServer and Get-TfsWorkspace (aliases: tfserver, tfworkspace) are intended to be “official” versions of James Manning’s <a href="http://blogs.msdn.com/jmanning/archive/2006/09/28/776141.aspx">get-tfs.ps1</a> and <a href="http://blogs.msdn.com/jmanning/archive/2006/09/30/777938.aspx">get-workspace.ps1</a> cmdlets.  To incorporate them into the main snap-in, Hyung ported them to C# and standardized the parameters.  Both will now accept either –Path or –Name (but not both).  For tfserver, –Name is the default [position = 1] and all others are named, while the reverse is true for tfworkspace, reflecting what we felt was the most common use of each.  Bottom line, these will all work:</p>
<p><span style="FONT-FAMILY: Courier New">&gt; $tfs = get-tfsserver njtfs<br />
&gt; $tfs = get-tfsserver –path .<br />
&gt; $ws = get-tfsworkspace .<br />
&gt; $ws = get-tfsworkspace –name njtfs<br />
&gt; $ws = get-tfsworkspace –servername .</span></p>
<p>There are also new parameters like –Credential on tfserver, and –Computer and –Owner on tfworkspace, which behave more or less how you’d expect.  In short, you can use tfserver to interface TFS with Powershell’s built-in credential management features, as well as tfworkspace to query for the Workspace object that represents remote workspaces you may not even own.</p>
<p>So back to the original topic.  The –All switch turns on the special script-friendly behavior that James pioneered and <a href="http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx">I later extended</a>.</p>
<p><a href="http://richardberg.net/blog/wp-content/uploads/2009/02/addtypeextensions.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="AddTypeExtensions" src="http://richardberg.net/blog/wp-content/uploads/2009/02/addtypeextensions-thumb.png" border="0" alt="AddTypeExtensions" width="674" height="426" /></a></p>
<p>As you can see there are a few differences between the final shipping behavior and the various get-tfs.ps1 scripts floating on the web:</p>
<ul>
<li>Once you choose –All, every TFS assembly is loaded immediately, rather than on-demand as you use the ScriptProperties.  The idea here is to “fail early” rather than introduce a ticking bomb into downstream scripts that may depend on these objects.</li>
<li>The types that we import as NoteProperties are prefixed with the same shorthand as the ScriptProperties, plus an underscore.  Even though we continue to weed out types that aren’t useful (anything private, an exception, or an event) there are still a ton to sort thru; this tweak helps segregate the huge list into “namespaces” that are still marginally navigable with Tab completion.</li>
<li>C# is a much uglier language to do this work than Powershell!</li>
</ul>
<p>All in all, you can now do cool things like:</p>
<p><span style="FONT-FAMILY: Courier New">PS C:\workspaces\ws1&gt; $tfs = get-tfsserver njtfs -all<br />
<span style="font-family: Courier New;">PS C:\workspaces\ws1&gt; $tfs.vcs.GetChangeset(1234) </span></span> </p>
<p><span style="FONT-FAMILY: Courier New">Changes Owner                  CreationDa Comment<br />
   etId                                te<br />
------- -----                  ---------- -------<br />
   1234 COATUECAP\LDeGrazia    10/27/2007</span></p>
<p><span style="FONT-FAMILY: Courier New">PS C:\workspaces\ws1&gt; new-object $tfs.VCS_ChangesetVersionSpec 1234 </span></p>
<p><span style="FONT-FAMILY: Courier New">                            ChangesetId DisplayString<br />
                            ----------- -------------<br />
                                   1234 C1234</span></p>
<p><span style="FONT-FAMILY: verd">So why not have this option switched on permanently?  The vanilla <strong>TeamFoundationServer</strong> object isn’t very useful on its own; the entire point of James’ original wrapper was to quickly access the <strong>VersionControlServer </strong>and similar objects.  Well first of all, it’s noticeably slower – on my machine, testing a “cold” Powershell console, the cmdlet takes 3 seconds with the default parameters and 6 seconds with –All.  We’re loading more assemblies than ever, not to mention deep reflection on each one (in order to test an upcast and a string comparison, not exactly speedy operations in themselves).  More importantly, the extra properties add enormous clutter to the objects when not needed.  And I think you’ll be more likely to use those TFS objects in vanilla form in your future scripts.  For example, most of the version control cmdlets in the Fall 2008 suite take a TeamFoundationServer as either pipeline input or a named parameter.  I’m sure whatever Microsoft is cooking up for the next batch will include even more interactivity and flow between cmdlets.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/17/what-does-get-tfsserver-all-do-exactly/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to prevent people from opening new bugs</title>
		<link>http://richardberg.net/blog/2009/02/17/how-to-prevent-people-from-opening-new-bugs/</link>
		<comments>http://richardberg.net/blog/2009/02/17/how-to-prevent-people-from-opening-new-bugs/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 15:12:29 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Work Item Tracking]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=35</guid>
		<description><![CDATA[We’re in the middle of transitioning to a new team project.&#160; On the source control side, Microsoft has made a huge investment to support arbitrary renames throughout the tree.&#160; No reason to mess with TFS-&#62;TFS migration when I can move the native items!&#160; On the other hand, migrating work items across team projects is notoriously [...]]]></description>
			<content:encoded><![CDATA[<p>We’re in the middle of transitioning to a new team project.&#160; On the source control side, Microsoft has made a huge investment to support arbitrary renames throughout the tree.&#160; No reason to mess with <a href="http://www.codeplex.com/tfstotfsmigration">TFS-&gt;TFS migration</a> when I can move the native items!&#160; On the other hand, migrating work items across team projects is notoriously tricky.&#160; I decided it would be easiest to steadily phase out the work items remaining in the old project while forcing people to open new issues in the new project.</p>
<p>Being relatively new to WIT customization, the answer wasn’t immediately obvious.&#160; TFS doesn’t let you stick an ALLOWEDVALUES rule on fields like <strong>System.CreatedDate</strong> that the system populates on creation.&#160; And anything you stick on a user-editable field will inevitably block users from navigating an existing work item through the rest of its legitimate workflow.&#160; The path I took was modifying the initial transition from “”.&#160; XML excerpt:</p>
<p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:91642765-bf45-46ed-90d9-05f9f2fe557a" class="wlWriterEditableSmartContent">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">        </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TRANSITION from</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;&quot;</span><span style="color: #000000;"> to</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">Active</span><span style="color: #800000;">&quot;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">REASONS</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">REASON value</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">Build Failure</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">DEFAULTREASON value</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">New</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">REASONS</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELDS</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD refname</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">Microsoft.VSTS.Common.ActivatedBy</span><span style="color: #800000;">&quot;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">COPY from</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">currentuser</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">VALIDUSER </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">REQUIRED </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD refname</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">Microsoft.VSTS.Common.ActivatedDate</span><span style="color: #800000;">&quot;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">SERVERDEFAULT from</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">clock</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD refname</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">System.AssignedTo</span><span style="color: #800000;">&quot;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">DEFAULT from</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">currentuser</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FIELD refname</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">System.Title</span><span style="color: #800000;">&quot;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ALLOWEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
                </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">LISTITEM value</span><span style="color: #000000;">=</span><span style="color: #800000;">&quot;</span><span style="color: #800000;">Before 2009-02-12</span><span style="color: #800000;">&quot;</span><span style="color: #000000;"> </span><span style="color: #000000;">/&gt;</span><span style="color: #000000;">
              </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">ALLOWEDVALUES</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
            </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELD</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FIELDS</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">TRANSITION</span><span style="color: #000000;">&gt;</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
</p>
<p>Most of this comes from the stock MSF Agile v4.2 template; the <strong>System.Title</strong> field with the strange rule toward the end is my addition.&#160; Doesn’t really matter what you put in the value, so long as you don’t tell your users what it is :)</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/17/how-to-prevent-people-from-opening-new-bugs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unlocking other people’s files. Yes, again.</title>
		<link>http://richardberg.net/blog/2009/02/14/unlocking-other-peoples-files-yes-again/</link>
		<comments>http://richardberg.net/blog/2009/02/14/unlocking-other-peoples-files-yes-again/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 05:51:33 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=16</guid>
		<description><![CDATA[You’re going about your business, trying to refactor some code, when suddenly things come to a crashing halt.  “The item foo.cs is locked for check-out by DOMAIN\user in workspace ws1.”  Since Microsoft shipped the first public betas of TFS in 2005, there have probably been more blog posts on this pitfall than any other -- [...]]]></description>
			<content:encoded><![CDATA[<p>You’re going about your business, trying to refactor some code, when suddenly things come to a crashing halt.  “The item foo.cs is locked for check-out by DOMAIN\user in workspace ws1.”  Since Microsoft shipped the first public betas of TFS in 2005, there have probably been more blog posts on this pitfall than any other -- I’ll pick on <a href="http://blogs.msdn.com/jmanning/archive/2006/01/26/518175.aspx">James</a> for an example.  The frustration also spawned Status Sidekick (now part of <a href="http://www.attrice.info/cm/tfs/index.htm">TFS Sidekicks</a>), the first 3rd-party TFS tool to my knowledge. </p>
<p>The arrival of the <a href="http://blogs.msdn.com/bharry/archive/2008/10/01/preview-of-the-next-tfs-power-tools-release.aspx">Fall 2008 Powertools</a> hinted at yet another possibility based on Powershell.  Script-friendly unlocking is particularly enticing for scenarios like the one I found myself in last week: transitioning a team from exclusive checkouts to an edit-merge-commit workflow.  Turning off the exclusive settings on the Team Project is the obvious first step, but what to do about the hundreds of existing pending changes?  I can’t ask everyone to suddenly checkin their work (which may be far from ready to share, or even build), but I also can’t reorganize the tree unless every lock is removed.  Thus:</p>
<div id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:7f2b063a-6582-4bc3-822b-3b7b4900218b" class="wlWriterEditableSmartContent" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">
<pre style="background-color:White;;overflow: auto;">
<div><!--

Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/

--><span style="color: #000000;">del temp.hat </span><span style="color: #800080;">2</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> $</span><span style="color: #0000FF;">null</span><span style="color: #000000;">
</span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> ($pendingSet </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;">-</span><span style="color: #000000;">tfspendingchange </span><span style="color: #000000;">-</span><span style="color: #000000;">user </span><span style="color: #000000;">*</span><span style="color: #000000;">)
{
    $workspace </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">"</span><span style="color: #800000;">'</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> $pendingSet.Name </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">";</span><span style="color: #800000;">'</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> $pendingSet.OwnerName
    $pendingSet.PendingChanges </span><span style="color: #000000;">|</span><span style="color: #000000;"> </span><span style="color: #0000FF;">where</span><span style="color: #000000;"> {$_.IsLock} </span><span style="color: #000000;">|</span><span style="color: #000000;"> </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> {
      $item </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">"</span><span style="color: #800000;">'</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> $_.ServerItem </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">'</span><span style="color: #800000;">"</span><span style="color: #800000;">'</span><span style="color: #000000;">
      </span><span style="color: #800000;">"</span><span style="color: #800000;">lock /lock:none /workspace:$workspace $item</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">|</span><span style="color: #000000;"> </span><span style="color: #0000FF;">out</span><span style="color: #000000;">-</span><span style="color: #000000;">file temp.hat </span><span style="color: #000000;">-</span><span style="color: #000000;">append
    }
}
tf </span><span style="color: #800000;">"</span><span style="color: #800000;">@temp.hat</span><span style="color: #800000;">"</span><span style="color: #000000;">
del temp.hat
</span></div>
</pre>
<p><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>This isn’t the cleanest solution in the world.  You couldn’t just wire up the “find all locks in the system” example I provided for Brian’s post to a Remove-TfsLock cmdlet -- even if the Power Tools provided one (which they don’t yet).  By convention, <a href="http://richardberg.net/blog/?p=30">a pipeline of TFS cmdlets transmits QualifiedItems</a><em></em>, but to unlock an arbitrary item we need two additional pieces of information from the <em>PendingSet</em> object.  So we fall back on good old procedural loops around <a href="http://blogs.msdn.com/phkelley/archive/2008/11/12/everything-you-ever-wanted-to-know-about-locks.aspx">tf lock</a>.</p>
<p>Could we improve the script?  Sure.  We could batch ~12 items at a time* for a better performance, though the gain is not nearly as big as using a @hatfile in the first place.  We could also be a little more robust.  Get-TfsPendingChange returns a full PendingSet in the general case, but <a href="http://richardberg.net/blog/?p=19">sometimes the return type decays to a simple PendingChange[]</a>.  If our query returns exactly 1 workspace, then our logic for populating $workspace won’t work. </p>
<p>Of course, we could also do a lot worse!  I originally tried to add the wrapper quotes in-place, but quickly got into syntax trouble.  After consulting <a href="http://blogs.msdn.com/powershell/archive/2006/07/15/Variable-expansion-in-strings-and-herestrings.aspx">the relevant Powershell blog post</a> I <em>eventually</em> got it right, but it was an unreadable mess.  For example, line 4 read:</p>
<p><span style="font-family: Courier New;">$workspace = "`"$($pendingSet.Name)`";$($pendingSet.OwnerName)"</span></p>
<p>Yuck.</p>
<p>*<a href="http://social.msdn.microsoft.com/Forums/en-US/tfsversioncontrol/thread/f4c283ef-8b94-4103-ac09-3e1d819906e2/">3200 character limit</a> on each line of a tf.exe script file; TFS paths are 260 chars max</p>
<ul></ul>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/14/unlocking-other-peoples-files-yes-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Get-TfsPendingChange doesn’t always return pending changes</title>
		<link>http://richardberg.net/blog/2009/02/14/get-tfspendingchange-doesnt-always-return-pending-changes/</link>
		<comments>http://richardberg.net/blog/2009/02/14/get-tfspendingchange-doesnt-always-return-pending-changes/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 05:50:04 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=19</guid>
		<description><![CDATA[Depending on how extensively you’ve played with the new TFS powershell cmdlets, you may have noticed one oddity: Get-TfsPendingChange doesn’t always return a PendingChange[] array. PS C:\workspaces\ws1\MAIN&#62; tfstatus Version CreationDa ChangeType      ServerItem                 te ------- ---------- ----------      ----------    7415  2/13/2009 Edit            $/Research Platform (R...rLife.v2 Web.vssscc    8024  2/13/2009 Edit            $/Research Platform (R...ckerLife.v2 Web.sln PS [...]]]></description>
			<content:encoded><![CDATA[<p>Depending on how extensively you’ve played with the new TFS powershell cmdlets, you may have noticed one oddity: Get-TfsPendingChange doesn’t always return a PendingChange[] array.</p>
<p><span style="font-family: courier new">PS C:\workspaces\ws1\MAIN&gt; tfstatus </span></p>
<p><span style="font-family: courier new">Version CreationDa ChangeType      ServerItem<br />
                te<br />
------- ---------- ----------      ----------<br />
</span><span style="font-family: courier new">   </span><span style="font-family: courier new">7415  2/13/2009 Edit            $/Research Platform (R...rLife.v2 Web.vssscc<br />
</span><span style="font-family: courier new">   8024  2/13/2009 Edit            $/Research Platform (R...ckerLife.v2 Web.sln </span></p>
<p><span style="font-family: courier new">PS C:\workspaces\ws1\MAIN&gt; tfstatus -user rwilliams </span></p>
<p><span style="font-family: courier new">Name                Computer            OwnerName           Type<br />
----                --------            ---------           ----<br />
CoatueResearch      CMXP123             COATUECAP\rwilliams Workspace<br />
BuildTypeEditor_... CMXP123             COATUECAP\rwilliams Workspace </span></p>
<p>The second command is actually returning a PendingSet[] array.  Each PendingSet contains a PendingChange[] array that’s specific to a particular workspace or shelveset, plus some metadata about the workspace or shelveset itself.</p>
<p>What gives?  Actually, the underlying APIs <em>always</em> return PendingSet[].  If Get-TfsPendingChange merely pushed the result of the API call onto the pipeline, as most other TFS cmdlets do, then every time you ran it you’d get something more like this:</p>
<p><span style="font-family: courier new">PS C:\workspaces\ws1\MAIN&gt; $ws = get-tfsworkspace .<br />
</span><span style="font-family: courier new">PS C:\workspaces\ws1\MAIN&gt; $ws.QueryPendingSets($null, $ws.Name, $ws.OwnerName, $false) </span></p>
<p><span style="font-family: courier new">Name                Computer            OwnerName           Type<br />
----                --------            ---------           ----<br />
ws1                 RICHARD490          COATUECAP\rberg     Workspace</span></p>
<p>…which is clearly not as useful as the output of the first “tfstatus” example above.  Furthermore, people only use Get-TfsPendingChange (and its tf.exe predecessor) to query across multiple workspaces 5% of the time, if that.  I decided to optimize for the 95% case.  That meant checking to see how many PendingSets were returned from the server, pushing its PendingChange[] array onto the pipeline instead if there was only 1.</p>
<p>Note: the <a href="http://msdn.microsoft.com/en-us/library/bb138979.aspx">QueryShelvedChanges API</a> we use takes a single shelveset.  Unfortunately that means the cmdlet does not support queries like “show me everyone who has shelved $/project/foo.cs” in a single server call.  (QueryShelvedChanges() does have the necessary overloads; we simply inherited this limitation from tf.exe and didn’t have time to rewrite it).  Thus, whenever you specify the –shelveset parameter to Get-TfsPendingChange, you are assured to get a PendingChange[].</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/14/get-tfspendingchange-doesnt-always-return-pending-changes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Birth of a power tool: QualifiedItem and the Powershell pipeline</title>
		<link>http://richardberg.net/blog/2009/02/14/birth-of-a-power-tool-qualifieditem-and-the-powershell-pipeline/</link>
		<comments>http://richardberg.net/blog/2009/02/14/birth-of-a-power-tool-qualifieditem-and-the-powershell-pipeline/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 05:38:03 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=30</guid>
		<description><![CDATA[When I was pondering what the oft-requested Powershell interface should look like, one of the main goals was to offer the power of that raw version control API while being easier to use than tf.exe.&#160; Both existing approaches were too clumsy for many of the tasks customers commonly request.&#160; The canonical example seems to be [...]]]></description>
			<content:encoded><![CDATA[<p>When I was pondering what the oft-requested Powershell interface should look like, one of the main goals was to offer the power of that raw version control API while being <em>easier </em>to use than tf.exe.&#160; Both existing approaches were too clumsy for many of the tasks customers commonly request.&#160; The canonical example seems to be “how do I add the items modified in changeset to a label.”&#160; I once answered a forum post with a <a href="http://blogs.msdn.com/richardb/archive/2007/02/21/powershell-example-adding-items-from-a-changeset-to-a-label.aspx">Powershell function targeting the API</a>.&#160; Fairly clean, but not exactly concise.&#160; My coworker Mohamed answered a different customer with a <a href="http://blogs.msdn.com/mohamedg/archive/2008/03/27/label-items-in-a-changeset-using-tf-label.aspx">tf-based solution</a>.&#160; Good display of his ingenuity, but when I’m using development tools I just want to be efficient, not clever.</p>
<p><font face="Courier New">for /f &quot;usebackq tokens=2 delims=$&quot; %i in (`tf changeset 1256 /i ^| find &quot;$/&quot;`) do tf label goodbuild $%i;C1256 </font></p>
<p>Yuck (not to mention slow).</p>
<p>And so an idea was born.&#160; Much progress came “free” from Powershell itself: it’s far, far easier to script than cmd.exe is, and when scripting fails, you can drop right into the TFS .Net API without missing a beat.&#160; Some more came from conventions -- standardized verbs, standardized parameters, etc. – and examining how tf commands should be merged, split, or otherwise molded to fit them.&#160; (I admit to being dragged kicking &amp; screaming through this process!)&#160; But ultimately, the biggest value would come from the ability to seamlessly string together multiple commands.</p>
<p>How to reconcile these goals?&#160; To retain their power, cmdlets must output native API objects wherever possible.&#160; The user receives the full data set in structured, strongly-typed form, including the ability to call properties and methods.&#160; Yet for simplicity, the input parameters are rarely more than a couple strings.&#160; In the pipeline I conceived, a form of weakly-typed items are the “glue” that allow rich outputs to feed limited inputs.</p>
<p>Recall that a <a href="http://richardberg.net/blog/?p=17">QualifiedItem</a> represents a simple tuple of {path, deletionID, versionspec}.&#160; By qualifying individual items on the command line, tf.exe commands let you attach a deletion ID and/or versionspec directly to each.&#160; This is the most general way to control the underlying API that tf offers.</p>
<p>The prototype I wrote in early 2007 was just a crude layer on top of tf.exe plus a “magic” <strong>extract-items.ps1</strong> script that could turn any suitable object in the public API back into tf’s internal format – QualifiedItem[].&#160; It worked like this:</p>
<p><font face="Courier New">tfps changeset 1256 | extract-items | tfps label goodbuild</font></p>
<p>The syntax was nowhere near idiomatic Powershell; the capabilities unlocked by inserting magic scripts in various places were not at all discoverable.&#160; But I was hooked.&#160; Henceforth, I used this little shell as my daily work environment for testing &amp; debugging TFS.&#160; (Direct programmatic access to the data returned by any tf.exe command sure sped things up.)&#160; All the while I collected real-world use cases, tightened/tweaked/fixed, and shopped the demo around in search of a sympathetic ear.&#160; As anyone who’s worked in a huge organization knows, nothing moves without a lot of pushing…and suffice to say that wasn’t my strong suit.&#160; Eventually I did find myself in <a href="http://blogs.msdn.com/bharry/default.aspx">Brian’s</a> office in spring 2008.&#160; He gave me a green light, conditioned on fixing the fit &amp; finish to <a href="http://www.microsoft.com/technet/scriptcenter/resources/interviews/snover.mspx">Jeffrey’s</a> satisfaction.</p>
<p>Redesigning the cmdlets based on PS conventions wasn’t a technical challenge per se (modulo the kicking :)).&#160; But having to stick a magic cmdlet in between each pipe wasn’t going to fly, no matter its pretty new name <strong>Select-TfsItem</strong> and incorporation into the main (read: discoverable) C# snap-in.&#160; The final innovation came from <a href="http://www.leeholmes.com/blog/default.aspx">Lee Holmes</a>, who suggested we use Powershell’s built-in type coercion to help the pipeline link up automatically: all you need is a constructor on the input type with a single parameter of the output type.&#160; <a href="http://social.msdn.microsoft.com/en-US/profile/?user=Hyung%20S%20Kwon&amp;referrer=http%3A//social.msdn.microsoft.com/Forums/en-US/tfspowertools/thread/d573d0e2-0a2f-4c36-b0d5-a62542161c4d#sort=recent&amp;page=0&amp;filter=allcontent">Hyung</a> implemented it as QualifiedItemSpec:</p>
<p><a href="http://richardberg.net/blog/wp-content/uploads/2009/02/qualifieditemspec.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="qualifieditemspec" border="0" alt="qualifieditemspec" src="http://richardberg.net/blog/wp-content/uploads/2009/02/qualifieditemspec-thumb.png" width="674" height="478" /></a> </p>
</p>
<p>A QualifiedItemSpec represents the collection of QIs extracted from a single input object.&#160; Cmdlets then take an array of these collections as input.&#160; Where appropriate, some cmdlets process each collection as a single entity and yield control; most, however, batch up the entire list of lists and execute a single server call in EndProcessing().&#160; There are also subtleties in the way different object types are coerced into the much weaker QI type.&#160; In the future we’ll look at the various ways such “chunks” of data stream along a TFS pipeline.</p>
<p>Select-TfsItem remains in the toolkit for completeness, but you can see in Reflector that its implementation has degenerated to nothing; the QualifiedItemSpec[] parameter does all the heavy lifting.&#160; It’s still useful for quickly dumping the contents of a huge object like PendingSet into the console or a file.&#160; Meanwhile, let’s see what the final version of our “label a changeset” script looks like:</p>
<p><font face="Courier New">Get-TfsChangeset 1256 | New-TfsLabel goodbuild</font></p>
<p>Easy as pie!&#160; Except for the fact that *-TfsLabel commands haven’t actually shipped :)&#160; I coded cmdlets replacing nearly all of tf.exe before leaving, and I know that power tools development remain in good hands, so I’ll leave you with the above example in the hopes it’ll work after the next release or two.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/14/birth-of-a-power-tool-qualifieditem-and-the-powershell-pipeline/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Advanced tf.exe syntax, or what on earth is a QualifiedItem?</title>
		<link>http://richardberg.net/blog/2009/02/13/advanced-tfexe-syntax-or-what-on-earth-is-a-qualifieditem/</link>
		<comments>http://richardberg.net/blog/2009/02/13/advanced-tfexe-syntax-or-what-on-earth-is-a-qualifieditem/#comments</comments>
		<pubDate>Fri, 13 Feb 2009 23:41:40 +0000</pubDate>
		<dc:creator>RichardB</dc:creator>
				<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://richardberg.net/blog/?p=17</guid>
		<description><![CDATA[An item that’s qualified, duh :)&#160; Real answer: it comes from tf.exe versionspec syntax.&#160; Let’s demonstrate by example: 1) tf get foo.cs&#160; # not qualified – falls back to default 2) tf get foo.cs /version:1234&#160; # not qualified – falls back to /version parameter 3) tf get foo.cs;1234&#160; # qualified 4) tf get foo.cs;X56&#160; # [...]]]></description>
			<content:encoded><![CDATA[<p>An item that’s qualified, duh :)&#160; Real answer: it comes from <a href="http://msdn.microsoft.com/en-us/library/56f7w6be.aspx">tf.exe versionspec syntax</a>.&#160; Let’s demonstrate by example:</p>
<p><font face="Courier New">1) tf get foo.cs&#160; # not qualified – falls back to default      <br />2) tf get foo.cs /version:1234&#160; # not qualified – falls back to /version parameter       <br />3) tf get foo.cs;1234&#160; # qualified       <br />4) tf get foo.cs;X56&#160; # qualified with deletion ID       <br /></font><font face="Courier New">5) tf get foo.cs;X56;LmyLabel&#160; # qualified with both – betcha didn’t know this was possible      <br />6) tf get foo.cs;1234 bar.cs;X56 baz.cs;789 *quux* /version:LmyLabel&#160; # mix &amp; match<font face="Courier New">        <br />7) tf history foo.cs;1234~5678&#160; # qualified with two versions         <br />8) tf history foo.cs;~5678&#160; # default versionFrom, qualified versionTo         <br />9) tf history foo.cs;5678&#160; # same as above         <br />10) tf history foo.cs;1234~&#160; # qualified versionFrom, default versionTo         </p>
<p></font></font></p>
<p><font face="ver">“Qualifying” an item means telling tf.exe exactly what version to operate on.&#160; We do this by combining a <a href="http://blogs.msdn.com/richardb/archive/2007/09/15/tfs-version-control-concepts-3-item-versions-and-the-two-meanings-of-changeset.aspx">name</a> with a <a href="http://blogs.msdn.com/adamsinger/archive/2005/11/28/497645.aspx">versionspec</a>.&#160; Most tf commands take qualified items as their main piece of input.&#160; (Commands that don’t include things like Checkin, Shelve, Undo, or Status that need to use whatever’s already in the workspace; and of course ones like Workfold or Configure that don’t touch the repository at all).</font></p>
<h2>Implementation</h2>
<p>If you examine tf.exe in Reflector, you’ll see that <em>QualifiedItem</em> is a simple class encapsulating a Path, a DeletionId, and a VersionSpec[] array.&#160; The array almost always has just one member; only a few commands take two versionspecs, and none takes more.&#160; Most items have a deletion ID of 0 to indicate “not deleted.”</p>
<p><a href="http://richardberg.net/blog/wp-content/uploads/2009/02/qualifieditem.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="qualifieditem" border="0" alt="qualifieditem" src="http://richardberg.net/blog/wp-content/uploads/2009/02/qualifieditem-thumb.png" width="674" height="467" /></a> </p>
<p>To see how it’s used, start by drilling into the <em>VersionControlCommand</em> class to find the methods named ParseQualifiedItem().&#160; I’ll leave this journey as an exercise for the reader.&#160; Suffice to say here’s what you’d find:</p>
<h2>Behavior - single versionspec</h2>
<p>The goal is to give the user fine-grained control over tf operations.&#160; Examples #1-4 are straightforward.&#160; #5 is a quirk of syntax with no real import.&#160; #6 shows the power of this approach: a single command pulls different versions of foo, bar, baz, while applying a fallback versionspec to all non-qualified items – in this case, the set intersection of all files in the current directory matching the *quux* pattern with the contents of the “myLabel” label.</p>
<p>If not specified by a /version parameter, the default versionspec is T.</p>
<h2>Behavior – version range (2 versionspecs)</h2>
<p>Example #7 is straightforward.&#160; #8-10 show off some syntax sugar.&#160; When you have a command that expects a version range, you need only type one end of the range if the default suffices for the other.&#160; The default versionFrom spec is C1 and the default versionTo is T.</p>
<p>Note that there is no opportunity for fallback.&#160; You can use the /version parameter or qualified items, but not both.&#160; All of the commands that operate on a version range have additional limitations that make the general syntax seen in #6 impossible.</p>
<ul>
<li>Diff – takes exactly one item with a version range (<font face="Courier New">foo.cs;10~20</font>), or two items with one versionspec each (<font face="courier new">foo.cs;10 bar.cs;20</font>), but no other variations. </li>
<li>History – takes exactly one item with a version range.</li>
<li>Merge – takes exactly two items.&#160; The first one has a version range and the second has no version. </li>
<li>Rollback – introduces some new parameters that are beyond the scope of this post, not to mention still subject to change before TFS 2010’s release.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://richardberg.net/blog/2009/02/13/advanced-tfexe-syntax-or-what-on-earth-is-a-qualifieditem/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

