I have created a custom property for the right button menu that allows me to "Firewall Rule" any file in Windows 10 and block its internet access.

Similarly, I have another property that can disable or delete the rule I created.
However, I encountered a small problem.

The property works as intended, but it "deletes all rules with the same name".
It does not take into account the path of the file, only its name.

How can I modify the code below so that it only deletes the rule for the specific path?

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall]
@=""
"MUIVerb"="Windows Firewall"
"icon"="%SystemRoot%\\system32\\FirewallControlPanel.dll,0"
"subcommands"=""

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall]

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall\shell\Add Blocking Rule (Outgoing)]
@=""
MUIVerb"="Add Blocking Rule (Outgoing)"
"Icon"="%SystemRoot%\\system32\\FirewallControlPanel.dll,1"

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall\shell\Add Blocking Rule (Outgoing)\command]
@="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -Executionpolicy ByPass -WindowStyle Hidden -NoLogo -Command \"start powershell -Verb runas -ArgumentList \\\"-NoLogo -WindowStyle Hidden -command `\\\"New-NetFirewallRule -DisplayName ([System.IO.Path]::GetFilenameWithoutExtension('%1')) -Name '%1' -Enabled True -Direction Outbound -Action Block -Program '%1'`\\\"\\\"\""

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall\shell\Delete Rule (Outgoing)]
@=""
MUIVerb"="Unblock Rule (Outgoing)"
"Icon"="%SystemRoot%\\system32\\FirewallControlPanel.dll,2"

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall\shell\Delete Rule (Outgoing)\command]
@="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -Executionpolicy Bypass -WindowStyle Hidden -NoLogo -Command \"Start-Process powershell -Verb RunAs -ArgumentList \\\"-NoLogo -WindowStyle Hidden -Command `\"& {netsh advfirewall firewall delete rule name='\"'([System.IO.Path]::GetFileNameWithoutExtension('%1'))'\"' dir=out}'%1'`\\\"\\\"\""

I would appreciate any help or guidance on this issue. Thank you for your attention and interest in advance.

1

There are 1 answers

1
mklement0 On BEST ANSWER
  • Using just name=... in a netsh advfirewall firewall delete rule call deletes all rules by that name.

  • To limit deletion to those rules by that name that target a specific executable, you must add a program=... argument.

Using the tips regarding PowerShell's CLI syntax below, try the following in your .reg file:

[HKEY_CLASSES_ROOT\*\shell\Windows Firewall\shell\Delete Rule (Outgoing)\command]
@="powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -Command Start-Process -Verb RunAs powershell.exe '-NoExit -ExecutionPolicy Bypass -NoProfile -Command netsh advfirewall firewall delete rule name=$([IO.Path]::GetFileNameWithoutExtension(\\\\\\\"%1\\\\\\\")) program=\\\\\\\"%1\\\\\\\" dir=out'"

Important:

  • As in your question, the above uses [System.IO.Path]::GetFileNameWithoutExtension() to get the input file's name without the filename extension, e.g., some for C:\Users\jdoe\some.exe; to keep the extension, use [System.IO.Path]::GetFileName() instead.

  • To assist in troubleshooting, I have removed -WindowStyle Hidden from the Start-Process call and have added -NoExit to the nested powershell.exe call.

  • This will open the elevated session visibly and keep it open, so that you can inspect what happens.

  • Running [Environment]::CommandLine in the session will show you the exact process command line that the nested, elevated powershell.exe process saw; e.g., you'll see the following after invoking the shortcut-menu command on file C:\User\jdoe\some.exe:

    "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoExit -ExecutionPolicy Bypass -NoProfile -Command netsh advfirewall firewall delete rule name=$([IO.Path]::GetFileNameWithoutExtension(\"C:\Users\jdoe\some.exe\")) program=\"C:\Users\jdoe\some.exe\" dir=out
    
  • The above translates to the following netsh call (note the absence of "..." quoting, because, when PowerShell - of necessity - rebuilds the process command line behind the scenes, it employs on-demand double-quoting: only if the argument contains spaces does it get enclosed in "..." - invariably as a whole):

    netsh advfirewall firewall delete rule name=some program=C:\Users\jdoe\some.exe dir=out
    

General tips regarding the PowerShell CLI and the necessary escaping:

  • There's no reason to use "& { ... }" in order to invoke code passed to PowerShell's CLI via the -Command (-c) parameter - just use "..." directly.

    • Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.

    • In no-shell invocations, such as in your case, even the "..." enclosure isn't necessary, which is why it was omitted below for simplicity.

      • There's a largely hypothetical concern when omitting the "..." enclosure with respect to whitespace normalization, which would only apply if embedded strings with multiple adjacent whitespace characters had to be passed as-is.
  • There is no reason to use -NoLogo in CLI calls that use -Command in order to suppress the startup banner; -Command alone does that (it also isn't necessary when using -File, unless -NoExit is also specified).

    • However, it is generally worth adding the -NoProfile switch parameter, which suppresses loading of any profile files, which are typically only useful in interactive sessions; not loading them both improves performance and makes for a more predictable execution environment.
  • Getting the escaping and quoting right in your case is exceptionally difficult, given that there are multiple layers of interpretation to deal with:

    • The .reg file format in which \ must be used to escape " chars. as well as verbatim \ itself.

    • Two layers of interpretation by powershell.exe, the Windows PowerShell CLI, due to requiring a nested call via Start-Process -Verb Runas in order to launch an elevated PowerShell session.

      • Each PowerShell CLI call itself has two layers of interpretation:
        • Unquoted " chars. are removed during command-line processing - unless they're escaped as \".
        • The result is then interpreted as PowerShell code.