we recently had the case where some of our tenants had bandwith issues caused by still running backup jobs pointing to Cloudconnect/Objectstorage repositories during work hours. Veeam Agent for Windows just offers a general bandwith throttling option but no possibility to apply only during work hours. We realized the time based throttling policy through a registry key indicated by veeam support which is set according to predefined time windows through windows task scheduler. In case anyone finds it useful below the script and the XML which can be imported as scheduled Task.
-Script
Code: Select all
<#.SYNOPSIS
Veeam Agent Bandwidth Throttling Scheduler (Registry-Based)
.DESCRIPTION
Schedules and manages Veeam Agent bandwidth throttling via registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Veeam\Veeam Endpoint Backup
Dev_RepositoryThrottlingMb (REG_DWORD)
#>
# ====================== CONFIGURATION ====================
$Config = @{
LogPath = "C:\System\Veeambackup\VeeamBandwithScheduler\VeeamBandwidthScheduler.log"
MaxLogSizeMB = 10
LogRetentionDays = 30
# Bandwidth limits in Mbps (script will convert to MB/s for registry)
BusinessHoursLimit = 8 # Mbps for business hours
OffHoursLimit = 0 # 0 = No limit
WeekendLimit = 0 # 0 = No limit
# Time Windows
BusinessHours = @{
StartHour = 7
EndHour = 18
Days = @('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')
}
WeekendDays = @('Saturday', 'Sunday')
# Registry Target
RegistryPath = 'HKLM:\SOFTWARE\Veeam\Veeam Endpoint Backup'
RegistryValueName = 'Dev_RepositoryThrottlingMb'
BackupPath = "C:\System\Veeambackup\VeeamBandwithScheduler\VeeamRegistryBackup_$(Get-Date -Format yyyyMMddHHmmss).reg"
# Logging
EnableDetailedLogging = $true
}
# ========================= LOGGING =========================
function Write-Log {
param([string]$Message, [string]$Level="INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$entry = "[$timestamp] [$Level] $Message"
Add-Content -Path $Config.LogPath -Value $entry
if ($Config.EnableDetailedLogging -or $Level -eq "ERROR") { Write-Host $entry }
}
function Manage-LogFiles {
if (Test-Path $Config.LogPath) {
$logFile = Get-Item $Config.LogPath
if ($logFile.Length -gt ($Config.MaxLogSizeMB * 1MB)) {
$archive = $Config.LogPath -replace "\.log$", "_$((Get-Date).ToString('yyyyMMddHHmmss')).log"
Move-Item $Config.LogPath $archive
Write-Log "Log rotated to $archive"
}
# Cleanup old logs
$logDir = Split-Path $Config.LogPath
Get-ChildItem $logDir -Filter "*.log" | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-$Config.LogRetentionDays)} | ForEach-Object {Remove-Item $_.FullName}
}
}
# ================== REGISTRY FUNCTIONS ====================
function Backup-VeeamRegSetting {
Write-Log "Backing up registry to $($Config.BackupPath)"
reg export "HKLM\SOFTWARE\Veeam\Veeam Endpoint Backup" $Config.BackupPath /y | Out-Null
}
function Get-VeeamThrottlingReg {
try {
$val = Get-ItemProperty -Path $Config.RegistryPath -Name $Config.RegistryValueName -ErrorAction Stop
Write-Log "Current registry value: $($val.Dev_RepositoryThrottlingMb) MB/s" "DEBUG"
return $val.Dev_RepositoryThrottlingMb
} catch {
Write-Log "Registry value not found, assuming throttling OFF" "WARN"
return 0
}
}
function Set-VeeamThrottlingReg {
param([int]$MbPerSec)
try {
Write-Log "Updating Veeam throttling to $MbPerSec MB/s (REG_DWORD $($Config.RegistryPath) $($Config.RegistryValueName))"
Set-ItemProperty -Path $Config.RegistryPath -Name $Config.RegistryValueName -Value $MbPerSec -Type DWord
Write-Log "Registry updated successfully"
return $true
} catch {
Write-Log "ERROR setting Veeam throttling in registry: $_" "ERROR"
return $false
}
}
# ================== SCHEDULING LOGIC ======================
function Get-CurrentTimeWindow {
$now = Get-Date
$day = $now.DayOfWeek.ToString()
$hour = $now.Hour
if ($Config.WeekendDays -contains $day) {
return @{ Window="Weekend"; BandwidthMbps=$Config.WeekendLimit }
}
if ($Config.BusinessHours.Days -contains $day -and $hour -ge $Config.BusinessHours.StartHour -and $hour -lt $Config.BusinessHours.EndHour) {
return @{ Window="BusinessHours"; BandwidthMbps=$Config.BusinessHoursLimit }
}
return @{ Window="OffHours"; BandwidthMbps=$Config.OffHoursLimit }
}
function MbpsToMBps([int]$Mbps) {
[int][Math]::Round($Mbps / 8)
}
function Invoke-BandwidthScheduling {
Write-Log "Checking current schedule/time window"
$win = Get-CurrentTimeWindow
$throttleMb = if ($win.BandwidthMbps -le 0) {0} else {MbpsToMBps $win.BandwidthMbps}
Write-Log "Throttling to $($win.BandwidthMbps) Mbps ($throttleMb MB/s) for window $($win.Window)"
$curr = Get-VeeamThrottlingReg
if ($curr -ne $throttleMb) {
Backup-VeeamRegSetting
Set-VeeamThrottlingReg $throttleMb | Out-Null
} else {
Write-Log "No registry update needed, value already correct"
}
return $true
}
# ================== SCRIPT ENTRY ==================
param(
[ValidateSet("Schedule", "Test", "Status", "Help")]
[string]$Operation = "Schedule"
)
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
Write-Error "Script must be run as Administrator"
exit 1
}
Manage-LogFiles
switch ($Operation) {
"Schedule" {
Invoke-BandwidthScheduling
exit 0
}
"Test" {
Write-Log "Testing registry setting and logic:"
$curr = Get-VeeamThrottlingReg
Write-Host "Current registry bandwidth: $curr MB/s"
$win = Get-CurrentTimeWindow
Write-Host "Time window: $($win.Window), Limit: $($win.BandwidthMbps) Mbps"
Write-Host "Would set registry to: $(if($win.BandwidthMbps -le 0){0}else{MbpsToMBps $win.BandwidthMbps}) MB/s"
}
"Status" {
$curr = Get-VeeamThrottlingReg
Write-Host "Current Veeam registry throttle: $curr MB/s"
}
"Help" {
Write-Host @"
This script will update the Veeam bandwidth throttling setting for Windows Agent using the registry key:
HKLM:\SOFTWARE\Veeam\Veeam Endpoint Backup
Value: Dev_RepositoryThrottlingMb
Type : REG_DWORD
Throttling disables at 0. Any other value = bandwidth in MB/sec.
Operations:
Schedule - Apply throttling for current time window
Test - Show what the script would do
Status - Show current registry value
Help - Display this help
CRON/Scheduler: Use Task Scheduler to run hourly under SYSTEM
"@
}
}
Code: Select all
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2024-08-14T00:00:00</Date>
<Author>YourName</Author>
<Description>Runs the VeeamBandwidthScheduler.ps1 script every 5 minutes to enforce time-based repository bandwidth throttling using the registry key Dev_RepositoryThrottlingMb.</Description>
<URI>\Veeam Agent Bandwith Throttling Schedule - Scheduled Task</URI>
</RegistrationInfo>
<Triggers>
<BootTrigger>
<Enabled>true</Enabled>
</BootTrigger>
<CalendarTrigger>
<Repetition>
<Interval>PT5M</Interval>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>2024-08-14T00:00:00</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-1-5-18</UserId>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>Queue</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>false</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>true</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT10M</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-NoProfile -ExecutionPolicy Bypass -File "C:\System\Veeambackup\VeeamBandwidthScheduler.ps1" -Operation Schedule</Arguments>
<WorkingDirectory>C:\System\Veeambackup</WorkingDirectory>
</Exec>
</Actions>
</Task>