Windows Service Project Setup in Octopus Server

usability
server
known
(Sriram Ravi) #1

Hi Team,

Good Morning.

We are planning to migrate our existing release process to Octopus Deploy. To achieve this, we create a new build definition in TFS and pushed the build to octopus deploy successfully.

In the next step, we created a series of Deployment Steps in the newly created Octopus Project.
The steps will include the below deployment proces:

  1. Stop the windows service - Working fine
  2. Delete windows service - Working fine
  3. Create and Start the windows service : #we encounter the below issue:
  • we used the below powershell script to create and start the windows service from Octopus Server:

param
(
[Parameter(Position = 0)]
[string]$sub,
[Parameter(Position = 1)]
[string]$action,
[Parameter(Position = 2)]
[string]$username,
[Parameter(Position = 3)]
[string]$password
)
$DDCServers = @(
#machine name#”
)

$currentserver = ($env:computername).ToUpperInvariant()
$basepath = “#service project path#”
$rootpath = “$basepath”
$services = & “#service installation direction#”

switch ($action){
“start” {
foreach ($service in $services){
:inner for ( $n = 1; $n -le 5; $n++ ) {
if($service.startmethod -ne “Disabled”)
{sc.exe Start “”"$($service.name)""" 2>&1 | Out-Null}

			if ($LASTEXITCODE -eq 0){
					{echo "$($service.name) started successfully."}
			}elseif ($LASTEXITCODE -eq 1056){
				echo "$($service.name) is starting. Please check its status later."
			}elseif ($LASTEXITCODE -eq 1060){
				write-error "!!!Skipped: $($service.name) - doesn't exist!"
				break inner
			}elseif ($LASTEXITCODE -eq 1069){
				write-error "!!!Skipped: $($service.name) - wrong runtime credentials!"
				break inner
			}elseif ($LASTEXITCODE -eq 1058){
				write-warning "!!!Skipped: $($service.name) - disabled!"
				break inner
			} else {
				echo "Attempt $n - Error while starting $($service.name). (Code: $LASTEXITCODE)"
				if ($n -eq 5){
					write-error "!!!Skipped: $($service.name)"
				}else{
					sleep 1
				}
			}
		}
	}
}
"stop" {
	foreach ($service in $services){
		:inner for ( $n = 1; $n -le 5; $n++ ) {
			sc.exe Stop """$($service.name)""" 2>&1 | Out-Null
			if (($LASTEXITCODE -eq 0) -Or ($LASTEXITCODE -eq 1060) -Or ($LASTEXITCODE -eq 1062)){
				echo "$($service.name) stoped successfully or already stopped or doesn't exist."
				break inner
			} else {
				echo "Attempt $n - Error while stopping $($service.name). (Code: $LASTEXITCODE)"
				if ($n -eq 5){
					write-error "!!!Skipped: $($service.name)"
				}else{
					sleep 1
				}
			}
		}
	}	
}
default {write-error "Wrong action!"}

}

Output from above service execution:

The step failed: Activity Create Win Services on #####machine name###### failed with error ‘The remote script failed with exit code 1’.

Could you please help us to resolve this issue.

Thanks in Advance.

Regards,
Sriram Ravi

(Paul Calvert) #2

Hi Sriram,

Thanks for getting in touch!

Does this Powershell script work if run directly on the target machine within Powershell?
Also, Octopus does have a built-in step for deploying and creating Windows services, have you given that step a try or is it missing some functionality that you require?

Finally, when attaching scripts, if you enclose them in blocks of three backticks ``` it should format the script more neatly :slight_smile:
e.g.

param
(
[Parameter(Position = 0)]
[string]$sub,
[Parameter(Position = 1)]
[string]$action,
[Parameter(Position = 2)]
[string]$username,
[Parameter(Position = 3)]
[string]$password
)
$DDCServers = @(
“#machine name#”
)

$currentserver = ($env:computername).ToUpperInvariant()
$basepath = “#service project path#”
$rootpath = “$basepath”
$services = & “#service installation direction#”

switch ($action){
“start” {
foreach ($service in $services){
:inner for ( $n = 1; $n -le 5; $n++ ) {
if($service.startmethod -ne “Disabled”)
{sc.exe Start “”"$($service.name)""" 2>&1 | Out-Null}
if ($LASTEXITCODE -eq 0){
					{echo "$($service.name) started successfully."}
			}elseif ($LASTEXITCODE -eq 1056){
				echo "$($service.name) is starting. Please check its status later."
			}elseif ($LASTEXITCODE -eq 1060){
				write-error "!!!Skipped: $($service.name) - doesn't exist!"
				break inner
			}elseif ($LASTEXITCODE -eq 1069){
				write-error "!!!Skipped: $($service.name) - wrong runtime credentials!"
				break inner
			}elseif ($LASTEXITCODE -eq 1058){
				write-warning "!!!Skipped: $($service.name) - disabled!"
				break inner
			} else {
				echo "Attempt $n - Error while starting $($service.name). (Code: $LASTEXITCODE)"
				if ($n -eq 5){
					write-error "!!!Skipped: $($service.name)"
				}else{
					sleep 1
				}
			}
		}
	}
}
"stop" {
	foreach ($service in $services){
		:inner for ( $n = 1; $n -le 5; $n++ ) {
			sc.exe Stop """$($service.name)""" 2>&1 | Out-Null
			if (($LASTEXITCODE -eq 0) -Or ($LASTEXITCODE -eq 1060) -Or ($LASTEXITCODE -eq 1062)){
				echo "$($service.name) stoped successfully or already stopped or doesn't exist."
				break inner
			} else {
				echo "Attempt $n - Error while stopping $($service.name). (Code: $LASTEXITCODE)"
				if ($n -eq 5){
					write-error "!!!Skipped: $($service.name)"
				}else{
					sleep 1
				}
			}
		}
	}	
}
default {write-error "Wrong action!"}
}

Best regards,
Paul

(Sriram Ravi) #4

[quote=“paul.calvert, post:2, topic:24229”]
Does this Powershell script work if run directly on the target machine within Powershell?
Sriram : The same code works fine for other windows service. I can share the screen…

Also, Octopus does have a built-in step for deploying and creating Windows services, have you given that step a try or is it missing some functionality that you require?

Sriram: I tried the above step as well. Can you give some steps on how to setup your above built-in step?

(Paul Calvert) #5

Hi,

To configure the built-in ‘Deploy a Windows Service’ step, you would just need to pass in the same information you are using for your script. Typically, I would use variables for these values within the process step, and then create and define them within the Project Variables section. This way it provides flexibility for having different service names or paths for different environments or roles without having to have multiple process steps.
e.g.


You can also configure what user the service should run under, and again use variables to alter this based on the environment, and a sensitive variable for the user password.

Best regards,
Paul

(Sriram Ravi) #6

Thanks for the update Paul.

I will try this.

Regards,
Sriram

1 Like
(Sriram Ravi) #7

Hi Paul

Can you guide me on this issue as well:

Thanks,
Sriram

(Sriram Ravi) #8

Hi Paul,

I tried with the steps that you mentioned. I am getting some issues.

Can you help me.

Can we have a call. so that I will find it more helpfule instead of chat.

Please let me know how we can meet?

(Paul Calvert) #9

Hi Sriram,

Are you able to expand on what issues you are experiencing, please?
If you are seeing errors during deployment, perhaps it would be useful to attach the deployment log for me to take a look at?

Regards,
Paul

(Sriram Ravi) #10

Hello Paul,

We are preparing the log. Will share you in detail by tomorrow.

Thanks in Advance.

Regards,
Sriram

(Sriram Ravi) #11

Hi Paul,

How are you?

When I specify a space in the ‘File Path’, below powershell script is unable to execute.

Is there any way to escape the space in the below script in the variable ‘args’


$services = New-Object System.Collections.ArrayList
[void]$services.Add(@{`
	name = "SERVICE NAME HERE";`
	exePath = "SAMPLE PATH HERE";`
	args = "D:\Sample Services\";`--WITH SPACE
	startMethod = "Auto"`
})
return $services

$basepath = "C:\Sample Services" -- WITH SPACE
$rootpath = "$basepath\"
$services = & ".\SAMPLE.ps1"

switch ($action){ 
	"create" {
		foreach ($service in $services){
			:inner for ( $n = 1; $n -le 5; $n++ ) {				
					sc.exe create """$($service.name)""" displayname= """$($service.name)""" binpath= """$rootpath$($service.exePath) /Path=""$($service.args)""""" start= """$($service.startmethod)""" obj= """$username""" password= """$password""" 2>&1 | Out-Null
				
			}
		}
	}
	"start" {
		foreach ($service in $services){
			:inner for ( $n = 1; $n -le 5; $n++ ) {
				if($service.startmethod -ne "Disabled")
					{sc.exe Start """$($service.name)"""  2>&1 | Out-Null}
				}
			}
		}
	}
	default {write-error "Wrong action!"}
}
exit 0```
(Paul Calvert) #12

Hi Sriram,

As long as the path is within a variable you shouldn’t have to escape the space. However, calling the item directly from the array does look like it causes the wrong value to be inserted but it didn’t error for me.

I put together two test scripts to create services using your values, and both of these resulted in the service being created with the correct path and arguments.

With just variables:

$serviceName = "Service Name Here"
$serviceExe = "C:\Program Files\Octopus Deploy\Tentacle\Octopus.Manager.Tentacle.exe"
$serviceArgs = "D:\Sample Services\"
New-Service -Name $serviceName -BinaryPathName "$serviceExe $servicesArgs" -DependsOn NetLogon -DisplayName $serviceName -StartupType Automatic
Start-Service -Name $serviceName

Using the array:


$services = New-Object System.Collections.ArrayList
[void]$services.Add(@{`
	name = "SERVICE NAME HERE";`
	exePath = "C:\Program Files\Octopus Deploy\Tentacle\Octopus.Manager.Tentacle.exe";`
	args = "D:\Sample Services\";#-WITH SPACE
})

$serviceName = $services.Name
$serviceExe = $services.exePath
$serviceArgs = $services.args
New-Service -Name $serviceName -BinaryPathName "$serviceExe $servicesArgs" -DependsOn NetLogon -DisplayName $serviceName -StartupType Automatic
Start-Service -Name $serviceName

Regards,
Paul

(Sriram Ravi) #13

Hi Paul,

How are you?

We did the changes as you suggested, unfortunately it didn’t resolved my issue. We searched in google and found the below Octopus ticket:

We changed our script based on the above ticket and we made it worked successfuly.

You can close this ticket.

Thanks for your support.

Warm Regards,
Sriram

1 Like