Skip to main content

Useful PowerShell script to update a Visual Studio Project version in an msbuild .props file. Found in the SonarLint extension for VisualStudio repository on Github.

[CmdletBinding()]
Param(
    [Parameter(Mandatory = $True, Position = 1)]
    [ValidatePattern("^\d{1,3}\.\d{1,3}\.\d{1,3}$")]
    [string]$version
)

function Write-Header([string]$message) {
    Write-Host "================================================"
    Write-Host $message
    Write-Host "================================================"
}

function Set-VersionForDotNet {
    Write-Header "Updating version in .Net files"

    try {
        Push-Location ".\build"
        $versionPropsFile = Resolve-Path "Version.props"
        $xml = [xml](Get-Content $versionPropsFile)
        $xml.Project.PropertyGroup.MainVersion = ${version}
        $xml.Save($versionPropsFile)
        msbuild "ChangeVersion.proj"
    }
    finally {
        Pop-Location
    }
}

Set-VersionForDotNet


<#
=========================================================================
    Version File Contents: '.\build\Version.props'
=========================================================================

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <MainVersion>4.5.0</MainVersion>
    <BuildNumber>0</BuildNumber>
    <Sha1>not-set</Sha1>
    <BranchName>not-set</BranchName>
    <FullVersion>$(MainVersion).$(BuildNumber)</FullVersion>
    <AssemblyVersion>$(MainVersion)</AssemblyVersion>
    <AssemblyFileVersion>$(FullVersion)</AssemblyFileVersion>
    <AssemblyInformationalVersion>Version:$(FullVersion) Branch:$(BranchName) Sha1:$(Sha1)</AssemblyInformationalVersion>
    <VsixVersion>$(FullVersion)</VsixVersion>
  </PropertyGroup>
</Project>
#>

<#
=========================================================================
    Regex Transform Tasks: '.\build\RegexTransform.tasks'
=========================================================================

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="RegexTransform" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup>
            <Items ParameterType="Microsoft.Build.Framework.ITaskItem[]" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System.IO" />
            <Using Namespace="System.Text.RegularExpressions" />
            <Using Namespace="Microsoft.Build.Framework" />
            <Code Type="Fragment" Language="cs">
                <![CDATA[
            foreach(ITaskItem item in Items) {
              string fileName = item.GetMetadata("FullPath");
              string find = item.GetMetadata("Find");
              string replaceWith = item.GetMetadata("ReplaceWith");
              string replaceGroup = item.GetMetadata("ReplaceGroup");
              int expectedMatchCount;
              if (!int.TryParse(item.GetMetadata("ExpectedMatchCount"), out expectedMatchCount))
              {
                Log.LogError("ExpectedMatchCount could not be parsed, the value is '{0}', which is not an integer", item.GetMetadata("ExpectedMatchCount"));
              }

              if(!File.Exists(fileName)) {
                Log.LogError("Could not find version file: {0}", fileName);
              }
              string content = File.ReadAllText(fileName);
              int matchCount = 0;

              string replacedContent = Regex.Replace(content, find, (match) =>
              {
                  matchCount++;
                  return match.Result(replaceWith);
              });

              if (matchCount != expectedMatchCount)
              {
                Log.LogError("Actual ({0}) and expected ({1}) match count doesn't match", matchCount, expectedMatchCount);
              }
              else
              {
                File.WriteAllText(fileName, replacedContent, Encoding.UTF8);
                Log.LogMessage(MessageImportance.High, string.Format("{0} matches (on pattern '{2}') have been replaced (with '{3}') in file '{1}'", matchCount, fileName, find, replaceWith));
              }
            }
          ]]>
            </Code>
        </Task>
    </UsingTask>
</Project>

#>

<#
=========================================================================
    Change Version: '.\build\ChangeVersion.proj'
=========================================================================

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildProjectDirectory)\Version.props" />
  <Import Project="$(MSBuildProjectDirectory)\RegexTransform.tasks" />
  <PropertyGroup>
    <SolutionRoot>$(MSBuildProjectDirectory)\..</SolutionRoot>
  </PropertyGroup>

  <ItemGroup>
    <AssemblyVersion Include="$(SolutionRoot)\src\AssemblyInfo.Shared.cs">
      <Find>(?&lt;=\[assembly\: AssemblyVersion\(")([^"]*)</Find>
      <ReplaceWith>$(AssemblyVersion)</ReplaceWith>
      <ExpectedMatchCount>1</ExpectedMatchCount>
    </AssemblyVersion>
    <AssemblyFileVersion Include="$(SolutionRoot)\src\AssemblyInfo.Shared.cs">
      <Find>(?&lt;=\[assembly\: AssemblyFileVersion\(")([^"]*)</Find>
      <ReplaceWith>$(AssemblyFileVersion)</ReplaceWith>
      <ExpectedMatchCount>1</ExpectedMatchCount>
    </AssemblyFileVersion>
    <AssemblyInformationalVersion Include="$(SolutionRoot)\src\AssemblyInfo.Shared.cs">
      <Find>(?&lt;=\[assembly\: AssemblyInformationalVersion\(")([^"]*)</Find>
      <ReplaceWith>$(AssemblyInformationalVersion)</ReplaceWith>
      <ExpectedMatchCount>1</ExpectedMatchCount>
    </AssemblyInformationalVersion>

    <VsixVersion Include="$(SolutionRoot)\src\Integration.Vsix\source.extension.vsixmanifest">
      <Find>(?&lt;=Identity.*Version=")([^"]*)</Find>
      <ReplaceWith>$(VsixVersion)</ReplaceWith>
      <ExpectedMatchCount>1</ExpectedMatchCount>
    </VsixVersion>
    <VsixVersion Include="$(SolutionRoot)\src\Integration.Vsix_2017\source.extension.vsixmanifest">
      <Find>(?&lt;=Identity.*Version=")([^"]*)</Find>
      <ReplaceWith>$(VsixVersion)</ReplaceWith>
      <ExpectedMatchCount>1</ExpectedMatchCount>
    </VsixVersion>

    <VsPackageVersion Include="$(SolutionRoot)\src\Integration.Vsix\SonarLintIntegrationPackage.cs">
      <Find>(?&lt;=\[InstalledProductRegistration\("#110", "#112", ")([^"]*)</Find>
      <ReplaceWith>$(AssemblyFileVersion)</ReplaceWith>
      <ExpectedMatchCount>1</ExpectedMatchCount>
    </VsPackageVersion>
  </ItemGroup>

  <Target Name="UpdateAssemblyVersion">
    <RegexTransform Items="@(AssemblyVersion)" />
    <RegexTransform Items="@(AssemblyFileVersion)" />
    <RegexTransform Items="@(AssemblyInformationalVersion)" />
    <RegexTransform Items="@(VsixVersion)" />
    <RegexTransform Items="@(VsPackageVersion)" />
  </Target>
</Project>
#>

<#
=========================================================================
    Shared Assembly Info: '.\src\AssemblyInfo.Shared.cs'
=========================================================================

using System.Reflection;
using System.Runtime.InteropServices;

// Note: keep the version numbers in sync with the VSIX (source.extension.manifest)
[assembly: AssemblyVersion("4.5.0")]
[assembly: AssemblyFileVersion("4.5.0.0")] // This should exactly match the VSIX version
[assembly: AssemblyInformationalVersion("Version:4.5.0.0 Branch:not-set Sha1:not-set")]
[assembly: AssemblyConfiguration("")]
[assembly: ComVisible(false)]
[assembly: AssemblyProduct("SonarLint for Visual Studio")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyCompany("SonarSource")]
[assembly: AssemblyCopyright("Copyright (C) SonarSource SA 2016-2018")]
[assembly: AssemblyTrademark("")]

#>