Search code examples
c#powershelljenkinsconsole-applicationmsdeploy

MSDeploy deploy c# console application on remote server


There will be used Jenkins automation server.

What I need to do during deployment:

  1. Stop console application
  2. Deploy via MSDeploy service
  3. Run the console application again

The main problem is that the console application has to work always (there is an endless cycle) and it displays important information about processes inside. And admin can logon anytime under Administrator account and see if any error/warning displays in the console window.

What I have for now:

"C:\Program Files\IIS\Microsoft Web Deploy V3\MSDeploy.exe" -verb:sync -preSync:runCommand=D:\Dev\tools\pre-deploy.cmd -postSync:runCommand="powershell -file D:\Dev\tools\run.ps1",waitInterval=3000 -source:contentpath="D:\Publish\" -dest:contentpath="D:\Dev",computername=https://somedomain:8172/MsDeploy.axd,username=adminuser,password=adminpassword,authtype=Basic -allowUntrusted=True -verbose

pre-deploy.cmd just contains script to kill the running process (working well)

run.ps1 constains the next script

$username = 'adminuser'; 
$password = 'adminpassword'; 
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force; 
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword; 
$proc = Start-Process D:\Dev\ConsoleApp.exe 0 -Credential $credential -PassThru; 
$proc.WaitForExit();

First, D:\Dev\ConsoleApp.exe starts in the background under proper user (it's expected), I can't see the console window and it is not what I'm expecting.

Second, when MsDeploy has been finished deployment it kills powershell process on the remote computer and D:\Dev\ConsoleApp.exe also ends with the parent process.

As for me, the console application should be converted into windows service, then there is no problem with deploying and running it. But the customer wants to see the console window with information inside, and I'm on investigation way now.


Solution

  • It seems there is no way except create a task via Windows Scheduler to run a console application like it was run by user himself.

    To run under the specific user you need first off all create some wrapper script

    wrapper.ps1

    param(
        [string] $UserName,
        [string] $Password,
        [string] $DestPath,
        [string] $Engine,
        [string] $EngineArgs
    )
    
    $securePassword = ConvertTo-SecureString $Password -AsPlainText -Force; 
    $credential = New-Object System.Management.Automation.PSCredential $UserName, $securePassword; 
    $proc = Start-Process powershell -ArgumentList "-noexit ""$DestPath\tools\run.ps1"" -UserName $UserName -DestPath """"$DestPath"""" -Engine """"$Engine"""" -EngineArgs $EngineArgs" -Credential $credential -PassThru;
    $proc.WaitForExit();
    exit 0
    

    then you need create Windows Scheduler task

    run.ps1

    param(
        [string] $UserName,
        [string] $DestPath,
        [string] $Engine,
        [string] $EngineArgs
    )
    
    $A = New-ScheduledTaskAction -Execute "$DestPath\$Engine.exe" -Argument $EngineArgs
    $T = New-ScheduledTaskTrigger -Once -At (get-date).AddSeconds(10); $t.EndBoundary = (get-date).AddSeconds(60).ToString('s')
    $S = New-ScheduledTaskSettingsSet -StartWhenAvailable -DeleteExpiredTaskAfter 00:00:30
    
    $Task = New-ScheduledTask -Action $A -Trigger $T -Settings $S
    $Task | Register-ScheduledTask -Force -TaskName "$Engine For Customer $EngineArgs" -User "$UserName"
    
    #Fix Stuck BITS job
    
    $A = New-ScheduledTaskAction -Execute "powershell.exe" -Argument '-command &{Get-BitsTransfer -AllUsers | Where-Object { $_.JobState -like "TransientError" } | Remove-BitsTransfer}'
    $T = New-ScheduledTaskTrigger -Once -At (get-date).AddSeconds(10); $t.EndBoundary = (get-date).AddSeconds(60).ToString('s')
    $S = New-ScheduledTaskSettingsSet -DeleteExpiredTaskAfter 00:00:40
    Register-ScheduledTask -Force -user $UserName -TaskName "Fix Stuck BITS" -Action $A -Trigger $T -Settings $S
    exit 0