I\'ve got a PowerShell script as follows
##teamcity[progressMessage \'Beginning build\']
# If the build computer is not running the appropriate version of .N
None of these options worked for me in my PowerShell script for whatever reason. I spent hours on it.
For me the best option was to put a layer between TeamCity and PowerShell. So I simply wrote a C# console application which calls the PowerShell script.
The way I do it is, in TeamCity we call a script named: RemoteFile.ps1
With script arguments: %system.RemoteServerFQDN% %system.RemoteUser% %system.RemoteUserPassword% %system.RemoteScriptName% %system.RemotePropertiesFile% %system.BuildVersion% %system.RunList%
param (
[Parameter(Mandatory=$true)]
$Computername,
[Parameter(Mandatory=$true)]
$Username,
[Parameter(Mandatory=$true)]
$Password,
[Parameter(Mandatory=$true)]
$ScriptName,
[Parameter(Mandatory=$true)]
$Propfile,
[Parameter(Mandatory=$true)]
$Version,
[Parameter(Mandatory=$true)]
[string[]]$DeploymentTypes
)
$securePassword = ConvertTo-SecureString -AsPlainText -Force $Password
$cred = New-Object System.Management.Automation.PSCredential $Username, $securePassword
Write-Host "Readying to execute invoke-command..."
Invoke-Command -ComputerName $Computername -Credential $cred -ScriptBlock { D:\Deployment\PowershellWrapper.exe $using:ScriptName $using:Propfile $using:Version $using:DeploymentTypes } -ArgumentList $ScriptName,$Propfile,$Version,$DeploymentTypes
Which exists on the remote server in the specified location.
Then that file calls this: powershellwrapper.exe also in the specified location (my script has four parameters to pass to the PowerShell script)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace PowershellWrapper
{
class Program
{
static void Main(string[] args)
{
try
{
string argFull = @"""{0} {1} {2} {3}""";
string arg0 = args[0];
string arg1 = args[1];
string arg2 = args[2];
string arg3 = args[3];
string argFinal = string.Format(argFull, arg0, arg1, arg2, arg3);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = @"powershell.exe";
startInfo.Arguments = argFinal;
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardError = false;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
startInfo.CreateNoWindow = false;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
Console.WriteLine("An error occurred in the deployment.", e);
Console.WriteLine("Please contact test@test.com if error occurs.");
}
}
}
}
And that calls my script with four parameters. The script being the first parameter, plus three arguments. So essentially what is going on here is that I'm executing the PowershellWrapper.exe instead of the PowerShell script itself to capture the erroneous exit code 0's, and it still reports the full script running back to the TeamCity log.
I hope that makes sense. It works like a charm for us.