This document provides details on how to contribute code or to prepare yourself to extend this firewall for your own needs.
- How to contribute
Here is a list of introductory material to help you get started.
It's recommended to read up to date version of this document which is located on develop
branch
here
The following two pages below explain general starting guidelines regarding open source
First step is to fork a project
Next if needed, you might want to set up your SSH
keys
The following optional tutorial may help you setting up git for PowerShell (but it's out of date)
Regarding license and Copyright practices adopted by this project see
- Maintaining file-scope copyright notices
- Requirements under U.S. and E.U. Copyright Law
- Copyright Notices
Regarding versioning adopted see
Few additional references regarding open source worth reading
For quick markdown referencesee
References for tools used by this project
It is highly recommended to stick with Visual Studio Code, because this repository includes settings specific to Visual Studio Code, aka "Workspace", these settings include:
- Code formatting settings which are automatically enforced, and can also be manually applied.
- List of recommended extensions which are automatically listed for installation once you open
repository folder with VSCode. - Debugging and code analysis settings which you can use to debug code.
- Settings for recommended extensions, ex. markdown and script formatting or code editing.
- Spelling settings which help to detect misspelled words and correct them as you type.
- Many other minor workspace settings to improve coding experience.
In addition to VSCode
and setting up git
which was already covered in introductory section
you'll need a good console setup, Windows PowerShell
is part of operating system but in addition
you want PowerShell Core
and Windows Terminal
installed.
Reason why you need Windows Terminal is because when you run it as Administrator you can create additional PS consoles (either Core or Desktop editions) without having to type Administrator password and not needing to fire up console from start menu or taskbar and then navigating to location each time.
For introduction about Windows Terminal
see Windows Terminal
For introduction about Windows PowerShell
see Windows PowerShell
To manage your GPG
keys it's highly recommended to use Kleopatra
which is part of Gpg4win
suite.
You can get it from gpg4win.org
If you don't want your computer to be testing ground and subject to potential problems you'll also want to set up virtual machine, suggested virtual machine is Hyper-V
When you open up repository with VSCode the following extensions will be suggested for installation.
It's highly recommended to install them to have a good and stressless coding experience.
-
Automatic scrolling of log files, useful to tail firewall logs.
This extension complementsLog File Highlighter
extension below. -
Helps you to bookmark various places in code to easily navigate choke points of interest.
-
Helps to spell words correctly, you get a list of misspelled words in VSCode and fix them, you also get suggestions to fix words as you type.
-
Filter log files according to json config, string or regex pattern.
-
Helps to detect gremlins (bad chars), which cause issues such as unable to save file in
UTF-8
format -
Provides support for
INI
files, ex. document outline in VSCode. -
Custom syntax highlighting for log files, useful for firewall logs as an alternative of
mTail
.
This extension complementsAuto Scroll
extension above. -
Provides markdown language support such as document formatting and generating table of contents.
-
Helps to write better markdown, you get a list of problems in VSCode and fix them.
-
PowerShell syntax highlighting, intellisense, formatting and other language support.
-
Firewall rules can be exported into
CSV
file, this extension provides syntax highlighting forCSV
files. -
Lets you use any remote machine with a SSH server as your development environment.
-
This extension complements the
Remote - SSH
extension with syntax colorization, keyword intellisense, and simple snippets when editing SSH configuration files. -
View a list of remote machines for
Remote - SSH
in action bar. -
Shows the count of selected lines in status bar.
-
Sorts the keys in selected JSON objects or entire file according to desired criteria.
-
Let's you sort lines in file according to desired criteria.
-
Required to easily navigate
TODO
,HACK
,NOTE
and similar tagged comments located in source files. -
Toggle single quotes to double quotes or vice versa.
-
Highlight trailing spaces and delete them in an instant.
-
Provides xml language support, can also help to detect issues with xml files.
-
Provides yaml language support, can also help to detect issues with yaml files.
Once your environment is set, next step is to visit Config\ProjectSettings.ps1
located in repository root directory, at a minimum you should set the following variables to $true
before doing anything else:
Develop
ProjectCheck
ModulesCheck
ServicesCheck
ErrorLogging
WarningLogging
In addition verify the following variables are set to desired user
DefaultUser
TestAdmin
TestUser
Note that some of these may be auto adjusted after setting Develop
variable to $true
Then restart PowerShell and run .\Deploy-Firewall.ps1 -Force
to deploy firewall, or at least run
Initialize-Project
function which will prompt you to perform recommended and required checks.
Detailed description of variables is located in Config\ProjectSettings.ps1
Once environment is intialized $ProjectCheck
variable should be disabled, logging variables can be
disabled too.
If you don't have this environment setup, you'll have to do this some other way around for your code editor and the rest of environment.
It is recommended to also enable specific development features in Windows which you can find in:
Settings -> Update & Security -> For Developers
, there under File Explorer
apply all settings.
This workspace includes code formatting settings, which means you don't have to spend time
formatting source files manually, otherwise it's enough to right click into any source file and
select Format document
.
Lines should be kept within 100-120 columns, however it is not always practical, so it's not a hard rule, workspace settings are configured to show rulers in code editor.
If you use some other code editor it's recommended you configure it according to these rules which
are found in .vscode
and Config
directories.
The following link explains the must know style guidelines to write functions and commandlets
The following link describes general rules about PowerShell code style if you like reading, however keep in mind, it's not completely in line with this repository best practices
The following links may help with exception and error handling:
Use risk mitigation features if applicable for functions that you write, see Remarks
sections on
the links below to understand how to implement ShouldProcess
and ShouldContinue
:
Not everything is automatically formatted, in short:
Use PascalCase for variables, types, symbols etc. and lowercase for language keywords,
for more information about type casing run:
[PSCustomObject].Assembly.GetType("System.Management.Automation.TypeAccelerators")::get.GetEnumerator() | Sort-Object Key
Use the following command to see allowed verbs to name your functions
# PowerShell Core
Get-Verb | Select-Object Verb, Group, Description | Sort-Object Verb
# Windows PowerShell
Get-Verb | Select-Object Verb, Group | Sort-Object Verb
For function nouns prefer one word or maximum three (distinguished by uppercase letters) for example:
Invoke-Process
Get-SqlServer
Sometimes this is not possible, for example Get-SqlServer
function may collide with existing
PowerShell commandlets, in this case it's better to use three words rather than naming your function
to something that doesn't describe it's purpose, ex. Get-SqlServerInstance
would be fine too,
although such exceptions should be rare.
Noun word must be singular not plural, regardless if input or output is an array of objects.
For more information about naming see Naming Convention
All scripts use the same code style, it's recommended to take a look at the existing scripts and figure out.
Code and comments in scripts are put into "sections" which depends on script and purpose, in the following way and may be different if applicable:
- License notice
PSScriptInfo
comment (if it's script file)- Comment based help
- Initialization (ex. imports of modules and scripts)
- User input
- Script local variables (ex. default installation directories)
- Removal of exiting rules / Unit test startup etc..
- Rules / functions / code etc..
Each firewall rule uses the same order of parameters split into the same number of lines.
This is so that when you need to change or search for something or do some regex magic then it's
easy to see where stuff is and it's easy to use advanced search/replace or multicursor tricks.
Performing regex operations on firewall rules in combination with multicursor feature can be done in a matter of minutes, without this strict rule design it would take an entire day and might result in bugs or random issues.
Repository contains several custom modules of various purpose, module functionality is grouped by relevance on what the module is supposed to expose.
Try to limit dependency on 3rd party modules and module code.
If needed existing modules can be extended or new written without introducing dependencies or new
languages.
Only if this is not enough we can try to look for 3rd party modules which could be easily customized without too much change or learning curve.
3rd party module scripts or functions should be included into existing modules as scripts instead of copy pasted into existing code directly, this must be so, to easily see to which file does license and Copyright apply.
Exception to this rule are complete modules (larger portion of code) which should retain their directory domain and content within repository.
Most important is to keep each function in it's own script, separated into Public/Private folders, this is required for reasons:
- To perform tests on private functions without exporting them from module
- For organizational purposes, to make it easy to maintain and navigate module functions.
Module naming convention is simple:
Ruleset.ModulePurpose
For example:
Ruleset.ComputerInfo
Ruleset.Utility
PSScriptAnalyzer is used to perform basic code quality analysis.
VSCode workspace includes static analysis settings file, so all you have to do is cd
into project
root directory and invoke analyzer as follows:
Invoke-ScriptAnalyzer -Path .\ -Recurse -Settings Config\PSScriptAnalyzerSettings.psd1 |
Format-List -Property Severity, RuleName, RuleSuppressionID, Message, Line, ScriptPath
Config\PSScriptAnalyzerSettings.psd1
settings file includes all rules, including code formatting
rules.
If you get an error such as:
Invoke-ScriptAnalyzer: Object reference not set to an instance of an object.
then try again and keep repeating until OK, or cleanup repository and restart VSCode.
There is also a script Test\Invoke-CodeAnalysis.ps1
which you can run to invoke code analysis with
additional options such as logging results to file.
Documentation and comments reside in six places as follows:
Sections of code should be documented as shown in existing scripts.
To comment on things that need to be done add TODO:
tag + comment,
similarly for important notes add NOTE:
tag + comment.
For things which are hard to resolve or require huge changes add HACK:
tag + comment,
if you're pasting Microsoft's documentation add MSDN:
tag and optionally a link to source.
similarly if you're pasting documentation from non Microsoft site add DOCS:
tag + copied comment.
Links to github issues should be prefixed with ISSUE:
tag which help to resolve problems in the future.
These tags are colored in editor and can be navigaged with todo-tree
extension in action bar,
for a complete list of tags and their purpose and coloring scheme see .vscode\settings.json
file.
For any generic code comments you might want to add, use line comments (preferred) and block comments only if comment spans five or more lines.
It is important that each firewall rule contains good description of it's purpose, when a user clicks on rule in firewall GUI she\he wants to see what this rule is about and easily conclude whether to enable/disable rule or allow/block network traffic.
In general regarding firewall rules, provide documentation and official reference for your rules so that it can be easy to verify that these rules don't contain mistakes, for example, for ICMP rules you would provide a link to IANA with relevant reference document.
Every script that's being executed either directly or called by other script will not run
until a user accepts the prompt to run the script.
Similar prompts may appear at various points in code during execution.
Each of these prompts have ?
mark option which a user can type to get more information about
prompt choices.
Functions ShouldProcess
and ShouldContinue
do not support customizing command line help, for
that reason there is Approve-Execute
function which allows you to customize prompt help.
Functions that are part of a module or solo scripts must have comment based help.
Purpose of comment based help is for the end user or developer to learn what the code does or to be
able to run Get-Help
on target function, script or module.
For examples, and comment based syntax see:
You must avoid the following comment based content to avoid errors and unexpected output while generating online help (markdown) files:
.LINK
entries must contains only one link and nothing else.- Do not use multiple dashes in comments such as
------
. - Use spaces instead of tabs and do not indent comments.
- Code samples in
.EXAMPLE
portion must not be separated by blank lines except for sample output - To number out things use
-
and keep one line between comment and listed things. - For anything else keep in mind that your comment based help will be formatted in the resulting markdown file as markdown not as you type it, which may give unexpected results.
For more information see also PlatyPS.schema
The Scripts\Utility
directory contains Update-HelpContent.ps1
which when run will scan comment
based help and generate online markdown documentation for Get-Help -Online
and help content for
Update-Help
on target module.
Purpose of the generated markdown module documentation is that project users and repository visitors
can read module documentation on github site either manually or with Get-Help -Online
Update-HelpContent.ps1
script is not perfect and requires additional editing of help files once
documentation is regenerated, diff tool in VSCode is essential to finalize generated files manually.
The docs
directory in repository root contains random documentation that covers wide range of
aspects such as troubleshooting, todo list, FAQ, changelog and general project documentation.
docs
directory is also the root directory for web site of this repository
Remember, documenting code and features is as important as writing code!
It is important that a rule is very specific and not generic, that means specifying protocol, IP addresses, ports, system user, interface type and other relevant information.
For example just saying: allow TCP outbound port 80 for any address or any user or no explanation what is this supposed to allow or block is not acceptable.
Each function should have it's own unit test and each test should cover as much code/test
cases as possible, making changes to exiting code can then be easily tested.
If test case/concept expands to several functions or if it's completely
unrelated to functions it should be a separate test.
All tests reside in Test
directory which contains subdirectories for each module,
take a look there for examples.
Few pester tests are located in some module directories.
Pester is preferred method to write tests, however those non pester tests are not just custom tests,
but they are also used by debugger configuration to debug code for which pester isn't a solution.
Also some test cases need other ways around, or more customized setup, for example sometimes you
want to see the representation of errors or the actual output for which pester also isn't a solution.
There is a module called Ruleset.Test
, which is customized for this repository, the reason why
pester isn't used as much is that I just didn't have enough time and will to learn it.
Tests must pass both Desktop and Core editions of PowerShell on multiple Windows editions to be successful.
To test code on different OS editions you should use Hyper-V and set up virtual machines, there is
experimental script called Initialize-Development.ps1
which will attempt to set up git, gpg, ssh,
update or install missing modules and start required system services.
It's recommended to do this manually because this script is unfinished.
A hint to quickly run any function from any module in this repository is to run the following command in ex. integrated terminal in VSCode (assuming PowerShell prompt is at project root):
.\Modules\Import-All.ps1
This will import all repository modules at once.
Debugging Windows Firewall Ruleset
consists of two parts, debugging code and auditing firewall
rules.
Precondition to debug code is to run VSCode
as Administrator because majority of scripts and
module functions perform administrative tasks which requires elevation.
There is workspace debugging configuration for each module function and script in repository which
you can access from Run and Debug
badge in action bar, at the top is a drop down list listing
module functions and scripts sorted alphabetically.
These configurations actually run unit tests from Test
directory, you can set breakpoints in
referenced module function or script if desired and click Start Debugging
button.
The debugging configuration itself is located in .vscode\launch.json
file.
For more information on how to debug see the following links:
There are few good reasons why would you wish to debug to wild, such as:
-
A function or script you wish to debug is not configured or appropriate for debugger or there is no unit test which would call module function or script.
-
A function or script is relatively simple or there is no space for mistakes to appear.
-
You want testing procedure to go faster and immediately affecting target system.
-
You prefer running code in the console as Administrator and\or do everything else as standard user.
Here are recommendations if you whish to debug code without using debugger:
-
Use
Write-Debug
andWrite-Verbose
commandlets in your code to see what the code is doing, this is much faster and sometimes more useful and informative than stepping trough code. -
Run PS as Admin and copy commands which you wish to test out of code editor into the console, this is much more practical than stepping trough code because you can handle various scenarios by simply modifying variables and using console history to repeat steps.
-
In
Config\ProjectSettings.ps1
debug and verbose preferences can be set in single place and entire repository is affected, you don't even have to restart PS or reimport modules when$Develop
variable is set because each run of some scripts gives you fresh environment for testing.
Some variables are however exception to this and will require restart of PS. -
For deployment testing or testing which affects firewall or system configuration on your host simply set up multiple Hyper-V guest systems attached to external switch (NIC) and optionally map your repo from host to guest system.
For remoting tests Hyper-V guest on same subnet and mapped drive proves most useful since you neither need additional hardware nor do you affect your host system.
The most efficient and safe method to debug and test code is to use Remote-SSH
extension in
combination with virtual machine, this process consists of the following:
- Set up Hyper-V, install a new guest system and enable
OpenSSH
SSH server in optional features in the guest system. - clone
WindowsFirewallRuleset
into your VM, for this you'll need git and other development environment setup configured in VM. - Edit
Config\SSH\sshd_config
file and update parameters with correct values as needed. - Copy your edited
Config\SSH\sshd_config
in the guest system into%ProgramData%\ssh
- Restart
OpenSSH
SSH service to pick up copied configuration and set it to automatic startup - Make sure you install VSCode in virtual machine which will provide server services for
Remote SSH
- On your host system create a new SSH key that will be used for
Remote-SSH
extension and put it into your your$HOME\.ssh
directory - On your host system edit
Config\SSH\config
file and update parameters with correct values as needed. - On your host system copy editted
Config\SSH\config
file into your$HOME\.ssh
folder - On your host system restart
OpenSSH client
service to pick up your config file. - Fire up PowerShell console and cd into
WindowsFirewallRuleset
then run:
.\Modules\Import-All.ps1
# Update UPPERCASE parameters of the command below:
Publish-SshKey -Domain VM_GUEST_NAME -User VM_ADMIN -System -Key $HOME\.ssh\YOUR_KEY.pub
Next step is to add the following settings into your VSCode user settings which is found in:
%UserProfile%\AppData\Roaming\Code\User\settings.json
// Extension: remote - SSH
"remote.SSH.remotePlatform": {
"REMOTE_COMPUTER_NAME": "windows"
},
// Local extensions that actually need to run remotely (will appear dimmed and disabled locally)
// This are all workspace recommended extensions excluding remote SSH which should be omitted:
"remote.SSH.defaultExtensions": [
// cSpell:disable
// AutoScroll
"pejmannikram.vscode-auto-scroll",
// Bookmarks
"alefragnani.bookmarks",
// Code Spell Checker
"streetsidesoftware.code-spell-checker",
// Filter Line
"everettjf.filter-line",
// Hightlight Bad Chars
"wengerk.highlight-bad-chars",
// Ini for VSCode
"DavidWang.ini-for-vscode",
// Log File Highlighter
"emilast.logfilehighlighter",
// Markdown All in One
"yzhang.markdown-all-in-one",
// markdownlint
"davidanson.vscode-markdownlint",
// PowerShell
"ms-vscode.powershell",
// Rainbow CSV
"mechatroner.rainbow-csv",
// Select Line Status Bar
"tomoki1207.selectline-statusbar",
// Sort JSON objects
"richie5um2.vscode-sort-json",
// Sort Lines
"Tyriar.sort-lines",
// Todo Tree
"gruntfuggly.todo-tree",
// Toggle Quotes
"BriteSnow.vscode-toggle-quotes",
// Trailing Spaces
"shardulm94.trailing-spaces",
// XML
"redhat.vscode-xml",
// YAML
"redhat.vscode-yaml"
// cSpell:enable
]
Now restart VSCode on your host system and in Remote Explorer
in VSCode you'll find an option
to open VSCode to remote host, once you connect select WindowsFirewallRuleset
to be your default
remote directory for connection.
At this point you can run code on remote host in VSCode from your host either in a new VSCode window or in same window.
However to run scripts or functions which require elevation you'll need to run VSCode as Administrator and configure before mentioned steps for your Admin account on host system.
Secondary aspect of debugging is auditing firewall rules and networking issues which may or may not be as cool or as easy as debugging code.
First step is to get confortable with all the tools and methods described in MonitoringFirewall.md which will help to monitor firewall.
How do you proceed from that point on depends on firewall rules you're auditing or the kind of networking problems that you're trying to resolve.
Push commits that solve or improve single or specific problem, to reduce merge conflicts and
to be able to do git revert
easily if needed.
Do not wait too much to push changes which only contributes to less clear intentions in terms of what issue is supposed to be resolved or which component was improved.
If you spot something unrelated that could be resolved or improved, put TODO
comment, don't fix it.
Then once you commit, open todo-tree
to review what to do next.
Avoid making huge changes to existing code without consultation, new code and additions should not problem though.
At the moment focus is on Windows Firewall, if you want to extend code base to other firewalls or operating systems go ahead, it surely won't be easy!
If you decide to do so it is mandatory that these code additions are done on separate branch, which
should then be regularly maintained up until you are done.
And only when done it could be merged with develop branch for new changes.
It is desired to expand this project to manage nftables firewall on linux and other systems, but this likely won't happen any time soon unless more people get involved into this project.
Inside Templates
directory there are few template scripts as a starting point.
Copy them to target location, update starting code and you're ready to start working.
These templates are always up to date for current rule design, code and formatting style in this repository.
Please keep in mind that a portion of existing code is not in line with all the guidelines described
here, significant portion of code was written before this CONTRIBUTING.md
file even existed.
So it's an ongoing effort that by no means gets fulfilled.
It's recommended to take a look into TODO list and also use todo-tree
extension to see more specific or smaller todo's, unless you have specific ideas or recommendations.
You might find all these guidelines described here too much to chew and that I could understand.
Please run git log --reverse
search for commit hash and see for yourself how horrible my knowledge
of PowerShell was and perhaps still is, when I started all I knew is how to open the console but
not a single command was known to me, I'm not system admin and this is my first PowerShell project,
all these guidelines described here is what I learned on my own mistakes over time and by reading
various guidelines and documentation online, carefully updating this file with new knowledge and
still learning new stuff.
You might hate pascal case for ex. and a lot of coders don't like it either and there is surely a bunch of things to disagree with but that's the style used in this repository.
Knowing this I don't expect you follow all of this immediately but I expect you to be pedantic, explicit and to seek writing quality code.
If you're PowerShell begginner like I was you're most welcome as long as you're interested in
IT security and willing to read the docs online for anything you don't know.
Otherwise if you're expert that would be great because there is a lot to do and I could surely learn
something from you.
Suggestions regarding coding style and practices are welcome, I might consider changing my mind.