MSDeploy to install windows service? - windows-services

We have a website which publishes events using NServiceBus. The site is deployed using msdeploy. We also have the NServiceBus.exe which should run as a windows service to subscribe to these events, and we'd like to deploy that as well.
Is there any way to package the service as well as the website, so that it can be installed as well? Is it possible to package separately so we can deploy it to another server?
Any tips on where to find information on how to do this would be great, as we can do automated deployments for the website now.

I recently did this using MSDeploy, Phantom and installUtil.exe
You just basically need to modify your installer class and elevate your remote wmsvc service privileges if needed.
Link to blog

What we wound up doing was creating a 'controller' layer that coordinates deployment tasks, even one that could use msdeploy. Essentially, msdeploy is not the highest level of abstraction in our deployment system.
We chose to use MSBuild to coordinate those tasks of deploying items from a 'package'.
In our deployment process, a web application deployed with msdeploy is just another deployment item, just as is a Windows service.
In all disclosure, we have not actually created msdeploy deployment tasks yet, though it should/would drop in nicely to what we've already created, as MSBuild would invoke the msdeploy. We currently use MSBuild community tasks for webapp deployment automation, coordinated via MSBuild.
You can read a little more about how we 'generalized' our deployments via a blog post I did called "PANDA - Packaging ANd Deployment Automation".

Here is a msdeploy cmd line I used to sync an archivedir that is created from a post-build step in my Windows Service.proj file.
It is syncing from my build server to my app server on a different network. I have pre and post build steps that start and stop the services on the remote server. You must wrap the powershell script in a vb script due to a bug with powershell and msdeploy. The -verbose option is very helpful.
I also have the vbscript and ps1 script below. Be careful with the VB sleep and the pre and post msdeploy timeouts.
msdeploy -verb:sync -source:archivedir=\\qa-xxxxx1.qa.lan\deployment\backups\FreddieMacDelivery\FreddieMacDelivery.zip,tempAgent='True',computerName=qa-xxxxx1.qa.lan,userName=QA\xxxxx,password=xxxx,authtype=NTLM,includeAcls='False' -dest:dirpath=\\qa-xxxxxx1.qa.lan\protk\Services\FreddieMacDelivery\1.4.1.test -useCheckSum -verbose -preSync:runCommand="cscript.exe c:\temp\stop_win_svc.vbs" -postSync:runCommand="c:\temp\start_win_svc.vbs",waitInterval=15000,waitAttempts=1
VB script:
Option Explicit
Dim oShell, appCmd,oShellExec
Set oShell = CreateObject("WScript.Shell")
appCmd = "powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ""&c:/temp/Get_Win_SVC.ps1"" "
Set oShellExec = oShell.Exec(appCmd)
WScript.Sleep 1000
oShellExec.StdIn.Close()
Powershell script:
$username = 'QA\xxxxx'
$password = 'xxxxx'
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
(Get-WmiObject -computer qa-xxxx1.qa.lan -Credential $cred Win32_Service -Filter "Name='ProTeck.FreddieMac.DeliveryService'")
$svc = (Get-WmiObject -computer qa-xxxxx1.qa.lan -Credential $cred Win32_Service -Filter "Name='ProTeck.FreddieMac.DeliveryService'")
Write-Host $svc
$svc.InvokeMethod("StartService", $null)
(Get-WmiObject -computer qa-xxxxx1.qa.lan -Credential $cred Win32_Service -Filter "Name='ProTeck.FreddieMac.DeliveryService'")> c:\temp\win_stat_post.txt

Related

Install Jenkins slave as a Windows service in command line

