Automatically block RDP attacks using Windows Firewall and PowerShell

By accident I discovered, that in one of my eventlogs (“Applications and Services Logs\Microsoft\Windows\RemoteDesktopServices-RdpCoreTS\Operational”) several Entries with ID 140 are present. This events are logging attempts of users to login to my server via RDP but using wrong credentials. Obviously there should not be any attempt or maybe just one or two by myself. But in my case there are hundreds.

First I checked if my local and my domain administrator account are both disabled. This was the case so most of the login attempts will now also fail because the user is disabled. I assume most of them are trying to use this user. The user isn’t locked because of the attempts because there is enough time between the retries.

The text of the login attempt in the eventlog is “A connection from the client computer with an IP address of failed because the user name or password is not correct.”.

So I created a PowerShell script that is reading this messages, filtering the IP out of it and add it to the Windows Firewall Blacklist.
One prerequirement is, that there is already a firewall rule with at least 2 blocked IP addresses. I was just too lazy to solve this in my script. To create this rule, start the Windows Firewall Settings and create a new rule at “Inbound Rules”.

Select “Custom” auswählen. Leave “All programs” (just click “Next“). Leave any Protocol Type and Port (just “Next“). In the Scope section at “Which remote IP addresses does this rule apply to” select “These IP addresses” and add two dummy addresses. i.e. and We need at least two addresses for the script. Click “next“.

Select “Block the connection“.

At “Profile” check all profiles. At the last page enter a good name for your rule. We will need the name in our script. Now your rule configuration is done.


Now the script. This is the code that works with the already stated prerequirements. Copy the text to a file with the ending .ps1.

### Variables ###
# The name of the firewall rule in Windows Firewall
$firewallRuleName = "Block RDP Attackers"

# IPs that will not be blacklisted. i.e. your home IP if you are using Dyndns or any other static IP
$whiteList = @(
   [System.Net.Dns]::GetHostAddresses("").IPAddressToString, #Example for DNS entry
   "" #Example for IP

### Script ###
Write-Host "Running at $(Get-Date)"
$regExIp = "\d\d?\d?.\d\d?\d?.\d\d?\d?.\d\d?\d?"
$regExIp6 = "((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?"

# Get the current Eventlogs with the 140 event
$currentAttackers = @(Get-Winevent Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational | Where-Object {$_.Id -eq 140} | Select Message -ExpandProperty Message)

# If there is no response, there are no attacks
if ($currentAttackers -eq $null) {
   Write-Host "No current attackers"

# Get each attackermessage and filter the IP from it using the regex above
for ($i = 0; $i -lt $currentAttackers.Count; $i++) {
   if ($currentAttackers[$i] -match $regExIp -or $currentAttackers[$i] -match $regExIp6){
      $currentAttackers[$i] = $Matches[0]

# Get the already known attackers from the firewall rule
$knownAttackers = (Get-NetFirewallRule -DisplayName $firewallRuleName | Get-NetFirewallAddressFilter).RemoteAddress
if ($knownAttackers -eq $null){
   $knownAttackers = @()
$knownAttackers = $knownAttackers | Sort-Object -Unique

# Check each logged attacker and check if it is already known
foreach($newAttacker in $currentAttackers) {
   if ($knownAttackers.Contains($newAttacker)) { #If it is known, don't do anything
   elseif ($whiteList -contains $newAttacker) { #If it is whitelisted, don't do anything
      Write-Host "$newAttacker is dynamically whitelisted"
   else{ #otherwise it is a new attacker and add it to the blacklist
      $knownAttackers += $newAttacker
      Write-Host "Added $newAttacker"

# remove dublicates (should not be there, but anyway...)
$knownAttackers = $knownAttackers | Sort-Object -Unique
Write-Host "$($knownAttackers.Count) IPs on blacklist"

# Setting Firwall rules with all known and all new attackers
Set-NetFirewallRule -DisplayName $firewallRuleName -RemoteAddress $knownAttackers
Write-Host ""

Latest changes: (23.01.2021) IPv6 added and fixed an issue when only one Event exists. Thanks to Joachim

If you have a different name than “Block RDP Attackers” for the firewall rule, you have to change the line “$firewallRuleName = “Block RDP Attackers”” to your rule name.

Run the script “as administrator”. It will scan your eventlog and get all IPs that are mentioned in the events with the ID 140 in the corresponding log. This IPs will be added to the rule we created before and will block this IPs in the future.

I have a scheduled task for this script to run it frequently. In a timespan of just some hours already about 600 IP addresses are on my blocklist. If you configure the scheduled task, be sure that the checkbox “run with highest privileges” is checked.