<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Jason Stangroome</title>
		<link>/</link>
		<description>Recent content on Jason Stangroome</description>
		<generator>Hugo</generator>
		<language>en</language>
		
		
		
		
			<lastBuildDate>Sat, 11 Jul 2026 00:00:00 +0000</lastBuildDate>
		
			<atom:link href="/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>My Big Tech Exodus</title>
				<link>/2026/07/11/big-tech-exodus/</link>
				<pubDate>Sat, 11 Jul 2026 00:00:00 +0000</pubDate>
				<guid>/2026/07/11/big-tech-exodus/</guid>
				<description>&lt;p&gt;Over the last two years I&amp;rsquo;ve recovered the capacity in my personal life to think about my dependency&#xA;on the big tech companies and to start exploring and migrating to alternatives.&lt;/p&gt;&#xA;&lt;p&gt;Part of my motivations are to be voting with my wallet against enshittification, partly in response to increasing&#xA;geopolitical uncertainty, and partly to be an example that it&amp;rsquo;s possible to reduce the amount of big tech in your life.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Linux Desktop</title>
				<link>/2026/06/26/linux-desktop/</link>
				<pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate>
				<guid>/2026/06/26/linux-desktop/</guid>
				<description>&lt;p&gt;I replaced Windows 11 on all my home and work machines with Linux about 6 months&#xA;ago and I am not going back.&lt;/p&gt;&#xA;&lt;p&gt;I had been a Windows user at home and work for at least 30 years, starting with&#xA;Windows 3.1, and being an early adopter of NT 4.0 Workstation, XP 64-bit, and&#xA;all the way through to Windows 11, occasionally running the Betas and Release&#xA;Candidates. Windows is a kind of muscle memory for me.&lt;/p&gt;</description>
			</item>
			<item>
				<title>1Password and SSH_ASKPASS</title>
				<link>/2025/10/10/1password-ssh_askpass/</link>
				<pubDate>Fri, 10 Oct 2025 00:00:00 +0000</pubDate>
				<guid>/2025/10/10/1password-ssh_askpass/</guid>
				<description>&lt;p&gt;1Password has an excellent solution for managing SSH keys securely using their&#xA;&lt;a href=&#34;https://developer.1password.com/docs/ssh/agent/&#34;&gt;1Password SSH Agent&lt;/a&gt;.&#xA;However I interact with a few devices that either require keyboard-interactive&#xA;multi-factor authentication (MFA) or force the use of a password instead of&#xA;accepting keys or certificates.&lt;/p&gt;&#xA;&lt;p&gt;Thankfully, through the use of the&#xA;&lt;a href=&#34;https://developer.1password.com/docs/cli&#34;&gt;1Password CLI&lt;/a&gt;,&#xA;the &lt;a href=&#34;https://man.openbsd.org/ssh#SSH_ASKPASS&#34;&gt;&lt;code&gt;SSH_ASKPASS&lt;/code&gt;&lt;/a&gt;&#xA;environment variable, and a little shell script, we can use&#xA;1Password to fill in these MFA tokens and passwords too.&lt;/p&gt;&#xA;&lt;p&gt;The script, &lt;code&gt;op_ssh_askpass&lt;/code&gt; further below, is expected to be used as follows:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Understanding automated certificate options</title>
				<link>/2025/05/16/understanding-automated-certificate-options/</link>
				<pubDate>Fri, 16 May 2025 00:00:00 +0000</pubDate>
				<guid>/2025/05/16/understanding-automated-certificate-options/</guid>
				<description>&lt;p&gt;In April 2025, &lt;a href=&#34;https://groups.google.com/a/groups.cabforum.org/g/servercert-wg/c/bvWh5RN6tYI&#34;&gt;CA/B Forum ballot SC-081v3&lt;/a&gt;&#xA;was &lt;a href=&#34;https://groups.google.com/a/groups.cabforum.org/g/servercert-wg/c/9768xgUUfhQ&#34;&gt;passed&lt;/a&gt;&#xA;to reduce the maximum certificate validity to 47 days by the 15th of March 2029.&#xA;The first step will be to reduce the maximum validity period to 200 days by the 15th of March 2026.&lt;/p&gt;&#xA;&lt;p&gt;There has been &lt;a href=&#34;https://github.com/cabforum/servercert/pull/553&#34;&gt;a great deal of debate&lt;/a&gt; on whether this will be useful or, in some environments, even feasible.&lt;/p&gt;&#xA;&lt;p&gt;Regardless of our personal opinions on the matter, I think its worth clarifying the options we have today for certificate issuance and renewal. I believe that if you&amp;rsquo;re&#xA;aware of all the options, some scenarios where 47-day certificates seemed daunting will become far more achievable.&lt;/p&gt;</description>
			</item>
			<item>
				<title>minikube with WSL kubectl</title>
				<link>/2018/09/05/minikube-with-wsl-kubectl/</link>
				<pubDate>Tue, 04 Sep 2018 22:56:37 +0000</pubDate>
				<guid>/2018/09/05/minikube-with-wsl-kubectl/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href=&#34;https://github.com/kubernetes/minikube/releases/tag/v0.29.0&#34;&gt;minikube 0.29.0 has been released&lt;/a&gt; and includes my &lt;a href=&#34;https://github.com/kubernetes/minikube/pull/3065&#34;&gt;merged PR&lt;/a&gt; so you can enable embedded certificates with &lt;code&gt;minikube config set embed-certs true&lt;/code&gt; once and then just symlink your &lt;code&gt;.kube/config&lt;/code&gt; file from your WSL home directory to the same file in your Windows home directory.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;  I recently &lt;a href=&#34;http://blog.stangroome.com/2018/06/25/minikube-and-wsl/&#34;&gt;blogged about how I work with minikube from the Windows Subsystem for Linux (WSL)&lt;/a&gt;, describing some of the friction points and workarounds. At the time I recommended using the Windows version of kubectl to avoid needing to translate the Windows file paths found in the &lt;code&gt;.kube/config&lt;/code&gt; file to be usable with the Linux version of kubectl. Also, I hadn&amp;rsquo;t at that time encountered any use cases where using the Linux kubectl inside WSL would work better than the Windows version. The first scenario most people would likely encounter with different or breaking behaviour would be passing absolute file paths, e.g. &lt;code&gt;kubectl apply -f /home/jason/my.yaml&lt;/code&gt; would usually fail to locate the file with the Windows version. This is worked around most often by using paths relative to the working directory. Another scenario where the Linux version of kubectl is preferred is the TTY support when running &lt;code&gt;kubectl exec --tty mypod&lt;/code&gt;. This was the reason I personally decided to get the Linux version of kubectl working with minikube in my WSL environment. My first approach was to copy the &lt;code&gt;.kube/config&lt;/code&gt; file that is created in my Windows user profile directory during &lt;code&gt;minikube start&lt;/code&gt;, modify the three certificate paths to be WSL-compatible paths, and save the result in my WSL home directory. Later I realised (from the files generated by &lt;code&gt;kubeadm init&lt;/code&gt; on production Kubernetes clusters) that the certificate entries in the config file don&amp;rsquo;t need to be paths, but can have the certificate content embedded as base64 blobs. Naturally I wrote &lt;a href=&#34;https://gist.github.com/jstangroome/bb72c365ca7b4199e17f7b2e72d64d14&#34;&gt;a bash script&lt;/a&gt; that I could run from WSL to perform these steps for me each time my minikube IP address or certificates changed (which to be fair, isn&amp;rsquo;t often). The script will use the translated paths approach by default but if executed with the &lt;code&gt;--embed&lt;/code&gt; parameter it will use the embedded certificates alternative. After using this solution for a while I began wondering why minikube didn&amp;rsquo;t just generate a &lt;code&gt;.kube/config&lt;/code&gt; file with embedded certificates so WSL support could be solved with a simple symlink instead of copying and rewriting the file each time it changed. So I dived into the minikube source, and &lt;a href=&#34;https://github.com/kubernetes/minikube/pull/3065&#34;&gt;raised a pull request&lt;/a&gt;, and as at the time of writing this post, the PR has been merged into master and is just awaiting an official release. Once the new version of minikube is published (or if you&amp;rsquo;re keen to build it from source yourself), you will be able to execute &lt;code&gt;minikube config set embed-certs true&lt;/code&gt; once and then minikube will always generate a &lt;code&gt;.kube/config&lt;/code&gt; file with the certificates embedded as base64 blobs. Then you can symlink your WSL &lt;code&gt;~/.kube/config&lt;/code&gt; file to your Windows &lt;code&gt;%USERPROFILE%/.kube/config&lt;/code&gt; file and use either version of kubectl with no ongoing management. PS: hat tip to &lt;a href=&#34;https://twitter.com/nunixtech&#34;&gt;Nuno do Carmo&lt;/a&gt; who also found a solution to embedding the certificates in the &lt;code&gt;.kube/config&lt;/code&gt; file by using a pair of &lt;code&gt;kubectl config ... --embed-certs&lt;/code&gt; commands. See the &amp;ldquo;Bonus 3: Do the same with Minikube&amp;rdquo; section of his extensive blog on &lt;a href=&#34;https://medium.com/@hoxunn/wslinux-k8s-the-interop-way-2d98e5b88f08&#34;&gt;WSLinux+K8S: The Interop Way&amp;quot;&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sennheiser Presence headset review</title>
				<link>/2018/07/12/sennheiser-presence-headset-review/</link>
				<pubDate>Thu, 12 Jul 2018 04:24:13 +0000</pubDate>
				<guid>/2018/07/12/sennheiser-presence-headset-review/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update: I&amp;rsquo;ve been using the Sennheiser Presence for several hours every weekday for a year now and I&amp;rsquo;m still very happy with it and recommend it to others.&lt;/strong&gt; &lt;img src=&#34;https://blog.stangroome.com/wp-content/uploads/2018/07/headset.png&#34; alt=&#34;headset&#34;&gt;I work from home near full-time, and the rest of my team works remotely too, so I spend a decent amount of time on VoIP calls for scheduled meetings, paired debugging sessions, and general chit-chat. For at least the last four years I&amp;rsquo;ve been using a &lt;a href=&#34;https://www.plantronics.com/au/en/support/manuals-guides/audio-615m&#34;&gt;Plantronics .Audio 615M USB headset&lt;/a&gt; that I received free at a conference back around 2009 and it has been working very well. Built-in Windows drivers recognise it as a USB communications headset so it becomes the default microphone and speaker for Slack Calls, Zoom, Google Hangouts, etc. I also love that it is a single-ear headset so I can still be aware of my surroundings while I&amp;rsquo;m wearing it, and the over-ear design (as opposed to in-ear) means it is comfortable to wear for extended periods. What frustrated me about this headset was that I was tethered to my desk during a call, and I couldn&amp;rsquo;t use the same headset with my phone whilst on the go. The long cable also made it awkward to use when working from a café. So I started looking for an alternative. I found &lt;a href=&#34;https://www.techradar.com/au/news/the-best-bluetooth-headsets&#34;&gt;TechRadar&amp;rsquo;s best Bluetooth headsets 2018&lt;/a&gt; article and was drawn to the Sennheiser Presence UC at position 5 primarily because it &amp;ldquo;can connect to phone and laptop at the same time for easy switching&amp;rdquo;. The same article also called this headset &amp;ldquo;not the most comfortable&amp;rdquo; but I&amp;rsquo;ve had good experiences with other Sennheiser products, so I checked out the &lt;a href=&#34;https://en-au.sennheiser.com/presence-uc-ml&#34;&gt;official product page&lt;/a&gt; where I discovered that an &lt;a href=&#34;https://en-au.sennheiser.com/accessories-presence-headband&#34;&gt;over-ear headband&lt;/a&gt; and &lt;a href=&#34;https://en-au.sennheiser.com/accessories-mb-pro-1-mb-pro-2-ch-20-mb&#34;&gt;charging stand&lt;/a&gt; was also available for this device. So I took a chance, and ordered the whole set. I&amp;rsquo;ve been using the new Presence headset for over a week now and I am very happy with the product. It paired to my Android phone trivially, and the USB dongle for the laptop required no special drivers. Like the old Plantronics, the new Sennheiser headset also became the default device for my VoIP applications. The USB dongle also has a light indicating that the headset is paired (dull blue), active (bright blue), or even disabled (red) because I toggled the &amp;ldquo;microphone mute&amp;rdquo; key on my laptop keyboard. Battery life is supposedly 10 hours of talk time but with the charging stand in easy reach, I leave the headset there when I&amp;rsquo;m not on a call and I don&amp;rsquo;t need to think about the battery. The lack of cable also means I&amp;rsquo;m not getting it tangled in my chair wheels, and I can step away from my desk to refill my coffee while I&amp;rsquo;m on a call. So far I only have two complaints with Presence headset: firstly, the slider switch to power on/off the device is a little too easy to slide accidentally when picking up the headset from the stand to put it on for a call. I need to be mindful of how I pick it up to avoid waiting for a power-off, power-on, pair cycle. Secondly, it is not simple to remove the over-ear headband and revert back to the in-ear configuration. There are a couple of small pieces that need to be found and reconnected, and later removed again to re-attach the headband, and it would be easy to lose them. As such I think I&amp;rsquo;ll just be using the headband accessory while I&amp;rsquo;m travelling.&lt;/p&gt;</description>
			</item>
			<item>
				<title>minikube and WSL</title>
				<link>/2018/06/25/minikube-and-wsl/</link>
				<pubDate>Mon, 25 Jun 2018 12:54:14 +0000</pubDate>
				<guid>/2018/06/25/minikube-and-wsl/</guid>
				<description>&lt;p&gt;I develop services that run on Kubernetes. During development &lt;a href=&#34;https://github.com/kubernetes/minikube&#34;&gt;minikube&lt;/a&gt; provides an convenient way to run a local Kubernetes &amp;ldquo;cluster&amp;rdquo; regardless of whether you use Windows, OS X, or a Linux distribution as your host OS. Day-to-day I use minikube on Windows 10 and I prefer to use the Windows Subsystem for Linux (WSL) bash shell to have a scripting environment consistent with my colleagues, some of whom do not use Windows, and consistent with the CI system. The Linux binary of minikube isn&amp;rsquo;t very useful in WSL since it doesn&amp;rsquo;t support the Hyper-V driver and the Virtualbox driver cannot deal with the path differences it sees within WSL compared to those reported by &lt;code&gt;VboxManage.exe&lt;/code&gt;. However, when running the Windows &lt;code&gt;minikube.exe&lt;/code&gt; binary, many of the commands (e.g. &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;ip&lt;/code&gt;, &lt;code&gt;dashboard&lt;/code&gt;) just work without any special configuration. Furthermore, creating a symlink so minikube can be executed on the PATH without the &lt;code&gt;.exe&lt;/code&gt; extension easily improves the default experience. Beyond these initial commands though, some extra effort is required. SSH can be a little flakey with &lt;code&gt;minikube ssh&lt;/code&gt; so I find it better to create an alias to use WSL&amp;rsquo;s ssh client:&lt;/p&gt;</description>
			</item>
			<item>
				<title>wslpath and mktemp</title>
				<link>/2018/06/25/wslpath-and-mktemp/</link>
				<pubDate>Mon, 25 Jun 2018 05:17:23 +0000</pubDate>
				<guid>/2018/06/25/wslpath-and-mktemp/</guid>
				<description>&lt;p&gt;The Windows Subsystem for Linux (aka WSL or Bash on Ubuntu on Windows) provides a fantastic reproduction of a local Linux environment without needing a virtual machine. Even better than a virtual machine, WSL includes a lot of conveniences for interoperating with the host Windows file system and processes. That is, I can access my C: drive via &lt;code&gt;/mnt/c/&lt;/code&gt; and I can pop calc via &lt;code&gt;calc.exe&lt;/code&gt;. Naturally, the nature of file paths in Linux and Windows are quite different so WSL performs some translations where it can (e.g. for the current working directory) and provides the &lt;code&gt;wslpath&lt;/code&gt; utility for explicit conversions where necessary. Recently I discovered that even though the root filesystem of my particular WSL installation is accessible from Windows (via &lt;code&gt;%LocalAppData%/lxss/rootfs&lt;/code&gt; in my case), WSL will not translate just any path within Linux to a path within this rootfs directory. And this is &lt;a href=&#34;https://github.com/Microsoft/WSL/issues/3146&#34;&gt;because WSL is designed&lt;/a&gt; with the idea that Windows processes should not modify WSL files. However I work with various version controlled scripts shared amongst developers on Mac, Linux, and Windows (via Cygwin mostly) that use &lt;code&gt;/tmp/&lt;/code&gt; as a staging area (via &lt;code&gt;mktemp&lt;/code&gt;) and when using WSL, Windows processes don&amp;rsquo;t see this directory. If the current working directory is in &lt;code&gt;/tmp/&lt;/code&gt;, the working directory of the Windows process will become the Windows user profile directory instead. And running &lt;code&gt;wslpath -w /tmp/&lt;/code&gt; just returns &lt;code&gt;Result not representable&lt;/code&gt;. To avoid modifying the shared scripts to be WSL-aware, I instead converted my WSL tmp directory to be mounted from the Windows host file system via the following set of commands. First, define the directory to use as WSL&amp;rsquo;s tmp, I chose &lt;code&gt;C:\wsltemp\&lt;/code&gt; out of convenience, but it could be any path you prefer.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Inspecting Docker container processes from the host</title>
				<link>/2017/12/05/inspecting-docker-container-processes-from-the-host/</link>
				<pubDate>Tue, 05 Dec 2017 08:19:54 +0000</pubDate>
				<guid>/2017/12/05/inspecting-docker-container-processes-from-the-host/</guid>
				<description>&lt;p&gt;While I favour a containerize-all-the-things approach to new projects I still need to maintain systems that were designed several years ago around a combination of containers and host-based applications working together. In these situations it is common enough to execute &lt;code&gt;ps&lt;/code&gt; or &lt;code&gt;iotop&lt;/code&gt; on the host and see all the host and container processes together with no obvious indication of which processes belong to which containers. Here I will share some simple commands to help map the host-view of a containerised process to its container. First, given a host PID, how do I know which container it belongs to?&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lessons from DigitalOcean Networking</title>
				<link>/2017/10/04/lessons-from-digitalocean-networking/</link>
				<pubDate>Wed, 04 Oct 2017 08:24:14 +0000</pubDate>
				<guid>/2017/10/04/lessons-from-digitalocean-networking/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; On 2017-DEC-13, &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/digitalocean-private-networking-faq&#34;&gt;DigitalOcean announced that private networking will be isolated to each account&lt;/a&gt; beginning February 2018.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;If you&amp;rsquo;ve come from running virtual machines on AWS, Azure, or Google Cloud, you will be familiar with the idea that the VMs can have a public Internet-facing IP address and a private IP address, or some combination or multiple of the two options. DigitalOcean offers something similar, but just different enough to throw you when you&amp;rsquo;re accustomed to the networking models of the other cloud providers. When you create a DigitalOcean Droplet via their Control Panel, or &lt;a href=&#34;https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet&#34;&gt;via their API&lt;/a&gt;, you have the option to enable &amp;ldquo;Private networking&amp;rdquo; but when you read &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-set-up-and-use-digitalocean-private-networking&#34;&gt;the official documentation&lt;/a&gt;, this feature is actually called &amp;ldquo;Shared private networking&amp;rdquo; and it is a very important distinction. Where private networking in AWS, Azure, or Google Cloud gives your VM a private interface to a network shared only with your VMs, the shared private networking in DigitalOcean is, according to &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-isolate-servers-within-a-private-network-using-iptables&#34;&gt;this DigitalOcean tutorial&lt;/a&gt;, &amp;ldquo;accessible to other VPSs in the same datacenter&amp;ndash;which includes the VPSs of other customers in the same datacenter&amp;rdquo;. And I have verified that statement is true. To clarify, if you enable private networking on a DigitalOcean VM in their SFO2 region, every other VM in the SFO2 region from every other DigitalOcean customer can route packets to your VM&amp;rsquo;s private network interface. While I advocate the use of strict firewall configurations in any cloud hosting environment, the importance of doing so correctly is much higher on DigitalOcean, even for non-Production environments where firewalls have a history of being more relaxed. The bright side of all this is that DigitalOcean&amp;rsquo;s &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-organize-digitalocean-cloud-firewalls#using-tags&#34;&gt;tag-based Cloud Firewall&lt;/a&gt; applies to both the public and private network interfaces and implements a deny-by-default behaviour. By using tags to restrict which other droplets are permitted to communicate on specific ports and protocols you can achieve a very similar level of isolation as offered by other cloud providers. There is another caveat though: to improve the security of this shared private networking environment, &lt;a href=&#34;https://www.digitalocean.com/community/questions/nat-gateway-on-digital-ocean-s-droplet-possible?answer=13896&#34;&gt;DigitalOcean do not allow&lt;/a&gt; VMs to send packets with a source IP address that does not match their assigned private IP address. This prevents you, for example, from operating one DigitalOcean VM as a Virtual Private Network gateway for your other DigitalOcean VMs to connect through to another non-DigitalOcean private network. In summary, while DigitalOcean is providing a great service, and adding new features seemingly every quarter, it offers a conceptual model slightly out of sync with the big name cloud companies, and you need to by mindful of this, but the same would be true I guess for people experienced with DigitalOcean moving to AWS or Azure.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Finding deleted code in git</title>
				<link>/2017/09/12/finding-deleted-code-in-git/</link>
				<pubDate>Tue, 12 Sep 2017 11:38:44 +0000</pubDate>
				<guid>/2017/09/12/finding-deleted-code-in-git/</guid>
				<description>&lt;p&gt;Recently, &lt;a href=&#34;https://twitter.com/mjhilton_&#34;&gt;Matt Hilton&lt;/a&gt; blogged about &lt;a href=&#34;https://www.mjhilton.net/2017/09/06/source-control-antipatterns/&#34;&gt;Source Control Antipatterns&lt;/a&gt; which included the practice of commenting code instead of deleting the code. As wholeheartedly as I agree with deleting code, I know that a popular objection is that deleted code is harder to find. While it might be harder than your favourite editor&amp;rsquo;s Find In Files feature, it is important to know how to use the tools central to your development workflow. For my work, and seemingly the majority of projects today, git is the version control tool of choice. So I&amp;rsquo;m sharing some git commands here that I have found useful for locating deleted code. I&amp;rsquo;m using the &lt;a href=&#34;https://github.com/varnishcache/varnish-cache&#34;&gt;Varnish Cache repository&lt;/a&gt; for my examples if you want to try them yourself. If you know some text from the code that was deleted, you can find the commit where it was deleted. In this example I&amp;rsquo;m looking for when the C structure named &lt;code&gt;smu&lt;/code&gt; was deleted.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Beware Docker and sysctl defaults on GCE</title>
				<link>/2017/08/16/beware-docker-and-sysctl-defaults-on-gce/</link>
				<pubDate>Wed, 16 Aug 2017 11:00:40 +0000</pubDate>
				<guid>/2017/08/16/beware-docker-and-sysctl-defaults-on-gce/</guid>
				<description>&lt;p&gt;On Google Compute Engine (GCE) the latest VM boot images (at the time of writing) for Ubuntu 14.04 and 16.04 (eg &lt;code&gt;ubuntu-1604-xenial-v20170811&lt;/code&gt;) ship with a file at &lt;a href=&#34;https://gist.github.com/jstangroome/be4bee805c97063c28869ff4d636ed26&#34;&gt;/etc/sysctl.d/99-gce.conf&lt;/a&gt; which contains:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;    net.ipv4.ip_forward = 0&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This kernel parameter determines whether &lt;a href=&#34;https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt&#34;&gt;packets can be forwarded between network interfaces&lt;/a&gt;. On its own, the presence of this line isn&amp;rsquo;t a big deal. Separately, when you start the Docker daemon (at least in version 17.06.0-ce), it &lt;a href=&#34;https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communicating-to-the-outside-world&#34;&gt;sets this kernel parameter to 1&lt;/a&gt; (assuming you haven&amp;rsquo;t specified &lt;code&gt;--ip-forward=false&lt;/code&gt; in the Docker configuration). Docker needs packet forwarding enabled so that Docker containers using the default bridge network can communicate outside the host. If you later execute &lt;code&gt;sysctl --system&lt;/code&gt; or similar after has Docker has started, for example to apply a new value for the &lt;a href=&#34;https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt&#34;&gt;nf_conntrack_max kernel parameter&lt;/a&gt; that you&amp;rsquo;ve specified in another file under &lt;code&gt;/etc/sysctl.d/&lt;/code&gt;, then the &lt;code&gt;ip_forward&lt;/code&gt; parameter will revert to 0 care of GCE&amp;rsquo;s default conf file. At this point you&amp;rsquo;ll find your containers cannot reach the outside world, for example this will fail to resolve:&lt;/p&gt;</description>
			</item>
			<item>
				<title>The case of the addled ARP</title>
				<link>/2017/07/17/the-case-of-the-addled-arp/</link>
				<pubDate>Mon, 17 Jul 2017 12:09:11 +0000</pubDate>
				<guid>/2017/07/17/the-case-of-the-addled-arp/</guid>
				<description>&lt;p&gt;In recent weeks we started receiving alerts whenever a new AWS EC2 Instance running Ubuntu 14.04 LTS was launched for a specific Auto Scaling Group. On average, one new instance would be provisioned per day but the fault would only occur for about one or two of the new instances per week. The alert was an indicator that the new instance was unable to communicate with the message broker located on another instance. However, after approximately 20 minutes the issue would self-resolve. Also, if we manually provisioned a new replacement instance, it would successfully communicate with the broker. With the short window of failure and no consistent period between occurrences so this problem continued through several operations shifts and staff members before a plan was established to capture more details of the problem. On the next alert we were able to investigate and establish several facts:&#xA;1. The affected instance was unable to communicate due to a connection timeout. It was sending TCP SYN packets and receiving no reply.&#xA;2. The message broker was receiving the TCP SYN packet from the affected instance and replying with a SYN+ACK packet but the MAC address on the reply packet did not match the MAC address on the incoming SYN packet.&#xA;3. Running &lt;code&gt;ip neigh show&lt;/code&gt; on the message broker instance reported that the IP address of the affected instance was associated with an unrelated MAC address and was in the &lt;code&gt;STALE&lt;/code&gt; state but occasionally also in the &lt;code&gt;REACHABLE&lt;/code&gt; state.&#xA;4. The unrelated MAC address was not associated with any other instances running in the VPC nor any that had been recently terminated.&#xA;At this point we setup two monitors on the message broker instance while we waited for the problem to self-resolve. The first was a &lt;code&gt;tcpdump&lt;/code&gt; to capture all ARP traffic and the second was a shell script to continuously poll and record the ARP table. The ARP traffic capture contained very little and nothing at all helpful but the ARP table records were very interesting. While the affected instance was unable to connect to the message broker, the ARP table cycled through the states &lt;code&gt;REACHABLE&lt;/code&gt; then &lt;code&gt;STALE&lt;/code&gt; then &lt;code&gt;DELAY&lt;/code&gt;​ and back to &lt;code&gt;REACHABLE&lt;/code&gt; again, retaining the same incorrect MAC address association the whole time. The &lt;code&gt;DELAY&lt;/code&gt; state never lasted as long as five seconds. At the moment when the problem self-resolved, the &lt;code&gt;DELAY&lt;/code&gt; state did last for five seconds and then transitioned to the &lt;code&gt;PROBE&lt;/code&gt; state, then to the &lt;code&gt;FAILED&lt;/code&gt; state and finally back to &lt;code&gt;REACHABLE&lt;/code&gt; but this time with the correct MAC address. This insight lead one of our team members to find &lt;a href=&#34;https://bugzilla.redhat.com/show_bug.cgi?id=1450203&#34;&gt;this Red Hat bug&lt;/a&gt; describing a Linux kernel issue that aligned with exactly the behaviour we were experiencing. Unfortunately the &lt;a href=&#34;https://github.com/torvalds/linux/commit/29ba6e7400a317725bdfb86a725d1824447dbcd7&#34;&gt;fix for this bug wasn&amp;rsquo;t merged&lt;/a&gt; until Linux kernel 4.11 which was only released in May and &lt;a href=&#34;https://insights.ubuntu.com/2017/06/15/kernel-team-summary-june-15-2017/&#34;&gt;reportedly&lt;/a&gt; won&amp;rsquo;t be officially available in Ubuntu until Artful Aardvark 17.10. Our assessment of all the stale ARP entries on the message broker combined with the known scaling behaviours of the messaging clients suggested that some entries had been there for at least 8 weeks. So this wasn&amp;rsquo;t a by-product of replacing instances rapidly and recycling IP addresses in the subnet too quickly. As an interim solution we have implemented a cron job to remove any stale entries from the message broker&amp;rsquo;s ARP table and this has prevented the alerts from re-appearing for several weeks now.  &lt;/p&gt;</description>
			</item>
			<item>
				<title>Always upgrade ixgbevf on AWS EC2</title>
				<link>/2017/06/25/always-upgrade-ixgbevf-on-aws-ec2/</link>
				<pubDate>Sun, 25 Jun 2017 08:04:54 +0000</pubDate>
				<guid>/2017/06/25/always-upgrade-ixgbevf-on-aws-ec2/</guid>
				<description>&lt;p&gt;I recently had a frustrating experience with network connectivity for a set of AWS EC2 Instances running Ubuntu Trusty 14.04. Three instances, running &lt;a href=&#34;https://graphiteapp.org/&#34;&gt;Graphite&lt;/a&gt; and Carbon Cache 0.9.15 would intermittently become unreachable on the network for seconds or minutes at a time and several times a day. There was no obvious pattern to when these events would occur and when they did there was no interesting change in their CPU utilisation, memory usage, or disk IO aside from the inevitable reduction in activity associated with a lack of data or queries coming from the network. AWS reported the Graphite instances were failing their Instance Status Check. The external instances attempting to communicate with these Graphite machines just experienced TCP timeouts. When the Graphite instances themselves became network-reachable again, their system logs showed that processes had continued running as normal during the outage. The first hint of a reason for this behaviour came from the Graphite instances&amp;rsquo; syslog reporting &lt;code&gt;No route to host&lt;/code&gt; during the outage while a cron job was attempting to connect to another instance on the same subnet in the same Availability Zone. This suggested something was wrong with either ARP, or the network interface, but there were no logs or kernel messages suggesting the network interface had gone down and &lt;a href=&#34;https://aws.amazon.com/blogs/apn/amazon-vpc-for-on-premises-network-engineers-part-one/&#34;&gt;EC2 resolves ARP at the Hypervisor&lt;/a&gt;. I configured &lt;a href=&#34;https://collectd.org/&#34;&gt;collectd&lt;/a&gt; to harvest all the network-related metrics possible on the Graphite instances themselves and I configured &lt;a href=&#34;http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/flow-logs.html&#34;&gt;VPC Flow Logs&lt;/a&gt; to record details of all the network traffic in the subnet. After the next period of failed connectivity I discovered that Flow Logs showed that all packets were reaching the EC2 Network Interfaces of the Graphite instances but the instance&amp;rsquo;s collectd data showed no packets received, but no network errors either. These Graphite instances were now running the AWS M4 Instance Type but they were not originally provisioned as such which lead me to investigate the Enhanced Networking features available to these instance types. I eventually found this suspicious paragraph in the AWS documentation:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Queue a Team Build from another and pass parameters</title>
				<link>/2014/02/19/queue-a-team-build-from-another-and-pass-parameters/</link>
				<pubDate>Wed, 19 Feb 2014 10:05:32 +0000</pubDate>
				<guid>/2014/02/19/queue-a-team-build-from-another-and-pass-parameters/</guid>
				<description>&lt;p&gt;I have &lt;a href=&#34;http://blog.stangroome.com/2011/09/06/queue-another-team-build-when-one-team-build-succeeds/&#34; title=&#34;Queue another Team Build when one Team Build succeeds&#34;&gt;previously blogged about queuing a new Team Build at the successful completion of another&lt;/a&gt; Team Build for Team Foundation Server 2010. Since then I&amp;rsquo;ve had a few people ask how to queue a new Team Build and pass information into the new Team Build via the build process parameters. Recently I&amp;rsquo;ve needed to implement this exact behaviour for a client, and with TFS 2013 which has quite different default build process templates, so I thought I&amp;rsquo;d share it here. In my situation I&amp;rsquo;m building on top the default TfvcTemplate.12.xaml process but the same approach can be easily applied to the Git build templates too. To begin, I have added two build process parameters to the template:&#xA;1. &lt;strong&gt;Chained Build Definition Names&lt;/strong&gt; - this is an optional array of strings which refer to the list of Build Definitions that should be queued upon successful completion of the current build. All the builds will be queued immediately and will execute as the controller and agents are available. The current build does not wait for the completion of the builds it queues. My simple implementation only supports queuing builds within the same Team Project.&#xA;2. &lt;strong&gt;Source****BuildUri&lt;/strong&gt; - this is a single, optional, string which will accept the unique Team Build identifier of the previous build that queued it - this is not intended to be specified by a human but could be. When empty, it is ignored. However, when provided by a preceding build, this URI will be used to retrieve the Build Number and Drop Location of that preceding build and these values, plus the URI, will be made available to the projects and scripts executed within the new build. Following the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dn376353.aspx#env_vars&#34;&gt;new Team Build 2013 convention&lt;/a&gt;, these values are passed as environment variables named:&#xA;* TF_BUILD_&lt;strong&gt;SOURCE&lt;/strong&gt; BUILDURI&#xA;* TF_BUILD_&lt;strong&gt;SOURCE&lt;/strong&gt; BUILDNUMBER&#xA;* TF_BUILD_&lt;strong&gt;SOURCE&lt;/strong&gt; DROPLOCATION&#xA;The assumption is that a build definition based on my &amp;ldquo;chaining&amp;rdquo; template will only queue other builds based on the same template, or another template which also accepts a SourceBuildUri parameter. This also means that builds can be chained to any depth, each passing the BuildUri of itself to the next build in the chain. The projects and scripts can use the TF_BUILD_SOURCEDROPLOCATION variable to access the output of the previous build - naturally UNC file share drops are easier to consume &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/bb778394.aspx&#34;&gt;than drops into TFS itself&lt;/a&gt;. Also the TF_BUILD_SOURCEBUILDURI means that the TFS API can be used to query every aspect of the preceding build, notably including the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.build.client.informationnodeconverters.aspx&#34;&gt;Information Nodes&lt;/a&gt;. Prior to TFS 2012, queuing a new build from the workflow and passing parameters would have required a custom activity. However, in Team Build 2012 and 2013, Windows Workflow 4.0 is used which includes a new &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dd807388(v=vs.110).aspx&#34;&gt;InvokeMethod activity&lt;/a&gt; making it possible to add items to the Process Parameters dictionary directly from the XAML. The &lt;a href=&#34;https://gist.github.com/jstangroome/9089053&#34;&gt;final XAML for the Build Process Template with support for queuing and passing parameters is available as a Gist&lt;/a&gt;. If you&amp;rsquo;d like to be able to integrate the same functionality with your own Team Build 2013 template you can see the &lt;a href=&#34;https://gist.github.com/jstangroome/9089053/revisions&#34;&gt;four discrete edits I made to the default TfvcTemplate.12.xaml file from TFS 2013 in the Gist revisions&lt;/a&gt;. When a build using this chaining template queues another build it explicitly sets the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.build.client.ibuildrequest.requestedfor.aspx&#34;&gt;RequestedFor property&lt;/a&gt; to the same value as the current build so that the chain of builds will show in the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms181721.aspx#TeamExplorer&#34;&gt;My Builds view&lt;/a&gt; of the user who triggered the first build. In my current implementation, the SourceBuildUri passed to each queued build is the URI of the immediately preceding build, but it some cases it may be more appropriate to propagate the BuildUri of the original build that triggered the entire chain. This would be a somewhat trivial change to the workflow for whomever needs this behaviour instead.&lt;/p&gt;</description>
			</item>
			<item>
				<title>PowerShell Select-Xml versus Get-Content</title>
				<link>/2014/02/10/powershell-select-xml-versus-get-content/</link>
				<pubDate>Mon, 10 Feb 2014 12:29:32 +0000</pubDate>
				<guid>/2014/02/10/powershell-select-xml-versus-get-content/</guid>
				<description>&lt;p&gt;In PowerShell, one of the most common examples you will see for parsing an XML file into a variable uses the &lt;a href=&#34;http://technet.microsoft.com/en-us/library/hh849787.aspx&#34;&gt;Get-Content cmdlet&lt;/a&gt; and the &lt;a href=&#34;http://technet.microsoft.com/en-us/library/hh847732.aspx&#34;&gt;cast operator&lt;/a&gt;, like this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;    $Document = [xml](Get-Content -Path myfile.xml)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The resulting type of the $Document variable is an instance of &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.xml.xmldocument&#34;&gt;System.Xml.XmlDocument&lt;/a&gt;. However, there is another approach to get the same, or better, result using the &lt;a href=&#34;http://technet.microsoft.com/en-us/library/hh849968.aspx&#34;&gt;Select-Xml cmdlet&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;    $Document = ( Select-Xml -Path myfile.xml -XPath / ).Node&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Sure, using the second variant is slightly longer, but with an important benefit over the first, and it&amp;rsquo;s not performance related. In the first example, the file is first read into an array of strings and then cast. The casting operation (implemented by System.Management.Automation.LanguagePrimitives.ConvertToXml) is using an &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings&#34;&gt;XmlReaderSettings&lt;/a&gt; instance with the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings.ignorewhitespace&#34;&gt;IgnoreWhitespace&lt;/a&gt;property set to true and an XmlDocument instance with the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.preservewhitespace&#34;&gt;PreserveWhitespace&lt;/a&gt; property set to false. In the second example, the file is read directly into an XmlDocument (implemented by System.Management.Automation.InternalDeserializer.LoadUnsafeXmlDocument) using an XmlReaderSettings instance with the IgnoreWhitespace property set to false and an XmlDocument instance with the PreserveWhitespace property set to true - the opposite values of the first example. The Select-Xml approach won&amp;rsquo;t completely preserve all the original formatting from the source file but it preserves much more than the Get-Content approach will and I&amp;rsquo;ve found this extremely useful when bulk updating version controlled XML files with a PowerShell script and wanting the resulting file diff to show the intended change and not be obscured by formatting changes. You could construct the XmlDocument and XmlReaderSettings directly in PowerShell but not in so few characters. You can also load the System.Xml.Linq assembly and use the XDocument class which appears to give slightly better formatting consistency again but it&amp;rsquo;s still not perfect and PowerShell doesn&amp;rsquo;t provide the same quick access to elements and attributes as properties on the object.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Override the TFS Team Build OutDir property in TFS 2013</title>
				<link>/2014/02/10/override-the-tfs-team-build-outdir-property-in-tfs-2013/</link>
				<pubDate>Sun, 09 Feb 2014 20:22:24 +0000</pubDate>
				<guid>/2014/02/10/override-the-tfs-team-build-outdir-property-in-tfs-2013/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ve blogged &lt;a href=&#34;http://blog.stangroome.com/2012/02/03/override-the-tfs-team-build-outdir-property/&#34;&gt;twice&lt;/a&gt; &lt;a href=&#34;http://blog.stangroome.com/2012/05/10/override-the-tfs-team-build-outdir-property-net-4-5/&#34;&gt;before&lt;/a&gt; about the OutDir MSBuild property set by Team Build and I&amp;rsquo;ve recently discovered that with the default build process templates included with Team Foundation Server 2013, the passing of the OutDir can be disabled via a simple Team Build process parameter. The parameter I am referring to is the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dd647547.aspx#output&#34;&gt;&amp;ldquo;Output location&amp;rdquo;&lt;/a&gt;: &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2014/02/outputlocation.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2014/02/outputlocation.png&#34; alt=&#34;outputlocation&#34;&gt;&lt;/a&gt; This parameter&amp;rsquo;s default value, &amp;ldquo;SingleFolder&amp;rdquo;, gives the traditional Team Build behaviour - the OutDir property will be specified on the MSBuild command-line and, unless you&amp;rsquo;ve made other changes, all build outputs will be dropped into this single folder. Another value this parameter accepts is &amp;ldquo;PerProject&amp;rdquo; but this name can be slightly misleading. The OutDir property will still be specified on the MSBuild command-line but Team Build will append a subfolder for each project that has been specified in the Build Definition. That is, you may choose to build SolutionA.sln and SolutionB.sln from a single Build Definition and the &amp;ldquo;PerProject&amp;rdquo; option will split these into &amp;ldquo;SolutionA&amp;rdquo; and &amp;ldquo;SolutionB&amp;rdquo; subfolders. It &lt;strong&gt;will not&lt;/strong&gt; output to different subfolders for the projects contained within each solution - for this behaviour you should specify the GenerateProjectSpecificOutputFolder property as an MSBuild argument &lt;a href=&#34;http://blog.stangroome.com/2012/05/10/override-the-tfs-team-build-outdir-property-net-4-5/&#34;&gt;as I&amp;rsquo;ve blogged previously&lt;/a&gt;. The value of the &amp;ldquo;Output location&amp;rdquo; that you&amp;rsquo;ve probably been looking for is &amp;ldquo;AsConfigured&amp;rdquo;. With this setting, Team Build will not pass the OutDir property to MSBuild at all and your projects will all build to their usual locations, just like they do in Visual Studio - presumably to a \bin\ folder under each project. With this setting, it is then your responsibility to configure a post-build target or script to copy the required files from their default build locations to the Team Build binaries share. For this purpose, Team Build provides a &amp;ldquo;TF_BUILD_BINARIESDIRECTORY&amp;rdquo; environment variable specifying the destination path to use. There are also some other &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dn376353.aspx#env_vars&#34;&gt;environment variables populated by Team Build 2013 documented here&lt;/a&gt;. At the end of the build process, Team Build will then copy the contents of the TF_BUILD_BINARIESDIRECTORY to either the UNC path drop folder, or to storage within the TFS Collection database itself as you&amp;rsquo;ve chosen via the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/bb778394.aspx&#34;&gt;Staging Location setting&lt;/a&gt; on the Build Defaults page. However, before you rush away to use this new capability, consider that the MSBuild, or more accurately the set of Microsoft.*.targets files used by almost all projects, already contain a great quantity of logic for handling which files to copy to the build drop. For example, Web Application projects, will copy the contents of the \bin\ folder and all the other content files (eg css, javascript, and images) whilst excluding C# code files, and the project file. Instead of re-implementing this behaviour yourself, leverage what MSBuild already provides and use the existing hook points to adjust this behaviour when you need to alter it for your situation. If you&amp;rsquo;re interested, you&amp;rsquo;ll find that this new &amp;ldquo;Output location&amp;rdquo; behaviour is now implemented in the new RunMSBuild workflow activity, specifically within its RunMSBuildInternal private nested activity.&lt;/p&gt;</description>
			</item>
			<item>
				<title>NuGet Reference Paths for Projects in Multiple Solutions</title>
				<link>/2013/11/26/nuget-reference-paths-for-projects-in-multiple-solutions/</link>
				<pubDate>Tue, 26 Nov 2013 09:11:13 +0000</pubDate>
				<guid>/2013/11/26/nuget-reference-paths-for-projects-in-multiple-solutions/</guid>
				<description>&lt;p&gt;This year I have been working with a code base that exhibits Visual Studio projects with three characteristics:&#xA;1. The project references a NuGet package.&#xA;2. The project is included in more than one Visual Studio solution.&#xA;3. The solution files are located in different folders.&#xA;I&amp;rsquo;m not sure how common this scenario is. A few different threads on the NuGet CodePlex site suggests at least some other people are wrestling with it. Personally I endeavour to structure a code base to avoid sharing projects between solutions but for old, high-coupled code this can be difficult to achieve. The problem with this scenario is with the relative paths used to resolve the assemblies within the referenced NuGet package when building the project in clean or constrained working folders - such as on a build agent or when someone first clones a repository. When a NuGet package is installed or updated in a project, the path to the package assemblies are specified relative to the /packages/ folder of the currently open solution. However, when another solution including the same project is built, the assembly won&amp;rsquo;t be resolved either because the first solution&amp;rsquo;s /packages/ folder is not present in the workspace and the NuGet Package Restore workflow has put the assemblies in the second solution&amp;rsquo;s /packages/ folder. The existing attempts to solve this issue, and the same way I approached the problem originally, tend to be focused on writing reference paths relative to an MSBuild property like $(SolutionDir) or $(PackageDir) which then allows the path to be resolved correctly at build time. If I understand correctly, this approach has been rejected from becoming part of the official NuGet application because it doesn&amp;rsquo;t handle the scenario where a project is being built directly, not being built as part of a solution - something I also avoid generally. Last week I had an idea to tackle the problem dynamically at build time instead of when the reference path is written to the project file. My solution is to introduce (yet another) NuGet package to the affected projects as a development-only dependency. I call this the NugetReferenceHintPathRewrite package. This package adds an MSBuild targets file to the project which executes just before the standard ResolveAssemblyReferences MSBuild target. When it executes it looks for references that specify a /packages/ folder as part of their path and then replaces the part of the path up to and including the /packages/ folder with the a new path to the currently building solution&amp;rsquo;s packages folder. This rewrite is done to the MSBuild Items in-process and does not modify the project file on disk. The main benefit of this dynamic build-time approach is that I don&amp;rsquo;t have to worry about new packages being installed or packages being updated (ie re-installed) and the paths in the project file being set to the &amp;ldquo;wrong&amp;rdquo; path because someone else forgot to fix it before committing. You can find the &lt;a href=&#34;https://www.nuget.org/packages/NuGetReferenceHintPathRewrite&#34;&gt;NuGetReferenceHintPathRewrite package on NuGet.org&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>PowerShell Update-Help and an Authenticating Proxy</title>
				<link>/2013/08/02/powershell-update-help-and-an-authenticating-proxy/</link>
				<pubDate>Thu, 01 Aug 2013 22:24:41 +0000</pubDate>
				<guid>/2013/08/02/powershell-update-help-and-an-authenticating-proxy/</guid>
				<description>&lt;p&gt;PowerShell v3 doesn&amp;rsquo;t ship with help in the box anymore. You may love this or you may hate it. Regardless of your stance, if your environment is behind an authenticating web proxy, it is not obvious how to make it work. &lt;a href=&#34;http://blogs.technet.com/b/heyscriptingguy/archive/2012/08/31/understanding-and-using-updatable-powershell-help.aspx&#34;&gt;The general guidance&lt;/a&gt; is to use Save-Help from another computer but this doesn&amp;rsquo;t help when every computer is behind the proxy and &lt;a href=&#34;http://en.wikipedia.org/wiki/Sneakernet&#34;&gt;sneakernet&lt;/a&gt; is prohibited. This was my situation recently and I found a reasonably simple way to solve it. Firstly, when trying to run Update-Help, I received an error message:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Avoid password management with Group Managed Service Accounts</title>
				<link>/2013/07/28/avoid-password-management-with-group-managed-service-accounts/</link>
				<pubDate>Sun, 28 Jul 2013 07:17:02 +0000</pubDate>
				<guid>/2013/07/28/avoid-password-management-with-group-managed-service-accounts/</guid>
				<description>&lt;p&gt;A common problem when managing deployments of applications, manual or automated, is where to securely store the passwords for service accounts used by Windows Services, IIS Application Pools, and Scheduled Tasks in each of the environments the applications are deployed to. With Windows Server 2008 R2, the first step to simplifying this problem was introduced in the form of &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd560633(v=ws.10).aspx&#34;&gt;Managed Service Accounts&lt;/a&gt;. Unfortunately they suffered from the limitation of being restricted to a single computer so you couldn&amp;rsquo;t use them for load-balanced web applications, for example. It was also a challenge to get them to work for anything other than Windows Services in Server 2008. Now, with Windows Server 2012, these accounts have matured and become &lt;a href=&#34;http://technet.microsoft.com/en-us/library/hh831782.aspx&#34;&gt;Group Managed Service Accounts&lt;/a&gt; or gMSAs. They can be used to run processes on multiple machines and work well with IIS Application Pools and Scheduled Tasks too. I had an early opportunity to experiment with gMSAs when Server 2012 was still a Release Candidate but more recently I&amp;rsquo;ve been fortunate to use them extensively for a multitude of applications on my current client engagement so I thought I&amp;rsquo;d share my experience with the benefits and some of gotchas.&lt;/p&gt;</description>
			</item>
			<item>
				<title>WitMorph - Walkthrough a Conversion</title>
				<link>/2013/07/16/witmorph-walkthrough/</link>
				<pubDate>Tue, 16 Jul 2013 07:02:15 +0000</pubDate>
				<guid>/2013/07/16/witmorph-walkthrough/</guid>
				<description>&lt;p&gt;In &lt;a href=&#34;http://blog.codeassassin.com/2013/07/16/witmorph-changing-team-foundation-process-templates-in-place/&#34; title=&#34;WitMorph – changing Team Foundation process templates in-place&#34;&gt;my last post&lt;/a&gt; I described the problem of trying to change the Process Template of an existing Team Project in Team Foundation Server and the open-source project I built to solve it, &lt;a href=&#34;https://github.com/codeassassin/WitMorph&#34;&gt;WitMorph&lt;/a&gt;. In this post I want to demonstrate a simple walkthrough of the currently even simpler GUI. I have a Team Project, imaginatively named &amp;ldquo;Agile-6.1&amp;rdquo;, and it was originally created with the &amp;ldquo;MSF for Agile Software Development 6.1&amp;rdquo; process template. I also have another Team Project, named &amp;ldquo;Scrum-2.1&amp;rdquo;, and it was created with the &amp;ldquo;Microsoft Visual Studio Scrum 2.1&amp;rdquo; process template which should be no surprise. I am going to describe the process of converting the &amp;ldquo;Agile-6.1&amp;rdquo; Team Project to the Scrum template by using the &amp;ldquo;Scrum-2.1&amp;rdquo; Team Project as the definition of the goal. The reason for using another Team Project as the definition instead of the original process template is due to subtle differences between a template&amp;rsquo;s structure and the resulting Team Project that I haven&amp;rsquo;t addressed in WitMorph&amp;rsquo;s differencing engine yet. The very first step is to pull and build the WitMorph solution and then run UI project. It should look like this: &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step1.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step1.png&#34; alt=&#34;WitMorph UI&#34;&gt;&lt;/a&gt; Following the numbers I&amp;rsquo;ve added to the screenshot above, click each of the buttons to select:&#xA;1. The &amp;ldquo;Agile-6.1&amp;rdquo; Team Project. Clicking the button will reveal the standard TFS Team Project dialog.&#xA;2. The &amp;ldquo;Scrum-2.1&amp;rdquo; Team Project. In my example both Team Projects are in the same collection but they could be on different TFS instances entirely.&#xA;3. The &amp;ldquo;Agile6.1_to_Scrum2.1.witmap&amp;rdquo; Process Map File. This file can be found in the WitMorph project source under the ProcessTemplateMaps folder*****.&#xA;4. A file to which to save the generated action list.&#xA;It is important to note that when the &amp;ldquo;Generate Actions&amp;rdquo; button (5) is clicked, the two Team Projects will be queried for their current process metadata but no changes will be applied. After providing the required information and clicking the button the UI should look like this: &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step2.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step2.png&#34; alt=&#34;Generate Actions&#34;&gt;&lt;/a&gt; The contents of the generated &amp;ldquo;witact&amp;rdquo; file are not intended for human consumption but it is fairly comprehensible. It describes the series of incremental steps required to convert any Team Project based on the Agile template to the Scrum template: &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step3.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step3.png&#34; alt=&#34;Actions XML&#34;&gt;&lt;/a&gt; Now, we can apply the list of actions in this file to the &amp;ldquo;Agile-6.1&amp;rdquo; Team Project:&#xA;1. Leave the &amp;ldquo;Agile-6.1&amp;rdquo; Team Project selected as per step 1 above, or re-select it if WitMorph has been restarted since the action list was generated. You could also choose a different project to convert if it is also based on the same Agile 6.1 process.&#xA;2. Select the action list file generated above as the &amp;ldquo;Input Actions File&amp;rdquo;.******&#xA;3. Specify an Output Path where the process of applying the actions will output a log and the intermediate work item type definitions (mainly for diagnosing issues).&#xA;4. Click &amp;ldquo;Apply Actions&amp;rdquo; to convert the Team Project to the new process template. &lt;strong&gt;WARNING:&lt;/strong&gt; I highly recommend having a backup of the TFS collection database before doing this.*******&#xA;The WitMorph UI should look like this: &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step4.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2013/07/step4.png&#34; alt=&#34;Apply Actions&#34;&gt;&lt;/a&gt; Upon connecting******** to the &amp;ldquo;Agile-6.1&amp;rdquo; Team Project with Visual Studio, you will find that all the existing User Story work items have become Product Backlog Items with all their original work item IDs, attachments, links, and history. You will also find that you can now create new Impediment work items instead of Issues and the Bug work items now have a Backlog Priority field among many other differences between the two templates. There is still a lot of room for improvement in WitMorph (eg to update the work item queries) and if you&amp;rsquo;d like to contribute, simply fork the GitHub repository and send a Pull Request.&lt;/p&gt;</description>
			</item>
			<item>
				<title>WitMorph - changing Team Foundation process templates in-place</title>
				<link>/2013/07/16/witmorph-changing-team-foundation-process-templates-in-place/</link>
				<pubDate>Tue, 16 Jul 2013 06:02:52 +0000</pubDate>
				<guid>/2013/07/16/witmorph-changing-team-foundation-process-templates-in-place/</guid>
				<description>&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;&#xA;&lt;p&gt;Historically Team Foundation Server process templates have not had a good upgrade story. When you create a new Team Project you are required to select the process template (typically CMMI, Agile, or recently Scrum) and that is the process template used by your project for the rest of its life. From the first TFS version, customizing the project has always been possible - adding and removing fields to work items, or adding entirely new work item types, and the TFS Power Tools certainly improve that experience by providing a GUI instead of a wall of XML and a command-line. But when a new version of TFS ships with new versions of the process templates you’ve either had to create a new Team Project with the new template and try to copy most* of the data across, or hope someone publishes a way to upgrade between specific process template versions - typically another exercise in tedious manual XML manipulation. If you&amp;rsquo;ve chosen the wrong process template and want to change from Agile to Scrum then I really don’t envy the work ahead of you. Team Foundation Server 2012 included a wizard in Web Access for the first time to help add to an existing Team Project the process template components needed to enable the Task Board and Code Review functionality but it doesn’t upgrade the template completely, it only works with TFS 2010 templates or newer, and will be limited by any customizations that may have been made. Having performed many TFS upgrades for equally many clients over the years, I&amp;rsquo;ve often had to perform the manual analysis of the differences between various versions of a TFS process template or a client’s custom template, and find a way to migrate from one to the other. I&amp;rsquo;ve always felt that this process could be approached much like a database migration would and could be automated. This year I finally had the opportunity to try it.&lt;/p&gt;</description>
			</item>
			<item>
				<title>PowerShell Remoting, User Profiles, Delegation and DPAPI</title>
				<link>/2012/05/17/powershell-remoting-user-profiles-delegation-and-dpapi/</link>
				<pubDate>Thu, 17 May 2012 00:28:20 +0000</pubDate>
				<guid>/2012/05/17/powershell-remoting-user-profiles-delegation-and-dpapi/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ve been working with a PowerShell script to automatically deploy an application to an environment. The script is initiated on one machine and uses PowerShell Remoting to perform the install on one or more target machines. On the target machines the install process needs the username and password of the service account that the application will be configured to run as. I despise handling passwords in my scripts and applications so I avoid it wherever possible, and where I can&amp;rsquo;t avoid it, I make sure I handle them securely. And this is where the fun starts. By default, PowerShell Remoting suffers from the same &lt;a href=&#34;http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx&#34;&gt;multi-hop authentication problem&lt;/a&gt; as any other system using Windows security, i.e. the credentials used to connect to the target machine cannot be used to connect from the target machine to another resource requiring authentication. The most promising solution to this in PowerShell Remoting is &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/windows/desktop/ee309365(v=vs.85).aspx&#34;&gt;CredSSP&lt;/a&gt; which enables credentials to be delegated but it has some challenges:&#xA;1. It is not enabled by default, you need to execute &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd819517.aspx&#34;&gt;Enable-WSManCredSSP&lt;/a&gt; or use Group Policy to configure the involved machines to support CredSSP.&#xA;2. It is not available on Windows XP or Server 2003, a minor concern given that these OSes should be dead by now, but worth mentioning.&#xA;3. PS Remoting requires CredSSP to be used with &amp;ldquo;fresh&amp;rdquo; credentials even though CredSSP as a technology supports delegating default credentials (this is how RDP uses CredSSP).&#xA;It is the last point about fresh credentials that kills CredSSP for me, I don&amp;rsquo;t want to persist another password for my non-interactive script to use when establishing a remoting connection. There is &lt;a href=&#34;https://connect.microsoft.com/PowerShell/feedback/details/498377/credssp-should-allow-delegation-of-default-current-credentials&#34;&gt;a bug on Microsoft Connect&lt;/a&gt; about this that you can vote up. Instead I need to revert to the pre-CredSSP (and poorly documented) way of supporting multi-hop authentication with PS Remoting: Delegation. You basically require at least two things to be configured correctly in Active Directory for this to work.&#xA;1. The user account that is being used to authenticate the PS Remoting session must have its AD attribute &amp;ldquo;Account is sensitive and cannot be delegated&amp;rdquo; unchecked.&#xA;2. The computer account of the machine PS Remoting is connecting to must have either the &amp;ldquo;Trust this computer for delegation to any service&amp;rdquo; option enabled or have the &amp;ldquo;Trust this computer for delegation to specified services only&amp;rdquo; option enabled with a list of which services on which machines can passed delegated credentials. The latter is more secure if you know which services you&amp;rsquo;ll need.&#xA;&lt;del&gt;I&amp;rsquo;m not sure which caches needed to expire because it took a while for these changes to start working for me but once they did&lt;/del&gt; After the PS Remoting target computer refreshed its Kerberos ticket (every 10 hours by default) I could use PS Remoting with the default authentication method (Kerberos) and could authenticate to resources beyond the connected machine. Rebooting the target computer or using the &amp;ldquo;klist purge&amp;rdquo; command against the target computer&amp;rsquo;s system account will force the Kerberos ticket to be refreshed. With that hurdle overcome, the fun continues with the handling of the application&amp;rsquo;s service account credentials. PowerShell&amp;rsquo;s &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd347656.aspx&#34;&gt;ConvertTo-&lt;/a&gt; and &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd315356.aspx&#34;&gt;ConvertFrom-SecureString&lt;/a&gt; cmdlets enable me to encrypt the service account password using a Windows-managed encryption key specific to the current user, in my case this is the user performing the deployment and authenticating the PS Remoting session. As a one-time operation I ran an interactive PowerShell session as the deployment user and used &lt;code&gt;Read-Host -AsSecureString | ConvertFrom-SecureString&lt;/code&gt; to encrypt the application service account password and I stored the result in a file alongside the deployment script. At deployment time, the script uses ConvertTo-SecureString to retrieve the password from the encrypted file and configure the application&amp;rsquo;s service account. At least it worked with my interactive proof-of-concept testing. It failed to decrypt the password at deployment time with the error message &amp;ldquo;Key not valid for use in specified state&amp;rdquo;. After quite some digging I found the culprit. The Convert*-SecureString cmdlets are using the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms995355.aspx&#34;&gt;DPAPI&lt;/a&gt; and the current user&amp;rsquo;s key when a key isn&amp;rsquo;t specified explicitly. DPAPI is dependent on the current user&amp;rsquo;s Windows profile being loaded to obtain the key. When using &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd315384.aspx&#34;&gt;Enter-PSSession&lt;/a&gt; to do my interactive testing, the user profile is loaded for me but when using &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd347578.aspx&#34;&gt;Invoke-Command&lt;/a&gt; inside my deployment script, the user profile is not loaded by default so DPAPI can&amp;rsquo;t access the key to decrypt the password. Apparently this is &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.unprotect.aspx&#34;&gt;a known issue with impersonation and the DPAPI&lt;/a&gt;. It&amp;rsquo;s also worth noting that when using the DPAPI with a user key for a domain user account with a roaming profile, I found it needs to&lt;a href=&#34;http://support.microsoft.com/kb/309408#6&#34;&gt;authenticate to the domain controller&lt;/a&gt;, a nice surprise for someone trying to configure delegation to specific services only. My options now appear to be one of:&#xA;1. Use the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/aa379295(v=vs.85).aspx&#34;&gt;OpenProcessToken&lt;/a&gt; and &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/bb762281.aspx&#34;&gt;LoadUserProfile&lt;/a&gt; win32 API functions to load the user profile before making DPAPI calls.&#xA;2. Ignore the Convert*-SecureString cmdlets and call the DPAPI via the .NET &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/2c64xe0y&#34;&gt;ProtectedData class&lt;/a&gt; so I can use the local machine key for encryption instead of the current user&amp;rsquo;s key.&#xA;3. Decrypt the password outside the PS Remoting session and pass the unencrypted password into the Remoting session ready to be used. I don&amp;rsquo;t like the security implications of this.&#xA;I&amp;rsquo;ll likely go with option (2) to get something working as soon as possible and look into safely implementing option (1) when I have more time.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Override the TFS Team Build OutDir property in .NET 4.5</title>
				<link>/2012/05/10/override-the-tfs-team-build-outdir-property-net-4-5/</link>
				<pubDate>Thu, 10 May 2012 05:35:14 +0000</pubDate>
				<guid>/2012/05/10/override-the-tfs-team-build-outdir-property-net-4-5/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;a href=&#34;http://blog.stangroome.com/2014/02/10/override-the-tfs-team-build-outdir-property-in-tfs-2013/&#34; title=&#34;Override the TFS Team Build OutDir property in TFS 2013&#34;&gt;with Team Build 2013 it is easier still&lt;/a&gt;.&lt;/strong&gt; I&amp;rsquo;ve &lt;a href=&#34;http://blog.codeassassin.com/2012/02/03/override-the-tfs-team-build-outdir-property/&#34;&gt;blogged before about the challenge of overriding the OutDir MSBuild property&lt;/a&gt; set by Team Build but this hassle is gone in version 4.5 of the .NET Framework. I stumbled upon a change to the core Microsoft.Common.targets file while trying to understand some build issues with a work project and discovered new logic to modify the OutDir property depending on a variety of conditions. I went searching through the rest of the file for other references to OutDir and also discovered at the top of the file, a new attribute on the Project element. This new attribute&amp;rsquo;s name is &amp;ldquo;&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/bcxfsh87(v=vs.110).aspx&#34;&gt;TreatAsLocalProperty&lt;/a&gt;&amp;rdquo; and it&amp;rsquo;s value is simply &amp;ldquo;OutDir&amp;rdquo;. As at the time of posting this blog entry I could not find any documentation of this new functionality but based on my own testing I found that .NET Framework 4.5 now supports:&#xA;* Overriding the value of an MSBuild property that was specified at the MSBuild command-line by naming that property in the TreatAsLocalProperty attribute at the top of the build project.&#xA;* OutDir can now be specified at the command-line without a trailing slash and it will be corrected for you instead of failing the build.&#xA;* Projects can automatically build to subfolders of the Team Build drop location by setting a new MSBuild property named &amp;ldquo;GenerateProjectSpecificOutputFolder&amp;rdquo; to &amp;ldquo;true&amp;rdquo;.&#xA;* The project-subfolder will be named the same as the project file but can be overridden by specifying an alternate value for the &amp;ldquo;ProjectName&amp;rdquo; MSBuild property.&#xA;* The OutDir property can now be overridden in whatever custom way you like without modification of the Team Build workflow xaml or using a before-solution targets file.&#xA;And because .NET 4.5 is an addition to .NET 4 in the same way .NET 3.5 and .NET 3.0 were to .NET 2.0, your existing .NET 4/VS2010 projects can benefit from this new build-time functionality without taking on new run-time dependencies (&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/hh367887(v=vs.110).aspx&#34;&gt;with some exceptions&lt;/a&gt;). Here is a screenshot for how to configure Team Build 11 or a Team Build 2010 server with .NET 4.5 installed to create per-project folders in the build drop: &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2012/05/generateprojectspecificoutputfolder.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2012/05/generateprojectspecificoutputfolder.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Override the TFS Team Build OutDir property</title>
				<link>/2012/02/03/override-the-tfs-team-build-outdir-property/</link>
				<pubDate>Fri, 03 Feb 2012 04:02:37 +0000</pubDate>
				<guid>/2012/02/03/override-the-tfs-team-build-outdir-property/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;a href=&#34;http://blog.stangroome.com/2012/05/10/override-the-tfs-team-build-outdir-property-net-4-5/&#34; title=&#34;Override the TFS Team Build OutDir property in .NET 4.5&#34;&gt;with .NET 4.5 there is an easier way&lt;/a&gt;.&lt;/strong&gt; A very common complaint from users of Team Foundation Server&amp;rsquo;s build system is that it changes the folder structure of the project outputs. By default Visual Studio puts all the files in each project&amp;rsquo;s respective &lt;code&gt;/bin/&lt;/code&gt; or &lt;code&gt;/bin/&amp;lt;configuration&amp;gt;/&lt;/code&gt; folder but Team Build just uses a flat folder structure putting all the files in the drop folder root or, again, a &lt;code&gt;/&amp;lt;configuration&amp;gt;/&lt;/code&gt; subfolder in the drop folder, with all project outputs mixed together. Additionally because Team Build achieves this by setting the OutDir property via the MSBuild.exe command-line combined with&lt;a href=&#34;http://blogs.msdn.com/b/aaronhallberg/archive/2007/07/16/msbuild-property-evaluation.aspx&#34;&gt;MSBuild&amp;rsquo;s property precedence&lt;/a&gt; this value cannot easily be changed from within MSBuild itself and the popular solution is to &lt;a href=&#34;http://blogs.msdn.com/b/jimlamb/archive/2010/04/13/customizableoutdir-in-tfs-2010.aspx&#34;&gt;edit the Build Process Template *.xaml file to use a different property name&lt;/a&gt;. But I prefer not to touch the Workflow unless &lt;strong&gt;absolutely&lt;/strong&gt; necessary. Instead, I use both the &lt;a href=&#34;http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx&#34;&gt;Solution Before Target&lt;/a&gt; and the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dd722601.aspx&#34;&gt;Inline Task&lt;/a&gt; features of MSBuild v4 to override the default implementation of the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/z7f65y0d.aspx&#34;&gt;MSBuild Task&lt;/a&gt; used to build the individual projects in the solution. In my alternative implementation, I prevent the OutDir property from being passed through and I pass through a property called PreferredOutDir instead which individual projects can use if desired. The first part, substituting the OutDir property for the PreferredOutDir property at the solution level is achieved simply by adding a new file to the directory your solution file resides in. This new file should be named following the pattern &lt;code&gt;before.&amp;lt;your solution name&amp;gt;.sln.targets&lt;/code&gt;, eg for a solution file called &lt;code&gt;Foo.sln&lt;/code&gt; then new file would be &lt;code&gt;before.Foo.sln.targets&lt;/code&gt;. The contents of this new file should &lt;a href=&#34;https://gist.github.com/1727206#file_before.the_solution.sln.targets&#34;&gt;look like this&lt;/a&gt;. Make sure this new file gets checked-in to source control. The second part, letting each project control its output folder structure, is simply a matter of adding a line to the project&amp;rsquo;s *.csproj or *.vbproj file (depending on the language). Locate the first &lt;code&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/code&gt; element inside the project file that doesn&amp;rsquo;t have a Condition attribute specified, and the locate the corresponding &lt;code&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/code&gt; closing tag for this element. Immediately above the closing tag add a line something like this:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Create a PowerShell v3 ISE Add-on Tool</title>
				<link>/2012/01/16/create-a-powershell-v3-ise-add-on-tool/</link>
				<pubDate>Sun, 15 Jan 2012 23:38:27 +0000</pubDate>
				<guid>/2012/01/16/create-a-powershell-v3-ise-add-on-tool/</guid>
				<description>&lt;p&gt;&lt;em&gt;Note: This process is based on PowerShell v3 CTP 2 and is subject change.&lt;/em&gt; When you open PowerShell v3&amp;rsquo;s ISE (Integrated Scripting Environment) you should see a new Commands pane that wasn&amp;rsquo;t present in version 2. &lt;a href=&#34;http://blog.stangroome.com/wp-content/uploads/2012/01/commands-pane.png&#34;&gt;&lt;img src=&#34;http://blog.stangroome.com/wp-content/uploads/2012/01/commands-pane.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt; This is a built-in example of an ISE Add-on Tool but you can also create your own quite easily. At its simplest an ISE Add-on Tool is a WPF Control that implements the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/microsoft.powershell.host.ise.iaddontoolhostobject(v=vs.85).aspx&#34;&gt;IAddOnToolHostObject&lt;/a&gt;interface. To get started writing your own add-on follow these simple steps:&#xA;1. Open Visual Studio and create a new WPF User Control Library project. The new project should contain a new UserControl1.&#xA;2. Add a new Project Reference to the Microsoft.PowerShell.GPowerShell (version 3.0) assembly located in the GAC.&#xA;3. Open the UserControl1.xaml.cs code-behind file and change the UserControl1 class to implement the IAddOnToolHostObject interface.&#xA;4. The only member of this interface is the HostObject property which can be declared a a simple auto-property for now.&#xA;5. Build the project and find the path of the DLL it produces.&#xA;6. Open the PowerShell v3 ISE and load the DLL you have just built, eg: Add-Type -Path &amp;lsquo;c:\users\me\documents\project1\bin\debug\project1.dll&amp;rsquo;&#xA;7. Add the UserControl to the current PowerShell tab&amp;rsquo;s VerticalAddOnTools collection and make it visible (replace &amp;ldquo;Project1.UserControl1&amp;rdquo; below with the full namespace of your control): $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add(&amp;lsquo;MyAddOnTool&amp;rsquo;, [Project1.UserControl1], $true)&#xA;After following these steps you should see a new, blank pane as an extra tab where the Commands pane normally appears and now you can return to Visual Studio and start adding to the appearance and behaviour of your new add-on tool. There are some other things worth knowing about developing ISE Add-On Tools:&#xA;* When your UserControl is added to the ISE, the HostObject property is set to an object almost identical to the &lt;a href=&#34;http://technet.microsoft.com/en-us/library/dd819500.aspx&#34;&gt;$psISE&lt;/a&gt; variable and your control uses this to interact with the ISE itself. For example you can manipulate text in the editor, or you can register for events that tell your control when a new file is opened.&#xA;* While your UserControl is loaded in the ISE, you cannot build in Visual Studio because the DLL is locked and you need to close the ISE to unlock the file. I recommend adding a small PowerShell script to your project that performs steps 6 and 7 above and change your project&amp;rsquo;s Debug options in Visual Studio so that the ISE is started and your script is opened when you press F5.&#xA;* In step 7 above, your control is added to the VerticalAddOnTools collection but there is also a HorizontalAddOnTools collection and the user can move your control between these two at any time via the ISE menus so make sure you design the appearance of your Add-On Tool to work in both orientations.&#xA;Alternatively the &lt;a href=&#34;http://showui.codeplex.com/&#34;&gt;Show-UI module&lt;/a&gt; for PowerShell includes a ConvertTo-ISEAddOn cmdlet to create the necessary WPF objects natively from PowerShell and avoid the need for a Visual Studio project.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Queue another Team Build when one Team Build succeeds</title>
				<link>/2011/09/06/queue-another-team-build-when-one-team-build-succeeds/</link>
				<pubDate>Tue, 06 Sep 2011 06:26:46 +0000</pubDate>
				<guid>/2011/09/06/queue-another-team-build-when-one-team-build-succeeds/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;a href=&#34;http://blog.stangroome.com/2014/02/19/queue-a-team-build-from-another-and-pass-parameters/&#34; title=&#34;Queue a Team Build from another and pass parameters&#34;&gt;with Team Build 2013 you can even pass parameters to queued builds&lt;/a&gt;.&lt;/strong&gt; I have seen several Team Foundation Server environments where multiple build definitions exist in a single project and need to executed in a particular order. Two common techniques to achieve this are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Queue all the builds immediately and rely upon using a single build agent to serialize the builds. This approach prevents parallelization for improved build times and continues to build subsequent builds even when one fails.&lt;/li&gt;&#xA;&lt;li&gt;Check build artifact(s) into source control at the end of the build and let this trigger subsequent builds configured for Continuous Integration. This approach can complicate build definition workspaces and committing build artifacts to the same repository as code is not generally recommended.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;As an alternative I have developed a simple customization to TFS 2010&amp;rsquo;s default build process template (the DefaultTemplate.xaml file in the BuildProcessTemplates source control folder) that allows a build definition to specify the names of subsequent builds to queue upon success. It only requires two minor changes to the Xaml file. The first is a line inserted immediately before the closing &lt;code&gt;&amp;lt;/x:Members&amp;gt;&lt;/code&gt; element near the top of the file:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Executing individual PowerShell 2 commands using .NET 4</title>
				<link>/2011/03/23/executing-individual-powershell-commands-using-net-4/</link>
				<pubDate>Wed, 23 Mar 2011 09:34:27 +0000</pubDate>
				<guid>/2011/03/23/executing-individual-powershell-commands-using-net-4/</guid>
				<description>&lt;p&gt;One of the many great things about PowerShell is that it can utilise the .NET framework directly and third party .NET libraries whenever PowerShell doesn&amp;rsquo;t offer a native solution. However, the PowerShell console, the Integrated Scripting Environment (ISE) and PS-Remoting in PowerShell 2.0 are all built for use with .NET 2.0 through to .NET 3.5. With the release of version 4 of the .NET Framework though, there is an increasing amount of core functionality and third-party assemblies that are not accessible from PowerShell — the new &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx&#34;&gt;Is64BitOperatingSystem property&lt;/a&gt; on the System.Environment class is a simple example. So, given that .NET 4 has excellent support for being able to run most .NET 2 assemblies but PowerShell doesn&amp;rsquo;t have officially support for .NET 4 yet, how can we safely utilise new .NET 4 functionality from PowerShell without waiting for a new PowerShell release from Microsoft? A quick search of the web will reveal a few different approaches, each with their own major drawbacks:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Query all file references in a Visual Studio solution with PowerShell</title>
				<link>/2010/08/30/query-all-file-references-in-a-visual-studio-solution-with-powershell/</link>
				<pubDate>Mon, 30 Aug 2010 09:52:06 +0000</pubDate>
				<guid>/2010/08/30/query-all-file-references-in-a-visual-studio-solution-with-powershell/</guid>
				<description>&lt;p&gt;Today I was working on introducing Continuous Integration to a legacy code base and was discovering the hard way that the solution of about 20 projects had many conflicting references to external assemblies. Some assemblies were different versions, others the same version but in different paths, and others completely missing altogether. Needless to say this wasn&amp;rsquo;t going to build cleanly on a build server. Rather than manually checking the path and version of every assembly referenced by every project in the solution, I wrote a PowerShell script to parse a Visual Studio 2010 solution file, identify all the projects, then parse the project files for the reference information. The resulting &lt;a href=&#34;http://gist.github.com/557222&#34;&gt;Get-VSSolutionReferences.ps1 script is available on GitHub&lt;/a&gt;. Once I had a collection of objects representing all the assembly references I could perform some interesting analysis. Here is a really basic example of how to list all the assemblies referenced by two or more projects:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Create SCVMM Templates with PowerShell</title>
				<link>/2010/08/03/create-scvmm-templates-with-powershell/</link>
				<pubDate>Tue, 03 Aug 2010 12:32:06 +0000</pubDate>
				<guid>/2010/08/03/create-scvmm-templates-with-powershell/</guid>
				<description>&lt;p&gt;Now that I get to work with a TFS 2010 Lab Management environment most days, I find myself building various virtual machines to replicate the production environments of our clients for testing. With many different clients and projects, the range of virtual machine operating systems expands exponentially as matrix of core OS version, processor architecture, service pack, IE version, and other minor variations. However, for any particular configuration, I&amp;rsquo;ll also want multiple copies so naturally I want to make use of System Center Virtual Machine Manager&amp;rsquo;s VM Template Library. However, creating a template from a VM using the SCVMM Administrator Console, without destroying the original VM, is death by a thousand clicks:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Find Duplicate Files With PowerShell</title>
				<link>/2007/10/13/find-duplicate-files-with-powershell/</link>
				<pubDate>Sat, 13 Oct 2007 03:27:20 +0000</pubDate>
				<guid>/2007/10/13/find-duplicate-files-with-powershell/</guid>
				<description>&lt;p&gt;I have pieced together a simple PowerShell script to recursively locate all duplicate files (by content, not name) below a chosen directory. It is not the most elegant code but for my purposes it works and hopefully you will be able to tweak it to suit your needs. Firstly, it filters out any zero-length files. Zero-length files are naturally duplicates of each other and can be found quite trivially without my script. Secondly it groups all files by their length because if the length doesn&amp;rsquo;t match, they can&amp;rsquo;t have the same content. The script then excludes the length-groups with only one entry and calculates the MD5 hash of the remaining files. Groups of files with both matching size and hash are then returned in the results. The hashing function was taken from the &lt;a href=&#34;http://blogs.msdn.com/powershell/archive/2006/04/25/583225.aspx&#34;&gt;Duplicate Files&lt;/a&gt; post on the Windows PowerShell team blog. It simply uses the .NET cryptography namespace to compute the hash. From here you could easily exchange the MD5 algorithm for SHA1 or any other preferred algorithm. Due to the need to read the entire contents of potentially matching files to compute the hash this can cause the script to take a long time against larger files. Executing the script against deep directory structures with many files will take longer too. The script could be easily modified to take a filtered input of files to only find, for example, duplicate photos. Update: The &lt;a href=&#34;https://gist.github.com/2288218&#34;&gt;script is now available on github:gist&lt;/a&gt;. You should save it as &amp;ldquo;Get-DuplicateItems.ps1&amp;rdquo;. Once you have the output of the script you could use it delete the unnecessary files:&lt;/p&gt;</description>
			</item>
			<item>
				<title>PowerShell Registry Find and Replace</title>
				<link>/2007/08/02/powershell-registry-find-and-replace/</link>
				<pubDate>Thu, 02 Aug 2007 03:18:09 +0000</pubDate>
				<guid>/2007/08/02/powershell-registry-find-and-replace/</guid>
				<description>&lt;p&gt;I recently encountered a server where SQL Server had somehow been installed to the admin user&amp;rsquo;s mapped U: drive instead of drive C:. As a result all SQL file paths in the registry referred to &amp;ldquo;U:\Program Files\Microsoft SQL Server\&amp;hellip;&amp;rdquo; but for most users (including the SQL service account) the U: drive did not map to C:. This prevented Management Studio from working and probably many other issues that weren&amp;rsquo;t as visible. I wanted a fast way to find all &amp;ldquo;U:\Program Files&amp;rdquo; references in the registry and repoint them to drive C:. The standard Windows regedit.exe only supports Find but not Replace (and there were a lot of keys to fix) and third party registry tools available on the Internet fall into the untrustworthy category for fixing servers. I ended up writing a quick C# console app to perform the job.The C# app was able to solve the problem and the server works properly now but I felt there should be an easier way: PowerShell. I&amp;rsquo;ve spent an evening hammering out a basic pair of find and replace functions for PowerShell. They don&amp;rsquo;t make as much use of PowerShell&amp;rsquo;s declarative pipelined nature as I&amp;rsquo;d like but they work well. The replace function is particular dangerous if you misuse it so be careful. Perhaps I will implement the -WhatIf switch some day. The find function is simply named Find-RegistryValue. At the moment the function only looks in values, not keys or value names because these are already quite easy to search on with basic PowerShell one-liners. As input the function expects a &amp;ldquo;seek&amp;rdquo; parameter being the text sought and optionally a path to a registry key to begin searching from. If the &amp;ldquo;regpath&amp;rdquo; is not provided it defaults to Get-Location and if it is not a registry path it throws. The find function will return an array of Hashtable objects with all the information you should require: the RegistryKey, the name of the value in the key, and the value itself containing the sought text. The code follows: function Find-RegistryValue ( [string] $seek = $(throw &amp;ldquo;seek required.&amp;rdquo;), [System.Management.Automation.PathInfo] $regpath = (Get-Location) ) { if ($regpath.Provider.Name -ne &amp;ldquo;Registry&amp;rdquo;) { throw &amp;ldquo;regpath required.&amp;rdquo; } $keys = @(Get-Item $regpath -ErrorAction SilentlyContinue) ` + @(Get-ChildItem -recurse $regpath -ErrorAction SilentlyContinue); $results = @(); foreach ($key in $keys) { foreach ($vname in $key.GetValueNames()) { $val = $key.GetValue($vname); if ($val -match $seek) { $r = @{}; $r.Key = $key; $r.ValueName = $vname; $r.Value = $val; $results += $r; } } } $results; } The replace function is named Replace-RegistryValue and relies on the find function to work, resulting in very similar behaviour. It requires the text sought and the registry path just like the find function but it also requires the &amp;ldquo;swap&amp;rdquo; parameter which is the text to replace the sought value with. It calls the find function itself and uses the output to first promote the key to a writable instance then replace the value and return the results. The results include the RegistryKey, the name of the value in the key, the old value and also the new value. Here is the code: function Replace-RegistryValue ( [string] $seek = $(throw &amp;ldquo;seek required.&amp;rdquo;), [string] $swap = $(throw &amp;ldquo;swap required.&amp;rdquo;), [System.Management.Automation.PathInfo] $regpath = (Get-Location) ) { $find = Find-RegistryValue -seek $seek -regpath $regpath; $results = @(); foreach ($target in $find) { $nval = $target.Value -replace $seek, $swap; $r = @{}; $r.Key = $target.Key; $r.ValueName = $target.ValueName; $r.OldValue = $target.Value; $r.NewValue = $nval; $results += $r; $wKey = (Get-Item $r.Key.PSParentPath).OpenSubKey($r.Key.PSChildName, &amp;ldquo;True&amp;rdquo;); $wKey.SetValue($target.ValueName, $nval); } $results; } If you have any suggestions for improving the code or perhaps even a better naming convention for the pair, please leave a comment.&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
