Tasks/BuiltIn/Service/Set-ServiceStatus.ps1

<#
.SYNOPSIS
    Start, stop, restart, pause, or resume a Windows service
 
.DESCRIPTION
    Performs service control operations with validation and status monitoring. Waits for the service to reach the target state before completing.
 
.PARAMETER ServiceName
    Name of the service to modify
 
.PARAMETER Action
    Action to perform on the service. Valid values: Start, Stop, Restart, Pause, Resume
 
.PARAMETER TimeoutSeconds
    Timeout in seconds to wait for the action to complete. Default: 30
 
.NOTES
    TaskName: Service.ChangeStatus
    Version: 1.0.0
    Author: Toolbox
    Tags: Service, Windows, Management, Administration
    RequiresElevation: True
    SupportedOS: Windows
    PSEdition: Desktop, Core
    MinPSVersion: 5.1
    Timeout: 60
 
.EXAMPLE
    Invoke-Task -TaskName 'Service.ChangeStatus' -Computers 'localhost' -TaskParameters @{ ServiceName = 'Spooler'; Action = 'Restart' }
 
.EXAMPLE
    Invoke-Task -TaskName 'Service.ChangeStatus' -Computers 'SERVER01' -TaskParameters @{ ServiceName = 'W3SVC'; Action = 'Stop'; TimeoutSeconds = 60 }
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [string]$ServiceName,

    [Parameter(Mandatory)]
    [ValidateSet('Start', 'Stop', 'Restart', 'Pause', 'Resume')]
    [string]$Action,

    [Parameter()]
    [int]$TimeoutSeconds = 30
)

try {
    Write-Verbose "Performing action '$Action' on service '$ServiceName'..."
    
    # Get the service
    $service = Get-Service -Name $ServiceName -ErrorAction Stop
    $initialStatus = $service.Status.ToString()
    
    Write-Verbose "Current service status: $initialStatus"
    
    # Determine target status based on action
    $targetStatus = switch ($Action) {
        'Start'   { 'Running' }
        'Stop'    { 'Stopped' }
        'Restart' { 'Running' }
        'Pause'   { 'Paused' }
        'Resume'  { 'Running' }
    }
    
    # Validate service capabilities
    switch ($Action) {
        'Stop' {
            if (-not $service.CanStop) {
                throw "Service '$ServiceName' cannot be stopped"
            }
        }
        { $_ -in 'Pause', 'Resume' } {
            if (-not $service.CanPauseAndContinue) {
                throw "Service '$ServiceName' does not support pause/resume"
            }
        }
    }
    
    # Perform the action
    $startTime = Get-Date
    $actionPerformed = $false
    
    switch ($Action) {
        'Start' {
            if ($service.Status -ne 'Running') {
                Start-Service -Name $ServiceName -ErrorAction Stop
                $actionPerformed = $true
            }
        }
        'Stop' {
            if ($service.Status -ne 'Stopped') {
                Stop-Service -Name $ServiceName -Force -ErrorAction Stop
                $actionPerformed = $true
            }
        }
        'Restart' {
            Restart-Service -Name $ServiceName -Force -ErrorAction Stop
            $actionPerformed = $true
        }
        'Pause' {
            if ($service.Status -eq 'Running') {
                Suspend-Service -Name $ServiceName -ErrorAction Stop
                $actionPerformed = $true
            }
        }
        'Resume' {
            if ($service.Status -eq 'Paused') {
                Resume-Service -Name $ServiceName -ErrorAction Stop
                $actionPerformed = $true
            }
        }
    }
    
    # Wait for the service to reach target status
    if ($actionPerformed) {
        Write-Verbose "Waiting for service to reach status '$targetStatus' (timeout: $TimeoutSeconds seconds)..."
        
        $deadline = (Get-Date).AddSeconds($TimeoutSeconds)
        $statusReached = $false
        
        while ((Get-Date) -lt $deadline) {
            $service.Refresh()
            
            if ($service.Status.ToString() -eq $targetStatus) {
                $statusReached = $true
                break
            }
            
            Start-Sleep -Milliseconds 500
        }
        
        if (-not $statusReached) {
            throw "Timeout waiting for service to reach status '$targetStatus'. Current status: $($service.Status)"
        }
    }
    
    $duration = ((Get-Date) - $startTime).TotalSeconds
    $finalStatus = $service.Status.ToString()
    
    Write-Verbose "Action completed in $([math]::Round($duration, 2)) seconds. Final status: $finalStatus"
    
    # Return results
    [PSCustomObject]@{
        Success        = $true
        ServiceName    = $ServiceName
        Action         = $Action
        InitialStatus  = $initialStatus
        FinalStatus    = $finalStatus
        ActionPerformed = $actionPerformed
        DurationSeconds = [math]::Round($duration, 2)
    }
}
catch {
    Write-Error "Failed to perform action '$Action' on service '$ServiceName': $_"
    throw
}