diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index e69de29..0000000
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..2dcfc9a
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "editor.insertSpaces": true
+}
\ No newline at end of file
diff --git a/Extensions/Common/DeploymentSDK/Src/InvokeRemoteDeployment.ps1 b/Extensions/Common/DeploymentSDK/Src/InvokeRemoteDeployment.ps1
index c403135..07f9607 100644
--- a/Extensions/Common/DeploymentSDK/Src/InvokeRemoteDeployment.ps1
+++ b/Extensions/Common/DeploymentSDK/Src/InvokeRemoteDeployment.ps1
@@ -131,6 +131,7 @@ function Invoke-RemoteDeployment
{
Write-Host "Performing deployment in parallel on all the machines."
[hashtable]$Jobs = @{}
+ $dtlsdkErrors = @()
foreach($resource in $resourceList)
{
$winRmPort = [System.Convert]::ToInt32($resource.port)
@@ -161,6 +162,7 @@ function Invoke-RemoteDeployment
}
Write-Verbose ($output|Format-List -Force|Out-String)
Write-Host "Deployment failed on machine $machineName with following message : $errorMsg"
+ $dtlsdkErrors += $output.DeploymentSummary
}
else
{
@@ -173,7 +175,10 @@ function Invoke-RemoteDeployment
if($operationStatus -ne "Passed")
{
- $errorMsg = 'Deployment on one or more machines failed.'
+ foreach ($error in $dtlsdkErrors) {
+ Write-Telemetry "DTLSDK_Error" $error
+ }
+ $errorMsg = [string]::Format("Deployment on one or more machines failed. {0}", $errorMsg)
}
}
else
@@ -190,12 +195,13 @@ function Invoke-RemoteDeployment
if ($deploymentResponse.Status -ne "Passed")
{
$operationStatus = "Failed"
+ Write-Telemetry "DTLSDK_Error" $deploymentResponse.DeploymentSummary
Write-Verbose ($deploymentResponse|Format-List -Force|Out-String)
if($deploymentResponse.Error -ne $null)
{
$errorMsg = $deploymentResponse.Error.ToString()
break
- }
+ }
}
else
{
@@ -253,6 +259,7 @@ function Get-Credentials
Write-Verbose "Creating credentials object for connecting to remote host"
if([string]::IsNullOrWhiteSpace($userName) -or [string]::IsNullOrWhiteSpace($password))
{
+ Write-Telemetry "Input_Validation" "Invalid administrator credentials. UserName/Password null/empty"
throw "Invalid administrator credentials."
}
@@ -314,17 +321,20 @@ function Get-MachineNameAndPort
if($tokens.Count -gt 2)
{
+ Write-Telemetry "Input_Validation" "Invalid user input, speficy machines in machine:port format."
throw "Invalid user input, speficy machines in machine:port format."
}
[System.Int32]$port = $null
if($tokens.Count -eq 2 -and ![System.Int32]::TryParse($tokens[1], [ref]$port))
{
+ Write-Telemetry "Input_Validation" "Invalid user input, port is not an integer."
throw "Invalid user input, port is not an integer."
}
if([string]::IsNullOrWhiteSpace($tokens[0]))
{
+ Write-Telemetry "Input_Validation" "Invalid user input, machine name can not be empty."
throw "Invalid user input, machine name can not be empty."
}
diff --git a/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Definition.dll b/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Definition.dll
index 49f7168..208db21 100644
Binary files a/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Definition.dll and b/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Definition.dll differ
diff --git a/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Deployment.dll b/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Deployment.dll
index 80eadfd..d01cc12 100644
Binary files a/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Deployment.dll and b/Extensions/Common/DeploymentSDK/Src/Microsoft.VisualStudio.Services.DevTestLabs.Deployment.dll differ
diff --git a/Extensions/Common/DeploymentSDK/Src/Newtonsoft.Json.dll b/Extensions/Common/DeploymentSDK/Src/Newtonsoft.Json.dll
new file mode 100644
index 0000000..b7ef414
Binary files /dev/null and b/Extensions/Common/DeploymentSDK/Src/Newtonsoft.Json.dll differ
diff --git a/Extensions/Common/DeploymentSDK/Src/Utility.ps1 b/Extensions/Common/DeploymentSDK/Src/Utility.ps1
new file mode 100644
index 0000000..fefb245
--- /dev/null
+++ b/Extensions/Common/DeploymentSDK/Src/Utility.ps1
@@ -0,0 +1,54 @@
+function convertTo-JsonFormat($InputObject) {
+ if (Get-Command ConvertTo-Json -ErrorAction SilentlyContinue)
+ {
+ $jsonOutput = ConvertTo-Json -InputObject $InputObject
+ }
+ else
+ {
+ try
+ {
+ add-type -assembly system.web.extensions
+ $scriptSerializer = new-object system.web.script.serialization.javascriptSerializer
+ $jsonOutput = $scriptSerializer.Serialize($InputObject)
+ }
+ catch
+ {
+ Write-Verbose $_.Exception
+ $errorMessage = "Unable to convert json string to object. Please install WMF 4.0 and try again."
+ if($_.Exception.Message)
+ {
+ $errorMessage = [string]::Format("{0} {1} {2}", $errorMessage, [Environment]::NewLine, $_.Exception.Message)
+ }
+ throw $errorMessage
+ }
+ }
+ return $jsonOutput
+}
+
+function convertFrom-JsonFormat($InputObject) {
+ if (Get-Command ConvertTo-Json -ErrorAction SilentlyContinue)
+ {
+ $convertedObject = ConvertFrom-Json -InputObject $InputObject
+ }
+ else
+ {
+ try
+ {
+ add-type -assembly system.web.extensions
+ $scriptSerializer = new-object system.web.script.serialization.javascriptSerializer
+ $convertedObject = ,$scriptSerializer.DeserializeObject($InputObject)
+ }
+ catch
+ {
+ Write-Verbose $_.Exception
+ $errorMessage = "Unable to convert json string to object. Please install WMF 4.0 and try again."
+ if($_.Exception.Message)
+ {
+ $errorMessage = [string]::Format("{0} {1} {2}", $errorMessage, [Environment]::NewLine, $_.Exception.Message)
+ }
+ throw $errorMessage
+ }
+
+ }
+ return $convertedObject
+}
diff --git a/Extensions/Common/DeploymentSDK/Src/VisualStudioRemoteDeployer.exe b/Extensions/Common/DeploymentSDK/Src/VisualStudioRemoteDeployer.exe
index 07a6441..4a46e66 100644
Binary files a/Extensions/Common/DeploymentSDK/Src/VisualStudioRemoteDeployer.exe and b/Extensions/Common/DeploymentSDK/Src/VisualStudioRemoteDeployer.exe differ
diff --git a/Extensions/Common/DeploymentSDK/Tests/InvokeRemoteDeployment.Tests.ps1 b/Extensions/Common/DeploymentSDK/Tests/InvokeRemoteDeployment.Tests.ps1
index 0e1e2ff..c90d4eb 100644
--- a/Extensions/Common/DeploymentSDK/Tests/InvokeRemoteDeployment.Tests.ps1
+++ b/Extensions/Common/DeploymentSDK/Tests/InvokeRemoteDeployment.Tests.ps1
@@ -13,6 +13,9 @@ if(-not (Test-Path -Path $invokeRemoteDeployment ))
. "$invokeRemoteDeployment"
+## Mocking the telemetry method
+function Write-Telemetry {}
+
Describe "Tests for testing InitializationScript block" {
Context "Invoke-PsOnRemote successfully returns" {
. $InitializationScript
@@ -134,7 +137,7 @@ Describe "Tests for testing Invoke-RemoteDeployment functionality" {
It "Should process jobs in parallel and wait for their completion"{
Assert-VerifiableMocks
- ($errMsg) | Should Be "Deployment on one or more machines failed."
+ ($errMsg) | Should Be "Deployment on one or more machines failed. "
Assert-MockCalled Write-Host -Times 8 -Exactly
}
}
diff --git a/Extensions/Common/DeploymentSDK/Tests/Utility.Tests.ps1 b/Extensions/Common/DeploymentSDK/Tests/Utility.Tests.ps1
new file mode 100644
index 0000000..4c8953e
--- /dev/null
+++ b/Extensions/Common/DeploymentSDK/Tests/Utility.Tests.ps1
@@ -0,0 +1,75 @@
+$currentScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
+$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
+$VerbosePreference = 'Continue'
+
+$UtilityScript = "$currentScriptPath\..\Src\$sut"
+
+if(-not (Test-Path -Path $UtilityScript))
+{
+ throw [System.IO.FileNotFoundException] "Unable to find Utility.ps1 at $UtilityScript"
+}
+
+. "$UtilityScript"
+
+
+Describe "Tests for ConvertTo-JsonFormat method" {
+ Context "Convert object to json string on PS where ConvertTo-Json cmdlet exists" {
+ $argumentAsObject = @{Name="test";Type="task"}
+
+ Mock Get-Command -Verifiable { return $true}
+
+ $jsonOutput = ConvertTo-JsonFormat -InputObject $argumentAsObject
+
+ It "Should convert object to json string" {
+ $jsonOutput | Should Not be $null
+ $jsonOutput.GetType().Name | Should Be "String"
+ $jsonOutput.Contains("Name") | Should Be $true
+ $jsonOutput.Contains("Type") | Should Be $true
+ }
+ }
+
+ Context "Convert object to json string on PS where ConvertTo-Json cmdlet doesnot exists" {
+ $argumentAsObject = @{Name="test";Type="task"}
+
+ Mock Get-Command -Verifiable { return $false}
+
+ $jsonOutput = ConvertTo-JsonFormat -InputObject $argumentAsObject
+
+ It "Should convert object to json string" {
+ $jsonOutput | Should Not be $null
+ $jsonOutput.GetType().Name | Should Be "String"
+ $jsonOutput.Contains("Name") | Should Be $true
+ $jsonOutput.Contains("Type") | Should Be $true
+ }
+ }
+
+ Context "Convert json string to object on PS where ConvertTo-Json cmdlet exists" {
+ $jsonString = "{`"Name`":`"test`",`"Type`":`"task`"}"
+
+ Mock Get-Command -Verifiable { return $true}
+
+ $argObject = ConvertFrom-JsonFormat -InputObject $jsonString
+
+ It "Should convert json string into object" {
+ $argObject | Should Not be $null
+ $argObject.GetType().Name | Should Be "PSCustomObject"
+ $argObject.Name | Should Be "test"
+ $argObject.Type | Should Be "task"
+ }
+ }
+
+ Context "Convert json string to object on PS where ConvertTo-Json cmdlet doesnot exists" {
+ $jsonString = "{`"Name`":`"test`",`"Type`":`"task`"}"
+
+ Mock Get-Command -Verifiable { return $false}
+
+ $argObject = ConvertFrom-JsonFormat -InputObject $jsonString
+
+ It "Should convert json string into object" {
+ $argObject | Should Not be $null
+ $argObject.Name | Should Be "test"
+ $argObject.Type | Should Be "task"
+ }
+ }
+}
+
diff --git a/Extensions/Common/Helper/Src/Utility.ps1 b/Extensions/Common/Helper/Src/Utility.ps1
index aab2a14..e2e766a 100644
--- a/Extensions/Common/Helper/Src/Utility.ps1
+++ b/Extensions/Common/Helper/Src/Utility.ps1
@@ -1,87 +1,88 @@
-Import-Module $env:CURRENT_TASK_ROOTDIR\DeploymentSDK\InvokeRemoteDeployment.ps1
-
-Write-Verbose "Entering script Utility.ps1"
-
-function Validate-WaitTime()
-{
- [CmdletBinding()]
- Param
- (
- [Parameter(mandatory=$true)]
- [string[]]$runLockTimeoutString
- )
-
- $parsedRunLockTimeout = $null
- if([int32]::TryParse($runLockTimeoutString , [ref]$parsedRunLockTimeout))
- {
- if($parsedRunLockTimeout -gt 0)
- {
- return
- }
- }
-
- throw "Please provide a valid timeout input in seconds. It should be an integer greater than 0"
-}
-
-function Remote-ServiceStartStop()
-{
- [CmdletBinding()]
- Param
- (
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $serviceNames,
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $machinesList,
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminUserName,
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminPassword,
- [string][Parameter(Mandatory=$true)][ValidateSet("Disabled", "Manual", "Automatic")] $startupType,
- [string][Parameter(Mandatory=$true)] $protocol,
- [string][Parameter(Mandatory=$true)] $testCertificate,
- [string][Parameter(Mandatory=$true)] $waitTimeoutInSeconds,
- [string][Parameter(Mandatory=$true)] $internStringFileName,
- [string][Parameter(Mandatory=$true)] $killIfTimedOut,
- [bool]$runPowershellInParallel
- )
-
- Validate-WaitTime $waitTimeoutInSeconds
-
- $scriptArguments = "-serviceNames $serviceNames -startupType $startupType -waitTimeoutInSeconds $waitTimeoutInSeconds -killIfTimedOut $killIfTimedOut"
-
- Write-Host "ScriptArguments: $scriptArguments"
-
- Remote-RunScript -machinesList $machinesList -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate -internStringFileName $internStringFileName -scriptEntryPoint "StartStopServices" -scriptArguments $scriptArguments -runPowershellInParallel $runPowershellInParallel
-}
-
-function Remote-RunScript()
-{
- [CmdletBinding()]
- Param
- (
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $machinesList,
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminUserName,
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminPassword,
- [string][Parameter(Mandatory=$true)] $protocol,
- [string][Parameter(Mandatory=$true)] $testCertificate,
- [string][Parameter(Mandatory=$true)] $internStringFileName,
- [string][Parameter(Mandatory=$true)] $scriptEntryPoint,
- [string][Parameter(Mandatory=$true)] $scriptArguments,
- [bool]$runPowershellInParallel
- )
-
- $internScriptPath = "$env:CURRENT_TASK_ROOTDIR\$internStringFileName"
-
- $scriptToRun = Get-Content $internScriptPath | Out-String
-
- $scriptToRun = [string]::Format("{0} {1} {2} {3} ", $scriptToRun, [Environment]::NewLine, $scriptEntryPoint, $scriptArguments)
-
- Write-Output "Invoking deployment"
-
- Write-Output "Script Body: $scriptToRun"
-
- $errorMessage = Invoke-RemoteDeployment -machinesList $machinesList -scriptToRun $scriptToRun -deployInParallel $runPowershellInParallel -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate
-
- if(-Not [string]::IsNullOrEmpty($errorMessage))
- {
- $helpMessage = "Error returned from remote deployment."
- Write-Error "$errorMessage`n$helpMessage"
- return
- }
+Import-Module $env:CURRENT_TASK_ROOTDIR\DeploymentSDK\InvokeRemoteDeployment.ps1
+
+Write-Verbose "Entering script Utility.ps1"
+
+function Validate-WaitTime()
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(mandatory=$true)]
+ [string[]]$runLockTimeoutString
+ )
+
+ $parsedRunLockTimeout = $null
+ if([int32]::TryParse($runLockTimeoutString , [ref]$parsedRunLockTimeout))
+ {
+ if($parsedRunLockTimeout -gt 0)
+ {
+ return
+ }
+ }
+
+ throw "Please provide a valid timeout input in seconds. It should be an integer greater than 0"
+}
+
+function Remote-ServiceStartStop()
+{
+ [CmdletBinding()]
+ Param
+ (
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $serviceNames,
+ [string][Parameter(Mandatory=$true)][AllowEmptyString()] $instanceName,
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $machinesList,
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminUserName,
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminPassword,
+ [string][Parameter(Mandatory=$true)][ValidateSet("Disabled", "Manual", "Automatic")] $startupType,
+ [string][Parameter(Mandatory=$true)] $protocol,
+ [string][Parameter(Mandatory=$true)] $testCertificate,
+ [string][Parameter(Mandatory=$true)] $waitTimeoutInSeconds,
+ [string][Parameter(Mandatory=$true)] $internStringFileName,
+ [string][Parameter(Mandatory=$true)] $killIfTimedOut,
+ [bool]$runPowershellInParallel
+ )
+
+ Validate-WaitTime $waitTimeoutInSeconds
+
+ $scriptArguments = "-serviceNames $serviceNames -instanceName `"$instanceName`" -startupType $startupType -waitTimeoutInSeconds $waitTimeoutInSeconds -killIfTimedOut $killIfTimedOut"
+
+ Write-Host "ScriptArguments: $scriptArguments"
+
+ Remote-RunScript -machinesList $machinesList -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate -internStringFileName $internStringFileName -scriptEntryPoint "StartStopServices" -scriptArguments $scriptArguments -runPowershellInParallel $runPowershellInParallel
+}
+
+function Remote-RunScript()
+{
+ [CmdletBinding()]
+ Param
+ (
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $machinesList,
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminUserName,
+ [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $adminPassword,
+ [string][Parameter(Mandatory=$true)] $protocol,
+ [string][Parameter(Mandatory=$true)] $testCertificate,
+ [string][Parameter(Mandatory=$true)] $internStringFileName,
+ [string][Parameter(Mandatory=$true)] $scriptEntryPoint,
+ [string][Parameter(Mandatory=$true)] $scriptArguments,
+ [bool]$runPowershellInParallel
+ )
+
+ $internScriptPath = "$env:CURRENT_TASK_ROOTDIR\$internStringFileName"
+
+ $scriptToRun = Get-Content $internScriptPath | Out-String
+
+ $scriptToRun = [string]::Format("{0} {1} {2} {3} ", $scriptToRun, [Environment]::NewLine, $scriptEntryPoint, $scriptArguments)
+
+ Write-Output "Invoking deployment"
+
+ Write-Output "Script Body: $scriptToRun"
+
+ $errorMessage = Invoke-RemoteDeployment -machinesList $machinesList -scriptToRun $scriptToRun -deployInParallel $runPowershellInParallel -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate
+
+ if(-Not [string]::IsNullOrEmpty($errorMessage))
+ {
+ $helpMessage = "Error returned from remote deployment."
+ Write-Error "$errorMessage`n$helpMessage"
+ return
+ }
}
\ No newline at end of file
diff --git a/Extensions/Common/TelemetryHelper/Src/TelemetryHelper.ps1 b/Extensions/Common/TelemetryHelper/Src/TelemetryHelper.ps1
new file mode 100644
index 0000000..3520bf6
--- /dev/null
+++ b/Extensions/Common/TelemetryHelper/Src/TelemetryHelper.ps1
@@ -0,0 +1,34 @@
+# Telemetry Codes
+$telemetryCodes =
+@{
+ "Input_Validation" = "Input_Validation_Error";
+ "Task_InternalError" = "Task_Internal_Error";
+ "DTLSDK_Error" = "Dtl_Sdk_Error";
+ }
+
+ # Telemetry Write Method
+function Write-Telemetry
+{
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory=$True,Position=1)]
+ [string]$codeKey,
+
+ [Parameter(Position=2)]
+ [string]$errorMsg
+ )
+
+ $erroCodeMsg = $telemetryCodes[$codeKey]
+
+ ## If no error is passed mark it as not available
+ if([string]::IsNullOrEmpty($errorMsg))
+ {
+ $errorMsg = "No error details available"
+ }
+ $erroCode = ('"{0}":{1}' -f $erroCodeMsg, $errorMsg)
+ ## Form errorcode as json string
+ $erroCode = '{' + $erroCode + '}'
+
+ $telemetryString = "##vso[task.logissue type=error;code=" + $erroCode + ";]"
+ Write-Host $telemetryString
+}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRight.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRight.ps1
index 70f36a0..10cb70c 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRight.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRight.ps1
@@ -1,31 +1,40 @@
-[CmdletBinding()]
-Param()
-
-Trace-VstsEnteringInvocation $MyInvocation
-
-Try
-{
- [string]$userNames = Get-VstsInput -Name userNames -Require
- [string]$environmentName = Get-VstsInput -Name environmentName -Require
- [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
- [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
- [string]$protocol = Get-VstsInput -Name protocol -Require
- [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
- [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
-
- Write-Output "Granting LogonAsAService to $userNames. Version: {{tokens.BuildNumber}}"
-
- $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
-
- . $env:CURRENT_TASK_ROOTDIR\Utility.ps1
-
- $userNames = $userNames -replace '\s','' # no spaces allows in argument lists
-
- $scriptArguments = "-userNames $userNames"
-
- Remote-RunScript -machinesList $environmentName -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate -internStringFileName "GrantLogonAsAServiceRightIntern.ps1" -scriptEntryPoint "GrantLogonAsService" -scriptArguments $scriptArguments -runPowershellInParallel $runPowershellInParallel
-}
-finally
-{
- Trace-VstsLeavingInvocation $MyInvocation
+[CmdletBinding()]
+Param()
+
+Trace-VstsEnteringInvocation $MyInvocation
+
+Try {
+ [string]$userNames = Get-VstsInput -Name userNames -Require
+ [bool]$targetIsDeploymentGroup = Get-VstsInput -Name deploymentGroup -Require -AsBool
+
+ $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+ if ($targetIsDeploymentGroup)
+ {
+ . $env:CURRENT_TASK_ROOTDIR\GrantLogonAsAServiceRightIntern.ps1
+
+ $userNamesArray = [string[]]($userNames.Split(@(",", "`r", "`n"), [System.StringSplitOptions]::RemoveEmptyEntries).Trim())
+
+ GrantLogonAsServiceArray $userNamesArray;
+ }
+ else
+ {
+ . $env:CURRENT_TASK_ROOTDIR\TelemetryHelper\TelemetryHelper.ps1
+ . $env:CURRENT_TASK_ROOTDIR\Utility.ps1
+
+ $scriptArguments = "-userNames " + '"' + $userNames + '"'
+
+ [string]$environmentName = Get-VstsInput -Name environmentName -Require
+ [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
+ [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
+ [string]$protocol = Get-VstsInput -Name protocol -Require
+ [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
+ [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
+
+ Remote-RunScript -machinesList $environmentName -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate -internStringFileName "GrantLogonAsAServiceRightIntern.ps1" -scriptEntryPoint "GrantLogonAsService" -scriptArguments $scriptArguments -runPowershellInParallel $runPowershellInParallel
+ }
+
+}
+finally {
+ Trace-VstsLeavingInvocation $MyInvocation
}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRightIntern.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRightIntern.ps1
index 032051b..66423ce 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRightIntern.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/GrantLogonAsAServiceRightIntern.ps1
@@ -1,45 +1,45 @@
-function GrantLogonAsService(
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $userNames
-)
-{
- function New-TemporaryDirectory {
- $parent = [System.IO.Path]::GetTempPath()
- [string] $name = [System.Guid]::NewGuid()
- New-Item -ItemType Directory -Path (Join-Path $parent $name)
- }
-
- [string[]] $userNamesArray = ($userNames -split ',').Trim()
-
- foreach ($userName in $userNamesArray)
- {
- $tempDir = New-TemporaryDirectory
- #Get list of currently used SIDs
- secedit /export /cfg $tempDir\tempexport.inf
- $curSIDs = Select-String $tempDir\tempexport.inf -Pattern "SeServiceLogonRight"
- $Sids = $curSIDs.line
- $sidstring = ""
-
- $objUser = New-Object System.Security.Principal.NTAccount($userName)
- $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
- if(!$Sids.Contains($strSID) -and !$sids.Contains($userName))
- {
- $sidstring += ",*$strSID"
- }
- if($sidstring)
- {
- $newSids = $sids + $sidstring
- Write-Verbose "New Sids: $newSids"
- $tempinf = Get-Content $tempDir\tempexport.inf
- $tempinf = $tempinf.Replace($Sids,$newSids)
- Add-Content -Path $tempDir\tempimport.inf -Value $tempinf
- secedit /import /db $tempDir\secedit.sdb /cfg "$tempDir\tempimport.inf"
- secedit /configure /db $tempDir\secedit.sdb
- }
- else
- {
- Write-Verbose "No new sids"
- }
-
- del "$tempDir" -Recurse -force -ErrorAction SilentlyContinue
- }
-}
+function GrantLogonAsServiceArray(
+ [string[]][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] $userNames
+) {
+ function New-TemporaryDirectory {
+ $parent = [System.IO.Path]::GetTempPath()
+ [string] $name = [System.Guid]::NewGuid()
+ New-Item -ItemType Directory -Path (Join-Path $parent $name)
+ }
+ foreach ($userName in $userNames) {
+ $tempDir = New-TemporaryDirectory
+ #Get list of currently used SIDs
+ secedit /export /cfg $tempDir\tempexport.inf
+ $curSIDs = Select-String $tempDir\tempexport.inf -Pattern "SeServiceLogonRight"
+ $Sids = $curSIDs.line
+ $sidstring = ""
+
+ $objUser = New-Object System.Security.Principal.NTAccount($userName)
+ $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
+ if (!$Sids.Contains($strSID) -and !$sids.Contains($userName)) {
+ $sidstring += ",*$strSID"
+ }
+ if ($sidstring) {
+ $newSids = $sids + $sidstring
+ Write-Verbose "New Sids: $newSids"
+ $tempinf = Get-Content $tempDir\tempexport.inf
+ $tempinf = $tempinf.Replace($Sids, $newSids)
+ Add-Content -Path $tempDir\tempimport.inf -Value $tempinf
+ secedit /import /db $tempDir\secedit.sdb /cfg "$tempDir\tempimport.inf"
+ secedit /configure /db $tempDir\secedit.sdb
+ }
+ else {
+ Write-Verbose "No new sids"
+ }
+
+ del "$tempDir" -Recurse -force -ErrorAction SilentlyContinue
+ }
+}
+
+function GrantLogonAsService(
+ [string[]][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] $userNames
+) {
+ [string[]] $userNamesArray = [string[]]($userNames.Split(@(",", "`r", "`n"), [System.StringSplitOptions]::RemoveEmptyEntries).Trim())
+
+ return GrantLogonAsServiceArray $userNamesArray
+}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/task.json b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/task.json
index 4a182f0..2be108e 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/task.json
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/GrantLogonAsAServiceRight/task.json
@@ -1,90 +1,102 @@
-{
- "id": "762A1A9C-A8B0-4EC2-993F-42DBBB09FFBD",
- "name": "GrantLogonAsAServiceRight",
- "friendlyName": "Grant Logon As A Service Right",
- "description": "Grant logon as a service.",
- "helpMarkDown": "Version: {{tokens.BuildNumber}} [More Information](https://github.com/jabbera/my-vsts-tasks)",
- "category": "Utility",
- "visibility": [
- "Build",
- "Release"
- ],
- "author": "Michael Barry",
- "version": {
- "Major": "{{tokens.Major}}",
- "Minor": "{{tokens.Minor}}",
- "Patch": "{{tokens.Patch}}"
- },
- "minimumAgentVersion": "1.95.0",
- "inputs": [
- {
- "name": "UserNames",
- "type": "multiLine",
- "label": "User Names",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "The usernames to grant logon as a service with the domain appended."
- },
- {
- "name": "EnvironmentName",
- "type": "multiLine",
- "label": "Machines",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs.
Eg: dbserver.fabrikam.com,192.168.12.34
Or provide output variable of other tasks. Eg: $(variableName)"
- },
- {
- "name": "AdminUserName",
- "type": "string",
- "label": "Admin Login",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "Administrator login for the target machines."
- },
- {
- "name": "AdminPassword",
- "type": "string",
- "label": "Password",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "Password for administrator login for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. "
- },
- {
- "name": "protocol",
- "type": "radio",
- "label": "Protocol",
- "required": true,
- "defaultValue": "Http",
- "options": {
- "Http": "HTTP",
- "Https": "HTTPS"
- },
- "helpMarkDown": "Select the network protocol to use for the WinRM connection with the machine(s). The default is HTTPS."
- },
- {
- "name": "TestCertificate",
- "type": "boolean",
- "label": "Test Certificate",
- "defaultValue": "true",
- "visibleRule": "protocol = Https",
- "required": false,
- "helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate from a trusted certification authority. The parameter is required for the WinRM HTTPS protocol."
- },
- {
- "name": "RunPowershellInParallel",
- "type": "boolean",
- "label": "Run PowerShell in Parallel",
- "defaultValue": "true",
- "required": false,
- "helpMarkDown": "Setting it to true will run the PowerShell scripts in parallel on the target machines."
- }
- ],
- "instanceNameFormat": "Grant Logon As A Service: $(UserNames)",
- "execution": {
- "PowerShell3": {
- "target": "$(currentDirectory)\\GrantLogonAsAServiceRight.ps1",
- "argumentFormat": "",
- "workingDirectory": "$(currentDirectory)"
- }
- }
+{
+ "id": "762A1A9C-A8B0-4EC2-993F-42DBBB09FFBD",
+ "name": "GrantLogonAsAServiceRight",
+ "friendlyName": "Grant Logon As A Service Right",
+ "description": "Grant logon as a service.",
+ "helpMarkDown": "Version: {{tokens.BuildNumber}} [More Information](https://github.com/jabbera/my-vsts-tasks)",
+ "category": "Utility",
+ "visibility": [
+ "Build",
+ "Release"
+ ],
+ "author": "Michael Barry",
+ "version": {
+ "Major": "{{tokens.Major}}",
+ "Minor": "{{tokens.Minor}}",
+ "Patch": "{{tokens.Patch}}"
+ },
+ "minimumAgentVersion": "1.95.0",
+ "inputs": [{
+ "name": "UserNames",
+ "type": "multiLine",
+ "label": "User Names",
+ "defaultValue": "",
+ "required": true,
+ "helpMarkDown": "The usernames to grant logon as a service with the domain appended."
+ },
+ {
+ "name": "deploymentGroup",
+ "type": "boolean",
+ "label": "Target is Deployment Group",
+ "required": true,
+ "defaultValue": "false",
+ "helpMarkDown": "Agents run directly on the server in deployment group. No WinRM Necessary."
+ },
+ {
+ "name": "EnvironmentName",
+ "type": "multiLine",
+ "label": "Machines",
+ "defaultValue": "",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs.
Eg: dbserver.fabrikam.com,192.168.12.34
Or provide output variable of other tasks. Eg: $(variableName)"
+ },
+ {
+ "name": "AdminUserName",
+ "type": "string",
+ "label": "Admin Login",
+ "defaultValue": "",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Administrator login for the target machines."
+ },
+ {
+ "name": "AdminPassword",
+ "type": "string",
+ "label": "Password",
+ "defaultValue": "",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Password for administrator login for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. "
+ },
+ {
+ "name": "protocol",
+ "type": "radio",
+ "label": "Protocol",
+ "required": false,
+ "visibleRule": "deploymentGroup = false",
+ "defaultValue": "Http",
+ "options": {
+ "Http": "HTTP",
+ "Https": "HTTPS"
+ },
+ "helpMarkDown": "Select the network protocol to use for the WinRM connection with the machine(s). The default is HTTPS."
+ },
+ {
+ "name": "TestCertificate",
+ "type": "boolean",
+ "label": "Test Certificate",
+ "defaultValue": "true",
+ "visibleRule": "protocol = Https && deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate from a trusted certification authority. The parameter is required for the WinRM HTTPS protocol."
+ },
+ {
+ "name": "RunPowershellInParallel",
+ "type": "boolean",
+ "label": "Run PowerShell in Parallel",
+ "defaultValue": "true",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Setting it to true will run the PowerShell scripts in parallel on the target machines."
+ }
+ ],
+ "instanceNameFormat": "Grant Logon As A Service: $(UserNames)",
+ "execution": {
+ "PowerShell3": {
+ "target": "$(currentDirectory)\\GrantLogonAsAServiceRight.ps1",
+ "argumentFormat": "",
+ "workingDirectory": "$(currentDirectory)"
+ }
+ }
}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/InstallTopshelfService.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/InstallTopshelfService.ps1
index b34521a..a365c17 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/InstallTopshelfService.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/InstallTopshelfService.ps1
@@ -3,110 +3,106 @@ Param()
Trace-VstsEnteringInvocation $MyInvocation
-Try
-{
+Try {
[string]$topshelfExePaths = Get-VstsInput -Name topshelfExePaths -Require
- [string]$environmentName = Get-VstsInput -Name environmentName -Require
- [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
- [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
- [string]$protocol = Get-VstsInput -Name protocol -Require
- [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
- [string]$specialUser = Get-VstsInput -Name specialUser -Require
- [string]$serviceUsername = Get-VstsInput -Name serviceUsername
- [string]$servicePassword = Get-VstsInput -Name servicePassword
+ [string]$specialUser = Get-VstsInput -Name specialUser -Require
[string]$instanceName = Get-VstsInput -Name instanceName
- [string]$serviceName = Get-VstsInput -Name serviceName
- [string]$displayName = Get-VstsInput -Name displayName
- [string]$description = Get-VstsInput -Name description
- [string]$startupType = Get-VstsInput -Name startupType -Default "default"
- [string]$uninstallFirst = Get-VstsInput -Name uninstallFirst
- [string]$killMmcTaskManager = Get-VstsInput -Name killMmcTaskManager
- [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
-
- $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
-
- Import-Module $env:CURRENT_TASK_ROOTDIR\DeploymentSDK\InvokeRemoteDeployment.ps1
-
- Write-Output "Installing TopShelf service: $topshelfExePaths with instanceName: $instanceName. Version: {{tokens.BuildNumber}}"
-
- $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
-
- [string[]] $topshelfExePathsArray = ($topshelfExePaths -split ',').Trim()
-
- $servicePassword = $servicePassword.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&').Replace('''', '`''').Replace('(','`(').Replace(')','`)').Replace('@','`@').Replace('}','`}').Replace('{','`{')
-
- Write-Host ("##vso[task.setvariable variable=E34A69771F47424D9217F3A4D6BCDC94;issecret=true;]$servicePassword") # Make sure the password doesn't show up in the log.
-
- $instanceName = $instanceName.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&')
-
- $additionalSharedArguments = ""
- if ($specialUser -eq "custom")
- {
- $additionalSharedArguments += " -username:$serviceUsername"
- if (-Not [string]::IsNullOrWhiteSpace($servicePassword))
- {
- $additionalSharedArguments += " -password:$servicePassword"
- }
- }
- else
- {
- $additionalSharedArguments += " --$specialUser"
- }
-
- if (-Not [string]::IsNullOrWhiteSpace($instanceName))
- {
- $additionalSharedArguments += " -instance:$instanceName"
- }
- if (-Not [string]::IsNullOrWhiteSpace($serviceName))
- {
- $additionalSharedArguments += " -servicename:$serviceName"
- }
- if (-Not [string]::IsNullOrWhiteSpace($displayName))
- {
- $additionalSharedArguments += " -displayname ""$displayName"""
- }
- if (-Not [string]::IsNullOrWhiteSpace($description))
- {
- $additionalSharedArguments += " -description ""$description"""
- }
-
- $additonalInstallArguments = ""
- if ($startupType -ne "default")
- {
- $additonalInstallArguments = "--$startupType"
- }
-
- $cmd = "`$env:DT_DISABLEINITIALLOGGING='true'`n"
- $cmd += "`$env:DT_LOGLEVELCON='NONE'`n"
-
- if ($killMmcTaskManager -eq "true")
- {
- $cmd += "Stop-Process -name mmc,taskmgr -Force -ErrorAction SilentlyContinue`n"
- }
-
- foreach($topShelfExe in $topshelfExePathsArray)
- {
- if ($uninstallFirst -eq "true")
- {
- $cmd += "& ""$topShelfExe"" uninstall $additionalSharedArguments`n"
- }
-
- $cmd += "& ""$topShelfExe"" install $additionalSharedArguments $additonalInstallArguments`n"
- }
-
- Write-Output "CMD: $cmd"
-
- $errorMessage = Invoke-RemoteDeployment -machinesList $environmentName -scriptToRun $cmd -deployInParallel $runPowershellInParallel -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate
-
- if(-Not [string]::IsNullOrEmpty($errorMessage))
- {
- $helpMessage = "For more info please google."
- Write-Error "$errorMessage`n$helpMessage"
- return
- }
+ [string]$serviceName = Get-VstsInput -Name serviceName
+ [string]$displayName = Get-VstsInput -Name displayName
+ [string]$description = Get-VstsInput -Name description
+ [string]$startupType = Get-VstsInput -Name startupType -Default "default"
+ [string]$uninstallFirst = Get-VstsInput -Name uninstallFirst
+ [string]$killMmcTaskManager = Get-VstsInput -Name killMmcTaskManager
+ [bool]$targetIsDeploymentGroup = Get-VstsInput -Name deploymentGroup -Require -AsBool
+
+ Write-Output "Installing TopShelf service: $topshelfExePaths with instanceName: $instanceName. Version: {{tokens.BuildNumber}}"
+
+ $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+ [string[]] $topshelfExePathsArray = ($topshelfExePaths -split ',').Trim()
+
+ Write-Host ("##vso[task.setvariable variable=E34A69771F47424D9217F3A4D6BCDC94;issecret=true;]$servicePassword") # Make sure the password doesn't show up in the log.
+
+ $instanceName = $instanceName.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&')
+
+ $additionalSharedArguments = ""
+ if ($specialUser -eq "custom") {
+ [string]$serviceUsername = Get-VstsInput -Name serviceUsername -Require
+ [string]$servicePassword = Get-VstsInput -Name servicePassword
+
+ $servicePassword = $servicePassword.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&').Replace('''', '`''').Replace('(', '`(').Replace(')', '`)').Replace('@', '`@').Replace('}', '`}').Replace('{', '`{')
+
+ $additionalSharedArguments += " -username:$serviceUsername"
+ if (-Not [string]::IsNullOrWhiteSpace($servicePassword)) {
+ $additionalSharedArguments += " -password:""$servicePassword"""
+ }
+ }
+ else {
+ $additionalSharedArguments += " --$specialUser"
+ }
+
+ if (-Not [string]::IsNullOrWhiteSpace($instanceName)) {
+ $additionalSharedArguments += " -instance:$instanceName"
+ }
+ if (-Not [string]::IsNullOrWhiteSpace($serviceName)) {
+ $additionalSharedArguments += " -servicename:$serviceName"
+ }
+ if (-Not [string]::IsNullOrWhiteSpace($displayName)) {
+ $additionalSharedArguments += " -displayname ""$displayName"""
+ }
+ if (-Not [string]::IsNullOrWhiteSpace($description)) {
+ $additionalSharedArguments += " -description ""$description"""
+ }
+
+ $additonalInstallArguments = ""
+ if ($startupType -ne "default") {
+ $additonalInstallArguments = "--$startupType"
+ }
+
+ $cmd = "`$env:DT_DISABLEINITIALLOGGING='true'`n"
+ $cmd += "`$env:DT_LOGLEVELCON='NONE'`n"
+
+ if ($killMmcTaskManager -eq "true") {
+ $cmd += "Stop-Process -name mmc,taskmgr -Force -ErrorAction SilentlyContinue`n"
+ }
+
+ foreach ($topShelfExe in $topshelfExePathsArray) {
+ if ($uninstallFirst -eq "true") {
+ $cmd += "& ""$topShelfExe"" uninstall $additionalSharedArguments`n"
+ }
+
+ $cmd += "& ""$topShelfExe"" install $additionalSharedArguments $additonalInstallArguments`n"
+ }
+
+ Write-Output "CMD: $cmd"
+
+ if ($targetIsDeploymentGroup)
+ {
+ Invoke-Expression $cmd
+ }
+ else
+ {
+ . $env:CURRENT_TASK_ROOTDIR\TelemetryHelper\TelemetryHelper.ps1
+ Import-Module $env:CURRENT_TASK_ROOTDIR\DeploymentSDK\InvokeRemoteDeployment.ps1
+
+ [string]$environmentName = Get-VstsInput -Name environmentName -Require
+ [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
+ [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
+ [string]$protocol = Get-VstsInput -Name protocol -Require
+ [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
+ [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
+
+
+ $errorMessage = Invoke-RemoteDeployment -machinesList $environmentName -scriptToRun $cmd -deployInParallel $runPowershellInParallel -adminUserName $adminUserName -adminPassword $adminPassword -protocol $protocol -testCertificate $testCertificate
+
+ if (-Not [string]::IsNullOrEmpty($errorMessage)) {
+ $helpMessage = "For more info please google."
+ Write-Error "$errorMessage`n$helpMessage"
+ return
+ }
+ }
}
-finally
-{
- Trace-VstsLeavingInvocation $MyInvocation
+finally {
+ Trace-VstsLeavingInvocation $MyInvocation
}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/task.json b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/task.json
index 044dc17..84783ba 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/task.json
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/InstallTopshelfService/task.json
@@ -25,59 +25,6 @@
"required": true,
"helpMarkDown": "Full path to topshelf executables. (Comma separated list)"
},
- {
- "name": "EnvironmentName",
- "type": "multiLine",
- "label": "Machines",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs.
Eg: dbserver.fabrikam.com,192.168.12.34
Or provide output variable of other tasks. Eg: $(variableName)"
- },
- {
- "name": "AdminUserName",
- "type": "string",
- "label": "Admin Login",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "Administrator login for the target machines."
- },
- {
- "name": "AdminPassword",
- "type": "string",
- "label": "Password",
- "defaultValue": "",
- "required": true,
- "helpMarkDown": "Password for administrator login for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. "
- },
- {
- "name": "protocol",
- "type": "radio",
- "label": "Protocol",
- "required": true,
- "defaultValue": "Http",
- "options": {
- "Http": "HTTP",
- "Https": "HTTPS"
- },
- "helpMarkDown": "Select the network protocol to use for the WinRM connection with the machine(s). The default is HTTPS."
- },
- {
- "name": "TestCertificate",
- "type": "boolean",
- "label": "Test Certificate",
- "defaultValue": "true",
- "visibleRule": "protocol = Https",
- "required": false,
- "helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate from a trusted certification authority. The parameter is required for the WinRM HTTPS protocol."
- },
- {
- "name": "RunPowershellInParallel",
- "type": "boolean",
- "label": "Run PowerShell in Parallel",
- "defaultValue": "true",
- "required": false,
- "helpMarkDown": "Setting it to true will run the PowerShell scripts in parallel on the target machines."
- },
{
"name": "specialUser",
"type": "radio",
@@ -173,6 +120,72 @@
"visibleRule": "UninstallFirst = true",
"required": true,
"helpMarkDown": "Check to make the task kill all open instances of mmc and taskmgr in an attempt to avoid the dreaded: The specified service has been marked for deletion. See: http://stackoverflow.com/questions/20561990/how-to-solve-the-specified-service-has-been-marked-for-deletion-error"
+ },
+ {
+ "name": "deploymentGroup",
+ "type": "boolean",
+ "label": "Target is Deployment Group",
+ "required": true,
+ "defaultValue": "false",
+ "helpMarkDown": "Agents run directly on the server in deployment group. No WinRM Necessary."
+ },
+ {
+ "name": "EnvironmentName",
+ "type": "multiLine",
+ "label": "Machines",
+ "defaultValue": "",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs.
Eg: dbserver.fabrikam.com,192.168.12.34
Or provide output variable of other tasks. Eg: $(variableName)"
+ },
+ {
+ "name": "AdminUserName",
+ "type": "string",
+ "label": "Admin Login",
+ "defaultValue": "",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Administrator login for the target machines."
+ },
+ {
+ "name": "AdminPassword",
+ "type": "string",
+ "label": "Password",
+ "defaultValue": "",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Password for administrator login for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. "
+ },
+ {
+ "name": "protocol",
+ "type": "radio",
+ "label": "Protocol",
+ "required": false,
+ "defaultValue": "Http",
+ "visibleRule": "deploymentGroup = false",
+ "options": {
+ "Http": "HTTP",
+ "Https": "HTTPS"
+ },
+ "helpMarkDown": "Select the network protocol to use for the WinRM connection with the machine(s). The default is HTTPS."
+ },
+ {
+ "name": "TestCertificate",
+ "type": "boolean",
+ "label": "Test Certificate",
+ "defaultValue": "true",
+ "visibleRule": "protocol = Https && deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate from a trusted certification authority. The parameter is required for the WinRM HTTPS protocol."
+ },
+ {
+ "name": "RunPowershellInParallel",
+ "type": "boolean",
+ "label": "Run PowerShell in Parallel",
+ "defaultValue": "true",
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
+ "helpMarkDown": "Setting it to true will run the PowerShell scripts in parallel on the target machines."
}
],
"instanceNameFormat": "Install a Topshelf Service: $(TopshelfExePaths)",
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsService.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsService.ps1
index 2669849..ed9ccb6 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsService.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsService.ps1
@@ -1,31 +1,44 @@
-[CmdletBinding()]
-Param()
-
-Trace-VstsEnteringInvocation $MyInvocation
-
-Try
-{
- [string]$serviceNames = Get-VstsInput -Name serviceNames -Require
- [string]$environmentName = Get-VstsInput -Name environmentName -Require
- [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
- [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
- [string]$startupType = Get-VstsInput -Name startupType -Require
- [string]$protocol = Get-VstsInput -Name protocol -Require
- [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
- [string]$waitTimeoutInSeconds = Get-VstsInput -Name waitTimeoutInSeconds -Require
- [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
-
- Write-Output "Starting Windows Services $serviceNames and setting startup type to: $startupType. Version: {{tokens.BuildNumber}}"
-
- $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
-
- . $env:CURRENT_TASK_ROOTDIR\Utility.ps1
-
- $serviceNames = '"' + $serviceNames.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&').Replace('''', '`''') + '"'
-
- Remote-ServiceStartStop -serviceNames $serviceNames -machinesList $environmentName -adminUserName $adminUserName -adminPassword $adminPassword -startupType $startupType -protocol $protocol -testCertificate $testCertificate -waitTimeoutInSeconds $waitTimeoutInSeconds -internStringFileName "StartWindowsServiceIntern.ps1" -killIfTimedOut "false" -runPowershellInParallel $runPowershellInParallel
-}
-finally
-{
- Trace-VstsLeavingInvocation $MyInvocation
+[CmdletBinding()]
+Param()
+
+Trace-VstsEnteringInvocation $MyInvocation
+
+Try {
+ [string]$serviceNames = Get-VstsInput -Name serviceNames -Require
+ [string]$instanceName = Get-VstsInput -Name instanceName
+ [string]$waitTimeoutInSeconds = Get-VstsInput -Name waitTimeoutInSeconds -Require
+ [string]$startupType = Get-VstsInput -Name startupType -Require
+ [bool]$targetIsDeploymentGroup = Get-VstsInput -Name deploymentGroup -Require -AsBool
+
+ Write-Output "Starting Windows Services $serviceNames and setting startup type to: $startupType. Version: {{tokens.BuildNumber}}"
+
+ $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+ if ($targetIsDeploymentGroup)
+ {
+ . $env:CURRENT_TASK_ROOTDIR\StartWindowsServiceIntern.ps1
+
+ $serviceNamesArray = [string[]]($serviceNames.Split(@(",", "`r", "`n"), [System.StringSplitOptions]::RemoveEmptyEntries).Trim())
+
+ StartStopServicesArray $serviceNamesArray $instanceName $startupType $waitTimeoutInSeconds
+ }
+ else
+ {
+ $serviceNames = '"' + $serviceNames.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&').Replace('''', '`''') + '"'
+
+ . $env:CURRENT_TASK_ROOTDIR\TelemetryHelper\TelemetryHelper.ps1
+ . $env:CURRENT_TASK_ROOTDIR\Utility.ps1
+
+ [string]$environmentName = Get-VstsInput -Name environmentName -Require
+ [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
+ [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
+ [string]$protocol = Get-VstsInput -Name protocol -Require
+ [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
+ [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
+
+ Remote-ServiceStartStop -serviceNames $serviceNames -machinesList $environmentName -instanceName $instanceName -adminUserName $adminUserName -adminPassword $adminPassword -startupType $startupType -protocol $protocol -testCertificate $testCertificate -waitTimeoutInSeconds $waitTimeoutInSeconds -internStringFileName "StartWindowsServiceIntern.ps1" -killIfTimedOut "false" -runPowershellInParallel $runPowershellInParallel
+ }
+}
+finally {
+ Trace-VstsLeavingInvocation $MyInvocation
}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsServiceIntern.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsServiceIntern.ps1
index 92909dd..848ada4 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsServiceIntern.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/StartWindowsServiceIntern.ps1
@@ -1,37 +1,47 @@
-function StartStopServices(
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $serviceNames,
- [string][Parameter(Mandatory=$true)][ValidateSet("Manual", "Automatic")] $startupType,
- [int][Parameter(Mandatory=$true)] $waitTimeoutInSeconds,
- [string][Parameter(Mandatory=$true)] $killIfTimedOut
-)
-{
- [string[]] $servicesNamesArray = ($serviceNames -split ',' -replace '"').Trim()
+function StartStopServicesArray(
+ [string[]][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] $services,
+ [string][Parameter(Mandatory=$true)][AllowEmptyString()] $instanceName,
+ [string][Parameter(Mandatory = $true)][ValidateSet("Manual", "Automatic")] $startupType,
+ [int][Parameter(Mandatory = $true)] $waitTimeoutInSeconds
+) {
+ [bool] $atLeastOneServiceWasNotFound = $false
+ $presentServicesArray = $null
+ $services | ForEach-Object {
+ $serviceName = $_
+ if (-not [System.string]::IsNullOrWhiteSpace($instanceName)) {
+ $serviceName += "$" + $instanceName
+ }
+
+ $matchingServices = [PSCustomObject[]] (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)
- [bool] $atLeastOneServiceWasNotFound = $false
- $presentServicesArray = $null
- $servicesNamesArray | ForEach-Object {
- $serviceName = $_
- $matchingServices = [PSCustomObject[]] (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)
+ if ($matchingServices -eq $null) {
+ Write-Error "No services match the name: $serviceName"
+ $atLeastOneServiceWasNotFound = $true
+ }
+ else {
+ $presentServicesArray += $matchingServices
+ }
+ }
- if ($matchingServices -eq $null)
- {
- Write-Error "No services match the name: $serviceName"
- $atLeastOneServiceWasNotFound = $true
- }
- else
- {
- $presentServicesArray += $matchingServices
- }
- }
+ if ($atLeastOneServiceWasNotFound) {
+ return -1;
+ }
- if ($atLeastOneServiceWasNotFound)
- {
- return -1;
- }
+ Write-Verbose ("The following services were found: {0}" -f ($presentServicesArray -join ','))
- Write-Verbose ("The following services were found: {0}" -f ($presentServicesArray -join ','))
+ $presentServicesArray | % { Set-Service -Name $_.Name -StartupType $startupType }
+ $presentServicesArray | Where-Object { $_.Status -ne "Running" } | % { $_.Start() }
+ $presentServicesArray | % { $_.WaitForStatus("Running", [TimeSpan]::FromSeconds($waitTimeoutInSeconds)) }
+}
+
+function StartStopServices(
+ [string][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] $serviceNames,
+ [string][Parameter(Mandatory=$true)][AllowEmptyString()] $instanceName,
+ [string][Parameter(Mandatory = $true)][ValidateSet("Manual", "Automatic")] $startupType,
+ [int][Parameter(Mandatory = $true)] $waitTimeoutInSeconds,
+ [string][Parameter(Mandatory = $true)] $killIfTimedOut
+) {
+ [string[]] $serviceNamesArray = [string[]]($serviceNames.Split(@(",", "`r", "`n"), [System.StringSplitOptions]::RemoveEmptyEntries).Trim())
- $presentServicesArray | % { Set-Service -Name $_.Name -StartupType $startupType }
- $presentServicesArray | Where-Object { $_.Status -ne "Running" } | % { $_.Start() }
- $presentServicesArray | % { $_.WaitForStatus("Running", [TimeSpan]::FromSeconds($waitTimeoutInSeconds)) }
+ return StartStopServicesArray $serviceNamesArray $instanceName $startupType $waitTimeoutInSeconds
}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/task.json b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/task.json
index 4c3152c..d42f874 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/task.json
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StartWindowsService/task.json
@@ -16,8 +16,7 @@
"Patch": "{{tokens.Patch}}"
},
"minimumAgentVersion": "1.95.0",
- "inputs": [
- {
+ "inputs": [{
"name": "ServiceNames",
"type": "multiLine",
"label": "Service Names",
@@ -25,12 +24,49 @@
"required": true,
"helpMarkDown": "The name of the windows service to start. Comma separate to stop multiple. Supports wildcards (*)."
},
+ {
+ "name": "InstanceName",
+ "type": "string",
+ "label": "TopShelf Instance Name",
+ "defaultValue": "",
+ "required": false,
+ "helpMarkDown": "If you use topshelf, the instance name. This name will be appended to the end of each service in ServiceNames"
+ },
+ {
+ "name": "StartupType",
+ "type": "radio",
+ "label": "Service Startup Type",
+ "required": true,
+ "defaultValue": "Automatic",
+ "options": {
+ "Manual": "Manual",
+ "Automatic": "Automatic"
+ },
+ "helpMarkDown": "Select the startup type for the service."
+ },
+ {
+ "name": "WaitTimeoutInSeconds",
+ "type": "string",
+ "label": "Wait timeout",
+ "defaultValue": "120",
+ "required": true,
+ "helpMarkDown": "Amount of time in seconds to wait for the service to start"
+ },
+ {
+ "name": "deploymentGroup",
+ "type": "boolean",
+ "label": "Target is Deployment Group",
+ "required": true,
+ "defaultValue": "false",
+ "helpMarkDown": "Agents run directly on the server in deployment group. No WinRM Necessary."
+ },
{
"name": "EnvironmentName",
"type": "multiLine",
"label": "Machines",
"defaultValue": "",
- "required": true,
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
"helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs.
Eg: dbserver.fabrikam.com,192.168.12.34
Or provide output variable of other tasks. Eg: $(variableName)"
},
{
@@ -38,7 +74,8 @@
"type": "string",
"label": "Admin Login",
"defaultValue": "",
- "required": true,
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
"helpMarkDown": "Administrator login for the target machines."
},
{
@@ -46,34 +83,16 @@
"type": "string",
"label": "Password",
"defaultValue": "",
- "required": true,
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
"helpMarkDown": "Password for administrator login for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. "
},
- {
- "name": "StartupType",
- "type": "radio",
- "label": "Service Startup Type",
- "required": false,
- "defaultValue": "Automatic",
- "options": {
- "Manual": "Manual",
- "Automatic": "Automatic"
- },
- "helpMarkDown": "Select the startup type for the service."
- },
- {
- "name": "WaitTimeoutInSeconds",
- "type": "string",
- "label": "Wait timeout",
- "defaultValue": "120",
- "required": true,
- "helpMarkDown": "Amount of time in seconds to wait for the service to start"
- },
- {
+ {
"name": "protocol",
"type": "radio",
"label": "Protocol",
- "required": true,
+ "required": false,
+ "visibleRule": "deploymentGroup = false",
"defaultValue": "Http",
"options": {
"Http": "HTTP",
@@ -86,7 +105,7 @@
"type": "boolean",
"label": "Test Certificate",
"defaultValue": "true",
- "visibleRule": "protocol = Https",
+ "visibleRule": "protocol = Https && deploymentGroup = false",
"required": false,
"helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate from a trusted certification authority. The parameter is required for the WinRM HTTPS protocol."
},
@@ -95,6 +114,7 @@
"type": "boolean",
"label": "Run PowerShell in Parallel",
"defaultValue": "true",
+ "visibleRule": "deploymentGroup = false",
"required": false,
"helpMarkDown": "Setting it to true will run the PowerShell scripts in parallel on the target machines."
}
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsService.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsService.ps1
index 1e70874..c23d714 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsService.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsService.ps1
@@ -1,32 +1,45 @@
-[CmdletBinding()]
-Param()
-
-Trace-VstsEnteringInvocation $MyInvocation
-
-Try
-{
- [string]$serviceNames = Get-VstsInput -Name serviceNames -Require
- [string]$environmentName = Get-VstsInput -Name environmentName -Require
- [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
- [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
- [string]$startupType = Get-VstsInput -Name startupType -Require
- [string]$protocol = Get-VstsInput -Name protocol -Require
- [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
- [string]$waitTimeoutInSeconds = Get-VstsInput -Name waitTimeoutInSeconds -Require
- [string]$killIfTimedOut = Get-VstsInput -Name killIfTimedOut -Require
- [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
-
- Write-Output "Stopping Windows Service: $serviceName and setting startup type to: $startupType. Kill: $killIfTimedOut Version: {{tokens.BuildNumber}}"
-
- $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
-
- . $env:CURRENT_TASK_ROOTDIR\Utility.ps1
-
- $serviceNames = '"' + $serviceNames.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&').Replace('''', '`''') + '"'
-
- Remote-ServiceStartStop -serviceNames $serviceNames -machinesList $environmentName -adminUserName $adminUserName -adminPassword $adminPassword -startupType $startupType -protocol $protocol -testCertificate $testCertificate -waitTimeoutInSeconds $waitTimeoutInSeconds -internStringFileName "StopWindowsServiceIntern.ps1" -killIfTimedOut $killIfTimedOut -runPowershellInParallel $runPowershellInParallel
-}
-finally
-{
- Trace-VstsLeavingInvocation $MyInvocation
+[CmdletBinding()]
+Param()
+
+Trace-VstsEnteringInvocation $MyInvocation
+
+Try {
+ [string]$serviceNames = Get-VstsInput -Name serviceNames -Require
+ [string]$instanceName = Get-VstsInput -Name instanceName
+ [string]$startupType = Get-VstsInput -Name startupType -Require
+ [string]$waitTimeoutInSeconds = Get-VstsInput -Name waitTimeoutInSeconds -Require
+ [string]$killIfTimedOut = Get-VstsInput -Name killIfTimedOut -Require
+ [bool]$targetIsDeploymentGroup = Get-VstsInput -Name deploymentGroup -Require -AsBool
+
+ Write-Output "Stopping Windows Service: $serviceName and setting startup type to: $startupType. Kill: $killIfTimedOut Version: {{tokens.BuildNumber}}"
+
+ $env:CURRENT_TASK_ROOTDIR = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+ if ($targetIsDeploymentGroup)
+ {
+ . $env:CURRENT_TASK_ROOTDIR\StopWindowsServiceIntern.ps1
+
+ $serviceNamesArray = [string[]]($serviceNames.Split(@(",", "`r", "`n"), [System.StringSplitOptions]::RemoveEmptyEntries).Trim())
+
+ StartStopServicesArray $serviceNamesArray $instanceName $startupType $waitTimeoutInSeconds $killIfTimedOut
+ }
+ else
+ {
+ $serviceNames = '"' + $serviceNames.Replace('`', '``').Replace('"', '`"').Replace('$', '`$').Replace('&', '`&').Replace('''', '`''') + '"'
+
+ [string]$environmentName = Get-VstsInput -Name environmentName -Require
+ [string]$adminUserName = Get-VstsInput -Name adminUserName -Require
+ [string]$adminPassword = Get-VstsInput -Name adminPassword -Require
+ [string]$protocol = Get-VstsInput -Name protocol -Require
+ [string]$testCertificate = Get-VstsInput -Name testCertificate -Require
+ [bool]$runPowershellInParallel = Get-VstsInput -Name RunPowershellInParallel -Default $true -AsBool
+
+ . $env:CURRENT_TASK_ROOTDIR\TelemetryHelper\TelemetryHelper.ps1
+ . $env:CURRENT_TASK_ROOTDIR\Utility.ps1
+
+ Remote-ServiceStartStop -serviceNames $serviceNames -instanceName $instanceName -machinesList $environmentName -adminUserName $adminUserName -adminPassword $adminPassword -startupType $startupType -protocol $protocol -testCertificate $testCertificate -waitTimeoutInSeconds $waitTimeoutInSeconds -internStringFileName "StopWindowsServiceIntern.ps1" -killIfTimedOut $killIfTimedOut -runPowershellInParallel $runPowershellInParallel
+ }
+}
+finally {
+ Trace-VstsLeavingInvocation $MyInvocation
}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsServiceIntern.ps1 b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsServiceIntern.ps1
index 543a3ae..9d3e189 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsServiceIntern.ps1
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/StopWindowsServiceIntern.ps1
@@ -1,61 +1,71 @@
-function StartStopServices(
- [string][Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] $serviceNames,
- [string][Parameter(Mandatory=$true)][ValidateSet("Disabled", "Manual", "Automatic")] $startupType,
- [int][Parameter(Mandatory=$true)] $waitTimeoutInSeconds,
- [string][Parameter(Mandatory=$true)] $killIfTimedOut
-)
-{
- [string[]] $servicesNamesArray = ($serviceNames -split ',' -replace '"').Trim()
-
- $presentServicesArray = $null
- $servicesNamesArray | ForEach-Object {
- $serviceName = $_
- $matchingServices = [PSCustomObject[]] (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)
-
- if ($matchingServices -eq $null)
- {
- Write-Verbose "No services match the name: $serviceName"
- }
- else
- {
- $presentServicesArray += $matchingServices
- }
- }
-
- if ($presentServicesArray.Length -eq 0)
- {
- Write-Verbose "No services matching the given names were found."
- return
- }
-
- Write-Verbose ("The following services were found: {0}" -f ($presentServicesArray -join ','))
-
- try
- {
- $presentServicesArray | % { Set-Service -Name $_.Name -StartupType $startupType -ErrorAction SilentlyContinue }
- $presentServicesArray | Where-Object { $_.Status -ne "Stopped" } | % { $_.Stop() }
- $ErrorActionPreference = "SilentlyContinue" # I don't want the wait for status to throw in the case of a timeout
- $presentServicesArray | % { $_.WaitForStatus("Stopped", [TimeSpan]::FromSeconds($waitTimeoutInSeconds)) }
- $ErrorActionPreference = "Stop"
- }
- Catch
- {
- $ErrorActionPreference = "Stop"
- if ($killIfTimedOut -eq "false")
- {
- $errorMessage = $_.Exception.Message
- Write-Verbose $errorMessage
- throw
- }
-
- $nonStoppedServices = $presentServicesArray | Where-Object { $_.Status -ne "Stopped" } | % { $_.ServiceName }
-
- $nonStoppedServices | % { Write-Verbose "Killing service after not stopping within timeout: $_" }
-
- (get-wmiobject win32_Service | Where-Object { $nonStoppedServices -contains $_.Name }).ProcessID | % { Stop-Process -Force $_ }
- }
- Finally
- {
- $presentServicesArray | % { Set-Service -Name $_.Name -StartupType $startupType }
- }
+function StartStopServicesArray(
+ [string[]][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] $services,
+ [string][Parameter(Mandatory=$true)][AllowEmptyString()] $instanceName,
+ [string][Parameter(Mandatory = $true)][ValidateSet("Disabled", "Manual", "Automatic")] $startupType,
+ [int][Parameter(Mandatory = $true)] $waitTimeoutInSeconds,
+ [string][Parameter(Mandatory = $true)] $killIfTimedOut
+) {
+ $presentServicesArray = $null
+ $services | ForEach-Object {
+ $serviceName = $_
+
+ if (-not [System.string]::IsNullOrWhiteSpace($instanceName)) {
+ $serviceName += "$" + $instanceName
+ }
+
+ $matchingServices = [PSCustomObject[]] (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)
+
+ if ($matchingServices -eq $null)
+ {
+ Write-Verbose "No services match the name: $serviceName"
+ }
+ else
+ {
+ $presentServicesArray += $matchingServices
+ }
+ }
+
+ if ($presentServicesArray.Length -eq 0) {
+ Write-Verbose "No services matching the given names were found."
+ return
+ }
+
+ Write-Verbose ("The following services were found: {0}" -f ($presentServicesArray -join ','))
+
+ try {
+ $presentServicesArray | % { Set-Service -Name $_.Name -StartupType $startupType -ErrorAction SilentlyContinue }
+ $presentServicesArray | Where-Object { $_.Status -ne "Stopped" } | % { $_.Stop() }
+ $ErrorActionPreference = "SilentlyContinue" # I don't want the wait for status to throw in the case of a timeout
+ $presentServicesArray | % { $_.WaitForStatus("Stopped", [TimeSpan]::FromSeconds($waitTimeoutInSeconds)) }
+ $ErrorActionPreference = "Stop"
+ }
+ Catch {
+ $ErrorActionPreference = "Stop"
+ if ($killIfTimedOut -eq "false") {
+ $errorMessage = $_.Exception.Message
+ Write-Verbose $errorMessage
+ throw
+ }
+
+ $nonStoppedServices = $presentServicesArray | Where-Object { $_.Status -ne "Stopped" } | % { $_.ServiceName }
+
+ $nonStoppedServices | % { Write-Verbose "Killing service after not stopping within timeout: $_" }
+
+ (get-wmiobject win32_Service | Where-Object { $nonStoppedServices -contains $_.Name }).ProcessID | % { Stop-Process -Force $_ }
+ }
+ Finally {
+ $presentServicesArray | % { Set-Service -Name $_.Name -StartupType $startupType }
+ }
}
+
+function StartStopServices(
+ [string][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()] $serviceNames,
+ [string][Parameter(Mandatory=$true)][AllowEmptyString()] $instanceName,
+ [string][Parameter(Mandatory = $true)][ValidateSet("Disabled", "Manual", "Automatic")] $startupType,
+ [int][Parameter(Mandatory = $true)] $waitTimeoutInSeconds,
+ [string][Parameter(Mandatory = $true)] $killIfTimedOut
+) {
+ [string[]] $serviceNamesArray = [string[]]($serviceNames.Split(@(",", "`r", "`n"), [System.StringSplitOptions]::RemoveEmptyEntries).Trim())
+
+ return StartStopServicesArray $serviceNamesArray $instanceName $startupType $waitTimeoutInSeconds $killIfTimedOut
+}
\ No newline at end of file
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/task.json b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/task.json
index cbb160c..d35b187 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/task.json
+++ b/Extensions/WindowsServiceReleaseTasks/Src/Tasks/StopWindowsService/task.json
@@ -16,8 +16,7 @@
"Patch": "{{tokens.Patch}}"
},
"minimumAgentVersion": "1.95.0",
- "inputs": [
- {
+ "inputs": [{
"name": "ServiceNames",
"type": "multiLine",
"label": "Service Names",
@@ -25,12 +24,50 @@
"required": true,
"helpMarkDown": "The name of the windows service to stop. Comma separate to stop multiple. Supports wildcards (*)."
},
+ {
+ "name": "InstanceName",
+ "type": "string",
+ "label": "TopShelf Instance Name",
+ "defaultValue": "",
+ "required": false,
+ "helpMarkDown": "If you use topshelf, the instance name. This name will be appended to the end of each service in ServiceNames"
+ },
+ {
+ "name": "StartupType",
+ "type": "radio",
+ "label": "Service Startup Type",
+ "required": true,
+ "defaultValue": "Disabled",
+ "options": {
+ "Disabled": "Disabled",
+ "Manual": "Manual",
+ "Automatic": "Automatic"
+ },
+ "helpMarkDown": "Select the startup type for the service."
+ } ,
+ {
+ "name": "KillIfTimedOut",
+ "type": "boolean",
+ "label": "Kill service if stop fails",
+ "defaultValue": "true",
+ "required": true,
+ "helpMarkDown": "Select this option for force terminate the service if the stop fails."
+ },
+ {
+ "name": "deploymentGroup",
+ "type": "boolean",
+ "label": "Target is Deployment Group",
+ "required": true,
+ "defaultValue": "false",
+ "helpMarkDown": "Agents run directly on the server in deployment group. No WinRM Necessary."
+ },
{
"name": "EnvironmentName",
"type": "multiLine",
"label": "Machines",
"defaultValue": "",
- "required": true,
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
"helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs.
Eg: dbserver.fabrikam.com,192.168.12.34
Or provide output variable of other tasks. Eg: $(variableName)"
},
{
@@ -38,7 +75,8 @@
"type": "string",
"label": "Admin Login",
"defaultValue": "",
- "required": true,
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
"helpMarkDown": "Administrator login for the target machines."
},
{
@@ -46,23 +84,11 @@
"type": "string",
"label": "Password",
"defaultValue": "",
- "required": true,
+ "visibleRule": "deploymentGroup = false",
+ "required": false,
"helpMarkDown": "Password for administrator login for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. "
},
- {
- "name": "StartupType",
- "type": "radio",
- "label": "Service Startup Type",
- "required": false,
- "defaultValue": "Disabled",
- "options": {
- "Disabled": "Disabled",
- "Manual": "Manual",
- "Automatic": "Automatic"
- },
- "helpMarkDown": "Select the startup type for the service."
- },
- {
+ {
"name": "WaitTimeoutInSeconds",
"type": "string",
"label": "Wait timeout",
@@ -70,11 +96,12 @@
"required": true,
"helpMarkDown": "Amount of time in seconds to wait for the service to start"
},
- {
+ {
"name": "protocol",
"type": "radio",
"label": "Protocol",
- "required": true,
+ "required": false,
+ "visibleRule": "deploymentGroup = false",
"defaultValue": "Http",
"options": {
"Http": "HTTP",
@@ -87,7 +114,7 @@
"type": "boolean",
"label": "Test Certificate",
"defaultValue": "true",
- "visibleRule": "protocol = Https",
+ "visibleRule": "protocol = Https && deploymentGroup = false",
"required": false,
"helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate from a trusted certification authority. The parameter is required for the WinRM HTTPS protocol."
},
@@ -97,15 +124,8 @@
"label": "Run PowerShell in Parallel",
"defaultValue": "true",
"required": false,
+ "visibleRule": "deploymentGroup = false",
"helpMarkDown": "Setting it to true will run the PowerShell scripts in parallel on the target machines."
- },
- {
- "name": "KillIfTimedOut",
- "type": "boolean",
- "label": "Kill service if stop fails",
- "defaultValue": "true",
- "required": true,
- "helpMarkDown": "Select this option for force terminate the service if the stop fails."
}
],
"instanceNameFormat": "Stop Windows Service: $(ServiceNames)",
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/overview.md b/Extensions/WindowsServiceReleaseTasks/Src/overview.md
index 11fadc3..90966bc 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/overview.md
+++ b/Extensions/WindowsServiceReleaseTasks/Src/overview.md
@@ -1,33 +1,31 @@
-# Windows service release management tasks
-This extension contains tasks to start and stop windows services as well as change the startup type. This uses powershell remoting.
-
-1. **Start Windows Service(s)**
-
- This task will start windows service(s) on a list of machines and change the startup type to Automatic or Manual.
-
-2. **Stop Windows Service(s)**
-
- This task will stop windows service(s) on a list of machines and change the startup type to Disabled, Automatic or Manual.
-
-3. **Install (TopShelf) Windows Service(s)**
-
- Can be used to call executables that use [TopShelf](http://topshelf-project.com/) and install them as a service.
-
-4. **Grant Logon As A Service Right**
-
- Topshelf handles this for you, but if you are winging it, you'll need this.
-
-Note: This release migrates to the VSTS sdk and includes some major enhancements\fixes.
-
-Primary Changes include:
-
- * Ability to kill all open mmc\taskmgr to attempt to avoid the: Service is pending deletion issue
- * Proper escaping of passwords
- * Support spaces and $ in service names
- * Embed the DeploymentSdk and use that
- * Support parallel running of tasks
- * Chnage to the powershell 3 VSTS-SDK
-
-
-Icons made by [Google](http://www.flaticon.com/authors/google) [www.flaticon.com](http://www.flaticon.com) [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/)
-Icons made by [Freepik](http://www.freepik.com) [www.flaticon.com](http://www.flaticon.com) [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/)
+# Windows service release management tasks
+
+### Now Supporting deployment groups
+No more usernames and passwords for deployment accounts!
+
+This extension contains tasks to start and stop windows services as well as change the startup type.
+
+1. **Start Windows Service(s)**
+
+ This task will start windows service(s) on a list of machines and change the startup type to Automatic or Manual.
+
+2. **Stop Windows Service(s)**
+
+ This task will stop windows service(s) on a list of machines and change the startup type to Disabled, Automatic or Manual.
+
+3. **Install (TopShelf) Windows Service(s)**
+
+ Can be used to call executables that use [TopShelf](http://topshelf-project.com/) and install them as a service.
+
+4. **Grant Logon As A Service Right**
+
+ Topshelf handles this for you, but if you are winging it, you'll need this.
+
+
+Version 7 changes:
+
+ * Support deployment groups nativly. No more managing remote credentials in your releases!
+ * Support instance names in start\stop tasks
+
+Icons made by [Google](http://www.flaticon.com/authors/google) [www.flaticon.com](http://www.flaticon.com) [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/)
+Icons made by [Freepik](http://www.freepik.com) [www.flaticon.com](http://www.flaticon.com) [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/)
diff --git a/Extensions/WindowsServiceReleaseTasks/Src/vss-extension.json b/Extensions/WindowsServiceReleaseTasks/Src/vss-extension.json
index 05fd10f..36ecb23 100644
--- a/Extensions/WindowsServiceReleaseTasks/Src/vss-extension.json
+++ b/Extensions/WindowsServiceReleaseTasks/Src/vss-extension.json
@@ -1,101 +1,95 @@
-{
- "manifestVersion": 1,
- "id": "windows-service-release-tasks",
- "name": "Windows Service Release Tasks",
- "version": "{{tokens.BuildNumber}}",
- "publisher": "jabbera",
- "public": "true",
- "targets": [
- {
- "id": "Microsoft.VisualStudio.Services"
- }
- ],
- "description": "Release management tasks for the starting, stopping, and install(TopShelf) of windows services.",
- "categories": [
- "Build and release"
- ],
- "tags": [ "service", "release", "windows service" ],
- "content": {
- "license": {
- "path": "license.txt"
- },
- "details": {
- "path": "overview.md"
- }
- },
- "screenshots": [
- {
- "path": "screenshots/screenshot1.png"
- }
- ],
- "links": {
- "getstarted": {
- "uri": "https://github.com/jabbera/my-vsts-tasks"
- },
- "support": {
- "uri": "https://github.com/jabbera/my-vsts-tasks/issues"
- }
- },
- "icons": {
- "default": "extension-icon.png"
- },
- "files": [
- {
- "path": "Tasks/StartWindowsService"
- },
- {
- "path": "Tasks/StopWindowsService"
- },
- {
- "path": "Tasks/InstallTopshelfService"
- },
- {
- "path": "Tasks/GrantLogonAsAServiceRight"
- }
- ],
- "contributions": [
- {
- "id": "start-windows-service-task",
- "type": "ms.vss-distributed-task.task",
- "targets": [
- "ms.vss-distributed-task.tasks"
- ],
- "properties": {
- "name": "Tasks/StartWindowsService"
- }
- },
- {
- "id": "stop-windows-service-task",
- "type": "ms.vss-distributed-task.task",
- "targets": [
- "ms.vss-distributed-task.tasks"
- ],
- "properties": {
- "name": "Tasks/StopWindowsService"
- }
- },
- {
- "id": "install-topshelf-service-task",
- "type": "ms.vss-distributed-task.task",
- "targets": [
- "ms.vss-distributed-task.tasks"
- ],
- "properties": {
- "name": "Tasks/InstallTopshelfService"
- }
- },
- {
- "id": "grant-logon-as-a-service-right-task",
- "type": "ms.vss-distributed-task.task",
- "targets": [
- "ms.vss-distributed-task.tasks"
- ],
- "properties": {
- "name": "Tasks/GrantLogonAsAServiceRight"
- }
- }
- ],
- "galleryFlags": [
- "Public"
- ]
+{
+ "manifestVersion": 1,
+ "id": "windows-service-release-tasks",
+ "name": "Windows Service Release Tasks",
+ "version": "{{tokens.BuildNumber}}",
+ "publisher": "jabbera",
+ "public": "true",
+ "targets": [{
+ "id": "Microsoft.VisualStudio.Services"
+ }],
+ "description": "Release management tasks for the starting, stopping, and install(TopShelf) of windows services.",
+ "categories": [
+ "Build and release"
+ ],
+ "tags": ["service", "release", "windows service"],
+ "content": {
+ "license": {
+ "path": "license.txt"
+ },
+ "details": {
+ "path": "overview.md"
+ }
+ },
+ "screenshots": [{
+ "path": "screenshots/screenshot1.png"
+ }],
+ "links": {
+ "getstarted": {
+ "uri": "https://github.com/jabbera/my-vsts-tasks"
+ },
+ "support": {
+ "uri": "https://github.com/jabbera/my-vsts-tasks/issues"
+ }
+ },
+ "icons": {
+ "default": "extension-icon.png"
+ },
+ "files": [{
+ "path": "Tasks/StartWindowsService"
+ },
+ {
+ "path": "Tasks/StopWindowsService"
+ },
+ {
+ "path": "Tasks/InstallTopshelfService"
+ },
+ {
+ "path": "Tasks/GrantLogonAsAServiceRight"
+ }
+ ],
+ "contributions": [{
+ "id": "start-windows-service-task",
+ "type": "ms.vss-distributed-task.task",
+ "targets": [
+ "ms.vss-distributed-task.tasks"
+ ],
+ "properties": {
+ "name": "Tasks/StartWindowsService"
+ }
+ },
+ {
+ "id": "stop-windows-service-task",
+ "type": "ms.vss-distributed-task.task",
+ "targets": [
+ "ms.vss-distributed-task.tasks"
+ ],
+ "properties": {
+ "name": "Tasks/StopWindowsService"
+ }
+ },
+ {
+ "id": "install-topshelf-service-task",
+ "type": "ms.vss-distributed-task.task",
+ "targets": [
+ "ms.vss-distributed-task.tasks"
+ ],
+ "properties": {
+ "name": "Tasks/InstallTopshelfService"
+ }
+ },
+ {
+ "id": "grant-logon-as-a-service-right-task",
+ "type": "ms.vss-distributed-task.task",
+ "targets": [
+ "ms.vss-distributed-task.tasks"
+ ],
+ "properties": {
+ "name": "Tasks/GrantLogonAsAServiceRight"
+ }
+ }
+ ],
+ "galleryFlags": [
+ "Public"
+ ]
}
\ No newline at end of file
diff --git a/common.json b/common.json
index 08fd89e..e7cdd8d 100644
--- a/common.json
+++ b/common.json
@@ -1,54 +1,66 @@
-{
- "StartWindowsService": [
- {
- "module": "Helper",
- "dest": ""
- },
- {
- "module": "DeploymentSDK",
- "dest": "DeploymentSDK"
- },
- {
- "module": "VstsTaskSdk",
- "dest": "ps_modules"
- }
- ],
- "StopWindowsService": [
- {
- "module": "Helper",
- "dest": ""
- },
- {
- "module": "DeploymentSDK",
- "dest": "DeploymentSDK"
- },
- {
- "module": "VstsTaskSdk",
- "dest": "ps_modules"
- }
- ],
- "GrantLogonAsAServiceRight": [
- {
- "module": "Helper",
- "dest": ""
- },
- {
- "module": "DeploymentSDK",
- "dest": "DeploymentSDK"
- },
- {
- "module": "VstsTaskSdk",
- "dest": "ps_modules"
- }
- ],
- "InstallTopshelfService": [
- {
- "module": "DeploymentSDK",
- "dest": "DeploymentSDK"
- },
- {
- "module": "VstsTaskSdk",
- "dest": "ps_modules"
- }
- ]
+{
+ "StartWindowsService": [{
+ "module": "Helper",
+ "dest": ""
+ },
+ {
+ "module": "DeploymentSDK",
+ "dest": "DeploymentSDK"
+ },
+ {
+ "module": "VstsTaskSdk",
+ "dest": "ps_modules"
+ },
+ {
+ "module": "TelemetryHelper",
+ "dest": "TelemetryHelper"
+ }
+ ],
+ "StopWindowsService": [{
+ "module": "Helper",
+ "dest": ""
+ },
+ {
+ "module": "DeploymentSDK",
+ "dest": "DeploymentSDK"
+ },
+ {
+ "module": "VstsTaskSdk",
+ "dest": "ps_modules"
+ },
+ {
+ "module": "TelemetryHelper",
+ "dest": "TelemetryHelper"
+ }
+ ],
+ "GrantLogonAsAServiceRight": [{
+ "module": "Helper",
+ "dest": ""
+ },
+ {
+ "module": "DeploymentSDK",
+ "dest": "DeploymentSDK"
+ },
+ {
+ "module": "VstsTaskSdk",
+ "dest": "ps_modules"
+ },
+ {
+ "module": "TelemetryHelper",
+ "dest": "TelemetryHelper"
+ }
+ ],
+ "InstallTopshelfService": [{
+ "module": "DeploymentSDK",
+ "dest": "DeploymentSDK"
+ },
+ {
+ "module": "VstsTaskSdk",
+ "dest": "ps_modules"
+ },
+ {
+ "module": "TelemetryHelper",
+ "dest": "TelemetryHelper"
+ }
+ ]
}
\ No newline at end of file
diff --git a/config.bootstrap.json b/config.bootstrap.json
index 9d16bfe..314b4f0 100644
--- a/config.bootstrap.json
+++ b/config.bootstrap.json
@@ -1,8 +1,8 @@
{
- "tokens":{
- "Major": 6,
- "Patch": 1
- },
- "prefix" : "{{",
- "suffix" : "}}"
+ "tokens": {
+ "Major": 6,
+ "Patch": 1
+ },
+ "prefix": "{{",
+ "suffix": "}}"
}
\ No newline at end of file
diff --git a/config.json b/config.json
index 7eabe76..67f7c4a 100644
--- a/config.json
+++ b/config.json
@@ -1,10 +1,10 @@
-{
- "tokens":{
- "BuildNumber": "{{tokens.Major}}.{{tokens.Minor}}.{{tokens.Patch}}",
- "Major": {{tokens.Major}},
- "Minor": {{tokens.Minor}},
- "Patch": {{tokens.Patch}}
- },
- "prefix" : "{{",
- "suffix" : "}}"
+{
+ "tokens":{
+ "BuildNumber": "{{tokens.Major}}.{{tokens.Minor}}.{{tokens.Patch}}",
+ "Major": {{tokens.Major}},
+ "Minor": {{tokens.Minor}},
+ "Patch": {{tokens.Patch}}
+ },
+ "prefix" : "{{",
+ "suffix" : "}}"
}
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index 4abc1b9..4c95e03 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,106 +1,114 @@
-var del = require("del");
-var gulp = require("gulp");
-var gulpUtil = require('gulp-util');
-var path = require("path");
-var shell = require("shelljs");
-var spawn = require('child_process').spawn;
-var fs = require('fs-extra');
-var pkgm = require('./package');
-var replace = require('gulp-token-replace');
-var debug = require('gulp-debug');
-var chmod = require('gulp-chmod');
-
-var buildRoot = "_build";
-var packageRoot = "_package";
-var extnBuildRoot = "_build/Extensions/";
-var sourcePaths = "Extensions/**/*";
-var vstsTaskSdkPath = "node_modules/vsts-task-sdk/VstsTaskSdk/**/*";
-var commonSrc = "Extensions/Common";
-
-gulp.task("clean", function() {
- return del([buildRoot, packageRoot]);
-});
-
-gulp.task("compile", ["clean"], function(done) {
- return gulp.src(sourcePaths, { base: "." }).pipe(chmod(666)).pipe(gulp.dest(buildRoot));
-});
-
-gulp.task("copyPowershellModulesToCommon", ["compile"], function (done) {
- var dest = path.join(extnBuildRoot, 'Common', 'VstsTaskSdk', 'Src');
- return gulp.src(vstsTaskSdkPath, { base: "node_modules/vsts-task-sdk" }).pipe(gulp.dest(dest));
-});
-
-gulp.task("build", ["copyPowershellModulesToCommon"], function () {
- //Foreach task under extensions copy common modules
- fs.readdirSync(extnBuildRoot).filter(function (file) {
- return fs.statSync(path.join(extnBuildRoot, file)).isDirectory() && file != "Common";
- }).forEach(copyCommonModules);
-});
-
-gulp.task("package", ["token-replace"], function() {
- fs.readdirSync(extnBuildRoot).filter(function (file) {
- return fs.statSync(path.join(extnBuildRoot, file)).isDirectory() && file != "Common";
- }).forEach(createVsixPackage);
-});
-
-gulp.task("token-replace", ["token-replace-bootstrap"], function(){
- var config = require("./" + buildRoot + "/config.json");
- return gulp.src([
- extnBuildRoot + "/**/*.json",
- extnBuildRoot + "/**/*.ps1"
- ])
- .pipe(replace({tokens:config}))
- .pipe(gulp.dest(extnBuildRoot));
-
-});
-
-gulp.task("token-replace-bootstrap", ["build"], function(){
- var config = require("./config.bootstrap.json");
- config.tokens["Minor"] = getMinorVersion();
- return gulp.src("./config.json")
- .pipe(replace({tokens:config}))
- .pipe(gulp.dest(buildRoot));
-});
-
-var copyCommonModules = function(extensionName) {
-
- var commonDeps = require('./common.json');
- var commonSrc = path.join(__dirname, extnBuildRoot, 'Common');
-
- var currentExtnRoot = path.join(__dirname, extnBuildRoot, extensionName);
- return gulp.src(path.join(currentExtnRoot, '**/task.json'))
- .pipe(pkgm.copyCommonModules(currentExtnRoot, commonDeps, commonSrc));
-}
-
-var createVsixPackage = function(extensionName) {
- var extnOutputPath = path.join(packageRoot, extensionName);
- var extnManifestPath = path.join(extnBuildRoot, extensionName, "Src");
- del(extnOutputPath);
- shell.mkdir("-p", extnOutputPath);
- var packagingCmd = "node_modules\\.bin\\tfx extension create --manifeset-globs vss-extension.json --root " + extnManifestPath + " --output-path " + extnOutputPath;
- executeCommand(packagingCmd, function() {});
-}
-
-var executeCommand = function(cmd, callback) {
- shell.exec(cmd, {silent: true}, function(code, output) {
- if(code != 0) {
- console.error("command failed: " + cmd + "\nManually execute to debug");
- }
- else {
- callback();
- }
- });
-}
-
-var getMinorVersion = function()
-{
- var now = new Date();
- var start = new Date(now.getFullYear(), 0, 0);
- var diff = now - start;
- var oneDay = 1000 * 60 * 60 * 24;
- var day = Math.floor(diff / oneDay);
- var twoDigitYear = now.getFullYear().toString().substr(2,2);
- return twoDigitYear.toString() + day.toString();
-}
-
+var del = require("del");
+var gulp = require("gulp");
+var gulpUtil = require('gulp-util');
+var path = require("path");
+var shell = require("shelljs");
+var spawn = require('child_process').spawn;
+var fs = require('fs-extra');
+var pkgm = require('./package');
+var replace = require('gulp-token-replace');
+var debug = require('gulp-debug');
+var chmod = require('gulp-chmod');
+
+var buildRoot = "_build";
+var packageRoot = "_package";
+var extnBuildRoot = "_build/Extensions/";
+var sourcePaths = "Extensions/**/*";
+var vstsTaskSdkPath = "node_modules/vsts-task-sdk/VstsTaskSdk/**/*";
+var commonSrc = "Extensions/Common";
+
+gulp.task("clean", function () {
+ return del([buildRoot, packageRoot]);
+});
+
+gulp.task("compile", ["clean"], function (done) {
+ return gulp.src(sourcePaths, {
+ base: "."
+ }).pipe(chmod(666)).pipe(gulp.dest(buildRoot));
+});
+
+gulp.task("copyPowershellModulesToCommon", ["compile"], function (done) {
+ var dest = path.join(extnBuildRoot, 'Common', 'VstsTaskSdk', 'Src');
+ return gulp.src(vstsTaskSdkPath, {
+ base: "node_modules/vsts-task-sdk"
+ }).pipe(gulp.dest(dest));
+});
+
+gulp.task("build", ["copyPowershellModulesToCommon"], function () {
+ //Foreach task under extensions copy common modules
+ fs.readdirSync(extnBuildRoot).filter(function (file) {
+ return fs.statSync(path.join(extnBuildRoot, file)).isDirectory() && file != "Common";
+ }).forEach(copyCommonModules);
+});
+
+gulp.task("package", ["token-replace"], function () {
+ fs.readdirSync(extnBuildRoot).filter(function (file) {
+ return fs.statSync(path.join(extnBuildRoot, file)).isDirectory() && file != "Common";
+ }).forEach(createVsixPackage);
+});
+
+gulp.task("token-replace", ["token-replace-bootstrap"], function () {
+ var config = require("./" + buildRoot + "/config.json");
+ return gulp.src([
+ extnBuildRoot + "/**/*.json",
+ extnBuildRoot + "/**/*.ps1"
+ ])
+ .pipe(replace({
+ tokens: config
+ }))
+ .pipe(gulp.dest(extnBuildRoot));
+
+});
+
+gulp.task("token-replace-bootstrap", ["build"], function () {
+ var config = require("./config.bootstrap.json");
+ config.tokens["Minor"] = getMinorVersion();
+ return gulp.src("./config.json")
+ .pipe(replace({
+ tokens: config
+ }))
+ .pipe(gulp.dest(buildRoot));
+});
+
+var copyCommonModules = function (extensionName) {
+
+ var commonDeps = require('./common.json');
+ var commonSrc = path.join(__dirname, extnBuildRoot, 'Common');
+
+ var currentExtnRoot = path.join(__dirname, extnBuildRoot, extensionName);
+ return gulp.src(path.join(currentExtnRoot, '**/task.json'))
+ .pipe(pkgm.copyCommonModules(currentExtnRoot, commonDeps, commonSrc));
+}
+
+var createVsixPackage = function (extensionName) {
+ var extnOutputPath = path.join(packageRoot, extensionName);
+ var extnManifestPath = path.join(extnBuildRoot, extensionName, "Src");
+ del(extnOutputPath);
+ shell.mkdir("-p", extnOutputPath);
+ var packagingCmd = "node_modules\\.bin\\tfx extension create --manifeset-globs vss-extension.json --root " + extnManifestPath + " --output-path " + extnOutputPath;
+ executeCommand(packagingCmd, function () {});
+}
+
+var executeCommand = function (cmd, callback) {
+ shell.exec(cmd, {
+ silent: true
+ }, function (code, output) {
+ if (code != 0) {
+ console.error("command failed: " + cmd + "\nManually execute to debug");
+ } else {
+ callback();
+ }
+ });
+}
+
+var getMinorVersion = function () {
+ var now = new Date();
+ var start = new Date(now.getFullYear(), 0, 0);
+ var diff = now - start;
+ var oneDay = 1000 * 60 * 60 * 24;
+ var day = Math.floor(diff / oneDay);
+ var twoDigitYear = now.getFullYear().toString().substr(2, 2);
+ return twoDigitYear.toString() + day.toString();
+}
+
gulp.task("default", ["build"]);
\ No newline at end of file