Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?


Failed to load latest commit information.
Latest commit message
Commit time


The PowerShell Armoury is meant for pentesters, "insert-color-here"-teamers and everyone else who uses a variety of PowerShell tools during their engagements. It allows you to download and store all of your favourite PowerShell scripts in a single, obfuscated file.

You do not have to hassle with updating Rubeus, PowerView, ... manually. Just create a configuration file once or use the default one included with the tool. From now on, you just have to run "New-PSArmoury" before you head to the next engagement. In addition, PSArmoury obfuscates your code and comes with an included AMSI bypass. The modular design should it make it easy for you to change the evasion or obfuscation code in case there's a detection on that.

General structure

The current version of PSArmoury favours a modular design.


The code is split into a main generator script called New-PSArmoury.ps1, which is the one you execute. The code for evasion, obfuscation and deobfuscation is stored in separate .ps1 files in the modules directory. These separate files are invoked by the main script and should make it easier for you to change specific functions (like an AMSI bypass). In addition to the modules directory, there's also the utilities directory. Here you'll find standalone scripts that can be useful in specific scenarios.

The modules directory

The default path of the modules directory is .\modules where the dot refers to the current working directory of your shell. You can change the path of the modules directory by using the -ModulesDirectory argument of New-PSArmoury. The names of the script files themselves however are hard-coded in the main script and always expected to be:

  • evasion.ps1
  • obfuscation.ps1

Let's have a closer look at these two.


This script should contain the code intended to bypass whatever you intend to bypass. By default, it contains a well-known AMSI bypass (thanks Please note that:

  • the code in here runs BEFORE everything else runs (e.g. deobfuscation)
  • there is absolutely NO KIND OF VALIDATION! Everything you put here will be piped to IEX as is.


This script should contain the code used for obfuscation and deobfuscation. The default obfuscation.ps1 uses RC2 encryption. Ready-to-use examples:

  • TEMPLATE_obfuscation_RC2.ps1 --> this is the default
  • TEMPLATE_obfuscation_byte_convert.ps1
  • TEMPLATE_obfuscation_empty.ps1

Note that the TEMPLATE_obfuscation_empty.ps1 really does nothing at all and serves as a template for you to build your own function.

If you want to use any one of those, just rename it to "obfuscation.ps1" and delete the default file.

If you want to create a customized version, keep the following in mind regarding obfuscation:

  • The function name MUST always be "Get-PSArmouryObfuscation" with a single string-parameter called "Code" cause that's what the main script will call on any item you want to put in the armoury.
  • The function SHOULD return the obfuscated version of the code again as a single string value. The main code of the scripts runs an additonal base64 encode/decode loop to make sure that we can also handle other stuff you throw at it but it would be easier if you could just make it a string ;-)
  • The corresponding deobfuscation function MUST understand whatever you return here. The main script is just passing around results --> no magic happens here

And make sure to remember these things in terms of deobfuscation:

  • The function name MUST always be Get-PSArmouryDeObfuscation with no parameter since it itterates over a fixed, global variable.
  • The function MUST return the deobfuscated version of the code again as a single string value, ready to execute. We are just piping everything you return into IEX so the rest is up to you.

The utilities directory

The utilities directory contains useful standalone scripts.

  • ConvertTo-Powershell.ps1
  • Invoke-Shuffle.ps1
    • A simple obfuscation script that converts a single line of code into multiple variables holding parts of the original string that are then merged and invoked during execution.

Config reference

The config file needs to be a valid json that consists of a single array with one or more objects, where every object is interpreted as a single script source. Every object has the following attributes

Name (Mandatory)

A name of your choice to identify the script included in this object. This is just meant as a reference for yourself.

URL (Mandatory)

