Created
October 16, 2024 16:11
-
-
Save 9000cats/b1ade1c68293184a9b9179060231de12 to your computer and use it in GitHub Desktop.
Stops all Veeam services on Windows in reverse dependency order while displaying real-time status updates.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
This PowerShell script retrieves all active Veeam services along with their dependencies and handles their status updates. | |
It then processes each service in reverse dependency order to stop them gracefully, ensuring dependencies are handled correctly. | |
The script also provides real-time status updates for all services. | |
.DESCRIPTION | |
The script includes the following functions: | |
- `Get-VeeamServicesWithDependencies`: Retrieves all Veeam services that are not stopped or disabled, along with their dependencies. | |
- `Get-ServiceDependencies`: Returns the active dependent services for a given service. | |
- `Update-StatusDisplay`: Displays the current status of the services with real-time updates. | |
- `Stop-ServiceAndDependencies`: Stops a service and its dependencies in a safe order, displaying the process status. | |
.NOTES | |
Version: 1.0 | |
Authors: Warren Held, ChatGPT o1-preview, Claude 3.5 Opus | |
Date: 10/16/2024 | |
#> | |
# Function to get all Veeam services and their dependencies | |
function Get-VeeamServicesWithDependencies { | |
$veeamServices = Get-WmiObject Win32_Service | Where-Object { | |
$_.Name -like "*Veeam*" -and $_.State -ne "Stopped" -and $_.StartMode -ne "Disabled" | |
} | |
$result = @() | |
foreach ($service in $veeamServices) { | |
$dependencies = Get-ServiceDependencies -ServiceName $service.Name | |
$result += [PSCustomObject]@{ | |
Name = $service.Name | |
DisplayName = $service.DisplayName | |
Dependencies = $dependencies | |
Status = $service.State | |
} | |
} | |
return $result | |
} | |
# Function to get service dependencies | |
function Get-ServiceDependencies { | |
param ([string]$ServiceName) | |
$service = Get-Service -Name $ServiceName | |
return $service.DependentServices | Where-Object { $_.Status -ne "Stopped" -and $_.StartType -ne "Disabled" } | Select-Object -ExpandProperty Name | |
} | |
# Function to update the status display | |
function Update-StatusDisplay { | |
param ( | |
[array]$Services, | |
[string]$CurrentlyStoppingService = "" | |
) | |
Clear-Host | |
Write-Host "Veeam Services Status:" | |
Write-Host "----------------------" | |
# Calculate the maximum length of the DisplayName, with an upper limit | |
$maxNameLength = ($Services | ForEach-Object { $_.DisplayName.Length } | Measure-Object -Maximum).Maximum | |
$maxNameLength = [Math]::Min($maxNameLength, 60) # Set an upper limit to keep the output tidy | |
# Create a format string for consistent alignment | |
$formatString = "{0,-$($maxNameLength + 2)}{1}" | |
foreach ($service in $Services) { | |
$currentService = Get-Service -Name $service.Name -ErrorAction SilentlyContinue | |
if ($currentService) { | |
# Determine the status | |
$status = if ($service.Name -eq $CurrentlyStoppingService) { "Stopping" } else { $currentService.Status.ToString() } | |
# Choose the color based on the status | |
$statusColor = switch ($status) { | |
"Running" { "Yellow" } | |
"Stopped" { "Green" } | |
"Stopping" { "Cyan" } | |
default { "White" } | |
} | |
# Truncate or pad the DisplayName to fit the column width | |
$displayName = $service.DisplayName | |
if ($displayName.Length -gt $maxNameLength) { | |
$displayName = $displayName.Substring(0, $maxNameLength - 3) + "..." | |
} else { | |
$displayName = $displayName.PadRight($maxNameLength) | |
} | |
# Prepare the status text | |
$paddedStatus = "[{0}]" -f $status.PadRight(8).Substring(0, 8) | |
# Write the output with proper alignment | |
Write-Host ($formatString -f $displayName, $paddedStatus) -ForegroundColor $statusColor | |
} | |
} | |
} | |
# Function to stop a service and its dependencies | |
function Stop-ServiceAndDependencies { | |
param ( | |
[string]$ServiceName, | |
[array]$AllServices | |
) | |
$service = $AllServices | Where-Object { $_.Name -eq $ServiceName } | |
if ($service -and (Get-Service -Name $ServiceName).Status -ne "Stopped") { | |
foreach ($dep in $service.Dependencies) { | |
Stop-ServiceAndDependencies -ServiceName $dep -AllServices $AllServices | |
} | |
try { | |
Update-StatusDisplay -Services $AllServices -CurrentlyStoppingService $ServiceName | |
Start-Sleep -Seconds 1 # Give time to see the "Stopping" status | |
Stop-Service -Name $ServiceName -Force -ErrorAction Stop | |
$stopTime = [DateTime]::Now.AddSeconds(30) | |
while ((Get-Service -Name $ServiceName).Status -ne 'Stopped' -and [DateTime]::Now -lt $stopTime) { | |
Start-Sleep -Milliseconds 500 | |
Update-StatusDisplay -Services $AllServices -CurrentlyStoppingService $ServiceName | |
} | |
if ((Get-Service -Name $ServiceName).Status -ne 'Stopped') { | |
Write-Host "Service stop operation timed out after 30 seconds: $($service.DisplayName)" -ForegroundColor Red | |
} | |
} catch { | |
Write-Host "Failed to stop service: $($service.DisplayName). Error: $_" -ForegroundColor Red | |
} | |
Update-StatusDisplay -Services $AllServices | |
Start-Sleep -Seconds 1 | |
} | |
} | |
# Main script (excerpt) | |
$veeamServices = Get-VeeamServicesWithDependencies | |
if ($veeamServices.Count -eq 0) { | |
Write-Host "No running Veeam services found that are not disabled." -ForegroundColor Yellow | |
exit | |
} | |
# Initial status display | |
Update-StatusDisplay -Services $veeamServices | |
# Stop services in reverse dependency order | |
$stopOrder = $veeamServices | Sort-Object { $_.Dependencies.Count } -Descending | |
foreach ($service in $stopOrder) { | |
Stop-ServiceAndDependencies -ServiceName $service.Name -AllServices $veeamServices | |
} | |
# Final status update | |
Update-StatusDisplay -Services $veeamServices | |
Write-Host "All eligible Veeam services have been processed." -ForegroundColor Green |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment