Skip to main content

Check and set Hardening on VBR server


damien commenge
Forum|alt.badge.img+5

Hello,

I want to share with you the last script I make to get hardening configuration of the VBR server and then remediate some of them.
The script need to be executed on the VBR server itself.

It's built with Veeam 12.1 beta. That means some checks can break on GA version.

I seperate it into 4 choices when you execute it :
choice 1 = Apply Level 1 security (security check done by veeam product itself when you execute security and compliance on the VBR console)
choice 2 = Apply Level 2 security (best practice about hardening Veeam product)
choice 3 = Remove VBR console (Carreful, you can't use anymore Veeam powershell after this action)
choice 4 = Get HTML security report

 

That means choice 1 or 2 or 3 will performs modifications on the system.

Choice 4 will not do any modifications, it just make the HTML report.


Some sample available on fresh installation, fresh installation + L1 applied, fresh installation + L1 + L2 applied

If you want to see report on fresh installation + after doing choice 1 + after doing choice 1 and 2 just look at the attachment at the end of this post

 


#region HTML style
$HTMLCSS=@'
<style>
body{color:black;font-family:Vinci Sans Light;font-size:0.79em;line-height:1.25;margin:5;}
a{color:black;}
H1{color:white;font-family:Verdana;font-weight:bold;font-size:20pt;margin-bottom:50px;margin-top:40px;text-align:center;background-color:#005EB8;}
H2{color:#A20067;font-family:Verdana;font-size:16pt;margin-left:14px;text-align:left;}
H3{color:#005EB8;font-family:Verdana;font-size:13pt;margin-left:16px;}
H4{color:black;font-family:Verdana;font-size:11pt;margin-left:16px;}
table {border-collapse: collapse;margin-left:10px;border-radius:7px 7px 0px 0px;}
th, td {padding: 8px;text-align: left;border-bottom: 1px solid #ddd;}
th {background-color: #A20067;color: white;}
tr:nth-child(even){background-color: #f2f2f2}
table.table2 td:first-child{background-color: #A20067;color: white}
</style>
'@

$date           = (get-date -Format "dd_MM_yyyy_HH_mm")
#Report file HTML path
$ReportPath     = "c:\temp\VeeamSecurityAudit\$date"
$VeeamServerName = $env:COMPUTERNAME


$dicts = @(
    [Ordered]@{ 
        Id = 1
        Name = "Computer is Workgroup member"
        Condition = {
            (Get-CimInstance -ClassName Win32_ComputerSystem).PartOfDomain
        }
        ComplianceValue = $False
        Level = "L1"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 2
        Name = "MFA is enabled"
        Condition = {
            [Veeam.Backup.Core.SBackupOptions]::GlobalMFA
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 3
        Name = "Configuration backup encryption is enabled"
        Condition = {
            (Get-VBRConfigurationBackupJob).EncryptionOptions.Enabled
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }

    [Ordered]@{ 
        Id = 4
        Name = "Encryption network rules added for LAN traffic"
        Condition = {
            ((Get-VBRNetworkTrafficRule).Count -ne 1) -and ((Get-VBRNetworkTrafficRule).EncryptionEnabled -notcontains $false)
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 5
        Name = "Remote desktop protocol is disabled"
        Condition = {
            (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name fDenyTSConnections).fDenyTSConnections -eq 1
        }
        ComplianceValue = $True 
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 6
        Name = "Windows firewall is enabled"
        Condition = {
            (Get-NetFirewallProfile).Enabled -Contains $False
        }
        ComplianceValue = $false
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 7
        Name = "Remote registry service is disabled"
        Condition = {
            (Get-Service RemoteRegistry).StartType -eq "Disabled"
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 8
        Name = "Password loss protection is enabled"
        Condition = {
            [Veeam.Backup.Core.CCryptoKey]::IsLossProtectionEnabled()
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 9
        Name = "SSL 2.0 is disabled"
        Condition = {
            Try {
                (get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -Name Enabled -ErrorAction Stop).Enabled -eq 0
            }
            Catch {
                $false
            }
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 10
        Name = "SSL 3.0 is disabled"
        Condition = {
            Try {
                (get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -Name Enabled -ErrorAction Stop).Enabled -eq 0
            }
            Catch {
                $false
            }        
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 11
        Name = "TLS 1.0 is disabled"
        Condition = {
            Try {
                (get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Name Enabled -ErrorAction Stop).Enabled -eq 0
            }
            Catch {
                $false
            }        
        }         
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 12
        Name = "TLS 1.1 is disabled"
        Condition = {
            Try {
                (get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Name Enabled -ErrorAction Stop).Enabled -eq 0
            }
            Catch {
                $false
            }        
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 13
        Name = "SMB 1.0 is disabled"
        Condition = {
            (Get-SmbServerConfiguration).EnableSMB1Protocol
        }
        ComplianceValue = $false
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 14
        Name = "NETBIOS is disabled"
        Condition = {
            (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\*" -Name NetbiosOptions).NetbiosOptions -notcontains 0 -and
            (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\*" -Name NetbiosOptions).NetbiosOptions -notcontains 1
        }
        ComplianceValue = $false
        Level = "L1"
        Remediation = "Script"
    }
        [Ordered]@{ 
        Id = 15
        Name = "Remote powershell is disabled (WinRM service)"
        Condition = {
            Try {
                [Bool](Test-WSMan -ComputerName localhost -ErrorAction Stop)
            }
            Catch {
                $false
            }  
        }
        ComplianceValue = $false
        Level = "L1"
        Remediation = "Script"
    }
        [Ordered]@{ 
        Id = 16
        Name = "Immutable or offline media is used"
        Condition = {
            ([Veeam.Backup.DBManager.CDBManager]::Instance.BestPractices.GetAll() | Where-Object {$_.Type -eq "ImmutableOrOfflineMediaPresence"}) -eq "OK"
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 17
        Name = "OS is up to date"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 18
        Name = "Antivirus exclusions added"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 19
        Name = "Use strong passphrases and not passwords"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 20
        Name = "Only mandatory applications are installed"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 21
        Name = "Backup network is isolated"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 22
        Name = "Veeam One is used for SNMP traps"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 23
        Name = "Veeam One ransomware activity alarm is enabled"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
        [Ordered]@{ 
        Id = 24
        Name = "WDigest credentials caching is disabled"
        Condition = {
            (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -ErrorAction Ignore).UseLogonCredential -ne 1
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 25
        Name = "Web Proxy Auto-Discovery service (WinHttpAutoProxySvc) is disabled"
        Condition = {
            (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\WinHttpAutoProxySvc -Name Start).Start -eq 4
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 26
        Name = "Windows Script Host is disabled"
        Condition = {
            Try {
                (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings" -Name Enabled -ErrorAction Stop).Enabled -eq 0
            }
            Catch {
                $false
            }                 
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 27
        Name = "Link-Local Multicast Name Resolution (LLMNR) is disabled"
        Condition = {
            Try {
                (Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Name EnableMultiCast -ErrorAction Stop).EnableMultiCast -eq 0
            }
            Catch {
                $false
            }                 
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 28
        Name = "SMB v3 encryption is enabled"
        Condition = {
            (Get-SmbServerConfiguration).EncryptData
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 29
        Name = "SMB v3 signing is enabled"
        Condition = {
            (Get-SmbServerConfiguration).EnableSecuritySignature -eq $true -and (Get-SmbServerConfiguration).RequireSecuritySignature -eq $true
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 30
        Name = "Configuration backup is enabled and use encryption"
        Condition = {
            (Get-VBRConfigurationBackupJob).Enabled -eq $true -and (Get-VBRConfigurationBackupJob).EncryptionOptions.Enabled -eq $true
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 31
        Name = "Credentials and encryption passwords rotates annually"
        Condition = {
			"Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 32
        Name = "Hardened repositories have SSH disabled"
        Condition = {
			"Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 33
        Name = "S3 Object Lock in the Governance mode doesn't provide true immutability"
        Condition = {
			"Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 34
        Name = "Backup jobs to cloud repositories is encrypted"
        Condition = {
			"Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 35
        Name = "Backup services run under the LocalSystem account"
        Condition = {
			((Get-CIMInstance -Class Win32_Service -Filter "Name like 'Veeam%'").StartName | 
			Where-Object {$_ -ne "LocalSystem"} | 
			Measure-Object | 
			Select-Object -ExpandProperty count) -eq 0
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 36
        Name = "Email notifications are enabled"
        Condition = {
			(Get-VBRMailNotificationConfiguration).Enabled        
		}
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 37
        Name = "All backups have at least one copy (the 3-2-1 backup rule)"
        Condition = {
			"Manual"       
		}
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 38
        Name = "Reverse incremental backup mode is not used"
        Condition = {
			(Get-VBRJob).BackupTargetOptions.Algorithm -contains "Syntethic" -eq $false        
		}
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 39
        Name = "Unknown Linux servers are not trusted automatically"
        Condition = {
            (Get-VBRLinuxTrustedHostPolicy).Type -eq "KnownHosts"
		}
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Script"
    }
	[Ordered]@{ 
        Id = 40
        Name = "The configuration backup is not stored on the backup server"
        Condition = {
			(Get-VBRConfigurationBackupJob).repository.Host.info.Name -ne "This server"
        }
        ComplianceValue = $True
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 41
        Name = "Hardened repositories are not hosted in virtual machines"
        Condition = {
			"Manual"
		}
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
	[Ordered]@{ 
        Id = 42
        Name = "Linux servers have password-based authentication disabled"
        Condition = {
			"Manual"
        }
        ComplianceValue = "Manual"
        Level = "L1"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 100
        Name = "Administrators group is not used for permissions"
        Condition = {
            $LocalAdminGroupName = (Get-LocalGroup -SID S-1-5-32-544).Name
            (Get-VBRUserRoleAssignment).Name -contains "BUILTIN\$LocalAdminGroupName"
        }
        ComplianceValue = $False
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 101
        Name = "Least privilege is used (not all RBAC roles are administrator)"
        Condition = {
            ((Get-VBRUserRoleAssignment | Where-Object {$_.Role -ne "BackupAdmin"}) | Measure-Object).count -ne 0
        }
        ComplianceValue = $True
        Level = "L2"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 102
        Name = "Auto logoff is enabled"
        Condition = {
            [Veeam.Backup.Core.SBackupOptions]::AutomaticallyTerminateSession
        }
        ComplianceValue = $True
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 103
        Name = "All Jobs are encrypted"
        Condition = {
            Try {
                (get-vbrjob -ErrorAction Stop).isencryptionEnabledSafe() -contains $false
            }
            Catch {
                $false
            }  
        }
        ComplianceValue = $False
        Level = "L2"
        Remediation = "Manual"
    }
    [Ordered]@{ 
        Id = 104
        Name = "VBR console is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Backup & Replication Console"
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 105
        Name = "Veeam explorer for Active directory is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Microsoft Active Directory" 
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 106
        Name = "Veeam explorer for Exchange is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Microsoft Exchange"
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 107
        Name = "Veeam explorer for OneDrive (Same than Sharepoint) is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Microsoft SharePoint"
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 108
        Name = "Veeam explorer for Sharepoint is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Microsoft SharePoint"
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 109
        Name = "Veeam explorer for SQL is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Microsoft SQL Server" 
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 110
        Name = "Veeam explorer for Teams is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Microsoft Teams"
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 111
        Name = "Veeam explorer for Oracle is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for Oracle"
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
    [Ordered]@{ 
        Id = 112
        Name = "Veeam explorer for PostgreSQL is not installed"
        Condition = {
            (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -contains "Veeam Explorer for PostgreSQL"       
        }
        ComplianceValue = $false
        Level = "L2"
        Remediation = "Script"
    }
        [Ordered]@{ 
        Id = 113
        Name = "Disable physical remote management"
        Condition = {
            "Manual"
        }
        ComplianceValue = "Manual"
        Level = "L2"
        Remediation = "Manual"
    }

) 


function Set-VBRHardeningL1
{
    Write-host "Disable Remote desktop protocol "
    Set-Service TermService -StartupType Disabled
    Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name fDenyTSConnections -Value 1

    Write-host "Enable Windows firewall"
    Set-NetFirewallProfile -All -Enabled True

    Write-host "Remote registry service is disabled"
    Set-Service -Name "RemoteRegistry" -StartupType Disabled
    Stop-Service -Name "RemoteRegistry" -Force

    Write-host "SSL 2.0 is disabled"
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null

    Write-host "SSL 3.0 is disabled"
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null

    Write-host "TLS 1.0 is disabled"
    New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Force | Out-Null
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null

    Write-host "TLS 1.1 is disabled"
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null
    New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null
    New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null

    Write-host "SMB 1.0 is disabled"
    Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol | Out-Null

    Write-host "Remote powershell is disabled (WinRM service)"
    Disable-PSRemoting -Force
    Set-Service -Name WinRM -StartupType Disabled
    Stop-Service WinRM -Force

    Write-host "Disable WDigest credentials caching"
    Remove-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -ErrorAction Ignore

    Write-host "Disable Web Proxy Auto-Discovery service (WinHttpAutoProxySvc)"
    Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\WinHttpAutoProxySvc -Name Start -Value 4

    Write-host "Disable Windows Script Host"
    New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings" -Name Enabled -PropertyType dword -Value 0 -Force | Out-Null

    Write-host "Disable Link-Local Multicast Name Resolution (LLMNR)"
    New-Item "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT" -Name DNSClient -Force | Out-Null
    New-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Name EnableMultiCast -Value 0 -PropertyType DWORD -Force | Out-Null

    Write-host "Set Linux servers should not be trusted automatically"
    Set-VBRLinuxTrustedHostPolicy -Type KnownHosts

    Write-host "Enable SMBv3 signing and encrption"
    Set-SmbServerConfiguration -EncryptData $true -Force
    Set-SmbServerConfiguration -EnableSecuritySignature $true -Force
    Set-SmbServerConfiguration -RequireSecuritySignature $true -Force
}

function Set-VBRHardeningL2
{
    Write-host "Administrator group is not used for permissions member must be remediate manually"
    Write-Host "processing : Adding current user as administrator and remove builtin\administrator"
    $ComputerName = $env:COMPUTERNAME
    $UserRoleName = $ComputerName + "\" + $env:USERNAME
    Add-VBRUserRoleAssignment -Name $UserRoleName -Role BackupAdmin | Out-Null
    $LocalAdminGroupName = (Get-LocalGroup -SID S-1-5-32-544).Name
    Write-Host "processing : Removing Builtin\administrators from Veeam permission role"
    Get-VBRUserRoleAssignment | Where-Object {$_.Name -eq "Builtin\$LocalAdminGroupName"} | Remove-VBRUserRoleAssignment


    Write-host "Enable Auto logoff"
    #https://forums.veeam.com/powershell-f26/several-cmdlet-missing-t90630.html 
    [Veeam.Backup.DBManager.CDBManager]::Instance.Options.UpdateAutomaticallyTerminateSession($true)

    Write-host "Remove Veeam explorer for Active directory"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for Microsoft Active Directory"}).uninstallstring
    if ($null -ne $CmdLine)
    {
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_ActiveDirectoryExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for Exchange is not installed"
    }

    Write-host "Remove Veeam explorer for Exchange"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for Microsoft Exchange"}).uninstallstring
    if ($null -ne $CmdLine)
    {
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $Arg = $Arg.Replace('/I','/X')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_ExchangeExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for Exchange is not installed"
    }


    Write-host "Remove Veeam explorer for OneDrive (Same than Sharepoint)"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for Microsoft SharePoint"}).uninstallstring
    if ($null -ne $CmdLine)
    {   
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $Arg = $Arg.Replace('/I','/X')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_OneDrive_and_SharepointExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for SharePoint and OneDrive is not installed"
    }

    Write-host "Remove Veeam explorer for SQL"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for Microsoft SQL Server"}).uninstallstring
    if ($null -ne $CmdLine)
    {   
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_SQLExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for SQL is not installed"
    }


    Write-host "Remove Veeam explorer for Teams"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for Microsoft Teams"}).uninstallstring
    if ($null -ne $CmdLine)
    {   
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $Arg = $Arg.Replace('/I','/X')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_TeamsExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for Teams is not installed"
    }



    Write-host "Remove Veeam explorer for Oracle"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for Oracle"}).uninstallstring
    if ($null -ne $CmdLine)
    {
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_OracleExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for Oracle is not installed"
    }


    Write-host "Remove Veeam explorer for PostgreSQL"
    $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Explorer for PostgreSQL"}).uninstallstring
    if ($null -ne $CmdLine)
    {
        $CmdLine = $CmdLine.split(" ")
        $process = $CmdLine[0]
        $Arg = $CmdLine[1].Replace('{','"{')
        $Arg = $Arg.Replace('}','}"')
        $arg = $Arg + " /qn /log $($env:windir)\temp\Uninstall_VBR_PostgreSQLExplorer.log"
        Start-Process -FilePath $process -ArgumentList $Arg -Wait
    }
    else {
        "Veeam explorer for PostgreSQL is not installed"
    }

    Write-host "Disable NETBIOS"
    $Interfaces = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\*" -Name NetbiosOptions)
    foreach ($interface in $Interfaces)
    {
        Set-ItemProperty -Path $interface.PSPath -Name NetbiosOptions -Value 0
    }
}

function Set-HTMLColor
{
    [CmdletBinding()]

    Param
    (
        #HTML table
        [Parameter(Mandatory=$true)]
        $HTMLTable,
        #Text to color
        [Parameter(Mandatory=$true)]
        [string] $Name,
        #Color code
        [Parameter(Mandatory=$true)]
        [string] $Color
    )
    $HTMLTable | ForEach-Object {$_ -replace "<td>$Name</td>", "<td style='background-color:$Color'>$Name</td>"}
}

function Get-HTMLReport
{
    [CmdletBinding()]

    Param
    (
        #HTML file path
        [Parameter(Mandatory=$true)]
        [string] $Path,
        #HTML file name
        [string] $FileName = "VBRHardening.html"
    )
    begin   
    {
        if(!(Test-Path $Path))
        {
            New-Item -Path $Path -ItemType directory | Out-Null
        }
        $HTMLfilename="$path\$filename"
        $Table = foreach ($obj in $results)
        {
            [PSCUstomObject]@{
                ID = $obj.id
                Test = $obj.name
                Level = $obj.level
                Result = switch ($obj.Result)
                        {
                            "Manual"
                            { 
                                "Manual"
                                break
                            }

                            {$obj.Result -eq $obj.ComplianceValue}
                            {
                                    "Compliant"
                            }
                            Default
                            {
                                    "Not compliant"
                            }
                        }
                Remediation = $obj.remediation
            }
        }
    }
    process
    {
        #HTML generation
        $HTMLTitle = "<h1>Veeam security Audit</h1>"  
        $Table = $Table | Sort-object Level,ID | ConvertTo-Html -Fragment
        $Table = Set-HTMLColor -HTMLTable $Table -Name "Not Compliant" -Color "#F91607"
        $Table = Set-HTMLColor -HTMLTable $Table -Name "Compliant" -Color "#1BC813"
        $Table = Set-HTMLColor -HTMLTable $Table -Name "Manual" -Color "#FBFB0B"

        #region HTML body

    $HTML = @"
        <!DOCTYPE html>
        <html>
        <head>
        <title>Report</title>
        <meta name="generator" content="PowerShell" />
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

        $HTMLCSS
        </head>
        <body>
        <br><br><br><br>

        $HTMLTitle

        $Table 


        <h4> $(get-date -Format "dd/MM/yyyy HH:mm")</h4>
        </body>
        </html>
"@
        $HTML | out-file -FilePath $HTMLfilename | Out-Null


        Invoke-Item $HTMLfilename
        }
}



function Get-VBRHardening
{
    param ($Path)

    $results = $dicts | ForEach-Object {
        [PSCustomObject]@{
            Id = $_.Id
            Name = $_.Name
            ComplianceValue = $_.ComplianceValue
            Result = & $_.Condition
            Level = $_.Level
            Remediation = $_.remediation
        } 
    }


    foreach ($obj in $results)
    {
        switch ($obj.Result)
        {
            "Manual"
            {
                Write-Host $obj.Id "-" $obj.Name ": " -NoNewline
                Write-Host "Manual" -ForegroundColor Yellow
                break

            }

            {$obj.Result -eq $obj.ComplianceValue}
            {
                Write-Host $obj.Id "-" $obj.Name ": " -NoNewline
                Write-Host "Compliant" -ForegroundColor Green
            }

            Default
            {
                Write-Host $obj.Id "-" $obj.Name ": " -NoNewline
                Write-Host "Not compliant" -ForegroundColor Red 
            }
        }
    }

    Get-HTMLReport -Path $ReportPath
}



<#
.SYNOPSIS
    Display menu 
.DESCRIPTION
    Display menu 
.OUTPUTS
    Results are printed to the console.
.EXAMPLE 
    Display menu
    Get-VeeamMenu
#>
function Get-VeeamMenu
{
    Write-host ""   
    Write-host "This script is intended to harden Veeam"
    Write-host ""
    Write-host "-------------------------------"
    Write-host "|             MENU            |"
    Write-host "-------------------------------"
    Write-host ""
    Write-host "1  : Set Veeam Hardening L1"
    Write-host "2  : Set Veeam Hardening L2"
    Write-host "3  : Remove only Veeam console"
    Write-host "10 : Get Veeam Hardening report"

    Write-host "0 : Exit" -foreground Yellow
    Write-host ""
}




###########################################
#               Main script               #
###########################################

#Connect to Veeam server
if ($null -eq (Get-VBRServerSession))
{
    Write-host "Connecting to Veeam server $VeeamServerName" 
    Connect-vbrserver -Server $VeeamServerName
}


do 
{
    Get-VeeamMenu
    $choice = Read-host "Enter action number you want to do"
    Write-host ""

    switch ($choice)
    {
        0 {
            break        
        }
        1 {
            #Apply Veeam hardening L1 security
            Set-VBRHardeningL1        
        }
        2 {
            #Apply Veeam hardening L2 security
            Set-VBRHardeningL2        

        }                
        3 {
                #Remove VBR console
                Write-host "ID 9 VBR console is not installed must be removed manually at the end because it removes Veeam powershell module"
                $CmdLine = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object {$_.Displayname -eq "Veeam Backup & Replication Console"}).uninstallstring
                if ($null -ne $CmdLine)
                {
                    $CmdLine = $CmdLine.split(" ")
                    $process = $CmdLine[0]
                    $Arg = $CmdLine[1].Replace('{','"{')
                    $Arg = $Arg.Replace('}','}"')
                    $arg = $Arg + " /qn /log $($env:windir)\temp\uninstall_VBR_Console.log"
                    Start-Process -FilePath $process -ArgumentList $Arg -Wait
                }
                else {
                    "Veeam backup and replication console is not installed"
                }     
          }
        10 {
            #Get Veeam hardening L2 Repport
            Get-VBRHardening -Path $ReportPath

        }

          default {write-host -ForegroundColor Red "Please enter correct value" }
    }
} until ($choice -eq 0)


# Disconnecting from Veeam powershell session
Write-host "Disconnecting to Veeam server $VeeamServerName" 
Disconnect-VBRServer

 

28 comments

Chris.Childerhose
Forum|alt.badge.img+21
  • Veeam Legend, Veeam Vanguard
  • 8400 comments
  • November 14, 2023

Wow!  That is one long script but definitely very useful.  I am going to test it out on my 12.1 Beta server to see. 😁


damien commenge
Forum|alt.badge.img+5
Chris.Childerhose wrote:

Wow!  That is one long script but definitely very useful.  I am going to test it out on my 12.1 Beta server to see. 😁

Thanks :) 
Let me see if you have some errors :)


Chris.Childerhose
Forum|alt.badge.img+21
  • Veeam Legend, Veeam Vanguard
  • 8400 comments
  • November 14, 2023

One issue is when running with an account that is MFA enabled within Veeam it throws many errors.  Need to run it with an account that does not have MFA enabled in Veeam.


damien commenge
Forum|alt.badge.img+5
Chris.Childerhose wrote:

One issue is when running with an account that is MFA enabled within Veeam it throws many errors.  Need to run it with an account that does not have MFA enabled in Veeam.

Thanks for your feedback.

I didn’t test it but I reproduce the issue and I see it’s totally normal as mentionned in the Veeam documentation :

Multi-Factor Authentication - User Guide for VMware vSphere (veeam.com)

  • MFA is not supported for PowerShell (either interactive logon or non-interactive connections). To use PowerShell cmdlets with Veeam Backup PowerShell Module or Microsoft Windows PowerShell, run the Veeam Backup & Replication console or Microsoft Windows PowerShell under the service account with disabled MFA.

 

That means is not related to the script but a Veeam requirement :)

Did you have other issues ?


Chris.Childerhose
Forum|alt.badge.img+21
  • Veeam Legend, Veeam Vanguard
  • 8400 comments
  • November 14, 2023
damien commenge wrote:
Chris.Childerhose wrote:

One issue is when running with an account that is MFA enabled within Veeam it throws many errors.  Need to run it with an account that does not have MFA enabled in Veeam.

Thanks for your feedback.

I didn’t test it but I reproduce the issue and I see it’s totally normal as mentionned in the Veeam documentation :

Multi-Factor Authentication - User Guide for VMware vSphere (veeam.com)

  • MFA is not supported for PowerShell (either interactive logon or non-interactive connections). To use PowerShell cmdlets with Veeam Backup PowerShell Module or Microsoft Windows PowerShell, run the Veeam Backup & Replication console or Microsoft Windows PowerShell under the service account with disabled MFA.

 

That means is not related to the script but a Veeam requirement :)

Did you have other issues ?

No other issues so far works great.  👌🏻


damien commenge
Forum|alt.badge.img+5
Chris.Childerhose wrote:
damien commenge wrote:
Chris.Childerhose wrote:

One issue is when running with an account that is MFA enabled within Veeam it throws many errors.  Need to run it with an account that does not have MFA enabled in Veeam.

Thanks for your feedback.

I didn’t test it but I reproduce the issue and I see it’s totally normal as mentionned in the Veeam documentation :

Multi-Factor Authentication - User Guide for VMware vSphere (veeam.com)

  • MFA is not supported for PowerShell (either interactive logon or non-interactive connections). To use PowerShell cmdlets with Veeam Backup PowerShell Module or Microsoft Windows PowerShell, run the Veeam Backup & Replication console or Microsoft Windows PowerShell under the service account with disabled MFA.

 

That means is not related to the script but a Veeam requirement :)

Did you have other issues ?

No other issues so far works great.  👌🏻

Thank you for your feeedback and your time to test it :)


Link State
Forum|alt.badge.img+11
  • Veeam Legend
  • 602 comments
  • November 14, 2023

hi @damien commenge 

thx for the script.

If I select 10 it only performs the checks and returns a report, correct?


Chris.Childerhose
Forum|alt.badge.img+21
  • Veeam Legend, Veeam Vanguard
  • 8400 comments
  • November 14, 2023
Link State wrote:

hi @damien commenge 

thx for the script.

If I select 10 it only performs the checks and returns a report, correct?

Yes it will create the report in the directory in the script and then open it - HTML file.


damien commenge
Forum|alt.badge.img+5
Link State wrote:

hi @damien commenge 

thx for the script.

If I select 10 it only performs the checks and returns a report, correct?

Hello,

 

Exactly, no modification are done with 10.


damien commenge
Forum|alt.badge.img+5
Chris.Childerhose wrote:
Link State wrote:

hi @damien commenge 

thx for the script.

If I select 10 it only performs the checks and returns a report, correct?

Yes it will create the report in the directory in the script and then open it - HTML file.

Normally, the report should be created on the path :

"c:\temp\VeeamSecurityAudit”

But I guess you execute the script from c:\temp :)


Link State
Forum|alt.badge.img+11
  • Veeam Legend
  • 602 comments
  • November 14, 2023

all well works as expected.
Thank you 


Scott
Forum|alt.badge.img+8
  • Veeam Legend
  • 993 comments
  • November 14, 2023

Wow! Great script.. Once I get my new test lab set up at work I’ll try and run it.


JMeixner
Forum|alt.badge.img+17
  • Veeam Vanguard
  • 2650 comments
  • November 14, 2023

Interesting script, @damien commenge .

I will test it tomorrow 😎 Thank you.


Stabz
Forum|alt.badge.img+8
  • On the path to Greatness
  • 351 comments
  • November 16, 2023

Wow ! @damien commenge nice script ! Need to test it in my future lab too ! thx!


damien commenge
Forum|alt.badge.img+5

I update the description. 

I’m waiting for the GA to see if I need to perform some updates on it !

I don’t use any AI to make this script and I’m surre for more experimented people, it should be possible to reduce it :)


HunterLAFR
Forum|alt.badge.img+8
  • Veeam Legend
  • 421 comments
  • November 18, 2023

Im impressed, thanks so much @damien commenge for the scrip!

Im not into scripting / coding, and this is awesome!

cheers!


coolsport00
Forum|alt.badge.img+20
  • Veeam Legend
  • 4109 comments
  • November 18, 2023

Very long, but very nice script @damien commenge ! Once I get 12.1 installed, I’ll be testing this out. Thank you for the share!


Nico Losschaert
Forum|alt.badge.img+12
  • On the path to Greatness
  • 681 comments
  • November 18, 2023

Will try it out! This is great @damien commenge !


marco_s
Forum|alt.badge.img+8
  • Influencer
  • 368 comments
  • November 20, 2023

Thank you @damien commenge ! 👏🏻


JNEAU
  • New Here
  • 2 comments
  • November 21, 2023

Thanks @damien commenge , Great Script !! 👏🏻


jos.maliepaard
Forum|alt.badge.img+7

this is great stuff. saves a lot of google time to figures out all the settings. 


jos.maliepaard
Forum|alt.badge.img+7

@damien commenge  the link is expired. can you share it again please?


damien commenge
Forum|alt.badge.img+5
jos.maliepaard wrote:

@damien commenge  the link is expired. can you share it again please?

Hello @jos.maliepaard  ,

Sorry about it. I just add it at the end of my first post. I hope it works now !


vAdmin
Forum|alt.badge.img+2
  • Influencer
  • 166 comments
  • November 30, 2023

Thank you @damien commenge for sharing this great script.


marco_s
Forum|alt.badge.img+8
  • Influencer
  • 368 comments
  • December 18, 2023

I don't know if it was already mentioned in some post, but a KB with official script came out: https://www.veeam.com/kb4525

Get royalties paid @damien commenge ! 😄


Comment