The location to get the script content from. This can be a URL to a web resource (https://) or a local path (C:) or a network resource (\...). The URL is thrown into Net.Webclient or Powershells Get-Item respectively. So basically every format that one of those two can handle by default should work.

Type (Mandatory)

This gives a hint about the script location to the armoury creator. There are three valid types:

  • GitHub
    • Will prompt for credentials so we can authenticate against the github API. Will also try to distinguish between a "raw" URL that directly poins to a file or a URL that points to a repository. If the URL points to a repository, the script will automatically search all Powershell files in that repository and include them. Like ""
  • WebDownloadSimple
  • LocalFile
    • A file on disk like "C:\temp\test.ps1". If the path points to a directory, all files (recursive) with the extension ".ps1" will be included.

FileInclusionFilter (Optional)

Will only be interpreted in an object of type "GitHub". Will be matched with Powershells "like" comparison operator against the whole filename so keep in mind that you need to include the wildcards yourself. Don't forget to include a star (*) if you want to match part of a filename. "*.ps1" means all files that end with ".ps1" but ".ps1" just means ".ps1".

You don't have to include a filter but if you do, you have to use it. An empty InclusionFilter means no files.

FileExclusionFilter (Optional)

Like the InclusionFilter but obviously the other way round. Exclusion takes precedence.


See inline Powershell help (man -full New-PSArmoury) for more details.


The path to your new armoury file. The default ist ".\MyArmoury.ps1"


Load your Powershell scripts directly from a local folder or file and you don't have to provide a config file.


The path to your JSON-config file. Have a look at the sample that comes with this script for ideas.


The path to the modules directory. The default is ".\modules". If ModulesDirectory is used, then the EvasionPath and ObfuscationPath Parameters cannot be used.


The path to the evasion script. If EvasionPath and ObfuscationPath are used, then the ModulesDirectory-Parameter cannot be used.


The path to the obfuscation script. If EvasionPath and ObfuscationPath are used, then the ModulesDirectory-Parameter cannot be used.


Use this together with "-Config" to let the script validate the basic syntax of your JSON config file without executing it.


Pass Github username and access token as a credential object so the script won't prompt for it. Useful if you create an armoury repeatedly for testing.

Use like this:

$c = get-credential
New-PSArmoury -GithubCredentials $c

Github access token

You have to provide a valid github username as well as a personal access token, so the script can properly use the github API. Do not use username/password since this will not work anyway if you have MFA enabled (and you should enable MFA). Also accessing the API with basic username/password is deprecated.

Follow this guide to create a personal access token.

Please note: the only permission we need on the access token is public_repo in the repo section.

This is because you only need the token so Github won't block us if you parse larger repositories (like PowerSploit) for .ps1 files to include.

Example usage

Example 1 - All default

If you want to create an armoury with default settings (note: this will not obfuscate at all besides base64 encoding), then just run the following.

. .\New-PSArmoury.ps1

This will create a .ps1 file called "MyArmoury.ps1" in the current working directory using

  • the default config ".\PSArmoury.json"
  • the default AMSI bypass found at ".\modules\evasion.ps1"
  • the default obfuscation/deobfuscation (base64) found at ".\modules\obfuscation.ps1" and ".\modules\deobfuscation.ps1" respectively.

You can load the armoury into your current session by using

cat -raw .\MyArmoury.ps1 | iex

Loading your armoury invokes the following steps:

  • Invoke evasion code
  • Hand over control to the deobfuscation function which in turn should
  • Go over every obfuscated item and
    • deobfuscate
    • pipe into IEX

After that, all powershell code you put in the armoury will be available. Just invoke the cmdlets as usual like this

Invoke-Rubeus -Command "kerberoast /stats"
Get-DomainGroupMember -Identity "Domain Admins" -Recurse

If it happens that you don't remember what you put inside the armoury, just load it and call the inventory :-)


Example 2 - Use the byte-convert/json-format obfuscation technique that comes with PSArmoury and different config file

Start New-PSArmoury with the -EvasionPath and -ObfuscationPath Parameters like this:

New-PSArmoury -Config C:\myarmouryconfig.json -ObfuscationPath .\modules\TEMPLATE_obfuscation_byte_convert.ps1 -EvasionPath .\modules\evasion.ps1

Example 3 - Create an armoury from a local folder containing powershell scripts

Note: in this case, all .ps1 files in the folder will be added since we submit a folder path. If we submit the path to a single file, then only that file we be processed.

New-PSArmoury -FromFile C:\myscriptfolder