You can use some pinvokes...
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetFileVersionInfoSize(string lptstrFilename, out int lpdwHandle);
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GetFileVersionInfo(string lptstrFilename, int dwHandle, int dwLen, byte[] lpData);
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool VerQueryValue(byte[] pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);
public static Tuple<string, string>[] GetVersionInfo(string fileName, params string[] keys)
{
    int num;
    int size = GetFileVersionInfoSize(fileName, out num);
    if (size == 0)
    {
        throw new Win32Exception();
    }
    var bytes = new byte[size];
    bool success = GetFileVersionInfo(fileName, 0, size, bytes);
    if (!success)
    {
        throw new Win32Exception();
    }
    int size2;
    IntPtr ptr;
    success = VerQueryValue(bytes, @"\VarFileInfo\Translation", out ptr, out size2);
    uint[] langs;
    if (success)
    {
        langs = new uint[size2 / 4];
        for (int i = 0, j = 0; j < size2; i++, j += 4)
        {
            langs[i] = unchecked((uint)(((ushort)Marshal.ReadInt16(ptr, j) << 16) | (ushort)Marshal.ReadInt16(ptr, j + 2)));
        }
    }
    else
    {
        // Taken from https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/FileVersionInfo.cs,470
        langs = new uint[] { 0x040904B0, 0x040904E4, 0x04090000 };
    }
    string[] langs2 = Array.ConvertAll(langs, x => @"\StringFileInfo\" + x.ToString("X8") + @"\");
    var kv = new Tuple<string, string>[keys.Length];
    for (int i = 0; i < kv.Length; i++)
    {
        string key = keys[i];
        string value = null;
        foreach (var lang in langs2)
        {
            success = VerQueryValue(bytes, lang + key, out ptr, out size2);
            if (success)
            {
                value = Marshal.PtrToStringUni(ptr);
                break;
            }
        }
        kv[i] = Tuple.Create(key, value);
    }
    return kv;
}
and then you use:
string name = "Win32Project1.exe";
var infos = GetVersionInfo(name, "LastModified", "Comments", "CompanyName", "FileVersion", "LegalCopyright", "LegalTrademarks", "ProductVersion", "InternalName", "OriginalFilename", "FileDescription", "ProductName", "BuildDate");
var buildDate = infos.Single(x => x.Item1 == "BuildDate").Item2;
Out of curiosity I've began exploring the various structs of the VS_VERSIONINFO, and I've written some code:
public class VersionInfo
{
    [DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetFileVersionInfoSize(string lptstrFilename, out int lpdwHandle);
    [DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool GetFileVersionInfo(string lptstrFilename, int dwHandle, int dwLen, byte[] lpData);
    [DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool VerQueryValue(byte[] pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);
    public readonly Version FileVersion;
    public readonly Version ProductVersion;
    public readonly uint FileFlagsMask;
    public readonly uint FileFlags;
    public readonly uint FileOS;
    public readonly uint FileType;
    public readonly uint FileSubtype;
    // Always null
    public readonly DateTime? FileDate;
    protected VersionInfo(Version fileVersion, Version productVersion, uint fileFlagsMask, uint fileFlags, uint fileOS, uint fileType, uint fileSubtype, DateTime? fileDate)
    {
        FileVersion = fileVersion;
        ProductVersion = productVersion;
        FileFlagsMask = fileFlagsMask;
        FileFlags = fileFlags;
        FileOS = fileOS;
        FileType = fileType;
        FileSubtype = fileSubtype;
        FileDate = fileDate;
    }
    // vi can be null on exit
    // Item1 = language | codepage
    // Item2 = Key
    // Item3 = Value
    public static IEnumerable<Tuple<uint, string, string>> ReadVersionInfo(string fileName, out VersionInfo vi)
    {
        int num;
        int size = GetFileVersionInfoSize(fileName, out num);
        if (size == 0)
        {
            throw new Win32Exception();
        }
        var buffer = new byte[size];
        bool success = GetFileVersionInfo(fileName, 0, size, buffer);
        if (!success)
        {
            throw new Win32Exception();
        }
        return ReadVersionInfo(buffer, out vi);
    }
    // vi can be null on exit
    // Item1 = language | codepage
    // Item2 = Key
    // Item3 = Value
    public static IEnumerable<Tuple<uint, string, string>> ReadVersionInfo(byte[] buffer, out VersionInfo vi)
    {
        int offset;
        // The offset calculated here is unused
        var fibs = ReadFileInfoBaseStruct(buffer, 0, out offset);
        if (fibs.Key != "VS_VERSION_INFO")
        {
            throw new Exception(fibs.Key);
        }
        // Value = VS_FIXEDFILEINFO
        if (fibs.ValueLength != 0)
        {
            uint signature = BitConverter.ToUInt32(buffer, fibs.ValueOffset);
            if (signature != 0xFEEF04BD)
            {
                throw new Exception(signature.ToString("X8"));
            }
            uint strucVersion = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 4);
            var fileVersion = new Version(BitConverter.ToUInt16(buffer, fibs.ValueOffset + 10), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 8), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 14), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 12));
            var productVersion = new Version(BitConverter.ToUInt16(buffer, fibs.ValueOffset + 18), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 16), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 22), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 20));
            uint fileFlagsMask = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 24);
            uint fileFlags = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 28);
            uint fileOS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 32);
            uint fileType = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 36);
            uint fileSubtype = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 40);
            uint fileDateMS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 44);
            uint fileDateLS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 48);
            DateTime? fileDate = fileDateMS != 0 || fileDateLS != 0 ?
                (DateTime?)DateTime.FromFileTime((long)fileDateMS << 32 | fileDateLS) :
                null;
            vi = new VersionInfo(fileVersion, productVersion, fileFlagsMask, fileFlags, fileOS, fileType, fileSubtype, fileDate);
        }
        else
        {
            vi = null;
        }
        return ReadVersionInfoInternal(buffer, fibs);
    }
    protected static IEnumerable<Tuple<uint, string, string>> ReadVersionInfoInternal(byte[] buffer, FileInfoBaseStruct fibs)
    {
        int sfiOrValOffset = (fibs.ValueOffset + fibs.ValueLength + 3) & (~3);
        while (sfiOrValOffset < fibs.Length)
        {
            int nextSfiOrValOffset;
            var sfiOrVal = ReadFileInfoBaseStruct(buffer, sfiOrValOffset, out nextSfiOrValOffset);
            if (sfiOrVal.Key == "StringFileInfo")
            {
                int stOffset = sfiOrVal.ValueOffset;
                while (stOffset < sfiOrVal.EndOffset)
                {
                    int nextStOffset;
                    var st = ReadFileInfoBaseStruct(buffer, stOffset, out nextStOffset);
                    uint langCharset = uint.Parse(st.Key, NumberStyles.HexNumber);
                    int striOffset = st.ValueOffset;
                    while (striOffset < st.EndOffset)
                    {
                        int nextStriOffset;
                        var stri = ReadFileInfoBaseStruct(buffer, striOffset, out nextStriOffset);
                        // Here stri.ValueLength is in words!
                        int len = FindLengthUnicodeSZ(buffer, stri.ValueOffset, stri.ValueOffset + (stri.ValueLength * 2));
                        string value = Encoding.Unicode.GetString(buffer, stri.ValueOffset, len * 2);
                        yield return Tuple.Create(langCharset, stri.Key, value);
                        striOffset = nextStriOffset;
                    }
                    stOffset = nextStOffset;
                }
            }
            else if (sfiOrVal.Key == "VarFileInfo")
            {
                int varOffset = sfiOrVal.ValueOffset;
                while (varOffset < sfiOrVal.EndOffset)
                {
                    int nextVarOffset;
                    var var = ReadFileInfoBaseStruct(buffer, varOffset, out nextVarOffset);
                    if (var.Key != "Translation")
                    {
                        throw new Exception(var.Key);
                    }
                    int langOffset = var.ValueOffset;
                    while (langOffset < var.EndOffset)
                    {
                        unchecked
                        {
                            // We invert the order suggested by the Var description!
                            uint high = (uint)BitConverter.ToInt16(buffer, langOffset);
                            uint low = (uint)BitConverter.ToInt16(buffer, langOffset + 2);
                            uint lang = (high << 16) | low;
                            langOffset += 4;
                        }
                    }
                    varOffset = nextVarOffset;
                }
            }
            else
            {
                Debug.WriteLine("Unrecognized " + sfiOrVal.Key);
            }
            sfiOrValOffset = nextSfiOrValOffset;
        }
    }
    protected static FileInfoBaseStruct ReadFileInfoBaseStruct(byte[] buffer, int offset, out int nextOffset)
    {
        var fibs = new FileInfoBaseStruct
        {
            Length = BitConverter.ToInt16(buffer, offset),
            ValueLength = BitConverter.ToInt16(buffer, offset + 2),
            Type = BitConverter.ToInt16(buffer, offset + 4)
        };
        int len = FindLengthUnicodeSZ(buffer, offset + 6, offset + fibs.Length);
        fibs.Key = Encoding.Unicode.GetString(buffer, offset + 6, len * 2);
        // Padding
        fibs.ValueOffset = ((offset + 6 + (len + 1) * 2) + 3) & (~3);
        fibs.EndOffset = offset + fibs.Length;
        nextOffset = (fibs.EndOffset + 3) & (~3);
        return fibs;
    }
    protected static int FindLengthUnicodeSZ(byte[] buffer, int offset, int endOffset)
    {
        int offset2 = offset;
        while (offset2 < endOffset && BitConverter.ToInt16(buffer, offset2) != 0)
        {
            offset2 += 2;
        }
        // In chars
        return (offset2 - offset) / 2;
    }
    // Used internally
    protected class FileInfoBaseStruct
    {
        public short Length { get; set; }
        public short ValueLength { get; set; }
        public short Type { get; set; }
        public string Key { get; set; }
        public int ValueOffset { get; set; }
        public int EndOffset { get; set; }
    }
}
use it like:
string name = "Win32Project1-loc.exe";
// vi could be null on return from ReadVersionInfo
VersionInfo vi;
// Note that it is an IEnumerable<>... If you want to use 
// it multipel times, you should .ToArray() it!
var infos = VersionInfo.ReadVersionInfo(name, out vi);
// For example
var buildDate = infos.Single(x => x.Item2 == "BuildDate").Item3;