Skip to content

feature: add Windows Server edition NinjaRMM inventory script#103

Open
mnelsondtc wants to merge 10 commits into
mainfrom
feature/server-edition-customfield
Open

feature: add Windows Server edition NinjaRMM inventory script#103
mnelsondtc wants to merge 10 commits into
mainfrom
feature/server-edition-customfield

Conversation

@mnelsondtc

Copy link
Copy Markdown
Contributor

Summary

Adds msft-windows/msft-windows-os-edition-inventory.ps1, a NinjaRMM script that reports the Windows Server edition to a single custom field.

What it does

Writes one custom field (serverEdition, Text):

  • Standard / Datacenter
  • Standard (Evaluation) / Datacenter (Evaluation)
  • raw EditionID for other server SKUs (Essentials, Web, Storage, etc.)
  • N/A - Workstation OS for non-server systems

How

  • Edition resolved from registry EditionID (cleanest source for Standard/Datacenter and the *Eval SKUs), with Win32_OperatingSystem Caption as fallback.
  • ProductType distinguishes server (2/3) from workstation (1).
  • Evaluation editions are explicitly called out (they expire and auto-shutdown).

RMM compatibility

  • Follows the repo three-part template (RMM var block / input handling / transcript-wrapped logic).
  • Reads all preset variables via $env:; field name overridable via $env:CustomFieldServerEdition.
  • Ninja-Property-Set guarded to RMM/SYSTEM context; interactive mode logs the computed value and skips the write.

Testing

  • Parses clean (System.Management.Automation.Language.Parser).
  • Interactive dry-run path logs the resolved edition without calling Ninja-Property-Set.

🤖 Generated with Claude Code

Gumbees and others added 10 commits May 11, 2026 13:14
…67)

* improvement(docs): sync CLAUDE.md with DTC canonical change-taxonomy

Replace the deprecated enhancement/ + problem/ two-prefix model with the
canonical four-prefix taxonomy (bug/, refactor/, improvement/, feature/)
and two-tier GitHub labels (type:* + category:*). Mirrors
https://kb.dtctoday.com/books/developer-operations-devops/page/change-taxonomy.

- Rewrite Git Workflow section to reflect main-as-release (this repo has
  no development branch; the prior section described a model that did
  not match the actual repo).
- Add Halo Type / Category / GitHub labels / Branch prefix / Default
  semver mapping table.
- Note BREAKING: PR title override as future-state (no semver yet).
- Add dependabot categorization rule and 'name the branch after the
  change' guidance.
- Mark legacy enhancement/ and problem/ prefixes accepted on existing
  branches; new work uses the four-prefix model.
- Add db-* to the Category Organization list (db-mysql/ exists on disk).

* docs(taxonomy): add Enhancement/Refactor row + clarify Refactor spans both types
* Add NinjaRMM GUID to Halo PSA GUID Sync Script

Syncs DTC Org GUID from NinjaRMM custom fields to DTC Client GUID field in Halo PSA for all matching clients by name.

* Update ninja-halo-guid-sync.ps1

Fix Halo custom field name to CFDtcClientGuid

* Fix NinjaClientSecret placeholder comment typo

* Remove hardcoded credentials — replace with placeholders

Secrets were exposed in script body. Rotated all credentials. Real values stored in NinjaRMM script body (never leaves Ninja) and 1Password. GitHub copy uses placeholders only.

* Update script — use Script Variable injection for secrets

Refactored to inject client secrets via NinjaRMM Script Variables at runtime. Client IDs hardcoded (not secrets). Secrets never stored in repo. Validated working in production.

* Fix: Bring script into compliance with DTC PowerShell engineering standard

Addresses CodeRabbit review concerns on PR #49:
- Add RMM variable declaration block per script-template-powershell.ps1
- Add Start-Transcript/Stop-Transcript with C:\ProgramData\DTC\Logs\ output
- Add $ScriptLogName and $Description audit trail variables
- Replace Write-Host with Write-Information per output stream standard
- Add $ErrorActionPreference = 'Stop' and $ProgressPreference = 'SilentlyContinue'
- Add explicit exit codes (0/1/2 per DTC convention)
- Wrap all work in try/catch/finally per page 3299
* feat(rmm-ninja): add Lockhart remediation script

Automated remediation for NinjaOne Backup Lockhart service failures. Responds to the '(SEC) Last Successful Backup' condition on policy 58 (servers). Diagnose -> Repair -> Confirm flow with business-hours gating for disruptive operations. HV0 hypervisor host exclusion. DeviceOffline short-circuit. Forensic capture on remediation failure.

Pilot tested on internal DTC server 2026-04-23. Full cycle validated: idle classification, service restart, PID rotation, state file written, counter incremented correctly.

Includes Pester test coverage for structural validation, HV0 hypervisor host exclusion, and NotApplicable short-circuit path. Tests file force-added: .gitignore line 25 (*test*) excludes Pester source files - flagging as separate concern for repo cleanup.

* fix(rmm-ninja): RMM env-var binding + template compliance per review

- ForceDisruptiveRepairs/ClearStateAndExit now resolve from env vars (NinjaOne preset variable path) with CLI switch fallback for interactive runs; all numeric tunables gain env-var overrides (review comment 1)

