Determine assembly version during a post-build event

Viewed 38988

Let's say I wanted to create a static text file which ships with each release. I want the file to be updated with the version number of the release (as specified in AssemblyInfo.cs), but I don't want to have to do this manually.

I was hoping I could use a post-build event and feed the version number to a batch file like this:

call foo.bat $(AssemblyVersion)

However I can't find any suitable variable or macro to use.

Is there a way to achieve this that I've missed?

13 Answers

As a workaround I've written a managed console application which takes the target as a parameter, and returns the version number.

I'm still interested to hear a simpler solution - but I'm posting this in case anyone else finds it useful.

using System;
using System.IO;
using System.Diagnostics;
using System.Reflection;

namespace Version
{
    class GetVersion
    {
        static void Main(string[] args)
        {
            if (args.Length == 0 || args.Length > 1) { ShowUsage(); return; }

            string target = args[0];

            string path = Path.IsPathRooted(target) 
                                ? target 
                                : Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + Path.DirectorySeparatorChar + target;

            Console.Write( Assembly.LoadFile(path).GetName().Version.ToString(2) );
        }

        static void ShowUsage()
        {
            Console.WriteLine("Usage: version.exe <target>");
        }
    }
}

I think the best thing you can do is look at MSBuild and MsBuild Extension Pack you should be able to edit you solution file so that a post build event occurs and writes to your test file.

If this is too complicated then you could simply create a small program that inspects all assemblies in you output directory and execute it on post build, you could pass in the output directory using the variable name... for example in the post build event...

AssemblyInspector.exe "$(TargetPath)"

class Program
{
    static void Main(string[] args)
    {
        var assemblyFilename = args.FirstOrDefault();
        if(assemblyFilename != null && File.Exists(assemblyFilename))
        {
            try
            {
                var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFilename);
                var name = assembly.GetName();

                using(var file = File.AppendText("C:\\AssemblyInfo.txt"))
                {
                    file.WriteLine("{0} - {1}", name.FullName, name.Version);
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }
    }
}

You could also pass in the text file location...

I don't know Why but Brent Arias macro not worked for me (@(VersionNumber) always was empty) :( .Net6 VS2022. I ended up with slightly modified version:

<Target Name="GetVersion" AfterTargets="PostBuildEvent">
    <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
        <Output TaskParameter="Assemblies" ItemName="AssemblyInfo" />
    </GetAssemblyIdentity>
    <PropertyGroup>
        <VersionInfo>%(AssemblyInfo.Version)</VersionInfo>
    </PropertyGroup>
    <!--And use it after like any other variable:-->
    <Message Text="VersionInfo = $(VersionInfo)" Importance="high" />
</Target>

Unless I'm missing something, this is a lot simpler. Put this in your post-build script:

@echo off

echo STARTING BUILD OF MAIN APP
echo ==========================

echo
set version=0.0.0.0
FOR /F delims^=^"^ tokens^=2 %%i in ('findstr /b /c:"[assembly: AssemblyVersion(" $(ProjectDir)\Properties\AssemblyInfo.cs') do (
  set version=%%i
)

echo Building Assembly Version: %version%

echo Version: %version%> readme.txt

This works with .net Framework and Winforms + WPF. Sorry about the formatting - couldn't find any lang for batch!

It should be noted that using the modernized (VS2017+) .csproj formatting and VS2022, $(AssemblyVersion) as in the original post can now be used directly.

If you have a library project you can try to use WMIC utility (available in windows). Here is an example. Good thing - you don't need to use any external tools.

SET pathFile=$(TargetPath.Replace("\", "\\"))

FOR /F "delims== tokens=2" %%x IN ('WMIC DATAFILE WHERE "name='%pathFile%'" get  Version /format:Textvaluelist')  DO (SET dllVersion=%%x)
echo Found $(ProjectName) version %dllVersion%

I looked for the same feature and i found the solution on MSDN. https://social.msdn.microsoft.com/Forums/vstudio/de-DE/e9485c92-98e7-4874-9310-720957fea677/assembly-version-in-post-build-event?forum=msbuild

$(ApplicationVersion) did the Job for me.

Edit:

Okay I just saw the Problem $(ApplicationVersion) is not from AssemblyInfo.cs, its the PublishVersion defined in the project Properties. It still does the job for me in a simple way. So maybe someone needs it too.

Another Solution:

You can call a PowerShell script on PostBuild, here you can read the AssemblyVersion directly from your Assembly. I call the script with the TargetDir as Parameter

PostBuild Command:

PowerShell -ExecutionPolicy Unrestricted $(ProjectDir)\somescript.ps1 -TargetDir $(TargetDir)

PowerShell Script:

param(
    [string]$TargetDir
)

$Version = (Get-Command ${TargetDir}Example.exe).FileVersionInfo.FileVersion

This way you will get the Version from the AssemblyInfo.cs

Related