This section explains the prerequisites, end‑to‑end pipeline flow, and a real‑world production use case for restarting Windows services securely using Azure DevOps and WinRM over HTTPS (5986).
π Table of Contents
- π Prerequisites
- π Pipeline Flow: Service Restart Using WinRM over Secure Port (5986)
- π Code Example Pipeline (Azure DevOps YAML)
- ✅ Notes
π Prerequisites
π· Azure DevOps
- Azure DevOps project and pipeline created
- Manual trigger enabled for UAT / PROD
- Pipeline parameters (START / STOP / RESTART)
- Secrets stored in Variable Groups
πͺ Windows DevOps Agent
- Self‑hosted Windows agent installed
- Agent pool access configured
- Outbound connectivity to target servers
- PowerShellOnTargetMachines available
π₯️ Target Windows Server
- WinRM enabled and running , Refrence link ( Secure WinRM Configuration Guide )
- WinRM configured over HTTPS (5986)
- CA SSL certificate installed
- 5986 allowed in Firewall / NSG
- Service credentials available
π Pipeline Flow: Service Restart Using WinRM over Secure Port (5986)
┌──────────────────────────────────────────────┐
│ Azure DevOps Pipeline │
│ (Manual Trigger) │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Parameter Selection (OPERATION) │
│ ─ START_WAS │
│ ─ STOP_WAS │
│ ─ RESTART_WAS │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Azure DevOps Windows Agent │
│ Pool: AppOps-Win-AgentPool │
│ Secrets: WinRM-Secrets (secure) │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Secure WinRM Session Initiated │
│ ─ Protocol : HTTPS │
│ ─ Port : 5986 │
│ ─ Auth : Negotiate │
│ ─ SSL Cert : CA Enterprise Certificate │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Target Windows Server │
│ WebSphere Application Server │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ PowerShellOnTargetMachines@ │
│ Remote Session via WinRM │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Operation Execution Logic │
└──────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌────────────────┐ ┌──────────────────────┐
│ START_WAS │ │ STOP_WAS │ │ RESTART_WAS │
│ Start Service │ │ Stop Service │ │ Stop → Cleanup │
│ Validate Run │ │ Validate Stop │ │ Start → Validate │
└───────────────┘ └────────────────┘ └──────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Logs Printed to Azure DevOps Console │
│ ─ Pre/Post Service Status │
│ ─ Cleanup Verification │
│ ─ Immediate Failure on Error │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Pipeline Result │
│ SUCCESS → Safe Completion │
│ FAILURE → Clear Error Output │
└──────────────────────────────────────────────┘
WAS Service Restart Using WinRM over HTTPS (5986) on Azure DevOps
π Code Example Pipeline (Azure DevOps YAML)
Below is a working Azure DevOps YAML pipeline example to START / STOP / RESTART an IBM WebSphere (WAS) Windows service using WinRM over HTTPS (5986). Secrets are stored securely in a Variable Group.
# ============================================================
# PIPELINE: WinRM (HTTPS 5986) – START / STOP / RESTART WAS Service
# TARGET : 172.23.XX.XX
# SERVICE : IBMWAS85Service - AppNode1
# AGENT : AppOps-Win-AgentPool
# SECRETS : Variable Group "WinRM-Secrets" (expects remotePassword)
# ============================================================
# Manual run only (no CI trigger)
trigger: none
# Azure DevOps agent pool (Windows agent recommended for this task)
pool:
name: AppOps-Win-AgentPool
# Runtime choice: which action to perform
parameters:
- name: OPERATION
displayName: "Select RESTART-APPNODE1 operation"
type: string
default: RESTART_WAS
values:
- START_WAS
- STOP_WAS
- RESTART_WAS
# Variables + Secret Variable Group
variables:
# Secret variable group should contain:
# - remotePassword (secret)
- group: WinRM-Secrets
# Target server (WinRM endpoint)
- name: remoteHost
value: "172.23.XX.XX"
# WinRM HTTPS port
- name: httpsPort
value: "5986"
# WAS Windows Service name (must match service name on target)
- name: wasServiceName
value: "IBMWAS85Service - AppNode1"
# PSSession options (relaxed cert validation for internal IP use cases)
# NOTE: For PROD hardening, remove Skip* flags and use proper cert CN/SAN.
- name: pssOptions
value: "-SkipCNCheck -SkipCACheck -SkipRevocationCheck -IdleTimeout 7200000 -OperationTimeout 0 -OutputBufferingMode Block"
steps:
# ============================================================
# START WAS
# ============================================================
# Runs ONLY when OPERATION = START_WAS
- ${{ if eq(parameters.OPERATION, 'START_WAS') }}:
- task: PowerShellOnTargetMachines@3
displayName: "WAS START (Windows Service)"
inputs:
# Remote host + WinRM port
Machines: "$(remoteHost):$(httpsPort)"
# Local admin user on target (change to domain user if needed)
UserName: ".\\username"
# Password from secret variable group (WinRM-Secrets)
UserPassword: "$(remotePassword)"
# WinRM protocol
CommunicationProtocol: "Https"
# Default authentication (Negotiate)
AuthenticationMechanism: "Default"
# Session options passed to New-PSSessionOption on agent side
NewPsSessionOptionArguments: "$(pssOptions)"
# Fail fast on any error
ErrorActionPreference: "Stop"
FailOnScriptError: true
# Single target execution
RunPowershellInParallel: false
# Inline PowerShell executed on target
ScriptType: "Inline"
InlineScript: |
# Stop immediately if any command fails
$ErrorActionPreference = 'Stop'
# Service name from pipeline variable
$service = '$(wasServiceName)'
Write-Host "============================================================"
Write-Host "ACTION : START_WAS"
Write-Host "SERVICE : $service"
Write-Host "HOST : $env:COMPUTERNAME"
Write-Host "USER : $(whoami)"
Write-Host "============================================================"
Write-Host "Starting service: $service"
Start-Service -Name $service
Start-Sleep -Seconds 5
$status = (Get-Service -Name $service).Status
Write-Host "Current service status: $status"
if ($status -ne 'Running') {
throw "WAS service failed to start"
}
Write-Host "RESULT: WAS service is RUNNING"
# ============================================================
# STOP WAS
# ============================================================
# Runs ONLY when OPERATION = STOP_WAS
- ${{ if eq(parameters.OPERATION, 'STOP_WAS') }}:
- task: PowerShellOnTargetMachines@3
displayName: "WAS STOP (Service + Cleanup)"
inputs:
Machines: "$(remoteHost):$(httpsPort)"
UserName: ".\\username"
UserPassword: "$(remotePassword)"
CommunicationProtocol: "Https"
AuthenticationMechanism: "Default"
NewPsSessionOptionArguments: "$(pssOptions)"
ErrorActionPreference: "Stop"
RunPowershellInParallel: false
FailOnScriptError: true
ScriptType: "Inline"
InlineScript: |
$ErrorActionPreference = 'Stop'
$service = '$(wasServiceName)'
$profilePath = 'D:\IBM\WebSphere\AppServer\profiles\AppSrv02'
$wstempPath = Join-Path $profilePath 'wstemp'
$tempPath = Join-Path $profilePath 'temp'
Write-Host "============================================================"
Write-Host "ACTION : STOP_WAS"
Write-Host "SERVICE : $service"
Write-Host "PROFILE : $profilePath"
Write-Host "HOST : $env:COMPUTERNAME"
Write-Host "============================================================"
Write-Host "Stopping service: $service"
Stop-Service -Name $service -Force
Start-Sleep -Seconds 5
$status = (Get-Service -Name $service).Status
Write-Host "Current service status: $status"
if ($status -ne 'Stopped') {
throw "WAS service failed to stop"
}
# Timestamped rename = safe backup (NO deletion)
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
if (Test-Path $wstempPath) {
Write-Host "Renaming wstemp -> wstemp_$timestamp"
Rename-Item $wstempPath "wstemp_$timestamp" -Force
} else {
Write-Host "INFO: wstemp not found: $wstempPath"
}
if (Test-Path $tempPath) {
Write-Host "Renaming temp -> temp_$timestamp"
Rename-Item $tempPath "temp_$timestamp" -Force
} else {
Write-Host "INFO: temp not found: $tempPath"
}
# Cleanup scripts (standard WAS maintenance)
Write-Host "Running: clearClassCache.bat"
& "$profilePath\bin\clearClassCache.bat"
Write-Host "Running: osgiCfgInit.bat"
& "$profilePath\bin\osgiCfgInit.bat"
Write-Host "RESULT: STOP completed successfully (service stopped + cleanup done)"
# ============================================================
# RESTART WAS
# ============================================================
# Runs ONLY when OPERATION = RESTART_WAS
- ${{ if eq(parameters.OPERATION, 'RESTART_WAS') }}:
- task: PowerShellOnTargetMachines@3
displayName: "WAS RESTART (Stop + Cleanup + Start)"
inputs:
Machines: "$(remoteHost):$(httpsPort)"
UserName: ".\\username"
UserPassword: "$(remotePassword)"
CommunicationProtocol: "Https"
AuthenticationMechanism: "Default"
NewPsSessionOptionArguments: "$(pssOptions)"
ErrorActionPreference: "Stop"
RunPowershellInParallel: false
FailOnScriptError: true
ScriptType: "Inline"
InlineScript: |
$ErrorActionPreference = 'Stop'
$service = '$(wasServiceName)'
$profilePath = 'D:\IBM\WebSphere\AppServer\profiles\AppSrv02'
$wstempPath = Join-Path $profilePath 'wstemp'
$tempPath = Join-Path $profilePath 'temp'
Write-Host "============================================================"
Write-Host "ACTION : RESTART_WAS"
Write-Host "SERVICE : $service"
Write-Host "PROFILE : $profilePath"
Write-Host "HOST : $env:COMPUTERNAME"
Write-Host "============================================================"
# -------- 1) STOP --------
Write-Host "Stopping service: $service"
Stop-Service -Name $service -Force
Start-Sleep -Seconds 5
$status = (Get-Service -Name $service).Status
Write-Host "Status after STOP: $status"
if ($status -ne 'Stopped') {
throw "WAS service failed to stop"
}
# -------- 2) CLEANUP (NO delete, only rename) --------
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
if (Test-Path $wstempPath) {
Write-Host "Renaming wstemp -> wstemp_$timestamp"
Rename-Item $wstempPath "wstemp_$timestamp" -Force
} else {
Write-Host "INFO: wstemp not found: $wstempPath"
}
if (Test-Path $tempPath) {
Write-Host "Renaming temp -> temp_$timestamp"
Rename-Item $tempPath "temp_$timestamp" -Force
} else {
Write-Host "INFO: temp not found: $tempPath"
}
Write-Host "Running: clearClassCache.bat"
& "$profilePath\bin\clearClassCache.bat"
Write-Host "Running: osgiCfgInit.bat"
& "$profilePath\bin\osgiCfgInit.bat"
# -------- 3) START --------
Write-Host "Starting service: $service"
Start-Service -Name $service
Start-Sleep -Seconds 8
$status = (Get-Service -Name $service).Status
Write-Host "Status after START: $status"
if ($status -ne 'Running') {
throw "WAS service failed to restart"
}
Write-Host "RESULT: WAS restarted successfully"
✅ Notes
- Manual run only: trigger: none
- Secure channel: WinRM over HTTPS 5986
- Safe cleanup: No delete, only rename (timestamped)
- Audit logs: printed directly to Azure DevOps console