# ADACLScanner: auditing Active Directory ACLs from the command line

> ADACLScanner is a PowerShell script that reads DACLs and SACLs across Active Directory, filters them by permission and identity, and exports them for review or comparison over time. It suits administrators who need a repeatable read on who holds which rights rather than a one-off inspection.

**canix1/ADACLScanner** — Repo for ADACLScan.ps1 - Your number one script for ACL's in Active Directory

- Repository: https://github.com/canix1/ADACLScanner
- Stars: 1,183 · Forks: 184
- Language: PowerShell
- License: MS-PL
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/canix1-adaclscanner

## ADACLScanner answers who holds which directory rights

The problem ADACLScanner addresses is narrow and real: in a directory with years of accumulated delegation, it becomes difficult to answer simple questions about who can change a computer object, who can read a LAPS password, or who inherited an ACE nobody intended. The tool reads access control lists and system access control lists on Active Directory objects and presents the result in a report you can sort, filter and save.

It is written entirely in PowerShell and ships as a single script, ADACLScan.ps1, at the root of the repository, with a src directory alongside it. There is also a graphical mode, and the README describes both a command line and a GUI workflow. The intended user is an administrator or auditor with permission to read security descriptors, running either interactively during an investigation or as part of a repeatable review.

Two design choices make it different from a generic LDAP browser. The first is that a query is expressed through named switches such as -Permission, -PropertyFilter, -ApplyTo and -AccessType, so the same finding can be reproduced later by rerunning a command. The second is that the output is treated as a baseline. The tool can compare a previous result with the current configuration and show differences by color, with green for matching permissions, yellow for new permissions and red for missing permissions.

## A single query describes scope, depth and permission type

The scanning model rests on parameters that narrow the work in stages. -Base points at the root of the search, either a distinguished name or rootdse, and -Scope with -SearchDepth decides how deep and how far the walk goes. -ApplyTo restricts the report to object classes such as User, Computer or a wildcard for everything. -Permission names the right being tested, -PropertyFilter narrows it to a specific property, and -AccessType selects Allow or Deny entries.

The example that finds who can read LAPS passwords shows the whole chain in one line. It starts at a domain root, walks the subtree, applies to every computer object, tests for ExtendedRight, GenericAll, WriteDACL and WriteOwner, includes inherited entries, skips built-in principals, and then narrows the target properties to the three LAPS attributes.

```
./ADACLScan.ps1 -Base "DC=contoso,DC=com" -Scope subtree -ApplyTo "computer|*" -Permission "ExtendedRight|GenericAll|WriteDACL|WriteOwner" -IncludeInherited -SkipBuiltIn -LDAPFilter "(|(objectCategory=OrganizationalUnit)(objectClass=domaindns))" -PropertyFilter "msLAPS-Password|msLAPS-EncryptedPassword|msLAPS-EncryptedPasswordHistory" | ft
```

An LDAPFilter parameter accepts a custom filter for object selection, so you can constrain the search to organizational units or to a class before any permission work happens. -RecursiveFind expands group membership so that a principal nested several levels deep inside a group still shows up on an object it never received a direct grant on.

## Running from a machine outside the domain with explicit credentials

The scanner does not require the host to be joined to the domain you are auditing. The documented pattern passes -Server with the domain name and -Credentials with a credential object, which is what a consultant running a laptop from another site would use. The following example finds every principal holding a reset password right over user objects inside one organizational unit, and it includes inherited permissions.

```
./ADACLScan.ps1" -base "OU=_Test2,DC=contoso,DC=com" -Server "contoso.com" -Credentials $(get-credential) -ApplyTo "User" -PropertyFilter "Reset Password" -Permission "ExtendedRight" -AccessType Allow -IncludeInherited | ft
```

A second variant looks for write access to two custom properties called drink and audio, which is a useful illustration of how the property filter works on attributes that are not standard security descriptors:

```
./ADACLScan.ps1" -base "OU=_Test2,DC=contoso,DC=com" -Server "contoso.com" -Credentials $(get-credential) -ApplyTo "User" -PropertyFilter "drink|audio" -Permission "WriteProperty" -AccessType Allow -IncludeInherited | ft
```

Both pipe their output into the Format-Table cmdlet, so results arrive as a table in the console rather than as a raw object dump. A third documented pattern adds -RecursiveFind to list all security principals with GenericAll on computer accounts, showing both direct grants and principals nested inside any group, against the IT organizational unit:

```
./ADACLScan.ps1" -base "OU=IT,DC=contoso,DC=com"" -Server "contoso.com" -Credentials  $(get-credential) -ApplyTo "Computer" -Permission "GenericAll" -AccessType Allow -IncludeInherited -RecursiveFind
```

Note that the credential is passed to the script as an object produced by get-credential, and that the account you supply determines what the scan can actually see. A query that looks empty is not proof that no one holds the right; it may mean the operator lacks the read access needed to see it.

## The GUI adds effective rights and side by side comparison

The interactive side of the tool covers the work that is awkward from a shell. The feature list describes a browser that can connect to a default domain, the schema, the configuration partition, or any naming context given as a distinguished name, and then walk it either by organizational unit or by object type. Nodes can be refreshed by right clicking a container, and a domain can be picked from a list.

Effective rights are the part that stands out. You select a security principal and the tool matches it against the permissions in the directory, then colors the resulting rights by criticality. A summary of criticality is produced for every report type, which gives a reviewer a quick read on severity without reading every line.

Comparison is the other half. A previous scan can be loaded against the current state, and the differences are shown with a color scheme: green for matching permissions, yellow for new permissions, red for missing permissions. Replication metadata can be used when comparing, which lets a report distinguish a recent change from long standing state. The README also notes that a CSV taken from one domain can be reused against another by replacing the old distinguished name and the short domain name security principals, and that nodes missing in Active Directory are reported as "Node does not exist in AD" rather than silently dropped.

## Three output formats, and only one of them diffs cleanly

Output is where this project makes a decision that will surprise people, so it is worth being precise. The default command line output is structured and translated. The default CSV file output is also structured and translated, and the README states plainly that it cannot be used for comparing. A separate output option exists for comparison, called CSVTEMPLATE from the command line and CSV Template in the GUI. The old command line output format is still reachable through the -RAW switch.

So if you plan to build a routine that diffs one run against the next, the default CSV export is the wrong artifact. You need the template format, and you need to keep the same template across runs for the comparison to be meaningful. An older CSV can also be converted into an HTML report on its own, and the tool verifies the format of CSV files used in the convert and compare functions, warning about a malformed file rather than failing quietly.

Reports are not limited to text output. HTML reports of DACLs and SACLs can be viewed and saved to disk, with headers included. There is also an option to report only explicitly assigned entries, to skip default permissions from the default security descriptor, to report the owner of an object, to report on disabled inheritance, and to list the size of the security descriptor in bytes. The progress bar can be turned off to gain speed when producing large reports, and objects can be excluded by matching a string against the distinguished name.

## Getting the script and the Excel dependency in place

There is no package manager step and no installer script here. The README points readers to the Release page on GitHub, and the repository itself is a single PowerShell file, so obtaining ADACLScan.ps1 is a download. The current version named in the README is 9.6, dated 7 July, 2026, and the release notes for that version list a bug in returning names to SID and a bug in a function call where a parameter name was missing. A SHA256 hash is published alongside the version so a download can be checked before it is run.

One dependency is worth calling out early. The tool can save to an Excel file without Excel being installed, from the user interface and from the command line, but this requires the ImportExcel PowerShell module, which the README says can be installed directly from the PowerShell Gallery. The README does not give a one line installation command for that module, so follow the Gallery listing for ImportExcel and confirm the module is loaded in your session before expecting spreadsheet output.

The remaining requirements are the ordinary ones for this class of tool: a PowerShell environment able to talk to the directory, and an account with the rights needed to read the security descriptors you intend to query.

## Where this scanner stops short

ADACLScanner answers questions, but it does not watch. It is a script you invoke, and it produces a point in time report. There is no scheduler, no alert on a permission change, and no continuous evaluation of rights. The comparison feature is the nearest thing to monitoring, and it still depends on you running a scan and keeping the earlier file.

The comparison workflow also has hard edges that the README is direct about. If the first node in the CSV file used for comparing cannot be connected, the scan will stop. The default CSV output cannot be compared at all, so a team that has been saving default exports will find its existing history unusable for diffing until it switches to the template format.

There is also a scope limitation worth stating plainly. The tool reports what it can read. In a domain where delegation is restricted, a query for ExtendedRight can come back empty for reasons that have nothing to do with the actual configuration. The same applies to the certificate template scan: from the command line you can select a target and select RiskyTemplates to scan published certificate templates that allow a subject to supply in request, which is a genuinely useful check, but it is one specific scenario among the many that exist around template enrollment, and it is not a full certificate template audit.

