Invoking batch script with specific user from TFS build server - tfs

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\"'

Related

How to get TFS2015 Build (Build.vnext) and NuGet package restore to use custom package sources

I'm trying to get our TFS2015 Build (TFSBuild vnext) going along with VS Team Services.
Thus far most blogs and documentation has been helpful, except for when trying to build a project that uses custom package sources for NuGet automatic package restore.
I've successfully deployed an a Team Services Build Agent (the new mechanism for builds) and all seemed to go well until the build task to Restore NuGet packages failed.
The failure was due to custom/private package source not being picked up from the installed VS configuration, so those packages could not be found. The traditional packages from the default NuGet package feed did restore without issue.
How do I specify the additional package sources for NuGet to use when using an agent?
EDIT: vcastro asked about the NuGet Installer build step and defining paths in the configuration of that build step. The above is using the Visual Studio Build step and the integrated option to have NuGet restore packages. Refer this image for reference:
Alternatively you could also add a NuGet Installer build step before the Visual Studio Build step in your build configuration to restore all NuGet packages.
There you can pass the location of your private repo as argument to nuget.exe:
-source "https://www.nuget.org/api/v2/;http://mynugetserver"
I've scrounged the web with little success, but after fiddling the following will help:
OK It seems that the package sources configured for NuGet.config is stored per user account, e.g.
c:\Users\<<username>>\AppData\Roaming\NuGet\NuGet.config
My issue was harder to resolve, because the build agent was running as a Windows Service under the Local System account. So to get NuGet configuration to for the build, I had to use the following path instead:
64-bit Windows C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config
32-bit Windows C:\Windows\System32\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config
You may need to have elevated permissions in order to create the NuGet subfolder and NuGet.Config file.
Note: I have no solution for using the Local Service account. The above only works for the Local System (or an actual user) account.
Add a NuGet.config to your project that specifies an alternate package location. The rules for resolution are well-defined and explained in the official documentation.
There is a new VSTS Task called "NuGet Installer" this allows you to check in your NuGet.config file and specify the different package sources. Run this task before you run MSBuild.
If you are using the VSTS NuGet Feed you will need to add the build service account to the feed to enable downloading of packages https://www.visualstudio.com/get-started/package/use/common-identities
One solution (works for me) is change account for tfs 2015 build agent service (on my build machine VSO Agent tsf.Agent-PC) to tfsagent, for example, and add Nuget.config to the C:\Users\tfsagent\AppData\Roaming\Nuget. That's all!
Specify your custom NuGet feed URL’s in the solution’s nuget.config file. Do not store any usernames & passwords in this file.
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
<add key="MyCompany" value="https://nuget.mycompany.com:443/nuget" />
Create username & password variables in your build definition in VSTS. Variables can be encrypted and will not be displayed in any of the build log outputs. Here I'll create MyCompanyNugetUser and MyCompanyNugetPwd variables.
In our build steps, we add a Powershell script as the first action, this will read the username & password variables and update the user level nuget.config file on the build machine. Below is the code snippet from my inline Powershell script:
Arguments:
$(MyCompanyNugetUser) $(MyCompanyNugetPwd)
Script:
param($user, $pwd)
$nugetFile = "$ENV:AGENT_HOMEDIRECTORY\agent\worker\tools\nuget.exe"
Write-Output "Looking for nuget.exe in $nugetFile"
if (-not (Test-Path $nugetFile))
{
Write-Error "nuget.exe could not be located."
return
}
Write-Output "nuget.exe located"
$cmd = "$nugetFile sources add -name MyCompany -source https://nuget.mycompany.com:443/nuget -username $user -password $pwd -StorePasswordInClearText"
Write-Output $cmd
iex $cmd
Next, we just continue to execute the default NuGet Restore step from Microsoft’s templates
More here: https://codingcase.com/2016/07/27/vsts-build-setup-custom-nuget-feeds-with-authentication/
HTH
In the RTM of Team Foundation Server 2015 you have to add a build step of the type "NuGet Installer", and restore the packages of the Solution file before you run the actual build process. In this task you can pass the argument -ConfigFile path/to/nuget.config which contains your repository path.
For Example:
<configuration>
<packageSources>
<add key="Internal Nuget" value="\\srv-nuget\Repo" />
</packageSources>
</configuration>
If you are having trouble getting this to work on UWP ONLY, then ensure that you have the CASE of the package name spelt correctly. If the case is wrong, then (for UWP only) our build server fails the build.
for instance, if you have a package called Com.Company.Components and update the package using "install-package com.company.components" (note the case of the initial letter) then the UWP build on the build server may fail to find the package in your local store.

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.

MSDeploy to install windows service?

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

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.

Creation of InstallAnywhere installer inside of Hudson CI

My company is trying to automate the creation of a nightly installer with Hudson. Our license to install anywhere is running on a separate server. We have an ANT build script set up to call the InstallAnywhere jar file which creates the installer automatically, and that works great when ran from the command prompt.
However when we try to run it inside of Hudson, Hudson is not able to connect to that license server. InstallAnywhere spits out The evaluation period has expired. Does anyone know what we can do to solve this issue?
I'm assuming it's a Hudson issue since our ANT script works fine when used outside of Hudson.
My best guess is that you need to set up some environment variables required by the InstallAnywhere process; I'm not very familiar with that product, but maybe it needs a home directory for the product, the location of the license file, the license key value, etc.
One easy way to debug this would be to check if Hudson is running under the same user that you are using to run the Ant script from the command line, then check the environment settings for the command line user if they are different.
Since I'm running Hudson as a service I had to use the "Default User" user. The solution was to copy the InstallAnywhere folder tree from "C:\Documents and Settings\MyUser" to "C:\Documents and Settings\Default User"
I just had the same issue, so I thought I would share my solution. You can also register the CI build user so you can continue using the automated user rather than switching it to your own user account: http://www.flexerasoftware.com/downloads/instructions/productlicensing/en/InstallAnywhereProductLicensing.pdf#page=15
Set up a bat file to execute:
<PATH_TO_IA>\build.exe -registerNodeLocked <PATH_TO_IA>\License.lic
Note, the License will be your mac address.lic, and you only have to do this once.
My bat was:
C:\Progra~2\Instal~2\build.exe -registerNodeLocked C:\Progra~2\Instal~2\[MAC].lic
Then I added a bat task to jenkins, and ran the job:
You should see something like:
Trying to checkout IAEE version=12.0
InstallAnywhere is successfully registered.

Resources