Build Process and Powershell - Visual Studio Project - c#

I am trying to add a script (possibly a PowerShell script) to my Visual Studio C# project. The goal of this script is to re-create a file every time I build my project. Ideally this script would run before Visual Studio's build process every time I want to build my project.
I am completely new to this process and I don't seem to find a way (or understand) a way of doing this.
Thank you in advance for your help!
EDIT : This is what my PowerShell script looks like.
$file_path = 'C:\Users\<username>\Desktop\TestScripts'
$file_name = 'test.xml'
$file = $file_path +'\'+ $file_name
$file_exist = Test-Path $file
If($file_exist)
{
Remove-Item $file
}
$file_header_comment = '<!-- This file was auto generated during the build process -->'
New-Item -Path $file_path -Name $file_name -Value $file_header_comment -ItemType file -force

In your project's properties, on the Build Events tab, invoke your script on the Pre-build event command line. Something like:
Powershell.exe -File myScript.ps1

Related

How to reproduce Visual Studio ClickOnce publish from command line

I have been publishing my app by clicking the Publish button in the VS2022 project Publish tool. I want to recreate the same behaviour from the command line.
My C# project targets .NET 6.0, and my .pubxml has <PublishProtocol>ClickOnce</PublishProtocol>.
These docs sound like they should document what I need, but the suggested variations on msbuild /target:publish absolutely do not produce the same result as clicking the button in VS:
The <PublishDir> and <PublishUrl> from the .pubxml are ignored.
The <ApplicationRevision> is not updated even when <IsRevisionIncremented> is true.
Most importantly, the output is missing the main MyApp.application file and the Application Files folder.
Update:
A script to achieve your requirements:
#find the .csproj file
$csproj = Get-ChildItem -Path . -Filter *.csproj
# #return the name of the project
$projectname = $csproj.Name -replace ".csproj",""
$publishdir = "bin\publish"
$publishXML = "Properties\PublishProfiles\ClickOnceProfile.pubxml"
#remove all content of the "$publishdir/Application Files" directory
Get-ChildItem -Path $publishdir"\Application Files" | Remove-Item -Recurse
MSBuild.exe /target:publish /p:COnfiguration=publish /p:PublishProfile=Properties\PublishProfiles\ClickOnceProfile.pubxml /p:PublishDir=$publishdir
#remove all files or directories except setup.exe, projectname.application and the directory "Application Files"
Get-ChildItem -Path $publishdir | Where-Object {$_.Name -ne "setup.exe" -and $_.Name -ne $projectname+".application" -and $_.Name -ne "Application Files"} | Remove-Item -Recurse
#get the content of Project.PropertyGroup.ApplicationRevision in the .pubxml file
$pubxmldata = [xml](Get-Content $publishXML)
$ApplicationRevision = $pubxmldata.Project.PropertyGroup.ApplicationRevision
#increment the ApplicationRevision value
$ApplicationRevision = [int]$ApplicationRevision + 1
#replace the ApplicationRevision value in the .pubxml file
$pubxmldata.Project.PropertyGroup.ApplicationRevision = [string]$ApplicationRevision
#save the .pubxml file
$pubxmldata.Save($publishXML)
Original Answer:
The <PublishDir> and <PublishUrl> from the .pubxml are ignored.
The <ApplicationRevision> is not updated even when
is true.
Most importantly, the output is missing the main
MyApp.application file and the Application Files folder.
For the first and the third requirement, using the below command will solve the issue:
msbuild -t:restore
msbuild /target:publish /p:Configuration=publish /p:PublishProfile=Properties\PublishProfiles\ClickOnceProfile.pubxml /p:PublishDir=bin\Release\net6.0-windows\app.publish\ /p:PublishUrl="bin\publish\"
Result:
For the second requirement, the value didn't increase is totally expected, because it is not automatically incremented for builds performed at the command-line. See this official document:
Publish Properties
Increase this value need based on IDE, pure msbuild command can't achieve this.

Use TextTransform (tt files) into the Azure Devops pipeline

