All in all the code generator creating C# classes out of XML config files and environment variables is a small piece of code. Writing it however was more painful than I expected: it takes quite some tricks to get MSBuild and PowerShell to work, resulting in way too many hours spent scouring the web. This blog goes through those tricks to make them a little less obscure.
The first part of the code is an MSBuild Target which NuGet injects into the VS project during package install. The target – called CreateSettingsClass – runs a PowerShell script right before compilation for each file with an .stx extension in the project folder.
The Target order needed to be specified twice: a first time via BeforeTargets=”ResolveAssemblyReferences” so the code gets generated before XAML compilation and a second time via CompileDependsOn to get Intellisense to work.
A couple more points of interest in that XML fragment:
An ItemGroup sub-element inside Target is used to add the generated files to the list of C# files to compile.
The target specifies both Inputs and Outputs attributes to enable incremental builds and avoid regenerating C# files when not needed. This is quite useful as PowerShell takes some time to start. The downside is that MSBuild does not detect registry-key modifications, so a forced rebuild is required for those changes to be applied.
Besides sluggishness, one other issue with using PowerShell inside MSBuild is that the latter does not understand well the error messages from the former. That tends to create obscure error messages in build logs. Using an MSBuild task instead of a script would likely improve that. This is left as an exercise for the reader.
The second part of the code is the PowerShell script. It takes a pair of XML files, merge them, merge environment variables, and generate the C# class definition. The main stumbling block there was the use of [ref] variables, needed for some reason to avoid PowerShell duplicating XML elements when calling the Update-Settings() function.