Best wishes everyone.
I'm trying to create a script that uses an API to put the client in downtime before installing a WSUS update. Does anyone have experience with this? Or any idea if this is possible?
I have something like this but its saying that server url not correct or something like that
# ========================
# CONFIGURATIE
# ========================
$apiUser = "xxx" # Icinga 2 API gebruiker
$apiPass = "xxxxx" # Wachtwoord van de API user
$icingaServer = "xxxxx" # Icinga 2 master host/IP
$durationSeconds = 3600 # 1 uur downtime
$comment = "WSUS Maintenance via RES" # Downtime comment
# ========================
# Credential object
# ========================
$SecurePassword = ConvertTo-SecureString $apiPass -AsPlainText -Force
$Credential = New-Object PSCredential($apiUser, $SecurePassword)
# ========================
# SSL errors negeren (alleen indien zelf-ondertekend cert)
# ========================
if (-not ([System.Net.ServicePointManager]::ServerCertificateValidationCallback)) {
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
}
# ========================
# Bereken UNIX timestamps
# ========================
$start = [int][double]::Parse((Get-Date -UFormat %s))
$end = $start + $durationSeconds
# ========================
# Hostname ophalen
# ========================
$hostname = "$env:COMPUTERNAME.amg.local"
# ========================
# API endpoints
# ========================
$baseUri = "https://$icingaServer:5665/v1"
$downtimeUri = "$baseUri/actions/schedule-downtime"
$servicesUri = "$baseUri/objects/services?filter=host.name==`"$hostname`""
# ========================
# Functie: Downtime plannen (met logging)
# ========================
function Schedule-Downtime {
param (
[string]$Type,
[string]$Filter,
[string]$Name
)
# === Instellingen ===
$logFile = "C:\Logs\icinga_downtime.log"
if (-not (Test-Path (Split-Path $logFile))) {
New-Item -ItemType Directory -Path (Split-Path $logFile) -Force | Out-Null
}
# Helperfunctie voor loggen
function Write-Log {
param (
[string]$Message,
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$entry = "[$timestamp] [$Level] $Message"
Write-Output $entry
Add-Content -Path $logFile -Value $entry
}
# === Request body ===
$body = @{
type = $Type
filter = $Filter
author = "RES"
comment = $comment
start_time = $start
end_time = $end
fixed = $true
duration = $durationSeconds
} | ConvertTo-Json -Compress
try {
$response = Invoke-RestMethod -Uri $downtimeUri `
-Method POST `
-Credential $Credential `
-Body $body `
-ContentType "application/json" `
-SkipCertificateCheck
if ($response.results[0].status -eq "Successfully scheduled downtime.") {
Write-Log "✅ Downtime gepland voor ${Type}: ${Name}" "SUCCESS"
}
else {
Write-Log "⚠️ Icinga gaf geen succesvolle response voor ${Type} ${Name}:" "WARNING"
Write-Log ($response | ConvertTo-Json -Depth 5) "DETAIL"
}
}
catch {
Write-Log "❌ Kan downtime niet plannen voor ${Type} ${Name}: $($_.Exception.Message)" "ERROR"
}
}
Hi,
Could you print out the full URL being sent to the server, and the exact error message being returned? Looking at the code, I can see no obvious issue other than “POST” being in uppercase instead of being “Post” as documented (but it is highly improbable that this is the issue).
Have you tested the API connectivity from the script with a simple GET statement?
Have you used `curl` to test the same API URI from the command line on the target Linux server?
In other words, is it the problem an API connectivity issue, or this particular schedule-downtime action?
Best regards,
Jean
Thank you Jean for the reply.
Wwhen i am running script on Windows client i am getting this error: an downtime niet plannen voor Host SV1312.amg.local: Cannot bind parameter ‘Uri’. Cannot convert value “https:///v1/actions/schedule-downtime” to type “System
.Uri”. Error: “Invalid URI: The hostname could not be parsed.”
My question is how can i find api URL? Because at $icingaServer i am using IP of icinga master server.
btw this is the scrip what giving the error:
========================
CONFIGURATIE
========================
$apiUser = “xxxx” # Icinga 2 API gebruiker
$apiPass = “xxxx” # Wachtwoord van de API user
$icingaServer = “xxxxx” # Icinga 2 master host/IP
$durationSeconds = 3600 # 1 uur downtime
$comment = “WSUS Maintenance via RES” # Downtime comment
========================
Credential object
========================
$SecurePassword = ConvertTo-SecureString $apiPass -AsPlainText -Force
$Credential = New-Object PSCredential($apiUser, $SecurePassword)
========================
SSL errors negeren (voor zelfondertekende certificaten)
========================
if (-not ([System.Net.ServicePointManager]::ServerCertificateValidationCallback)) {
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
}
========================
Bereken UNIX timestamps
========================
$start = [int][double]::Parse((Get-Date -UFormat %s))
$end = $start + $durationSeconds
========================
Hostname ophalen
========================
$hostname = “$env:COMPUTERNAME.amg.local”
========================
API endpoints
========================
$baseUri = “https://:5665$icingaServer/v1”
$downtimeUri = “$baseUri/actions/schedule-downtime”
$servicesUri = “$baseUri/objects/services?filter=host.name=="$hostname”"
========================
Functie: Logging helper
========================
function Write-Log {
param (
[string]$Message,
[string]$Level = “INFO”
)
$logFile = “C:\Logs\icinga_downtime.log”
if (-not (Test-Path (Split-Path $logFile))) {
New-Item -ItemType Directory -Path (Split-Path $logFile) -Force | Out-Null
}
$timestamp = Get-Date -Format “yyyy-MM-dd HH:mm:ss”
$entry = “[$timestamp] [$Level] $Message”
Write-Output $entry
Add-Content -Path $logFile -Value “$entry`n”
}
========================
Functie: Downtime plannen
========================
function Schedule-Downtime {
param (
[string]$Type,
[string]$Filter,
[string]$Name
)
$body = @{
type = $Type
filter = $Filter
author = "RES"
comment = $global:comment
start_time = $global:start
end_time = $global:end
fixed = $true
duration = $global:durationSeconds
} | ConvertTo-Json -Compress
try {
$response = Invoke-RestMethod -Uri $global:downtimeUri `
-Method POST `
-Credential $global:Credential `
-Body $body `
-ContentType "application/json" `
-SkipCertificateCheck
if ($response.results[0].status -eq "Successfully scheduled downtime.") {
Write-Log "✅ Downtime gepland voor ${Type}: ${Name}" "SUCCESS"
}
else {
Write-Log "⚠️ Icinga gaf geen succesvolle response voor ${Type} ${Name}:" "WARNING"
Write-Log ($response | ConvertTo-Json -Depth 5) "DETAIL"
}
}
catch {
Write-Log "❌ Kan downtime niet plannen voor ${Type} ${Name}: $($_.Exception.Message)" "ERROR"
}
}
========================
Downtime plannen voor host
========================
Write-Log “
Start downtime-procedure voor host ${hostname}” “INFO”
$hostFilter = “host.name=="$hostname”"
Schedule-Downtime -Type “Host” -Filter $hostFilter -Name $hostname
========================
Downtime plannen voor alle services op de host
========================
try {
$servicesResponse = Invoke-RestMethod -Uri $servicesUri -Credential $Credential -SkipCertificateCheck
if ($servicesResponse.results.Count -gt 0) {
foreach ($svc in $servicesResponse.results) {
$serviceName = $svc.name
$serviceFilter = "service.name==`"$serviceName`""
Schedule-Downtime -Type "Service" -Filter $serviceFilter -Name $serviceName
}
}
else {
Write-Log "⚠️ Geen services gevonden voor host ${hostname}" "WARNING"
}
}
catch {
Write-Log “
Fout bij ophalen van services voor ${hostname}: $($_.Exception.Message)” “ERROR”
}
Write-Log “
Downtime-procedure afgerond voor host ${hostname}” “INFO”
The line above has port and server swapped - should be:
$baseUri = “https://:5665$icingaServer/v1”
NB: This was not the case in the first version of the script
Now i am getting:
[2026-01-06 13:00:01] [INFO]
Start downtime-procedure voor host xxxxxx
[2026-01-06 13:00:01] [ERROR]
Kan downtime niet plannen voor Host xxxxx: Cannot bind parameter ‘Uri’. Cannot convert value "https://:5665(IP of master)/v1/actions/schedule-downtime
" to type “System.Uri”. Error: “Invalid URI: The hostname could not be parsed.”
[2026-01-06 13:00:01] [ERROR]
Fout bij ophalen van services voor xxxxx: Cannot bind parameter ‘Uri’. Cannot convert value “https://:5665(IP of mastere)/v1/objects/services?filter=ho
st.name==“xxxxxx”” to type “System.Uri”. Error: “Invalid URI: The hostname could not be parsed.”
[2026-01-06 13:00:01] [INFO]
Downtime-procedure afgerond voor host xxxx.
Atlease its can resolve the ip adres and showing in output.
The exact value of the $global:downtimeUri variable needs to be shared here, because obviously PowerShell cannot convert that value into a valid System.Uri variable.
The value provided in the log is useful but has been manipulated:
Of course the real IP addresses can be replaced by 1.2.3.4 and the real host names can be replaced by icinga-master.fqdn (for instance), but please keep all other characters untouched, including the quotes and double-quotes.
Debug messages with all parameter names and values passed to Invoke-RestMethod would also help troubleshooting why the parsing/conversion of those variables does not work.
Hello Jean,
Can you help me with the command to find it out the issue?
Sure, I’ll try. Please insert into the log file the exact value of the $global:downtimeUri variable, and the exact value of the $response variable, i.e., the output of the Invoke-RestMethod command.
Then share the log file here, please. As I said, for security reasons, the real IP addresses can be replaced by 1.2.3.4 and the real host names can be replaced by icinga-master.fqdn (for instance), but please keep all other characters untouched, including the quotes and double-quotes.
Debug messages with other parameter names and values passed to Invoke-RestMethod would also help troubleshooting why the parsing/conversion of those variables does not work.
Hello Jean,
I have fixen, here is the new scrip
=== INSTELLINGEN ===
$apiUser = ““xxxx”” # Icinga 2 API gebruiker
$apiPass = “xxxxx” # Wachtwoord API user
=== HOSTNAME OPHALEN BIJ AFTRAP ===
$hostname = $env:COMPUTERNAME
=== START & EINDE DOWNTIME (NU + 1 UUR) ===
$startLocal = Get-Date
$endLocal = $startLocal.AddHours(1)
=== CONVERSIE NAAR UNIX TIME ===
$startUnix = ([DateTimeOffset]$startLocal).ToUnixTimeSeconds()
$endUnix = ([DateTimeOffset]$endLocal).ToUnixTimeSeconds()
=== API URI (HOSTNAME DYNAMISCH) ===
$uri = “https://xxxxxxx:5665/v1/actions/schedule-downtime?type=Host&host=$hostname”
=== AUTHENTICATIE ===
$securePass = ConvertTo-SecureString $apiPass -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($apiUser, $securePass)
=== BODY ===
$body = @{
author = “Admin”
comment = “Automatische downtime bij scriptstart”
notify = $true
pretty = $true
start_time = $startUnix
end_time = $endUnix
fixed = $true
all_services = 1
} | ConvertTo-Json
=== API CALL ===
Invoke-RestMethod -Uri $uri
-Method Post -Headers @{ "Accept" = "application/json" }
-Body $body -ContentType "application/json"
-Credential $Credential
Glad to hear this, thank you for concluding the thread!