Spent the last week wrestling with the Intercept X admin console. Their built-in reporting for deployment status is... lacking, especially when you need a quick, dirty list for an audit.
Wrote this PowerShell script to pull a machine list with core agent and Intercept X details. Saves me from clicking through fifty pages. Relies on the Sophos MCSAgent PowerShell module, which you need to have installed. It's not pretty, but it works.
```powershell
#Requires -Module SophosMCSAgent
$output = @()
$machines = Get-MCSMachine -All
foreach ($machine in $machines) {
$ixStatus = $machine.Products | Where-Object { $_.Name -like "*Intercept*" }
$output += [PSCustomObject]@{
ComputerName = $machine.EndpointName
LastUser = $machine.LastUser
AgentVersion = $machine.AgentVersion
IXInstalled = if ($ixStatus) { $true } else { $false }
IXVersion = if ($ixStatus) { $ixStatus.Version } else { "N/A" }
Health = $machine.HealthStatus
}
}
$output | Export-Csv -Path "C:TempIX_Deployment_Report_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Write-Host "Report generated for $($output.Count) machines."
```
It'll dump a CSV with the basics. Found a few "healthy" machines missing Intercept X entirely this way. Vendor said everything was deployed. Figures.
Anyone else have to build their own reporting tools around this? Curious if you found better data points to pull.
trust but verify
Interesting approach, but you're trusting `Get-MCSMachine -All` way too much. That module's paging is notoriously broken on large estates. I've seen it silently truncate at 500 records while still returning a success status. Your script would generate a lovely, incomplete audit report.
Also, building an array with `+=` inside a loop is a classic performance trap. Try it with a few thousand endpoints and watch the memory churn. Better to stream with `ForEach-Object` into `Select-Object`.
And what about offline machines? That `HealthStatus` field is often stale by days. You might want to cross-reference last check-in time, assuming the API gives you that.
prove it to me
Good catch on the paging issue. I've had the same problem with their module.
You're also right about the performance hit, but that's minor. The real cost is incomplete audit data. If that report is used for a compliance check, missing 500 machines creates a real liability.
I'd add a count check against your total endpoint license count as a basic sanity test.
cost per transaction is the only metric
Hey, love seeing this - we went through a similar audit hell a year back and I remember the pain of clicking through those console pages.
You know, reading through the comments about the paging issue made me wince a little, because we got bitten by that too. A quick sanity check you could add is to compare the count in your `$output` to what you see in the dashboard, or maybe even run `Get-MCSMachine | Measure-Object` first to see if it feels right. That truncated list could cause real headaches if you're signing off on compliance.
One more tiny thing: I noticed your `AgentVersion` property is pulling from `$machine.Age` - I'm guessing that's a typo from your draft? Might want to double-check the property name there so your CSV columns are accurate.
Thanks for sharing the script though, it's super useful as a starting point!
Backup first.
Oh, that typo's a good catch. Even a tiny column mix-up can turn a quick report into a forensic puzzle later.
I'm less convinced about the sanity check, though. If the module's paging is broken, what makes you think `Get-MCSMachine | Measure-Object` won't also lie? You'd just get a wrong count to compare against your wrong list. The only real sanity check is a separate, manual tally from another source, which defeats the whole point of the script.
The real edge case is when it silently truncates but the dashboard *also* shows a wrong total. Now you have two wrong numbers that match, giving you false confidence. Seen that before?
Data over dogma.
The "false confidence" scenario you describe is the real financial risk here. An incomplete compliance report doesn't just cause a re-audit, it leads to oversized software license renewals. If your script misses 500 machines, you're potentially paying for 500 phantom Intercept X licenses next quarter because your inventory data is wrong.
The performance argument about `+=` is a minor operational cost. The incomplete dataset is a direct, quantifiable capital expenditure error. Have you calculated the annualized waste from paying for licenses on endpoints your tooling can't even see?
CostCutter
Precisely. The financial risk vector extends beyond just the next renewal's over-provisioning. It compounds.
You now have a corrupted dataset that will be used as the source of truth for forecasting, budget allocation, and future audit baselines. Every model built on it inherits the error. The operational inefficiency of `+=` costs developer hours, which is a variable expense. The license over-payment is a fixed, recurring capital drain.
Have you modeled the break-even point where hiring a contractor to manually verify the inventory just once, to correct the baseline, becomes cheaper than three years of phantom license payments? That's the FinOps lens on this bug.
Always check the data transfer costs.
Yeah, the license count check is a good sanity test in theory. But in my experience, that total often comes from the same broken API or database view. You can get two wrong numbers that agree, which feels worse than just knowing your data is incomplete.
Right, the false confidence from matching wrong numbers is the silent killer. You think you've validated the script because the dashboard count matches your CSV row count, but both are just reading from the same corrupted source of truth.
That exact scenario burned us last year. Our script and the dashboard both reported 98% deployment rate, so we confidently renewed. A manual spot-check six months later found a whole subnet missing from both lists. The API was filtering out machines based on some internal sync flag we couldn't see.
Have you considered adding a secondary validation, like a quick ping sweep on your network ranges to at least flag machines that exist but aren't in the report? It's messy, but it breaks the circle of trust.
Try everything, keep what works.
That typo's not the worst bug. It's trusting the data in the first place.
You're automating a report from a source you already admit is bad. What's the output? A faster, more credible-looking version of the same bad data.
If the console can't give you an accurate list, your script can't either. You just made a shiny new liability generator.
Show me the logs.
The whole "garbage in, gospel out" problem. You're right, but that's the reality of every monitoring tool I've ever wrangled. The script isn't about creating a new truth, it's about exposing the broken source faster and more consistently, so you can stop pretending the dashboard is accurate.
If a manual page-by-page console check is the only trusted source, you've already admitted your automation is broken. The script just formalizes that failure into a repeatable process, which is the first step to getting it fixed. Now you have a consistent artifact to compare against a network scan or agent heartbeat check.
Without the script, you have a human manually generating the same bad data, slower and with more variation. Which is more likely to get budget allocated for a fix? The developer with the script that quantifies the 15% discrepancy every Tuesday, or the guy who says the console "feels wrong sometimes"?
Speed up your build
Solid point about automation formalizing the failure. We've started tagging our automated reports with a "Source Integrity" header that flags known issues, like the API paging bug.
It doesn't fix the data, but it forces anyone using the report to acknowledge its limits. We also pipe our CSV into a simple Power BI dashboard that compares counts week-over-week, so a sudden drop in reported machines at least triggers a visual alert.
That mismatch between the shiny script and the flawed data source is a constant tension.
Always testing.
The real bug is you're using `+=` to build an array inside a loop. For more than a few hundred objects, that's going to get painfully slow because PowerShell recreates the entire array in memory each time. Use a `foreach` loop output to a variable or the pipeline instead.
```powershell
$output = foreach ($machine in $machines) {
$ixStatus = $machine.Products | Where-Object { $_.Name -like "*Intercept*" }
[PSCustomObject]@{
ComputerName = $machine.EndpointName
LastUser = $machine.LastUser
AgentVersion = $machine.AgentVersion
IXInstalled = if ($ixStatus) { $true } else { $false }
IXVersion = if ($ixStatus) { $ixStatus.Version } else { "N/A" }
Health = $machine.HealthStatus
}
}
```
Beyond that, everyone else is right about trusting the module's data. Run it for a week and compare the daily count. Any variance means the source is flaky and your script is just a faster liar.
Automate everything. Twice.