# example: sets and / or removes 3CX holidays in various departments at once
# authorization data
$tcxurl = "mypbx.mydomain.de" # needs port if not 443
$jsonauthbody = (@{
Username="988" # 3CX user, maybe email address
Password="Super_Secret0815" # 3CX user password
SecurityCode=""
} | ConvertTo-Json)
# array of department numbers which will be affected, number is from 3CX admin / call handling / extension
$departments = @( "GRP2", "GRP0000", "GRP0001", "GRP0003", "GRP0002" )
# array of strings with holiday names which will be deleted (asterisk for match all in front and/or end is possible), if empty none will deleted
$holidays_to_remove = @( "easter*", "laborday", "christmas*", "newyear*", "test*", "*2025", "*year*" )
# array of hashes with holiday params which will be added, if empty none will added
# HINT: do not use asterisk in department name in any way
$holidays_to_add = @( # name of holiday audio file name is recurring is the whole day start date start time if not end date end time if not
# may empty every year time will ignored yyyy-mm-dd whole day hh:mm yyyy-mm-dd whole day hh:mm
@{Name="easter2025"; HolidayPrompt="easter.wav"; IsRecurrent=$false; IsWholeDay=$true; Startdate="2025-04-18"; Starttime="00:00"; Enddate="2025-04-21"; Endtime="00:00"},
@{Name="easter2026"; HolidayPrompt="easter.wav"; IsRecurrent=$false; IsWholeDay=$true; Startdate="2025-04-03"; Starttime="00:00"; Enddate="2025-04-06"; Endtime="00:00"},
@{Name="laborday"; HolidayPrompt="laborday.wav"; IsRecurrent=$true; IsWholeDay=$true; Startdate="2025-05-01"; Starttime="00:00"; Enddate="2025-05-01"; Endtime="00:00"},
@{Name="christmas24"; HolidayPrompt="christmas.wav"; IsRecurrent=$true; IsWholeDay=$false; Startdate="2025-12-24"; Starttime="13:00"; Enddate="2025-12-24"; Endtime="00:00"},
@{Name="christmas2526"; HolidayPrompt="christmas.wav"; IsRecurrent=$true; IsWholeDay=$true; Startdate="2025-12-25"; Starttime="00:00"; Enddate="2025-12-26"; Endtime="00:00"},
@{Name="newyeareve"; HolidayPrompt="newyeareve.wav"; IsRecurrent=$true; IsWholeDay=$false; Startdate="2025-12-31"; Starttime="13:00"; Enddate="2025-12-31"; Endtime="00:00"},
@{Name="newyear"; HolidayPrompt="newyear.wav"; IsRecurrent=$true; IsWholeDay=$true; Startdate="2025-01-01"; Starttime="00:00"; Enddate="2025-01-01"; Endtime="00:00"},
@{Name="prayer2025"; HolidayPrompt="prayer.wav"; IsRecurrent=$false; IsWholeDay=$true; Startdate="2025-11-19"; Starttime="00:00"; Enddate="2025-11-19"; Endtime="00:00"},
@{Name="oldyearparty"; HolidayPrompt="wehaveparty.wav"; IsRecurrent=$false; IsWholeDay=$true; Startdate="2025-01-04"; Starttime="00:00"; Enddate="2025-01-04"; Endtime="00:00"},
@{Name="test01"; HolidayPrompt=""; IsRecurrent=$true; IsWholeDay=$false; Startdate="2025-03-01"; Starttime="14:01"; Enddate="2025-03-01"; Endtime="16:02"}
)
# === work starts here with authorization
$LoginResponse = Invoke-RestMethod -Uri "https://$tcxurl/webclient/api/Login/GetAccessToken" -Body $jsonauthbody -Method POST -ContentType "application/json"
$headers = @{Authorization = "Bearer $($LoginResponse.Token.access_token)"}
Function ReformatHolidaysToAdd
{
[CmdletBinding()]
param
(
$holidays_to_add
)
$holiaddcont=[System.Collections.ArrayList]@()
Foreach ($holiadd in $holidays_to_add)
{
If ($holiadd.IsWholeDay -eq $true)
{
$tosd = "P0D"
$toed = "P1D"
} Else
{
If ([int]($holiadd.Starttime.Split(':')[0]) -eq 0)
{
If ([int]($holiadd.Starttime.Split(':')[1]) -eq 0)
{
$tosd = "P0D"
} Else
{
$tosd = "PT0H$([int]($holiadd.Starttime.Split(':')[1]))M"
}
} Else
{
If ([int]($holiadd.Starttime.Split(':')[1]) -eq 0)
{
$tosd = "PT$([int]($holiadd.Starttime.Split(':')[0]))H"
} Else
{
$tosd = "PT$([int]($holiadd.Starttime.Split(':')[0]))H$([int]($holiadd.Starttime.Split(':')[1]))M"
}
}
If ([int]($holiadd.Endtime.Split(':')[0]) -eq 0)
{
If ([int]($holiadd.Endtime.Split(':')[1]) -eq 0)
{
$toed = "P1D"
} Else
{
$toed = "PT0H$([int]($holiadd.Endtime.Split(':')[1]))M"
}
} Else
{
If ([int]($holiadd.Endtime.Split(':')[1]) -eq 0)
{
$toed = "PT$([int]($holiadd.Endtime.Split(':')[0]))H"
} Else
{
$toed = "PT$([int]($holiadd.Endtime.Split(':')[0]))H$([int]($holiadd.Endtime.Split(':')[1]))M"
}
}
}
If ($holiadd.IsRecurrent -eq $true)
{
$years = 0
$yeare = 0
} Else
{
$years = [int]($holiadd.Startdate.Split('-')[0])
$yeare = [int]($holiadd.Enddate.Split('-')[0])
}
$acthash=@{Name = $holiadd.Name; IsRecurrent = $holiadd.IsRecurrent; HolidayPrompt = $holiadd.HolidayPrompt;
Day=[int]($holiadd.Startdate.Split('-')[2]); Month=[int]($holiadd.Startdate.Split('-')[1]); Year=$years; TimeOfStartDate=$tosd;
DayEnd=[int]($holiadd.Enddate.Split('-')[2]); MonthEnd=[int]($holiadd.Enddate.Split('-')[1]); YearEnd=$yeare; TimeOfEndDate=$toed }
$holiaddcont.Add($acthash) | Out-Null
}
$holiaddcont
} # end Function ReformatHolidaysToAdd
Function ReformatHolidaysToRemove
{
[CmdletBinding()]
param
(
$holidays_to_remove,
$holidays_original
)
$holirestcont=[System.Collections.ArrayList]@()
Foreach ($holiorig in $holidays_original)
{
$found = $false
Foreach ($holirem in $holidays_to_remove.Replace("*",".*"))
{
If ($holiorig.Name -match "^$($holirem)`$")
{
$found = $true
Break
}
}
If ($found -eq $false)
{
$holirestcont.Add($holiorig) | Out-Null
}
}
$holirestcont.ToArray()
} # end Function ReformatHolidaysToRemove
# main ...
$groups=(Invoke-RestMethod -uri "https://$tcxurl/xapi/v1/Groups?`$filter=not startsWith(Name, '___FAVORITES___')&`$select=Id,Number" -headers $headers -Method GET -ContentType "application/json").Value
Foreach ($group in $groups)
{
If ($departments -contains $group.Number)
{
$holis=(Invoke-RestMethod -uri "https://$tcxurl/xapi/v1/Groups($($group.Id))?`$select=OfficeHolidays&`$expand=OfficeHolidays" -headers $headers -Method GET -ContentType "application/json")
$holichangedcontent = (ReformatHolidaysToRemove -holidays_to_remove $holidays_to_remove -holidays_original $holis.OfficeHolidays)
$holichangedcontent = $holichangedcontent+(ReformatHolidaysToAdd -holidays_to_add $holidays_to_add)
If ($holichangedcontent.Count -eq 0 )
{
$holichangedcontent=@()
}
$holiaddcomplete = @{AllowCallService=$true; OverrideHolidays=$true; OfficeHolidays=$holichangedcontent } | ConvertTo-Json
Invoke-RestMethod -uri "https://$tcxurl/xapi/v1/Groups($($group.Id))" -headers $headers -Method PATCH -body $holiaddcomplete -ContentType "application/json" | Out-Null
}
}
exit