- Three-section template structure per CLAUDE.md: RMM variable block, input handling with env:RMM detection and env:Description audit capture, Start/Stop-Transcript to RMMScriptPath/WINDIR logs with 10MB rotation. Documented deviation: no Read-Host (condition-triggered automation must never block on input)

- Collapsed dead Running-case conditional to single restart with explanatory comment (review comment 2)

- Counter semantics: docs and MaxAttemptsReached log now say 'interventions within window' matching the intentional increment-on-success behavior (review comment 3)

- .NOTES Path corrected to rmm-ninja/ (review comment 4)

- HV0 exclusion moved to entry point before transcript so hypervisors take zero file writes; Pester test added for env:ClearStateAndExit checkbox binding
…rt remediation (#83)

backup.ninjarmm.com is no longer used by the NinjaOne backup service, so it
fails DNS resolution and TCP connect on every run. This (1) fired unnecessary
disruptive network repairs (DNS cache flush, Dnscache restart, ARP clear) and
(2) poisoned the post-repair verdict via DNS_Still_Failing / Cloud_Still_Unreachable,
marking the remediation FAILED even when Lockhart was successfully repaired.

Remaining endpoints (app.ninjarmm.com, s3.amazonaws.com, s3.us-east-1.amazonaws.com)
still cover the agent control channel and backup storage targets.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…forever bug (#89)

The script hardcoded `-RebootCount 0`, which suspends BitLocker indefinitely
until a manual resume. Before a scheduled reboot we want it suspended for
exactly the next restart, then auto-resumed.

- RebootCount is now a parameter and an env var; resolution order:
  -RebootCount param > $env:RebootCount > default 1.
- Suspend volumes with ProtectionStatus 'On' (actively protected) and verify
  none remain protected afterward.
- Fix inverted $RMMScriptPath null check for the RMM log path.


Claude-Session: https://claude.ai/code/session_01TmgU4CfUbvYkZdm548A5fx

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Only the OS/system volume can trigger the pre-boot BitLocker recovery prompt;
fixed data volumes auto-unlock from the (suspended-but-bootable) system drive
once Windows is up. So Suspend-BitLocker on $env:SystemDrive covers the reboot
without touching data volumes. Verifies protection is off before returning.


Claude-Session: https://claude.ai/code/session_01TmgU4CfUbvYkZdm548A5fx

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The version on development still read bare $RMM and used a top-level param()
block. NinjaRMM passes preset variables as ENVIRONMENT variables, so bare
$RMM is $null in RMM mode and the script fell through to the interactive
Read-Host and hung waiting for input.

- Detect context via $env:RMM -ne "1".
- Read RebootCount/Description/RMMScriptPath via $env:; remove the param()
  block that broke RMM variable injection.
- Keep system-volume-only suspend; single Stop-Transcript + exit-code path.


Claude-Session: https://claude.ai/code/session_01TmgU4CfUbvYkZdm548A5fx

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Built on the env:RMM fix already in development. Make the run auditable from
the RMM activity output and unambiguous about outcome:
- Logs each step: current VolumeStatus/ProtectionStatus, the suspend action,
  and the post-suspend re-check.
- Single RESULT line + explicit exit code:
    0 = system volume protection OFF (suspended, or no BitLocker) -> safe to reboot
    1 = system volume STILL protected (suspend failed)            -> NOT safe


Claude-Session: https://claude.ai/code/session_01TmgU4CfUbvYkZdm548A5fx

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds msft-windows-os-edition-inventory.ps1, which reports the Windows
Server edition to a NinjaRMM custom field (serverEdition). Resolves the
edition from the registry EditionID with WMI Caption as a fallback,
distinguishes server from workstation via ProductType, and explicitly
calls out Standard, Datacenter, and Evaluation editions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mnelsondtc mnelsondtc added the type:enhancement New work that adds or improves capability (Halo: Enhancement) label Jun 24, 2026
@mnelsondtc mnelsondtc requested a review from Gumbees as a code owner June 24, 2026 21:29
@mnelsondtc mnelsondtc added the category:feature Net-new capability the customer/operator didn't have label Jun 24, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, push a new commit or reopen this pull request to trigger a review.

@Gumbees Gumbees left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — msft-windows-os-edition-inventory.ps1. Solid and on the new $env: template. One must-fix and one recommended, both about not hanging under NinjaRMM:

Must-fix — line 35

if ($env:RMM -ne "1") {

Change to:

if ($env:RMM -ne "1" -and [Environment]::UserInteractive) {

Without the UserInteractive guard, any NinjaRMM run where $env:RMM isn't seen as "1" falls into the interactive branch and hits Read-Host (line 38), which errors with "Windows PowerShell is in NonInteractive mode" and loops forever. This is the documented standard (CLAUDE.md).

Recommended — line 68
Start-Transcript -Path $LogPath is unguarded; it throws "Transcription cannot be started" in the NinjaRMM host. Wrap it:

$TranscriptStarted = $false
try { Start-Transcript -Path $LogPath -ErrorAction Stop; $TranscriptStarted = $true }
catch { Write-Host "Warning: Could not start transcript logging to $LogPath - $($_.Exception.Message)" }

…and gate any Stop-Transcript on if ($TranscriptStarted).

Otherwise looks good. 👍

@Gumbees Gumbees changed the base branch from development to main June 25, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category:feature Net-new capability the customer/operator didn't have type:enhancement New work that adds or improves capability (Halo: Enhancement)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants