Tips for. NET Project Automation: One-click update version and full analysis of release scripts

Tips for. NET Project Automation: One-click update version and full analysis of release scripts

The article details how to use PowerShell scripts and batch files to automatically update program versions and one-click publishing in the. NET Avalonia UI project. First, the article explains the settings and modifications of PowerShell execution policies to ensure that scripts can execute normally. Then, it introduces ways to add scripts to Visual Studio pre-generated events to automatically update version numbers, and how to use batch files to publish applications on multiple platforms. Finally, an example of a PowerShell script is provided that can automatically update the version information of the program based on the Git tag. These methods can improve the development efficiency of. NET projects and the convenience of the release process.

最后更新 2/21/2025 10:30 PM
沙漠尽头的狼
预计阅读 11 分钟
分类
Avalonia UI
标签
.NET C# Avalonia UI Visual Studio released

In the journey of. NET development, efficient version management and convenient release process are key links to improve development efficiency and project quality. Today, let's discuss in depth how to use scripts to automatically update program versions and publish them in one click for the. NET Avalonia UI project (of course, these methods can also be used in other. NET projects) to make your development process smoother and more efficient.

PowerShell script execution permissions check

Before running PowerShell scripts, it is crucial to understand and set execution policies correctly. Execution policies determine whether PowerShell allows scripts to be run and what types of scripts to run. You can use the following simple command to view the current execution strategy:

Get-ExecutionPolicy

Different execution policy values have different meanings and impose different degrees of restrictions on the execution of scripts:

  • Restricted: This is the default policy. It is like a strict gatekeeper. No scripts are allowed to run. You can only type commands line by line in the PowerShell console. This ensures the security of the system to a certain extent, but it is undoubtedly a constraint for developers who need to execute scripts in batches.
  • AllSigned: Only scripts signed by trusted publishers are allowed to run. This is like allowing only people with a specific pass to enter, ensuring the reliability of the source of the script, but also increasing the threshold for script use, because not all scripts are signed.
  • RemoteSigned: Locally created scripts can be run directly, while scripts downloaded from the Internet must be signed by a trusted publisher to run. This is a setting that balances security and convenience, allowing flexibility for local development while also providing security for scripts downloaded online.
  • Unrestricted: All scripts are allowed to run, but scripts downloaded from the Internet will be prompted for confirmation before running. This gives developers a lot of freedom, but it also carries certain security risks, because scripts that are not strictly checked can carry malicious code.
  • Bypass: No scripts are blocked from running and there will be no security prompts. This is a very open setting and is generally only used in specific, safe and controllable environments, otherwise the system may be exposed to security threats.

By default, the execution policy is Restricted, which may cause writeback to the file to fail, prompting that writing to the stream is not allowed. For example, when you try to run a script that needs to modify the contents of a file, you encounter permissions issues.

Modify execution strategy

In order to run scripts smoothly, we need to choose the appropriate execution strategy based on our needs. If you want to easily run local scripts and network download scripts that have passed certain security checks while ensuring certain security, setting the execution policy to RemoteSigned is a good choice.

However, it should be noted that modifying the execution policy may require administrator privileges, so be sure to run PowerShell as an administrator and use the following command to modify it:

Set-ExecutionPolicy RemoteSigned

In this way, scripts created locally can be run directly, while scripts downloaded from the Internet need to be signed and verified, effectively reducing security risks.

Verify modification results

After modifying the execution policy, in order to ensure that the settings take effect, you can use the Get-ExecutionPolicy command again to verify that the modification was successful. When you see that the output is RemoteSigned, it means that you have successfully modified the execution policy, and you should be able to run the.ps1 script normally after that.

VS Release

In Visual Studio, we can automatically update project versions by adding scripts to pre-built events. The details are as follows: Find the "Build Events" tab in the project properties, and add the following command to the "Pre-Build Events Command Line":

powershell -ExecutionPolicy Bypass -File "UpdateAssemblyVersion.ps1" -AssemblyInfoFile "GlobalAssembly.cs" -Configuration "$(ConfigurationName)" -Platform "$(PlatformName)"

The parameters here have clear meanings:

  • ConfigurationName: Represents the active solution configuration, common ones such as Debug (debug mode) and Release (release mode). Under different configurations, we may want to generate programs with different version numbers to distinguish between development and official release versions.
  • PlatformName: Represents the active solution platform, such as AnyCPU (for any CPU architecture), x86 (32-bit architecture), x64 (64-bit architecture), etc. Different platforms may require different version identities to meet compatibility and performance requirements.

Batch document release

Sometimes, we may want to publish programs without opening Visual Studio and be able to easily expand to multiple platforms such as Windows, Linux, and macOS. At this time, batch files come in handy. The following is an example batch file:

@echo off
setlocal enabledelayedexpansion

rem 遍历 GlobalAssemblies 目录下的文件执行 PowerShell 脚本
for %%f in (GlobalAssemblies\*) do (
    powershell -ExecutionPolicy Bypass -File "UpdateAssemblyVersion.ps1" -AssemblyInfoFile "%%f" -Configuration "Release" -Platform "x64"
    rem 检查 PowerShell 脚本执行是否成功
    if !errorlevel! neq 0 (
        echo Failed to update assembly version for file %%f!
        endlocal
        exit /b !errorlevel!
    )
)

rem 设置发布路径
set PUBLISH_PATH=publish\win-x64

rem 定义项目信息数组,格式为 项目名称,项目路径(只写项目目录),相对发布目录名
set "projects=码坊工具箱,src\CodeWF.Toolbox.Desktop,codewf Avalonia发布测试,tests\AvaloniaAotDemo,AvaloniaAotDemo"

rem 遍历项目数组
for %%a in ("%projects: =","%") do (
    set "current_project=%%~a"
    for /f "tokens=1,2,3 delims=," %%b in ("!current_project!") do (
        set "projectName=%%b"
        set "projectPath=%%c"
        set "relativePublishDir=%%d"

        rem 拼接 .pubxml 文件的默认路径
        set "pubxmlPath=!projectPath!\Properties\PublishProfiles\FolderProfile-win_x64.pubxml"
        rem 拼接当前项目的发布路径
        set "CURRENT_PUBLISH_DIR=!PUBLISH_PATH!\!relativePublishDir!"

        echo "projectName after assignment: !projectName!"
        echo "projectPath after assignment: !projectPath!"
        echo "relativePublishDir after assignment: !relativePublishDir!"
        echo "pubxmlPath after assignment: !pubxmlPath!"
        echo "current publish dir after assignment: !CURRENT_PUBLISH_DIR!"


        echo Publishing !projectName! for win-64...
        rem 清空发布目录
        if exist "!CURRENT_PUBLISH_DIR!" (
            rd /s /q "!CURRENT_PUBLISH_DIR!"
        )
        rem 创建发布目录
        mkdir /p "!CURRENT_PUBLISH_DIR!" 2>nul
        rem 执行 dotnet publish 命令进行 AOT 发布,并指定目标框架
        dotnet publish "!projectPath!" /p:PublishProfile="!pubxmlPath!" -f net9.0-windows -o "!CURRENT_PUBLISH_DIR!"
        rem 检查 dotnet publish 命令的退出代码
        if !errorlevel! neq 0 (
            echo Publish of !projectName! failed!
            endlocal
            exit /b !errorlevel!
        )
        rem 检查发布目录是否存在
        if exist "!CURRENT_PUBLISH_DIR!" (
            rem 删除调试符号文件
            del "!CURRENT_PUBLISH_DIR!\*.pdb"
        )
        echo Publish of !projectName! succeeded!
        echo Published files of !projectName! are located at: "!CURRENT_PUBLISH_DIR!"
    )
)

endlocal

This batch file first traverses the files in the GlobalAssemblies directory and executes a PowerShell script to update the program version. It then defines an array of project information, including the project name, project path, and relative publishing directory name. Then, you loop through the array of items, publishing each item in turn. During the publishing process, first clear the publishing directory, then create a new publishing directory, and then execute the dotnet publish command for AOT publishing, and specify the target framework as net9.0-windows. Finally, check whether the release was successful. If it was successful, delete the debugging symbol file and output the success information and release path.

PowerShell scripts implement automatic version updates

The following PowerShell script is used to automatically update program versions based on Git tags:

param(
	[Parameter(Mandatory=$true)]
	[string]$AssemblyInfoFile,

	[Parameter(Mandatory=$true)]
	[string]$Configuration,

	[Parameter(Mandatory=$true)]
	[string]$Platform
)

# 检查文件是否存在
if (-not (Test-Path $AssemblyInfoFile)) {
    throw "错误:文件 $AssemblyInfoFile 不存在"
}

Write-Output "AssemblyInfoFile: $AssemblyInfoFile"
Write-Output "Configuration: $Configuration"
Write-Output "Platform: $Platform"



