So I needed to execute a custom task, mainly to transform some XML, as a part of the build. The build has largely migrated to msbuild. I've worked with make, ANT and other build systems before and they more or less all provide the same functionality: A way to specify a dependency relationship that ultimately ends in telling the compiler/linker what and when to compile/link.
MSBuild seems to take the object oriented metaphor a little deeper as it relates to XML. That is, both the verbs of the system (Targets and Tasks in msbuild-speak) and the nouns of the system (Properties and Items) are represented as elements. The best way to get a handle on these concepts is to peruse "MSBuild Concepts"
One of the first gotcha (there are always gotcha moments with build systems) moments I've encountered has been related to the Exec task. It's a built in task that ostensibly executes any command passed to it. Except that it seems to not like managed executables. Or parameters with whitespace (yep, 2013 and whitespace is still dangerous). It'll happily open notepad.exe (even without a fully qualified path) but chokes on a "Hello World" C# console app. But not a C++ "Hello World" app. And the exit code is usually -21474.... which to any programmer looks a lot like -(2^31) - 1 and is usually indicative of a bug lurking somewhere.
Fortunately it's pretty straightforward to roll your own Task. I love it when they provide both an interface and a handy default implementation so that you only have to override the behavior in which you're interested.
If you're doing anything other than calling cmd.exe intrinsics (e.g., echo, dir, etc...) then I highly recommend doing it inside a custom task.