<# Params [stirng]$Action - what to do: Protect - get a list of already connected appliances and allow conections from them. Restrict all connections from any other IPs to ports 1743-1749 Unprotect - remove all protection rules. Use case - you want to connect multiple appliances and you want to disable protection temporary. Another use case - you just removed the agent software and don't need this rule anymore. Allow - Ip - add this IP to the Allow rule. Use case - you want to connect the asset to one more appliance. Ip - If Action is "Allow" - add this Ip to the list of protected Ip's. If you would run the script without arguments or as "Protect" before adding this asset to an appliance - the list of addresses will be replaced by a list of already connected appliances #> param ( [Parameter()] [ValidateNotNullOrEmpty()] [ValidateSet('Protect', 'Unprotect', 'Block', 'Unblock', 'Allow')] [string]$Action = "Protect", [string]$Ip = "", [switch]$Legacy = $True ) trap { Write-Error $_ -ErrorAction Continue exit 0 } [string[]]$global:AllowRuleNames = @("MS SQL Agent","Unitrends Backup Agent", "Unitrends Agent Server", "Unitrends Agent Menu") [string]$global:OldAllowRuleName = "Allow Known Unitrends Agent Inbound Traffic" [string]$global:DenyRuleName = "Deny Unknown Unitrends Agent Inbound Traffic" [string]$global:AgentPortsRange = "1743-1749" # CreateApplianceObject # Creates a custom object to save an appliance ip and expiration_date # Properties: # [String]ip - an IP address # [String]expirationDate - expiration date in $Script:DateTimeFormat format function CreateApplianceObject { param( [String]$IP, [String]$ExpirationDate ) $appliance = "" | Select-Object -Property ip,expiration_date $appliance.ip = $IP if ("" -eq $ExpirationDate) { $ExpirationDate = GetExpirationDate } $appliance.expiration_date = $ExpirationDate return $appliance } # --------------------------------------------------------------------------------------------------------------------------- # CreateConfigObject # Creates a custom object to save default credentials and a list of registered appliances # This object is mapped to configuration ini file. It could be read from an .ini file and saved to an .ini file # Properties: # [String]username - a default user name # [String]password - a default password # [Object[]]appliances - a list of custom objects that are created by calling CreateApplianceObject function CreateConfigObject { $config = "" | Select-Object -Property username,password,appliances $config.username = $Script:DefaultUsername $config.password = $Script:DefaultPassword $config.appliances = @() return $config } # --------------------------------------------------------------------------------------------------------------------------- # ParseApplianceConfig # Parses a list of Strings and creates a list of Appliance objects and returns this list # each string lools like "ip = 192.168.134.150 , expiration_date = 09/04/2020 17:12" function ParseApplianceConfig { param( [String[]]$Strings ) [Object[]]$appliances = @() foreach ($appliance in $Strings) { [String[]]$pair = $appliance.Split(",") $pair = $pair | % {$_.Trim()} [String]$ipStr = $pair[0] [String]$expDateStr = $pair[1] [String]$ip = $ipStr.Split("=")[1] $ip = $ip.Trim() [String]$expirationDate = $expDateStr.Split("=")[1] $expirationDate = $expirationDate.Trim() $appliances += CreateApplianceObject -IP $ip -ExpirationDate $expirationDate } return $appliances } # --------------------------------------------------------------------------------------------------------------------------- # ParseConfig # Takes a content of config file and creates a Config object with the data from the String # Returns a Config object function ParseConfig { param( [String[]]$Content ) Write-Host "Parsing the config file..." $config = CreateConfigObject $appliancesStrings = @() $section = "" foreach ($line in $Content) { if ("[Credentials]" -eq $line -or "[Appliances]" -eq $line) { $section = $line continue } switch ($section) { "[Credentials]" { [String[]]$pair = $line.Split("=") $pair = $pair | %{$_.Trim()} $key = $pair[0] $value = $pair[1] switch ($key) { "username" { $config.username = $value } "password" { $config.password = $value } } } "[Appliances]" { $appliancesStrings += $line } ""{ continue } } } $appliances = ParseApplianceConfig -Strings $appliancesStrings if ($null -ne $appliances) { $config.appliances += $appliances } Write-Host "Done." return $config } # --------------------------------------------------------------------------------------------------------------------------- # ReadConfig # Reads a Config from a file. # Returns a Config object function ReadConfig { param( [string] $iniFilePath ) Write-Host "Reading the config file: $iniFilePath" $content = Get-Content -Path $iniFilePath $config = ParseConfig -Content $content return $config } function GetIniFilePath { $value = "BPDIR" Write-Host "Searching for PCBP directory location... Errors are fine here..." $key = 'HKLM:\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Unitrends\Backup Professional' $item = Get-ItemProperty -Path $key -Name $value $pcbp_path = "" if ($null -eq $item) { Write-Host "Not found. Trying another location..." $key = 'HKLM:\HKEY_LOCAL_MACHINE\SOFTWARE\Unitrends\Backup Professional' $item = Get-ItemProperty -Path $key -Name $value if ($null -eq $item) { Write-Host "Can't find PCBP location! Fallback to C:\PCBP\" $pcbp_path = "C:\PCBP\" } else { Write-Host "FOUND!" } } else { Write-Host "FOUND!" } if ($null -ne $item) { $pcbp_path = $item.$value } Write-Host "PCBP dir location is: $pcbp_path" $appliances_ini_path = "$pcbp_path" + "info.dir\appliances.ini" return $appliances_ini_path } function GetAppliancesIpList { param( [string]$separator = ',' ) $ini_file_path = GetIniFilePath $config = ReadConfig -iniFilePath $ini_file_path $ip_list = @() foreach ($appliance in $config.appliances) { $ip_list += $appliance.ip } return $ip_list } function IsAgentInstalled { $software = "Unitrends Agent" $installed = $null -ne (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where { $_.DisplayName -Match $software }) If(-not $installed) { Write-Host "'$software' is NOT installed."; } else { Write-Host "'$software' is installed." } return $installed } function IsRuleExists { param( [string]$DisplayName ) $is_exists = $False if ($Legacy) { $is_exists = $null -ne (netsh advfirewall firewall show rule name=all | select-string -pattern $DisplayName) } else { $is_exists = $null -ne (Get-NetFirewallRule -DisplayName $DisplayName) } return $is_exists } function RemoveFirewallRule { param( [string]$DisplayName ) $is_rule_exists = IsRuleExists -DisplayName $DisplayName if ($is_rule_exists) { Write-Host "Removing the $DisplayName rule" $is_done = $False if ($Legacy) { netsh advfirewall firewall delete rule name=$DisplayName } else { Remove-NetFirewallRule -DisplayName $DisplayName } $is_done = $? if ($is_done) { Write-Host "Done!" return $True } else { Write-Host "Failed!" return $False } } return $True } function CreateOrUpdateFirewallRule { param( [string]$DisplayName, [string[]]$IpList, [string]$Port = "any", [string]$Action ) $ip_list_str = "" if ($IpList.Count -le 0) { $ip_list_str = "any" } else { $ip_list_str = $IpList -join "," $ip_list_str } $is_done = $False $is_rule_exists = IsRuleExists -DisplayName $DisplayName if (-Not $is_rule_exists) { Write-Host "No such rule. Creating the Firewall rule $DisplayName ..." if ($Legacy) { netsh advfirewall firewall add rule name=$DisplayName dir=in action=$Action enable=yes remoteip="$ip_list_str" protocol=tcp localPort=$Port profile=Any $is_done = $? } else { $is_done = $null -ne (New-NetFirewallRule -DisplayName $DisplayName -RemoteAddress $IpList -Direction Inbound -Protocol TCP -LocalPort $Port -Action $Action) } } else { Write-Host "The Firewall rule $DisplayName already exists. Modifying ..." if ($Legacy) { Write-Host "New ip list is $ip_list_str" netsh advfirewall firewall set rule name=$DisplayName new remoteip="$ip_list_str" localPort=$Port } else { Set-NetFirewallRule -DisplayName $DisplayName -RemoteAddress $IpList -Direction Inbound -Protocol TCP -LocalPort $Port -Action $Action } $is_done = $? } if ($is_done) { Write-Host "Successfully Completed!" } else { Write-Host "Failed!" } return $is_done } function Protect { $is_agent_installed = IsAgentInstalled if (-not $is_agent_installed) { Write-Host "Unitrends Agent is not installed." Write-Host "Exiting." exit $is_done } $appliances_list = GetAppliancesIpList if ($appliances_list.Count -le 0) { Write-Host "No registered appliances." Write-Host "If you are sure that this asset is protected - please run inventory Sync and then re-run this script." Write-Host "Exiting." exit $is_allow_removed } Write-Host "Appliances:" $appliances_list Write-Host "Ports:" $global:AgentPortsRange foreach ($ruleName in $global:AllowRuleNames) { $is_rule_exists = IsRuleExists -DisplayName $ruleName if ($is_rule_exists) { $is_done = CreateOrUpdateFirewallRule -DisplayName $ruleName -IpList $appliances_list -Action allow } else { Write-Host "ERROR! Can't update rule $ruleName - it does not exists" Write-Host "It looks like your setup was corrupted or modified." } } if ($appliances_list.Coun -gt 0) { Unblock } Write-Host "Exiting." exit 0 } function GetIpListFromRule { param ( [string]$DisplayName ) $rule_ip_list = @() if ($Legacy) { $rule_details_list = (netsh advfirewall firewall show rule name=$DisplayName) foreach ($item in $rule_details_list) { if ($item.StartsWith("RemoteIP:")) { $parts = $item.Split(":") if ($parts.Count -eq 2) { $ip_addresses_list = $parts[1].Trim().Split(",") foreach ($addr_mask in $ip_addresses_list) { $addr = $addr_mask.Split("/")[0] if ($addr -ne "Any") { $rule_ip_list += $addr } } } break } } } else { $rule = Get-NetFirewallRule -DisplayName $DisplayName if ($nul -ne $rule) { Write-Host "Getting current Ip List..." $rule_ip_list = ($rule | Get-NetFirewallAddressFilter).RemoteAddress } } return $rule_ip_list } function Block { CreateOrUpdateFirewallRule -DisplayName $global:DenyRuleName -Port $global:AgentPortsRange -Action block } function Unblock { RemoveFirewallRule -DisplayName $global:DenyRuleName } function Allow { param( [string]$DisplayName, [string]$Ip ) Write-Host "Allowing $Ip" [string[]]$rule_ip_list = GetIpListFromRule -DisplayName $DisplayName if ($rule_ip_list -contains $ip) { Write-Host "Already Allowed." return $True } $rule_ip_list += $ip $is_done = $False $is_rule_exists = IsRuleExists -DisplayName $DisplayName if ($is_rule_exists) { $is_done = CreateOrUpdateFirewallRule -DisplayName $DisplayName -IpList $rule_ip_list -Action allow } else { Write-Host "ERROR! Can't update rule $DisplayName - it does not exists" Write-Host "It looks like your setup was corrupted or modified." } Write-Host "Done." return $is_done } function Unprotect { RemoveFirewallRule -DisplayName $global:OldAllowRuleName RemoveFirewallRule -DisplayName $global:DenyRuleName foreach ($ruleName in $global:AllowRuleNames) { CreateOrUpdateFirewallRule -DisplayName $ruleName -Action allow } } # -------- REGION MAIN -------- switch ($Action){ "Protect" { Protect } "Unprotect" { Unprotect } "Block" { Block } "Unblock" { Unblock } "Allow" { $is_agent_installed = IsAgentInstalled if (-not $is_agent_installed) { Write-Host "Unitrends Agent is not installed." Write-Host "Exiting." exit $is_done } foreach ($ruleName in $global:AllowRuleNames) { Allow -DisplayName $ruleName -Ip $ip } } }