Free tool · PowerShell
MECM Health Check
Where your ConfigMgr site stands — in one report, without changing a thing.
A read-only PowerShell script that reads your Configuration Manager site, its site systems, its clients and the hardening of every server, then writes a self-contained HTML report: what is fine, what is not, and what to fix first. The code is published below in full, to be read before it is run.
What you get
One report, seven tabs.
One HTML file with no dependencies: it opens in any browser, can be emailed and archived. Every check says what it measured, why it matters and where Microsoft's documentation is.
Overview
The compliance rate, critical findings first, and the priorities in the order to tackle them.
Servers
Every site system with its roles, disk space, version and failing or stopped components.
Clients
Coverage, inactive devices, stale policy and inventory, client versions, co-management and workloads, enrolment errors.
Health check
The site, its components, deployments, content distribution, update sync, ADRs, collections and status messages.
Site security
Full administrators, network access account, client push, PXE, boundaries too wide or orphaned, task sequences — against the Misconfiguration Manager guidance.
Server hardening
On every server: shares, local accounts, passwords, services, SMB, NTLM, LLMNR, RDP, WinRM, Defender, Credential Guard, LAPS, logging, TLS.
Troubleshooting
The Configuration Manager logs of every server, read over seven days: errors grouped by probable cause, with what to do, a timeline, and the status messages component by component.
Before you start
Prerequisites.
The bare minimum is short: PowerShell and a read-only account on the site. The rest unlocks parts of the report — without it, the script says so and carries on.
| Requirement | For | Notes |
|---|---|---|
| RequiredWindows PowerShell 5.1 or PowerShell 7 | The whole script. | Built into Windows Server 2016 and later. |
| RequiredAn account with at least the Read-only Analyst role on the site | Reading the site, its servers and its clients. | The current account, or another through -Credential. ConfigMgr recognises an administrator by its SID, not its name: an account deleted then recreated under the same name has no rights at all, even though the console still lists it. The site then answers without showing anything, and the script stops and says so — recreate the administrative user. |
| RequiredA machine that can reach the SMS Provider | Where every read goes. | The site server itself, or any domain machine that can reach it: HTTPS 443 (AdminService), otherwise WMI over WinRM (5985), otherwise over DCOM (135 + dynamic ports). |
| OptionalThe AdminService enabled | The fastest reads. | Without it, automatic fallback to WMI. Same report. |
| OptionalWinRM (5985/5986) to every site system, and local administrator | The Server hardening and Troubleshooting tabs. | Or a JEA endpoint (-HardeningEndpoint). Without access: tab marked "not collected", or -SkipHardening / -SkipLogs. |
| OptionalA PowerShell console run as administrator | Hardening of the local machine. | Local registry, services and password policy. |
| OptionalAn execution policy that allows a local script | Running the file. | RemoteSigned is enough for a file created on the machine. Otherwise, for this session only: Set-ExecutionPolicy -Scope Process Bypass. |
The script uses neither the ConfigurationManager module nor the console: it reads the AdminService over HTTPS, or WMI, with commands that ship with Windows. Nothing is installed, neither on the machine running it nor on the audited servers.
Transparency
What it reads. What it writes. What it never does.
An audit that changes what it audits is no longer an audit. Every statement below can be checked in the code, further down.
It reads
- The site: 23 WMI classes of the SMS Provider — site, components, roles, boundaries, deployments, content, updates, collections, status messages, administrators, boot images, and the site control file settings: client push, Network Access Account, communication security.
- The clients: the device inventory and its co-management state.
- Every server: registry keys, services, local groups, shares with their share and NTFS permissions, the Extended Protection of SQL Server instances, the client cache permissions and network settings.
- The directory: one value only, the domain's machine account quota (ms-DS-MachineAccountQuota), over LDAP and read only.
- The Configuration Manager logs of every server: only their end, only the error and warning lines, opened shared so the component writing them is never disturbed.
It writes
- The HTML report, in the current folder or wherever
-OutFilesays. - A JSON of the data read, if you ask for it (
-ExportJson). - On each audited server, a temporary
hc_secpol_<guid>.cfgfile in the account's temporary folder, produced bysecedit /export, read then deleted at once — Windows has no other way to read the password policy.-SkipSeceditto create nothing at all. - With the options window, in the temporary folder of the machine running it: a progress file and — if you enter another account there — that account encrypted by Windows (DPAPI, readable only by you on that machine), deleted as soon as it has been read.
It never
- Changes a setting, a deployment, a collection or a device: towards the site it only sends reads (
GETrequests to the AdminService,Get-CimInstanceover WMI). - Starts, stops or reconfigures a service, or changes a permission, a registry key, an account or a directory value.
- Installs anything, locally or remotely.
- Calls the Internet: no request leaves your network. The report's links point to Microsoft Learn and only open if you click them.
- Sends anything to LB IT Cloud. There is no telemetry, no licence, no account.
The traces it leaves
Nothing is changed, but a read shows, like that of any administrator looking around:
- network logons in the servers' Windows security log;
- the requests in
smsprov.logand, for the AdminService, in the IIS logs; - the collector's text in the PowerShell logs, when script block logging is on;
- the account's profile on each audited server, which PowerShell Remoting creates at the first session if it did not exist;
- a line in
secedit's own log (%windir%\security\logs).
To run nothing at all on the servers and read the site only: -SkipHardening -SkipLogs.
How to use it
Copy, paste, run.
Copy
Paste and save
Invoke-MecmHealthCheck.ps1. The file is ASCII: whatever encoding you save it in makes no difference.Run
.\Invoke-MecmHealthCheck.ps1With no parameter, a window opens: site, account, what is read, report folder — then it follows the run and opens the report at the end. From a command line, nothing is shown:
.\Invoke-MecmHealthCheck.ps1 -Client "Contoso" -Open
Parameters
-SiteServer | The SMS Provider to query. Default: this machine. |
-SiteCode | Site code. Discovered automatically when omitted. |
-Source | Auto (AdminService then WMI), AdminService or Wmi. |
-Credential | Another account for the site and for hardening. |
-MessageHours | Status message window, 0 to 168 h. Default: 24. |
-HistoryDays | Error message history read to date each component, 0 to 90 days. Default: 30. |
-LogDays / -MaxLogMB | How far back the servers' logs are read (0 to 60 days, default 7) and how much of the end of each is read (default 5 MB). |
-SkipLogs | Skips the servers' logs. |
-SkipClients | Skips the clients. |
-SkipHardening | Skips hardening collection. |
-HardeningHosts | Limits hardening to these machines. |
-SkipSecedit | Creates no file, not even a temporary one, on the servers. |
-ScanShares | Also looks for sensitive files (passwords, .kdbx, unattend.xml) in the shares. |
-Language | fr (default) or en. |
-Client | The name printed on the report. |
-OutFile / -ExportJson / -Open | Where to write the report, whether to add the JSON, and whether to open it. |
-Gui / -Silent | Forces the options window (pre-filled by the other parameters), or forbids it — for a scheduled task. With neither, it opens only when the script is started with no parameter at all, on an interactive desktop. |
With no parameter
A window to set up the health check.
Started with no parameter on a desktop, the script opens this window: the site, the account, what is read and where to write the report. Then the same window follows the run, phase by phase, and gives the verdict. Click around: it is the same window, in French as in the script.
Health check MECM
Lit le site Configuration Manager, ses serveurs, ses clients et le durcissement de chaque système de site, puis écrit un rapport HTML. Lecture seule : rien n'est modifié, rien n'est déployé.
The same thing, on a command line
Every choice in the window has its parameter. The line below follows your clicks: it is the one to put in a scheduled task or a remote session. The report is then written to the current folder, or wherever -OutFile says.
.\Invoke-MecmHealthCheck.ps1 -Open
The window never opens where it could hang an unattended run:
- as soon as any parameter is passed: a command line is an explicit intent.
-Guiopens it anyway, pre-filled by the other parameters; - under SYSTEM, nor in a session with no desktop;
- with
-Silent, for a scheduled task started with no other parameter.
The health check runs in a second PowerShell process, started by the window with these same parameters: the window stays responsive through the minutes of reading, and "Annuler" stops it outright. Started without administrator rights, it warns that the local machine's hardening will be partly unmeasured.
The code
The whole script.
Split into sections, each explained in one sentence. Everything is in plain text: no encoded block, no hidden download, no line that calls the Internet. You may run it in your organisation and at your clients': what is allowed is set out in its terms of use.
Invoke-MecmHealthCheck.ps1
What's new · version 1.72.2
What changes in this version.
1.72.2 makes its demonstration consistent, 1.72.1 gives the options window the site's design. Since 1.71.0: a window to start it, a validated remote run, reads fixed against a real production site, and a Security tab aligned with Misconfiguration Manager.
Starting it
- An options window opens when the script is started with no parameter: site, account, what is read, report folder — then it follows the run live.
-Guiforces it,-Silentforbids it. - Running it from a domain machine is validated. When the site answers without showing anything to the account — a missing role, or an account recreated while ConfigMgr keeps its old SID — the script stops and says what to check, instead of writing an empty report.
- Starting it from PowerShell ISE works.
Reads fixed
- Site system roles are counted: they stayed at zero on a real site.
- Status messages are filtered on the period over the AdminService too, which used to return the oldest ones. A read that fails shows as "not read", no longer 0.
- Client push is read where the site keeps it: automatic or not, domain controllers, accounts, NTLM fallback. The Network Access Account is actually read.
- The deployment chart says when the site returns no counter, instead of announcing "no failure".
Security
- A matrix of the 23 PREVENT measures of Misconfiguration Manager: for each one, the check that measures it and its status, or why it cannot be measured from the site.
- Five new checks: the KB15599094 client push update (PREVENT-1), the F8 prompt on boot images (PREVENT-7), SQL Server Extended Protection (PREVENT-14), the domain's machine account quota (PREVENT-16), client cache permissions (PREVENT-23).
- Shares are judged on their share AND NTFS permissions, compared with each product's baseline (ConfigMgr, WSUS, WDS): a write open to a broad group is critical.
Report
- Drives: amber beyond 80 % used, red beyond 95 %, and bars that show the space used.
- Clients: a "Healthy clients" tile — active, client health passing, recent policy and inventory.
- The report wears the LB IT Cloud design, and the server card no longer overlaps.
- 1.72.1 — the options window too: a plate on top, cut corners, narrow titles, monospaced labels, capital buttons.
- 1.72.2 — the demonstration report gets its status messages and timeline back: replayed, a test set is dated from the day it was recorded.
- The script's comments are in English and in French.