Check and set Hardening on VBR server


Userlevel 6
Badge +4

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

Userlevel 6
Badge +4

@marco_s 

Yes, I also saw it ^^ .

It “only” manage what is in the list → all the L1 I did in my script but there is no L2 like remove explorer. 

You have several way to do now ^^ but the KB is good because they write when new recommendation appear, they will maintained it !

Userlevel 7
Badge +20

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

Very cool there is a KB associated to this now and official script.  Bookmarked! 😎

Userlevel 7
Badge +6

Congrats, @damien commenge! This is a great posts for the community. The script worked perfectly! 👏🏻

Comment