I have been looking a lot on Google on how to install the service in
command line (so without manual interaction) but I am stuck on how to
get the jenkins-slave.exe
I found those instruction
https://wiki.jenkins.io/display/JENKINS/Installing+Jenkins+as+a+Windows+service
but I can't figure how to get the executable. I have downloaded and run
the slave.jar with the right key, which connects the slave, but the exe
is not generated.
I found this page
https://github.com/kohsuke/winsw/blob/master/doc/installation.md#winsw-installation-guide
to install it manually but that sounds like re-invented the wheel when
the jar can do it. Plus there is a risk the WinSW.exe is different and
doesn't get updated by the plugin (I saw some automatic update code in it).
So is there a way I can download the jenkins-slave.exe or generate it?
or is there a way to run the "Install as a service" in command line from
the slave.jar?
To answer my own question, after having contacted the plugin developers:
There is no actual way to download the exe from Jenkins directly, the slave.jar gets it from the master via the remoting protocol. I have created a request to be able to download it via an URL (as suggested by the developer), so it might be available in the future.
Right now the executable is a renamed Windows Service Wrapper binary: https://github.com/kohsuke/winsw so I used this binary the same way.
Regarding the configuration used by WinSW and XML files, I used the one from the GitHub repository https://github.com/jenkinsci/windows-slave-installer-module. The versions are compatible in terms of the configuration.
So basically I download the exe, get the private key from Jenkins and create the service using the configuration from the original plugin. Then I install the service using jenkins-slave.exe install.
Step by step:
Get the JNLP command from Jenkins (from the Node page) to get the private key, e.g. java -jar slave.jar -jnlpUrl http://jenkins...
Download the slave.jar file from Jenkins (gotten from the JNLP command)
Download the service wrapper executable, e.g. http://repo.jenkins-ci.org/public/com/sun/winsw/winsw/2.1.0/winsw-2.1.0-bin.exe
Rename winsw-2.1.0-bin.exe into jenkins-slave.exe
Setup the XML used to run the service (available in the module or directly on winsw website)
Setup the slave configuration XML file (available on the module source code)
Then install the service using jenkins-slave.exe install
What I would do is:
Download the slave.jar file (from the node's page of Jenkins)
Copy the java -jar slave.jar -jnlpUrl http://<YOUR URL HERE> command from the node's page
Paste this command into a new .bat file and save it
Register a scheduled task to run this .bat file when Windows starts
Or is there a way to run the "Install as a service" in command line from the slave.jar?
I don't use jenkins-slave.exe, but instead a custom script in which I can control the exact environment variable I want to set for the Jenkins slave, when launching java -jar slave.jar with the secret key you can see in the Jenkins master node page for that new slave.
To get slave.jar from the master onto the slave, execute from the slave Windows server:
curl -o slave.jar https://your.server/jenkins/jnlpJars/slave.jar
To replace the jenkins-slave.exe, I use a script declared as a Windows service, with nssm
The script is similar to agent.bat:
set PATH=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0
set PATH=D:\Tools\SonarRunner\bin;%PATH%
set M2_HOME=D:\Tools\apache-maven-3.5.0
set PATH=%M2_HOME%\bin;%PATH%
set PATH=D:\Tools\apache-ant-1.9.3\bin;%PATH%
set GH=D:\Tools\Git
set PATH=%GH%\bin;%GH%\usr\bin;%GH%\mingw64\bin;%PATH%
set PATH=%JAVA_HOME%\bin;%PATH%
set WORKSPACE_FOLDER=D:\Jenkins\workspace
set GIT_WORKSPACE_FOLDER=D:\Jenkins\workspace
java -Xmx768m -jar slave.jar -jnlpUrl https://your.server/jenkins/computer/<SlaveName>/slave-agent.jnlp -secret 87ef3d...
That script is then called as a Windows service, ran by a dedicated user account:
runas /user:<domain>\<jenkinsUser> cmd ( enter `jenkinsUser` Windows password )
D:\Tools\nssm-2.24\win64\nssm.exe install <SlaveName> D:\Jenkins\agent.bat
Its Windows service is then configured:
sc config <SlaveName> obj= <domain>\<jenkinsUsers> password= <jenkinsUser password>
sc config <SlaveName> start= auto
For automating the installation of other software: see Chocolatey - Software Management Automation, The package manager for Windows.
To fully automate the declaration-side of slaves, use the web API to create the slave, and a groovy script to retrieve the Jenkins node/slave secret JnlpMac key.
See this script for the creation.
And the groovy script (with Jenkins 2.46 or newer) to get the secret key:
echo 'println jenkins.model.Jenkins.instance.nodesObject.getNode("my-agent")?.computer?.jnlpMac' \
| java -jar ~/Downloads/jenkins-cli.jar -s https://jenkins/ groovy =
Using this windows service wrapper works too:
https://github.com/winsw/winsw
follow their installation, but you should update the xml with your desired configuration, be sure to remove all " in pathes within the xml and disable websockets in the jenkins master configuration page of the agent:
step by step:
download the exe: WinSW-x64.exe from https://github.com/winsw/winsw/releases
create your workspace-dir on the agent and paste it there, rename the WinSW-x64.exe to jenkins-slave.exe
copy your jenkins-slave.xml there, it should looke like:
<service>
<id>jenkins</id>
<name>Jenkins</name>
<description>This service runs Jenkins continuous integration system.</description>
<env name="JENKINS_HOME" value="%BASE%"/>
<executable>C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.275-1\jre\bin\java.exe</executable>
<arguments>-jar %BASE%\slave.jar -jnlpUrl https://<your_jenkins>.jenkins.bshg.com/computer/RBGWCW0281/jenkins-agent.jnlp -secret <your_secret> -workDir C:\<workspace-dir>\ -noCertificateCheck</arguments>
<logmode>rotate</logmode>
<onfailure action="restart" />
<delayedAutoStart/>
<!--
If uncommented, download the Remoting version provided by the Jenkins master.
Enabling for HTTP implies security risks (e.g. replacement of JAR via DNS poisoning). Use on your own risk.
NOTE: This option may fail to work correctly (e.g. if Jenkins is located behind HTTPS with untrusted certificate).
In such case the old agent version will be used; you can replace slave.jar manually or to specify another download URL.
-->
<download from="https://<your_jenkins>.jenkins.bshg.com/jnlpJars/slave.jar" to="%BASE%\slave.jar"/>
<!--
In the case WinSW gets terminated and leaks the process, we want to abort
these runaway JAR processes on startup to prevent "Slave is already connected errors" (JENKINS-28492).
-->
<extensions>
<!-- This is a sample configuration for the RunawayProcessKiller extension. -->
<extension enabled="true"
className="winsw.Plugins.RunawayProcessKiller.RunawayProcessKillerExtension"
id="killOnStartup">
<pidfile>%BASE%\jenkins_agent.pid</pidfile>
<stopTimeout>5000</stopTimeout>
<stopParentFirst>false</stopParentFirst>
</extension>
</extensions>
</service>
Use the option delayed Auto start, to ensure all the network services are started, that jenkins connect can not fail.
And i recommend to use a registry key to give the service more time to start:
Insert registry-key to give services more time to start:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\]
"ServicesPipeTimeout"=dword:0001d4c0
You can check here fore detailed info: https://serverfault.com/questions/622432/how-do-i-increase-windows-service-startup-timeout
And finally I recommend to autostart your jenkins at least once a week. with a scheduled task:
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2020-04-30T12:47:51.8471206</Date>
<Author>Domain/User</Author>
<Description>Some Comment</Description>
<URI>\CI-Restart</URI>
</RegistrationInfo>
<Triggers>
<CalendarTrigger>
<StartBoundary>2020-05-01T01:00:00</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>whatever</UserId>
<LogonType>Password</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>shutdown</Command>
<Arguments>/r /f /t 10 /d p:2:3 /c "CI-reconnect"</Arguments>
</Exec>
</Actions>
</Task>
Now do (with admin rights)
jenkins-slave.exe install
jenkins-slave.exe start
Your Jenkins will run forever!
Another recommendation: Enable the BIOS-setting to start pc on power-on. If you have troubles with interruptions of power-supply.

Invoking batch script with specific user from TFS build server

I'm new to TFS and need help to overcome following problem.
I have a desktop which has a licensed testing tool and automated tests developed using that tool. The license of the tool is tied up to the user logged in to that desktop.
Now I have created a batch file for my automated tests and I want to call this batch file from TFS. I've installed TFS agent on the desktop where that tool is and on TFS server configured a build definition which runs this batch file, everything working well till here.
The problem is, when the batch script is called by the TFS agent (I think) it is involved as SYSTEM user and not the user which is tied up to the license. Due to this the license check fails and my tests are unable to run.
Is there any way to tell TFS to run the batch script using a specific user ?
The batch scripts are run using the build service account. If you want to run the batch script using a specific account, you need to change your build agent service account.
For TFS 2015 Build agent, run the command:
C:\Agent\Agent\VsoAgent.exe /ChangeWindowsServiceAccount
Please refer to this document to change the account: https://www.visualstudio.com/en-us/docs/build/actions/agents/v1-windows
If you use TFS 2017 Build agent, just re-configure it and specify that account when you reconfigure it.
You can use a PowerShell wrapper script to start a executable with different identity.
param (
[Parameter(Mandatory=$True)]
    [string]$username,
[Parameter(Mandatory=$True)]
    [string]$password,
[Parameter(Mandatory=$True)]
    [string]$executable,
[Parameter(Mandatory=$False)]
    [string[]]$arguments,
[Parameter(Mandatory=$False)]
    [string]$workingDirectory
)
$secpassword = $password | ConvertTo-SecureString -asPlainText -Force
$password = $null
$credentials = New-Object System.Management.Automation.PSCredential($username,$secPassword)
$workingDirectory = if([string]::IsNullOrEmpty($workingDirectory)){(Get-Item -Path ".\").FullName}
Start-Process $executable -ArgumentList $arguments -WorkingDirectory $workingDirectory -Credential ($credentials)
Create a hidden variable 'password' in your build or release definition with the password and set the visibility to hidden.
Call this script with the powershell step:
-username "username" -password = $(password) -executable "myExecutable" -arguments '-param "param1"','-param2 "param2"','-param3"d:\directory\with blanks in a path\"'

Register dll with Jenkins + Octopus

I want to do deploy a DLL file into the Test environment with Jenkins and Octopus. How can I register the DLL file onto the Test environment straight from Octopus ? Is this the good approach or how can this be achieved ?
The main thing that I want to is that I do not want to run the regsvr32 instruction in cmd on the test server but instead I want to automate it and run it when the deploy from the Octopus happens.
Thank you
Open your Octopus project processes.
Add step (Run a script): You should do this with powershell.
Set your environments if necessary.
Example Powershell:First line is a Powershell command. Second line is executing CMD command on powershell with this:
& "someprogram.exe" parameters
copy-item -Path \\10.0.0.10\DllShareName\myapp.dll -Destination \\10.0.0.11\MyDllTargetFolder
& "C:\windows\system32\regsvr32.exe" myapp.dll

Running a Windows batch file in Jenkins

I trying to run my Tests cases for a project in Jenkins through DOS Command line on Windows server . I am using Jenkins ver. 1.559.
I am trying to run a Windows batch file through a Jenkins job that has the java command.
Under the "Build" section >> "Execute Windows Batch command" >> Command: call E:\Jenkins\App\UnitTests\App_UnitTests.bat
Save and Build the job.
I am getting an error and here is my Console Output
C:\Program Files (x86)\Jenkins\jobs\App Test Cases\workspace>java.exe -cp "E:\Jenkins\App\PPS\App\bin\;E:\Jenkins\App\PPS\App\lib\junit-4.10.jar;E:\Jenkins\App\PPS\App\lib\*.jar;" org.junit.runner.JUnitCore com.omnitracs.fra.junit.EventTests
'java.exe' is not recognized as an internal or external command, operable program or batch file.
C:\Program Files (x86)\Jenkins\jobs\App Test Cases\workspace>PAUSE
Press any key to continue . . .
C:\Program Files (x86)\Jenkins\jobs\App Test Cases\workspace>EXIT
Build step 'Execute Windows batch command' marked build as failure
Finished: FAILURE
The java command runs fine outside Jenkins.
I have set the JAVA_HOME for the local user and also the PATH variable to point to where java.exe is.
What am I doing wrong? Please help.
For a windows environment, there is some extra configuration needed for more advanced builds. Ultimately you have two options
From Jenkins, The Definitive Guide:
This basic installation will work fine in a simple context, but you
will often need to fine-tune your service. For example, by default,
the Jenkins service will be running under the local System account.
However, if you are using Maven, Jenkins will need an .m2 directory
and a settings.xml file in the home directory. Similarly, if you
are using Groovy, you might need a .groovy/lib directory. And so on.
To allow this, and to make testing your Jenkins install easier, make
sure you run this service under a real user account with the correct
development environment set up. Alternatively, run the application as the
system user, but use the System Information page in Jenkins to check
the /Users/johnsmart/Projects/Books/jenkins-thedefinitive- guide
directory, and place any files that must be placed in the user home
directory here....
To configure your Jenkins server to run under a service account (The suggested option), Install Jenkins as a service, and under the services properties set the log on user info.

Cause TFS InvokeProcess Build Activity to run under other credentials

We have customized the build process with a InvokeProcess action that runs a powershell script that deploys our sln.
Problem is that this script must be run under a given user (not the tfsbuild user).
How can we achive this?
Alternative 1: Make the InvokeProcess
run as a different user -
Alternative 2: Make the powershell script itself
run as different user
Problem is that I have no idea of how to do any of this.
I have created a blog post on this how you can achieve this: Customize Team Build 2010 – Part 9: Impersonate activities (run under other credentials)
A pure PowerShell option, assuming you have PowerShell 2.0 on your TeamBuild machine, is to use a background job. Start-Job allows you to specify the credentials of another account to perform the work. After spinning up the background job in your script you will probably want to wait for the job to finish and grab the results to output from the main script e.g.:
$cred = Get-Credential
$job = Start-Job -ScriptBlock { ls c:\windows\system32 -r *.sys } -Cred $cred
Wait-Job $job
Receive-Job $job
With respect to capturing, storing and retrieving the credentials, see this blog post for a good treatise on the subject.

Resources