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.
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.
"..."
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).
-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.
"
chars. are removed during command-line processing - unless they're escaped as \"
.