Is it possible to transform the **/*.tt file into a *.cs file.
Using Azure Devops pipeline?
Otherwise is there a CLI command available for Dotnet core using TextTransform ?
I already test : T5.TextTransform.Tool but is don't work (and deprecated)
Thanks for your help
How i solve this problem using Devops pipeline + script:
As mention #Leo Liu-MSFT Install dotnet-t4
install global -g
Create powershell script and find tt file
Seach all *.tt file and convert them with the t4 command
Get-ChildItem -Path .\ -Filter *.tt -Recurse -File -Name| ForEach-Object {
$file = [System.IO.Path]::GetFileName($_);
$directory = [System.IO.Path]::GetDirectoryName($_)
"Conversion file : " + $file
t4 "$directory\$file" -I="$directory"
}
NOTE : It is important to place the T4.ps1 file in the parent directory of your *.tt files
Is it possible to transform the **/*.tt file into a *.cs file. Using Azure Devops pipeline?
The answer is yes.
According to the state of the package T5.TextTransform.Tool:
T5 was a stopgap measure for a time when Mono.TextTemplating was not
available for .NET Core. Now that that is no longer the case, T5 is
not needed and no longer being maintained. Use Mono.TextTemplating's
dotnet-t4 instead.
So, we could use the Mono.TextTemplating instead of T5.TextTransform.Tool.
Besides, there is also an implementation of the TextTransform.exe command-line tool, we could use the command line to transform the .tt file into .cs file:
"%CommonProgramFiles%\Microsoft Shared\TextTemplating\1.2\texttransform.exe" -out %1.cs -P %2 -P "%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5" %1.tt
Check this thread for some more details.
Hope this helps.

Path for Add-PSSnapin not correct when running PowerShell Script from C#

I am running PowerShell Scripts from a C# Tool like this:
using (PowerShell pshell = PowerShell.Create())
{
pshell.AddCommand(scriptFullPath);
pshell.AddParameter("username", user);
pshell.AddParameter("password", pass);
PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
PSInvocationSettings settings = new PSInvocationSettings();
settings.ErrorActionPreference = ActionPreference.Stop;
pshell.Invoke(null, outputCollection, settings);
}
Almost everything works fine in the Script until I need special Cmdlets from other Assemblies. The Add-PSSnapin Command will always fail with:
Exception: The Windows PowerShell snap-in 'Microsoft.SharePoint.Powershell' is not installed on this computer.
Exception: Cannot bind parameter 'Path' to the target. Exception setting "Path": "Cannot find path 'D:\dev\tool\Microsoft.SharePoint.dll' because it does not exist."
when running
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq "Microsoft.SharePoint.Powershell"}
if ($snapin -eq $null)
{
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell"
Add-Type -Path "Microsoft.SharePoint.dll"
Add-Type -Path "Microsoft.SharePoint.Runtime.dll"
}
Everything works fine when running the Script directly in a PowerShell window, so I guess it has something to do with the PATH or Scope that is not forwarded from the C# Tool. Playing around with the Parameter useLocalScope of AddCommand or other Parameters did not yield any results (although I am not sure if this has anything to do with paths).
How can I make the Script work and find external Assemblies?
The SharePoint PowerShell snapin is available in 64bit only. Your C# tool may be running as an x86 process, and therefore would give you the error "not installed". Also you may have to run the program "as Administrator" as some of the commands need that to work.
The second error is, you're right, that there is no PATH variable set for SharePoint by default. The workaround is to specify the full path to the .dll, (and changing the version number for your install) e.g.
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.dll"

MSBuild failing. Missing Release/WinRTXamlToolkit

Trying to build a Windows 8.1 store app with msbuild but getting an error. This is my first battle with msbuild and I haven't had much luck with the documentation as it all appears to leverage UWP specific things. The error I'm getting reads
C:\git\adr\win8app\src\AppDataRoom.WinRT.Adr\AppDataRoom.WinRT.Adr.csproj" (default target) (1) ->
(_GenerateAppxPackageRecipeFile target) ->
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\AppxPackage\Microsoft.AppXPackage.Targets(2156,5): error
APPX0702: Payload file 'C:\app\bin\x64\Release\WinRTXamlToolkit\WinRTXamlToolkit.xr.xml' do
es not exist.
There are 25 other errors following all related to WinRTXamlToolkit missing inside of the bin\x64\Release folder
My msbuild command I'm running is:
msbuild .\app.csproj /p:Configuration="Release" /p:Platform="x64
I understand WinRTXamlToolKit is a nuget package and I can see the dll inside of the release folder but how what do I do to solve this error? What am I missing?
I ended up finding a solution (although it still feels a little hacky). I ended up wrapping everything in an a powershell script. The script first restores the projects nuget packages, just in case it's not there for some reason. Then the script copies the WinRTXamlToolKit folder from packages into the bin/x64/Release folder and then I run the MSBuild command and now everything appears to build correctly. Here is what the script looks like (I don't write powershell scripts very often so my conventions may not be the best)
#create some alias
$nugetPath = $sourceControlRoot + ".nuget/nuget.exe";
$nugetPackagesPath = $sourceControlRoot + "/packages/";
$projectPath = $sourceControlRoot + "/TestingProject/"
Set-Alias nuget $nugetPath
#Nuget Restore
$solutionPath = $sourceControlRoot + "/TestingProject.sln"
nuget restore $solutionPath
#To Help MSBuild we need to copy the WinRTXamlToolkit into the bin/Release folders
$winRtXamlToolkitPath = $nugetPackagesPath + "WinRTXamlToolkit.1.6.1.3/lib/netcore451/WinRTXamlToolkit"
$copyOutput64 = $projectPath + "bin/x64/Release/WinRTXamlToolkit"
$copyOutput86 = $projectPath + "bin/x86/Release/WinRTXamlToolkit"
$testPath = $copyOutput64
if (!(Test-Path $testPath )) {
Copy-Item $winRtXamlToolkitPath $copyOutput64 -recurse
Copy-Item $winRtXamlToolkitPath $copyOutput86 -recurse
Write-Output "WinRTXamlToolkit copied into bin folders"
}
#build the project
$buildPath = $projectPath + "TestingProject.csproj"
msbuild $buildPath /p:Configuration="Release" /p:Platform="x64"

