A reader of this blog asked me to review some reusable MSBuild file that he created. I won't reveal the details of his files here but here are my comments which are relevant to all reusable MSBuild files.
Properties in targets files
For targets file (MSBuild files designed to be imported by other files) if possible you should always define properties using conditions to ensure that the consumer hasn't alredy defined that value. See my new article MSBuild Best Practices (http://msdn.microsoft.com/en-us/magazine/dd419659.aspx) specifically the section titled "Defining Dynamic Items and Properties".
Assumptions in targets files
Your ProjectOutputHelper.targets file overrides the BuildDependsOn property. This is good and I am sure that it works great, but I don't agree 100% with this approach. You are assuming that the consumers of the file will be importing the Microsoft.Common.targets file which is most likely true, but in my opinion is a bad practice. Better would be to allow consumers of the file to extend the BuildDependsOn. See my new book Inside the Microsoft Build Engine in Chapter 7 you will find a section ‘Creating Reusable Build Elements’ which define some rules for targets files, this is explained more there.
Extendable targets should declare dependencies in a property
All non-internal targets contained inside of targets files should declare the target dependencies inside of a property. This allows consumers to inject steps into specific areas of the build process. For instance from Microsoft.Common.targets:
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
Design incremental targets
If possible you should design your targets to build incrementally ( Chapter 6 of my book explains this) so that the targets that are already up-to-date don’t have to be rebuilt. It is good to get into the habit of creating targets that build incrementally.