Daniel Cazzulino's Blog

Go Back to
kzu′s Latest post

How to transform T4 templates on build without installing a Visual Studio SDK

The MS recommended way is to just use the Microsoft.TextTemplating.targets which come with the Visual Studio Visualization and Modeling SDK. It makes me slightly nervous that it requires a little known SDK that is hosted on rather than something more “official” like the MSDN Download Center, where the proper VS SDK lives. It also turns out to be absolutely unnecessary, since all you need is already installed with your base Visual Studio setup.


Visual Studio installs the TextTransform.exe utility,  which can use used to transform a template automatically. Ideally, you shouldn’t have to do anything different than you do today when using text templates, and the automatic build-time transform should “just happen”. One way to achieve this is by grabbing all the files that have one of the T4 custom tools assigned (they are always assigned them when you create a new text template in VS):

<Target Name="TransformOnBuild" AfterTargets="BeforeBuild">

    <Error Text="Failed to find TextTransform.exe tool at '$(_TransformExe)."

        <_TextTransform Include="@(None)"
                        Condition="'%(None.Generator)' == 'TextTemplatingFilePreprocessor' Or '%(None.Generator)' == 'TextTemplatingFileGenerator'" />

    <!-- Perform task batching for each file -->
    <Exec Command="&quot;$(_TransformExe)&quot; &quot;@(_TextTransform)&quot;"
          Condition="'%(Identity)' != ''"/>


To determine the location of the utility, we can use a cascading mechanism where we probe for the current VS version as well as all the known ones if that doesn’t work. This is just to be on the super-safe side. Any version of the tool back to VS2010 will work just the same, since very little has changed in the T4 world since then:

    <!-- Initial default value -->
    <_TransformExe>$(CommonProgramFiles)\Microsoft Shared\TextTemplating\10.0\TextTransform.exe</_TransformExe>
    <!-- If explicit VS version, override default -->
    <_TransformExe Condition="'$(VisualStudioVersion)' != ''">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe</_TransformExe>
    <!-- Cascading probing if file not found -->
    <_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\10.0\TextTransform.exe"</_TransformExe>
    <_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\11.0\TextTransform.exe"</_TransformExe>
    <_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\12.0\TextTransform.exe"</_TransformExe>
    <!-- Future proof 'til VS2013+2 -->
    <_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\13.0\TextTransform.exe"</_TransformExe>
    <_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\14.0\TextTransform.exe"</_TransformExe>


That’s all that’s needed. In order to make it super-easy for myself and others, I put together a nuget package and accompanying github repo to maintain it. Just install it like:

PM> Install-Package Clarius.TransformOnBuild

You won’t need to do anything else and your text templates will start transforming automatically on build thanks to the included targets file.


I thought about making the target that transform smarter and only transform if the source template is changed with regards to the last generated output, but it gets very tricky if you use includes. I’m not sure if there should be an additional item property to explicitly mark an included template as the source for the change detection or if the straightforward case without includes is common enough that it’s worth including the smart check anyways despite resulting in outdated output when includes are used?