Post build event execute PowerShell

Is it possible to set up a .NET project with a post build event to execute a powershell script? I am using this script to generate some files.
Also can I pass whether it's a debug or release build to script. An example of this would be great.
Here is an example :
First of all : you must be aware of the fact that PowerShell must be configure to execute scripts. The following line allow PowerShell to execute scripts :
Set-ExecutionPolicy RemoteSigned
Special mention here : if you are running a 64bits system you've got to take care of the fact that 'devenv.exe' the Visual Studio 2010 executable is a 32Bits exe, so you need to allow PowerShell 32 to execute scripts.
Once here you can go in your project properties and configure post build as shown here under (sorry in french) :
For example :
Here is the file 'psbuild.ps1', it creates a 'test.txt' in the target path with the configuration name inside. I put in comment different ways to debug your postbuild script (message box, sound, message on the output)
param ([string]$config, [string]$target)
#[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
#[void][System.Windows.Forms.MessageBox]::Show("It works.")
#[Console]::Beep(600, 800)
#Write-Host 'coucou'
set-content $target -Value $config -Force
command Set-ExecutePolicy will temporarily set execution policy under current session. If you set this in powershell and run post build command in vs you will still get not allowed. So set first then run your ps1 script like bellow
powershell -ExecutionPolicy Unrestricted $(ProjectDir)Deploy.ps1 -ProjectDir $(ProjectDir) -TargetPath $(TargetPath)
Instead of messing with system-wide settings and having to differentiate between 32 and 64-bit environments, a much easier and more reliable approach is to specify the ExecutionPolicy in the call to PowerShell, as follows:
C:\Users\xyz>PowerShell -ExecutionPolicy Unrestricted
PS C:\Users\xyz> Get-ExecutionPolicy
Unrestricted
PS C:\Users\xyz> exit
C:\Users\xyz>PowerShell -ExecutionPolicy RemoteSigned
PS C:\Users\xyz> Get-ExecutionPolicy
RemoteSigned
Note in the above code how calling Get-ExecutionPolicy tells you the current mode. Also note how this mode is specified in the call to PowerShell itself, which can be combined with a script filename:
test.ps1 contents:
echo ('The current policy is ' + (Get-ExecutionPolicy)).ToString()
Calling test.ps1 with Unrestricted policy on a system having scripts disabled:
C:\Users\xyz>PowerShell -ExecutionPolicy Unrestricted -file test.ps1
The current policy is Unrestricted
Also note that the above call does not require admin rights, so it can be called in Visual Studio's Pre-Build Step or similar.
Before calling power-shell script from visual studio, set the ExecutionPolicy to RemoteSigned from power-shell window like this...
Set-ExecutionPolicy -Scope CurrentUser;
ExecutionPolicy: RemoteSigned;
then call powershell script in the following manner...
(no need to pass full "powershell.exe" file path)
powershell.exe $(SolutionDir)Setup.ps1 -SolutionDir $(SolutionDir) -ProjectPath $(ProjectPath)
then in the script, you can always read the parameter like this...
param([string]$SolutionDir,
[string]$ProjectPath);
#Write-Host ($SolutionDir +" Call this script with following aruments");
#Write-Host ($ProjectPath +" Call this script with following aruments");
I made it with below command in post-build even command:
PowerShell -NoProfile -ExecutionPolicy unrestricted -file $(SolutionDir)AutomationScript\DBAutomationScript.ps1 -target $(SolutionDir)MUFG.SECMOD.Data\SqlScripts -generatedFileName $(SolutionDir)MUFG.SECMOD.Data\SqlScripts\DeploymentDBScript.sql
DBAutomationScript.ps1 contents:
param ([string]$target, [string]$generatedFileName)

Categories

Resources