PowerShell module that registers Linux, macOS, FreeBSD, and any non-Windows server as real computer objects in Active Directory -- complete with OS name and version in the standard AD properties. Includes a self-registration agent that non-Windows systems can install to announce themselves automatically.
Non-Windows servers are invisible in AD. You open ADUC to find a server, it's not there, and 10 minutes later you figure out it's a Linux box that was never joined to the domain. Or you need to check a macOS build machine, but it doesn't exist in AD because macOS doesn't domain-join in any useful way. Or your FreeBSD firewall, your Solaris database, your AIX backend -- none of them show up alongside your Windows servers.
Every mixed-environment admin has been there. AD is the natural place to see all your servers, but anything that isn't Windows just doesn't show up. And even when someone manually creates a computer object, the operatingSystem and operatingSystemVersion fields are blank -- so the object is there but tells you nothing useful.
You run PowerShell commands from a Windows admin workstation to register servers manually or via CSV import. This is the original v1.0 workflow.
# Register a single server
Register-LinuxServer -Name "web-prod-01" -IPAddress "10.1.2.50" -OperatingSystem "Ubuntu 24.04.1 LTS" -OperatingSystemVersion "24.04.1"
# Bulk import from CSV
Import-LinuxInventory -CsvPath .\linux-servers.csvThe non-Windows box installs a lightweight shell agent and announces itself. The agent detects its own OS, collects system info (hostname, IPs, CPU, memory, disk, services, packages), and drops a JSON file on a shared folder. The PowerShell side picks it up and creates the AD object automatically.
One-liner install on any Linux box:
curl -sL https://raw.githubusercontent.com/larro1991/AD-LinuxInventory/master/agent/install.sh | sudo sh -s -- \
--share '//fileserver/registrations$' \
--token 'your-shared-secret'The agent runs hourly as a cron job (or launchd on macOS), keeping the AD record up to date with current IPs, uptime, and a "last seen" timestamp. No listening ports, no inbound connections, no SSH keys required.
When a macOS machine registers itself, ADUC shows:
Name: MACBOOK-DEV-01
Operating System: macOS 15.2 Sequoia
Operating System Version: 15.2
IPv4 Address: 10.1.4.30
Description: macOS | 10 cores | 16GB RAM | Last seen: 2026-02-17T10:30:00Z
Same for Linux:
Name: WEB-PROD-01
Operating System: Ubuntu 24.04.1 LTS
Operating System Version: 24.04.1
IPv4 Address: 10.1.2.50
Description: Linux | 8 cores | 32GB RAM | Last seen: 2026-02-17T10:30:00Z
FreeBSD:
Name: FIREWALL-01
Operating System: FreeBSD 14.1-RELEASE
Operating System Version: 14.1
IPv4 Address: 10.1.7.1
Description: FreeBSD | 4 cores | 8GB RAM | Last seen: 2026-02-17T10:30:00Z
| OS Family | Examples | Detection Method |
|---|---|---|
| Linux | Ubuntu, Debian, RHEL, CentOS, Rocky, Alma, SUSE, Fedora, Arch, Alpine | /etc/os-release, /etc/redhat-release |
| macOS | Ventura, Sonoma, Sequoia | sw_vers |
| FreeBSD | FreeBSD 13.x, 14.x | freebsd-version |
| Solaris/illumos | Solaris 11, OmniOS, SmartOS | /etc/release |
| AIX | AIX 7.x | oslevel |
| Other Unix | OpenBSD, NetBSD, HP-UX | uname -s/-r |
curl -sL https://raw.githubusercontent.com/larro1991/AD-LinuxInventory/master/agent/install.sh | sudo sh -s -- \
--share '//fileserver/registrations$' \
--token 'your-shared-secret'curl -sL https://raw.githubusercontent.com/larro1991/AD-LinuxInventory/master/agent/install.sh | sudo sh -s -- \
--share '//fileserver/registrations$' \
--token 'your-shared-secret'fetch -o - https://raw.githubusercontent.com/larro1991/AD-LinuxInventory/master/agent/install.sh | sudo sh -s -- \
--share '//fileserver/registrations$' \
--token 'your-shared-secret'Before agents can deliver their registrations, create a Windows file share:
- Create a folder, e.g.,
C:\Registrations - Share it as
registrations$(the$makes it a hidden share) - Grant write access to the service account or allow anonymous writes for the agent
- Point agents to the share with
--share '//fileserver/registrations$'
Alternatively, use --endpoint to POST to an HTTPS endpoint instead of SMB.
| Option | Description |
|---|---|
--share PATH |
SMB share path (e.g., //fileserver/registrations$) |
--endpoint URL |
HTTPS endpoint URL for JSON POST delivery |
--token SECRET |
Shared secret for authentication |
--ou NAME |
Target OU name (default: Non-Windows Servers) |
--smb-user USER |
SMB username for authenticated shares |
--smb-domain DOM |
SMB domain for authenticated shares |
--uninstall |
Remove the agent and all configuration |
sudo sh /path/to/install.sh --uninstall
# or
sudo sh /path/to/uninstall.shPre-built packages are available for major platforms. Download from the Releases page or use a package manager directly.
wget https://github.com/larro1991/AD-LinuxInventory/releases/latest/download/ad-register_2.0.0_all.deb
sudo dpkg -i ad-register_2.0.0_all.debwget https://github.com/larro1991/AD-LinuxInventory/releases/latest/download/ad-register-2.0.0.noarch.rpm
sudo rpm -i ad-register-2.0.0.noarch.rpmbrew tap larro1991/tools
brew install ad-registerAfter installing via any package manager, copy the example config and run the agent:
sudo cp /etc/ad-register/config.conf.example /etc/ad-register/config.conf
sudo nano /etc/ad-register/config.conf
sudo ad-registerSee packaging/README.md for full details on all package formats, building packages locally, and uninstalling.
# Process all pending registrations (auto-approve new entries)
Import-AgentRegistration -RegistrationPath '\\fileserver\registrations$' -Token 'your-shared-secret' -AutoApprove
# Process with manual confirmation for new systems
Import-AgentRegistration -RegistrationPath '\\fileserver\registrations$' -Token 'your-shared-secret'
# Check heartbeat status
Get-RegistrationHeartbeat -RegistrationPath '\\fileserver\registrations$' -StaleHours 2 -OfflineHours 24
# Generate an HTML heartbeat dashboard
Get-RegistrationHeartbeat -RegistrationPath '\\fileserver\registrations$' -OutputPath .\heartbeat-report.html| Function | Purpose |
|---|---|
Register-LinuxServer |
Manually create an AD computer object for any non-Windows server |
Import-LinuxInventory |
Bulk import from CSV |
Get-LinuxInventory |
List all registered servers with optional ping status |
Update-LinuxServer |
Update properties on existing entries |
Sync-LinuxInventory |
Ping all servers, stamp last-seen timestamps |
Import-AgentRegistration |
NEW -- Process self-registration JSON files from the agent |
Get-RegistrationHeartbeat |
NEW -- Monitor which systems are actively checking in |
Import-Module .\AD-LinuxInventory.psd1
# Register a single server
Register-LinuxServer -Name "web-prod-01" -IPAddress "10.1.2.50" -OperatingSystem "Ubuntu 22.04 LTS" -Description "Production web server"
# Bulk import from CSV
Import-LinuxInventory -CsvPath .\linux-servers.csv
# See everything with online status
Get-LinuxInventory -Online | Format-Table
# Sync and stamp descriptions
Sync-LinuxInventory -UpdateDescriptionRegister a server:
Name : WEB-PROD-01
DNSHostName : web-prod-01.contoso.com
IPv4Address : 10.1.2.50
OperatingSystem : Ubuntu 22.04 LTS
Description : Production web server
ManagedBy :
Status : Registered
Get inventory with ping status:
Name IPv4Address OperatingSystem Description Online ResponseTime
---- ----------- --------------- ----------- ------ ------------
WEB-PROD-01 10.1.2.50 Ubuntu 24.04.1 LTS Production web server True 2
MACBOOK-DEV-01 10.1.4.30 macOS 15.2 Sequoia macOS dev workstation True 3
DB-PROD-01 10.1.3.10 RHEL 9.3 Production PostgreSQL True 1
FIREWALL-01 10.1.7.1 FreeBSD 14.1-RELEASE Border firewall True 1
MONITOR-01 10.1.5.20 Debian 12 Grafana + Prometheus True 4
LEGACY-APP-01 10.1.4.100 CentOS 7 Legacy CRM application False
Heartbeat status:
ComputerName OperatingSystem Status HoursSinceHeartbeat
------------ --------------- ------ -------------------
WEB-PROD-01 Ubuntu 24.04.1 LTS Active 0.3
MACBOOK-DEV-01 macOS 15.2 Sequoia Active 0.5
DB-PROD-01 RHEL 9.3 Stale 4.2
FIREWALL-01 FreeBSD 14.1-RELEASE Offline 48.1
LEGACY-APP-01 CentOS 7 Never
Agent registration import summary:
RegistrationPath : \\fileserver\registrations$
Processed : 5
NewRegistrations : 2
Updated : 2
Rejected : 1
Errors : 0
HTML Dashboard:
See Samples/sample-report.html for the full dark-themed dashboard with online/offline indicators.
Name,IPAddress,OperatingSystem,OperatingSystemVersion,Description,ManagedBy
web-prod-01,10.1.2.50,Ubuntu 24.04.1 LTS,24.04.1,Production web server,jsmith
web-prod-02,10.1.2.51,Ubuntu 24.04.1 LTS,24.04.1,Production web server,jsmith
db-prod-01,10.1.3.10,RHEL 9.3,9.3,Production PostgreSQL primary,mgarcia
macbook-dev-01,10.1.4.30,macOS 15.2 Sequoia,15.2,Developer workstation,achen
firewall-01,10.1.7.1,FreeBSD 14.1-RELEASE,14.1,Border firewall,bwilson
monitor-01,10.1.5.20,Debian 12,12,Grafana + Prometheus monitoring,achenFrom PSGallery (when published):
Install-Module AD-LinuxInventoryManual / git clone:
git clone https://github.com/larro1991/AD-LinuxInventory.git
Copy-Item -Path .\AD-LinuxInventory -Destination "$env:USERPROFILE\Documents\PowerShell\Modules\" -Recurse- PowerShell 5.1+
- ActiveDirectory module (RSAT)
- Permission to create computer objects in the target OU
- ICMP access to servers (for
-OnlineandSync-LinuxInventory) - For agent self-registration: a Windows file share or HTTPS endpoint
- Real computer objects, not contacts -- The servers show up as actual computer icons in ADUC. Group Policy won't target them (they're not domain-joined), but they're visible in every tool that queries AD for computers. This is the right object class for inventory purposes.
- Dedicated OU keeps things organized -- Default is "OU=Linux Servers" for admin-driven registration (backward compatible with v1.0) and "OU=Non-Windows Servers" for agent-based self-registration. Separates entries from domain-joined Windows machines so you can filter or delegate permissions cleanly. The OU is auto-created on first use.
- Ping-based health check is simple and firewall-friendly -- ICMP is the lowest-common-denominator connectivity test. No agents, no SSH keys, no WinRM. The
Sync-LinuxInventoryfunction stamps the description with timestamps so you can see health at a glance in ADUC. - Agent uses /bin/sh for maximum portability -- The agent scripts avoid bash-specific features and run under any POSIX shell. Works on Alpine (ash), FreeBSD (sh), Solaris, AIX, and macOS without requiring bash to be installed.
- File-based delivery (SMB) is the simplest path -- The agent drops a JSON file on a Windows share. No API server to run, no database, no certificates to manage. For environments that prefer HTTPS, the agent also supports POSTing to an endpoint.
- Token-based authentication -- A shared secret prevents unauthorized registrations. New registrations can also require manual approval by omitting
-AutoApprove. - CSV import for day-one bulk load -- Most teams already have a spreadsheet of their servers somewhere. Export it as CSV, run one command, and they're all in AD.
- ShouldProcess on write operations --
Register-LinuxServer,Update-LinuxServer, andImport-AgentRegistrationsupport-WhatIfand-Confirmso you can preview changes before committing to AD.
AD-LinuxInventory/
├── AD-LinuxInventory.psd1 # Module manifest (v2.0.0)
├── AD-LinuxInventory.psm1 # Root module (dot-source loader)
├── Public/
│ ├── Register-LinuxServer.ps1 # Register a single server in AD
│ ├── Import-LinuxInventory.ps1 # Bulk import from CSV
│ ├── Get-LinuxInventory.ps1 # List registered servers with optional ping
│ ├── Update-LinuxServer.ps1 # Update server properties
│ ├── Sync-LinuxInventory.ps1 # Ping all servers, stamp descriptions
│ ├── Import-AgentRegistration.ps1 # Process agent JSON registrations (NEW)
│ └── Get-RegistrationHeartbeat.ps1 # Monitor agent heartbeat status (NEW)
├── Private/
│ ├── Initialize-LinuxOU.ps1 # Auto-create the target OU
│ └── New-HtmlDashboard.ps1 # Dark-themed HTML report generator
├── agent/ # Self-registration agent (NEW)
│ ├── install.sh # Universal installer for all Unix-like OS
│ ├── register-agent.sh # Agent script (collects info, delivers JSON)
│ ├── uninstall.sh # Clean removal script
│ └── README.md # Agent documentation
├── packaging/ # Native OS package building (NEW)
│ ├── build-packages.sh # Build .deb and .rpm via fpm
│ ├── post-install.sh # Post-install script (config template, cron)
│ ├── pre-remove.sh # Pre-remove script (cleanup cron)
│ ├── homebrew/
│ │ └── ad-register.rb # Homebrew formula for macOS
│ └── README.md # Packaging documentation
├── .github/
│ └── workflows/
│ └── build-packages.yml # CI: auto-build packages on release
├── Tests/
│ └── AD-LinuxInventory.Tests.ps1 # Pester tests
├── Samples/
│ └── sample-report.html # Example dashboard output
├── README.md
└── LICENSE
- The shared token prevents unauthorized registrations
- New registrations can require manual approval (omit
-AutoApprove) - Processed JSON files are archived to a "processed" subfolder, not deleted
- The agent runs as a cron job -- no listening ports, no inbound connections needed
- The agent config file is readable only by root (permissions 600)
- The agent script is read-only on the managed system
Invoke-Pester .\Tests\ -Output Detailed- GitHub Issues: Open an issue
- All Projects: larro1991.github.io
MIT