Would love to hear your thoughts on that. For the time being, simple “transform always” behavior it is :)





  1. This target was just what I was looking for! This works better than using a pre-build event.
    There is some problem however, on the build server the _TransformExe get’s no value as it is looking in the “C:\Program Files\Common Files\” folder but it should (also) look in the “C:\Program Files (x86)\Common Files\” folder. After I added some extra conditions to look in that folder, it works. Could you update your package with this?
    Thanks, Marco

    • What kind of OS does your build server run?

      Since any 64bit version of Windows will define the CommonProgramFiles variables as follows:

      CommonProgramFiles = C:\Program Files (x86)\Common Files
      CommonProgramW6432 = C:\Program Files\Common Files

      So, the .targets is always looking under (x86), which is the place where VS installs the exe. Maybe VS is missing from that server? In that case, you could provide the path yourself?

      I added a $(TextTransformPath) property that you can override for that purpose in the latest version.


  2. Don’t know if it helps, but the build server is a Windows Server 2008 R2 Enterprise 64-bit server, Visual Studio 2012 is installed, and TextTransform.exe is located here: “C:\Program Files (x86)\Common Files\microsoft shared\TextTemplating\11.0″
    Anyway, thanks for your quick response and I hope the new version will be available soon as an update for NuGet

    • As I mentioned on the above reply, that path is precisely right and is what $(CommonProgramFiles) resolves to. It does not resolve to the non x86.

  3. Great tool! Until now I had to use a dummy VSIX addin that I built which does nothing but triggers Build->Transform All T4 Templates before every build.

    I tried to replace my addin with your Nuget package but when I try to build my .tt files I’m getting an erro “Running transformation: System.InvalidCastException: Unable to cast object of type ‘Microsoft.VisualStudio.TextTemplating.CommandLine.CommandLineHost’ to type ‘System.IServiceProvider’.”

    I suspect it’s because the host environment is not available during transformation (I’m referencing EnvDTE.DTE in some parts of the template). The same transformation works when the above mentioned VS command is invoked before the build.

    Is this issue a scenario that simply can’t be supported, or the issue can be solved somehow? (I could provide more details about the .tt file, if needed.)


  4. Hi,

    Relating to the earlier thread about CommonProgramFiles, on my Win 8.1 x64 PC, if I run SET COMMAND at a command prompt I get

    CommonProgramFiles=C:\Program Files\Common Files
    CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
    CommonProgramW6432=C:\Program Files\Common Files

    If I do the same at a command prompt specifically launched as x86 (c:\windows\syswow64\cmd.exe) then I do get the behaviour you described
    CommonProgramFiles=C:\Program Files (x86)\Common Files
    CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
    CommonProgramW6432=C:\Program Files\Common Files

    Thought this might be why you’re both seeing different behaviour. The x86/x64 redirection stuff makes sense but can trip you up if you’re not specific about the bitness of the process you’re executing.

  5. Also, I’m a big fan (and paid-up user) of the T4 editor :P Are you planning on releasing any updates?

  6. This doesn’t appear to work if your T4 template uses VS build variables, such as $(SolutionDir) or $(OutDir). Anyone have any tips on solving this problem? All of my templates have those.

  7. I have got it working using the SDK method but I was curious to try this. It won’t work for me in this case. It found the texttemplate.exe no problem but my .tt has “var path = Path.GetDirectoryName(Host.TemplateFile)+”/..//”;
    var enResxFile = Host.ResolvePath(path + “Resources.resx”);” With the SDK method it was fine but using your method I got this error when compilling:

    “Error 7 Running transformation: System.IO.DirectoryNotFoundException: Could not find a part of the path ‘E:\Resources.resx’. E:\”

    For the MSBuild method the path is resolved via Path.GetDirectoryName(Host.TemplateFile) but it seems your method by passing the .tt to
    C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe” “ makes it not working with the path?

    To make everyone understand further. In my .tt file I have set hostspecific to true and I use Path.GetDirectoryName(Host.TemplateFile) to specify where my Resources.resx is located and then I used Host.ResovlePath to load the resx file. Any suggestion how I can solve this problem? Thanks so much in advance ;)

  8. Nice article. I do not fully understand how to use it. I believe it could help resolve an error I get when opening in VS2013 a project developed with VS2012: Could not load file or assembly ‘Microsoft.VisualStudio.TextTemplating.11.0 The system cannot find the file specified

    Could you help fix this issue? Check it online by remote desktop? For 1 hour consulting?

  9. Instead of hardcoding the VS Version number you can use $(VisualStudioVersion)

  10. I’m no expert but this doesn’t seem to be checking if outputs are timestamp’d before inputs and just generating every time you build – this is a very good first step, but with a large quantity of templating and code gen it’ll slow the build down for people who aren’t actively working in the code gen area needlessly (and substantially).

    Also, it’d be **great** to get something like this working in a standalone fashion for build servers (no VS, just MSBuild + .exe + necessary .dlls). As you’ve noted, the ‘official tooling’ in this area is woefully underaddressed.

    Thanks for the good start- I think that I can blend it with a few things I’d tried a few months ago to get something functioning and somewhat smart.

    • VERY good observations! Actually, I made it extremely simple on purpose.

      Most (all?) T4 templates transform some input other than the template itself, and the output they generate is dictated by the extension in the output directive. So the input/output check can only be done in an automatic fashion if you parse the T4 for the output directive AND somehow figure out what the template is reading to perform the transformation.

      One way of solving both would be by adding item metadata specifying that, which would be fairly straightforward but require manual changes to the project files.

  11. About using your tool, it makes me slightly nervous that it requires a little known tool developed by you that is hosted on NuGet rather than something more “official” like the MSDN Download Center, where the proper VS SDK lives.

  12. I just updated to the version 1.1.1 and it is not transforming files on build. Can you help me?

  13. I like this, but as per comment #6 above it doesn’t seem to handle compile-time variables int the tt script, such as TargetPath. E.g., the following works fine when i run the tt by hand, but not with this tool:

    I am using this because my script does reflection on the .dlls itself to autogenerate some properties..


    • What exactly are you using? I have the same problem. I am generating a javascript config file using some static properties set on a C# class living in the built assembly. I need to import the assembly and use the class inside the T4 template.

  14. Hi, installed from nuget package. Got below error.

    This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see The missing file is {0}.

  15. Simply genius! We have a which compiles to a Resources.ts which, in turns, compiles to a Resources.js (with all the resources in the application). Using your nugget and setting Build Action to None did the trick.

    Thank you!

  16. Thanks, this will help, in my case QA/Testers generate SQL code using t4 templates Our QAs don’t have Visual Studio installed, just Devs, I need to confirm if we can legally give QA a copy of TextTransform.exe, your blog is very helpful

  17. Doesn’t work if your .tt file contains macros like $(ProjectDir) or $(EnvironmentName).

  18. We tried your package, but only TextTransform.exe is not enough to make it work.

    We use TeamCity as build server, and I have copied TextTransform.exe to this path, since we are using Visual Studio 2012 on DEV computer:

    C:\Program Files (x86)\Common Files\microsoft shared\TextTemplating\11.0

    But at transformation time, we have this error:

    EXEC Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
    D:\HOMEWARE\TEAMCITY\BuildAgent2\work\72d3c196e0ab743c\packages\Clarius.TransformOnBuild.1.1.12\build\Clarius.TransformOnBuild.targets(45, 9): error MSB3073: The command “”C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0\TextTransform.exe” “D:\HOMEWARE\TEAMCITY\BuildAgent2\work\72d3c196e0ab743c\”" exited with code 1.

    We have not much code in the tt code, only this :

    And we use TopicPrefix as a variable in the code after.

    Thanks for the help.

  19. Unfortunately, we can’t install Visual Studio on our build server.
    Too bad TextTransform can’t work without VS. We can’t use this nuget package because of that…

  20. Is it fully standalone? It would be a great solution :)