Skip to main content

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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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 = $CmdLinen0]
$Arg = $CmdLinen1].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

 

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. 😁


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 :)


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.


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 ?


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.  👌🏻


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 :)


hi @damien commenge 

thx for the script.

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


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.


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.


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 :)


all well works as expected.
Thank you 


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


Interesting script, @damien commenge .

I will test it tomorrow 😎 Thank you.


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


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 :)


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

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

cheers!


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!


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


Thank you @damien commenge ! 👏🏻


Thanks @damien commenge , Great Script !! 👏🏻


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


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


@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 !


Thank you @damien commenge for sharing this great script.


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