#获取当前日期时间,并生成格式化的时间戳
$currentDateTime =Get-Date
#获取当前分支,签出标签创建时间[基准时间]
$strBranchCreateTime =git log -1 --format=%ai $latest_tag
$dateBranchCreateTime=[DateTime]::Parse($strBranchCreateTime)
#时间差的总分数
$timeDifMinutes =[math]::Round(($currentDateTime-$dateBranchcreateTime).TotalMinutes)
#版本号格式处理成x.x.65535.65535
$yy=[math]::Floor($timeDifMinutes/65535)
$thirdInfo=$timeDifMinutes-$yy*65535
#读取文件内容
$content = Get-Content -Path $AssemblyInfoFile -Encoding Unicode
#使用正则表达式获职 AssemblyProduct 的值
$productPattern='^\[assembly: AssemblyProduct\("([^"]+)"\)\]'
$product = ""
#查找包含 AssemblyProduct 的行,并匹配正则表达式
foreach($line in $content){
	if($line -match $productPattern){
		$product= $matches[1]
		break #找到匹配后退出循环
	}
}
$items=$product -split '_'
$product=$items[0]
#当前最近标签、checkout hash值
$currentCommitHash=git describe --always --tag --long
$items=$currentCommitHash.Split('-')
$hashInfo=$items[$items.Length-1]
$firstFileVersion="0.0"
$secondFileVersion="100"
if($items.Length -eq 3)
{
	$firstFileVersion=$items[0].Replace("v","");
	$firstFileItems=$firstFileVersion.split('.');
	$firstFileversion=$firstFileItems[0]+"."+$firstFileItems[1]
	$secondFileVersion=$items[1]+"$yy".PadLeft(2,'0')
}

$platformInfo = ""
if ($Configuration -eq "Debug") {
	$platformInfo = "D"
} elseif ($Configuration -eq "Release") {
	$platformInfo = "R"
} else {
	$platformInfo = "A"
}
switch ($Platform) {
	"x86" {
		$platformInfo += "-86"
	}
	"x64" {
		$platformInfo += "-64"
	}
	"ARM" {
		$platformInfo += "-ARM"
	}
	"AnyCPU" {
		$platformInfo += "-AnyCPU"
	}
	default {
		$platformInfo += "-Unknow"
	}
}

#定义新的 AssemblyProduct和 AssemblyFileversion
$strDayInfo= $currentDateTime.Tostring("yyyyMMddHHmm")
$newAssemblyProduct = "$product"+"_"+"$platformInfo"+"_"+"$hashInfo"+"_"+"$strDayInfo"
if($secondFileVersion -eq "000")
{
	$secondFileVersion="0"
}
$newAssemblyFileVersion = "$firstFileVersion"+"."+"$secondFileVersion"+"."+"$thirdInfo"

# 更新 AssemblyProduct
$content = $content -replace '^\[assembly: AssemblyProduct\(".*"\)\]', "[assembly: AssemblyProduct(`"$newAssemblyProduct`")]"

# 更新AssemblyVersion
$content = $content -replace '^\[assembly: AssemblyVersion\(".*"\)\]', "[assembly: AssemblyVersion(`"$newAssemblyFileVersion`")]"

# 更新AssemblyFileVersion
$content = $content -replace '^\[assembly: AssemblyFileVersion\(".*"\)\]', "[assembly: AssemblyFileVersion(`"$newAssemblyFileVersion`")]"

# 将更新后的内容写入 AssemblyInfo.cs 文件
Set-Content -Path $AssemblyInfoFile -Value $content -Encoding Unicode

This script first receives three parameters: AssemblyInfoFile (path to the assembly information file), Configuration (configuration name), and Platform (platform name). It then checks whether the file exists and throws an error if it does not. Then, each part of the version number is calculated by obtaining information such as the current date and time, the Git tag creation time, etc. Generate a new AssemblyProduct and AssemblyFileVersion based on configuration and platform information. Finally, regular expressions are used to replace the old version information in the file, and the updated content is written to the AssemblyInfo.cs file, realizing automatic update of the program version.

Through these scripts and methods, we can greatly improve the development efficiency of. NET projects and automate version management and release processes. I hope these contents will be helpful to your development work and make you more comfortable on the road to. NET development.

以上示例脚本可在开源项目找到:dotnet9/CodeWF.Toolbox: CodeWF Toolbox 使用 Avalonia 开发的跨平台工具箱 Cross platform toolbox developed using Avalonia

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 8/9/2025

Lang.Avalonia: Avalonia's multi-language solution seamlessly supports three formats: Resx/XML/JSON

This is a multi-language management library specially designed for the Avalonia framework. It reconstructs the multi-language support logic through plug-in architecture. It is not only compatible with traditional Resx resource files, but also adds support for XML and JSON formats. It also provides type-safe resource references, dynamic language switching and other capabilities make multi-language development simpler and more efficient.

继续阅读