Menu

Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

3 Apr 2026

πŸ” WAS Service Restart Using WinRM over HTTPS (5986) on Azure DevOps

WAS Service Restart Using WinRM over HTTPS (5986) on Azure DevOps

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

πŸ”· 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

⬆️ Back to Top


πŸ”„ 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               │
└──────────────────────────────────────────────┘

⬆️ Back to Top


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

πŸ”Preparing WinRM on Windows Server over HTTPS for Automation (Port-5986)

WinRM over HTTPS (5986)

πŸš€ Introduction

In many enterprises, automation is no longer optional—it’s a necessity. Tools like Azure DevOps, Jenkins, and Ansible need a secure way to connect to Windows servers to:

  • ▶️ Start/stop services
  • πŸ“¦ Deploy applications
  • ⚡ Run PowerShell scripts
  • πŸ› ️ Perform maintenance tasks

This blog explains how to securely configure WinRM over HTTPS (port 5986) using an enterprise SSL certificate, and why this approach is production-ready.


πŸ“˜ What is WinRM?

WinRM (Windows Remote Management) is Microsoft’s standard way to remotely manage Windows servers.

It allows you to:

  • πŸ–₯️ Run PowerShell commands on remote servers
  • 🚫 Execute scripts without logging in via RDP
  • πŸ” Automate tasks securely

By default, WinRM works over HTTP (port 5985), which is not secure for production. That’s where WinRM over HTTPS (port 5986) comes in.


πŸ”„ High-Level Flow (How It Works)

Azure DevOps Console
        |
        |  
        |  
        v		
Azure DevOps Agent
        |
        |  πŸ”’ WinRM over HTTPS (5986)
        |  πŸ” Encrypted using SSL Certificate
        v
Target Windows Server

🏒 Real-World Use Case

✅ Scenario: Production Application Automation

You have:

  • 🧩 A Windows server hosting applications (WebSphere, services, schedulers)
  • πŸš€ An Azure DevOps pipeline
  • ⛔ No permission or policy to use RDP in production

You want to:

  • πŸ”„ Restart services
  • 🧹 Clear cache folders
  • πŸ“€ Deploy builds
  • πŸ€– Run scripts automatically

# ============================================================
# πŸ” WinRM over HTTPS (5986)
# πŸ“œ Enterprise SSL Certificate
# πŸ€– Secure credential-based automation
# ✅ Production-ready for Azure DevOps
# ============================================================

# Architecture:
# Azure DevOps Agent / Admin Host
#   → πŸ”’ WinRM over HTTPS (5986)
#   → πŸ–₯️ Target Windows Server (172.23.XX.XX)

# ============================================================
# πŸ”‘ Install SSL Certificate on Target Windows Server and execute below steps on POWERShell
# ============================================================

# Step 1: ✅ Verify WinRM Service is installed and running
Get-Service WinRM

# Step 2: πŸ” Check existing WinRM listeners (HTTP / HTTPS)
winrm enumerate winrm/config/Listener

# Step 3: πŸ“œ Verify SSL certificate availability in Local Machine store,
#     ✅ Note the thumbprint for certificate
Get-ChildItem Cert:\LocalMachine\My | Select Subject, Thumbprint, NotAfter

# Step 4: 🧾 Validate certificate usage (must support Server Authentication),
#     πŸ” Replace with your certificate thumbprint
$cert = Get-Item "Cert:\LocalMachine\My\2FF032E91A3CF086C251B12D3AFCB5D71"
$cert.EnhancedKeyUsageList | Select FriendlyName

# Step 5: πŸ” Create WinRM HTTPS listener using certificate thumbprint
$Thumb = "2FF032E91A3CF086C251B12D3AFCB5D71"
New-Item -Path WSMan:\LocalHost\Listener `
-Transport HTTPS `
-Address * `
-CertificateThumbprint $Thumb

# Step 6: ▶️ Enable PowerShell Remoting and ensure WinRM auto-starts
Enable-PSRemoting -Force
Set-Service WinRM -StartupType Automatic
Start-Service WinRM

# Step 7: πŸ”‘ Allow local admin credentials over WinRM
New-ItemProperty `
-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" `
-Name LocalAccountTokenFilterPolicy `
-Value 1 `
-PropertyType DWord `
-Force

# Step 8: ✅ Final validation of WinRM listeners check for listening *5986 Port
winrm enumerate winrm/config/Listener

# Step 9: 🌐 Firewall / NSG validation
# Ensure port 5986 is allowed

# Step 10: πŸ§ͺ Client-side connectivity test (use valid username/password)
Invoke-Command `
-ComputerName 172.23.XX.XX `
-UseSSL `
-Port 5986 `
-Credential (Get-Credential) `
-Authentication Negotiate `
-SessionOption (New-PSSessionOption -SkipCNCheck -SkipCACheck -SkipRevocationCheck) `
-ScriptBlock { hostname; whoami }

# ============================================================
# ✅ End of WinRM HTTPS Configuration
# ============================================================