Skip to main content

Build/Deploy Windows service with TFS

Building and deploying a web service or website via TFS is pretty straight forward, but automatically deploying a windows service or console application takes a b it of setup. I’ve outlined the steps below to get your service deployed.

Step 1: Set up Automated Build and MSDeploy on the Target server.

If you are doing any sort of automated build/deploy I recommend using MSDeploy. You can follow steps 1-3 from a previous post here.

Step 2: Edit the .csproj file

The project file for the app you are trying to deploy needs to be edited so that TFS will create a directory for the output of the project. Otherwise the project will be built, but the assemblies will be placed in the code drop location with no organization to it.

To edit the file, go to the open file dialog and locate the csproj file. Select it but don’t click “Open. Instead click on the dropdown arrow next to the Open button, select “Open with”, and choose the XML (Text) editor as shown:

SNAGHTML37cb4280

Once the file is open, add the following “PropertyGroup” XML to the file above the ItemGroup section: 

  <PropertyGroup Condition="$(TeamBuildOutDir) != '' ">
<OutputPath>$(TeamBuildOutDir)\$(MSBuildProjectName)</OutputPath>
</PropertyGroup>

Step 3: Run the automated Build


At this point you want to run the automated build to verify that everything builds properly and that the output directory is created properly.


Step 4: Create a batch script to deploy the code


This approach is identical to the steps 5-7 outlined in the previous post here (same as above). However, the script will be different. We will still take the drop location as the first parameter, but instead of using the setparameters.xml file, we’ll set the parameters directly in the service call. We’ll also leverage the PreSync and PostSync abilities to uninstall the service before deploying and install the service after deploying. This way we don’t run into issues with the assemblies being in use while we are trying to deploy:

SET _location=###%1%###
SET _location=%_location:"###=%
SET _location=%_location:###"
=%
SET _location=%_location:###=%
rem set _logfile=%_location%DeployWindowsServices.txt
set _msdeploy="C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe"

set _serviceName=ACMEMonitorService
set _exeName="ACME.FASMonitor"
set _sourceDir=%_location%\ACME.FASMonitor
set _destDir=ACME_SchedulerJobs\ACME.FASMonitor\

echo Deploying %_serviceName% to %_destDir%

%_msdeploy% -verb:sync -source:dirPath="%_sourceDir%",includeAcls='False' -dest:dirpath="\\%_destServer%\c$\%_destDir%",computerName=%_destServer%,userName=%_user%,password=%_password%,authtype=NTLM -useCheckSum -preSync:runCommand="C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe c:\%_destDir%\%_exeName%.exe /u",waitInterval="15000",waitAttempts=1,dontUseCommandExe="false" -postSync:runCommand="C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe c:\%_destDir%\%_exeName%.exe",waitInterval="15000",waitAttempts=1,dontUseCommandExe="false"
%_msdeploy% -verb:sync -source:runCommand="net start %_serviceName%",waitInterval="25000",waitAttempts=1 -dest:auto,computerName=%_destServer%,userName=%_user%,password=%_password%,authtype=NTLM

echo Done Deploying %_serviceName% to %_destDir%



Step 5: Run the deployment.


That’s it! with the setup above, the windows service will be built, deployed to the code drop location and then deployed and installed on the destination server.


Other uses


The example above shows how to deploy a windows service, but if you have a console app, it can be done the same way, but without the preSync/postSync actions. You can even take it a step further and run schtasks to disable/enable a task if the windows service/console app is associated with a scheduled task.


Enjoy!

Comments

  1. Your batch file references several variables that don't seem to be defined anywhere:
    %_destServer%
    %_user%
    %_password%

    ReplyDelete

Post a Comment

Popular posts from this blog

Executing .ps1 files in a DockerFile

This week I was trying to containerize an existing java application. Part of "installing" the application  on the container required executing an PowerShell script in the container during the Image build. Based on the documentation here  I thought i could add the following command to my dockerfile and it would work: RUN install.ps1 However, when I went to build the image, it just hung on that step. I tried several other variations of the run command including: RUN ["Powershell", ".\install.ps1"] which resulted in the following error: '["Powershell"' is not recognized as an internal or external command,operable program or batch file. RUN ["Powershell.exe", ".\install.ps1"] which returned the same error as above. I was about to give up and move the PowerShell commands from the .ps1 file directly into the dockerfile itself as described here , but I had an "A HA!" moment and decided to give a simpler a

Get NodeAuthorization working in Kubernetes with acs-engine

Node Authorization in k8s I'm starting to get into the container world and I'm loving it. Recently we helped a client build out and deploy a micro-services application in Kubernetes. We created the cluster in Azure using the open source project  acs-engine . After we got the cluster set up, our client asked for some updates to the cluster for security reasons. One of those updates was to enable Node Authorization . What is Node Authorization? Node Authorization locks down each Node in the cluster to only be able to do actions on itself. If this is not turned on, its possible for a malicious pod to take actions on any other node, including reading secrets, deleting pods, etc. There is an excellent post by Antoine Cotten that explains this very well ( as well as RBAC, which is a different subject altogether). How do I set it up? Based on the current documentation, it looks like setting up Node Authorization should be easy. Basically follow these steps Turn on TLS

Keep a website alive – PowerShell style

  Recently, We had a website that didn’t have frequent visitors, but when the visitors did come, the website would take a long time to load up the first time. This is expected behavior because IIS shuts down its worker threads. 1 approach would be to set the IdleTimeout to 0 which means the threads are never aborted (details here: http://technet.microsoft.com/en-us/library/cc771956(v=ws.10).aspx ). Instead of that though I decided to try my hand at PowerShell and came up with the following script: 1: # List of URLS to Ping 2: $urls = @( "Http://URL1.com" , "https://URL2.com" ) 3:   4: #Ping all URLs in the list 5: foreach ($objItem in $urls) { 6: $req=[system.Net.HttpWebRequest]::Create($objItem); 7: $res = $req.getresponse(); 8: $stat = $res.statuscode; 9: $res.Close(); 10: 11: #Pump it out to a text file 12: $res | Out-File pingresults.txt -append 13: } After that I set up a simple