Finally, the tool is Windows and PowerShell bound. There is no cross platform entry point described anywhere in the documentation, and the GUI is a Windows presentation component. That is a real constraint for teams that standardize on macOS or Linux for their tooling.

## Permission hygiene checks that fit the available filters

The available feature list points to a set of practical checks rather than a single grand report. Linked Group Policy Objects can be scanned alongside directory objects, so a scan can cover both the objects and the policy containers that shape them. The schema can be checked for modified default security descriptors, which is how a hardened default can be detected after a template has been altered. Deny entries can be isolated with the access type filter, and a specific identity can be looked up with wildcards such as jdoe when you need to know where a single account has explicit access.

Search depth is adjustable, and the documented one level search with a configurable depth looks like this:

```
./ADACLScan.ps1 -Base rootdse -SearchDepth 3 -LDAPFilter "(objectClass=OrganizationalUnit)"
```

The pipeline support is worth noting as well. A distinguished name can be piped into ADACLScan.ps1, which makes it straightforward to feed a list of objects from another tool into a permissions query rather than constructing one long command line by hand.

The last point about maintenance is about the pace of work rather than the pace of commits. The last push was on 2026-09-24, and the repository is not archived. Releases 9.4, 9.5 and 9.6 landed on 2026-01-22, 2026-05-06 and 2026-07-07, so a moderately regular line of fixes rather than a rapid release train. The project is distributed under the MS-PL licence, with the licence text held in license.md in the repository root, so anyone embedding the script in an internal pipeline should read that file and confirm what the terms ask of their redistribution.

## Conclusion

ADACLScanner fits administrators and security engineers who already have read access to a domain and want a repeatable ACL inventory, a permission query they can script, or a baseline to diff against a later scan. It does not fit people who want a live monitoring agent, a change notification feed, or a clean default report, because everything is a query you launch and the default CSV output is built for reading rather than for diffing. Before adopting it, confirm two things in your own environment: that the operators running it hold the rights the query needs, since the script reads security descriptors rather than elevating your rights, and that the ImportExcel module is present if you want spreadsheet output without Excel installed. Then run the LAPS example against one organizational unit first and read the raw rows before trusting the colors.

## FAQ

### How do I install ADACLScanner?

There is no installer: the tool is a single PowerShell file, ADACLScan.ps1, that you take from the repository root or from the Release page on GitHub. The README names version 9.6, dated 7 July, 2026, and publishes a SHA256 hash so a download can be checked before it runs. Spreadsheet export needs the ImportExcel module from the PowerShell Gallery, which is a separate installation.

### Can ADACLScanner run from a machine that is not joined to the domain?

Yes. The documented examples pass -Server with the domain name and -Credentials with a credential object, which is how the tool is used from an external host. The account you supply decides what the scan can read, so an under privileged credential can return empty results rather than an error.

### Which CSV output should I use if I want to compare two scans?

Use the comparison output, called CSVTEMPLATE from the command line and CSV Template in the GUI. The default CSV file output is structured and translated and the README states it cannot be used for comparing, while the old command line format is reachable through the -RAW switch.

### Does ADACLScanner report on SACLs and linked Group Policy Objects as well as DACLs?

Yes. The tool reports DACLs and SACLs, and scanning linked Group Policy Objects is part of the feature list. It can also filter for Deny entries, report object owners, flag disabled inheritance, and report the size of the security descriptor in bytes.

### How do I find who can read LAPS passwords with ADACLScanner?

Run a scan whose -Permission filter lists ExtendedRight, GenericAll, WriteDACL and WriteOwner, and whose -PropertyFilter names the LAPS attributes, as in the example that targets computer objects under a domain root with -Scope subtree and -IncludeInherited. The same shape of query works for reset password rights over user objects.

## Sources

- [canix1/ADACLScanner on GitHub](https://github.com/canix1/ADACLScanner)
- [Issues](https://github.com/canix1/ADACLScanner/issues)
- [License: MS-PL](https://github.com/canix1/ADACLScanner/blob/master/LICENSE)
- [README](https://github.com/canix1/ADACLScanner/blob/master/README.md)
- [Releases](https://github.com/canix1/ADACLScanner/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/canix1-adaclscanner
