Tech by Jeff
Newsletter (Digital)
This is a blog maintained by me, Jeffrey Stuhr, where I attempt to document some tech related things whether it's in a professional aspect or at home. For work it'll probably be Microsoft related - Azure, Entra, M365, powershell, graph, VS Code, or on-prem AD/SCCM. For home all bets are off as whimsy and shiny things attract me. Maybe someone will find this useful. Source
Actions
Media Outlet details
| Scope | Local |
|---|---|
| Language | English |
| Country | N/A |
|
Similarweb UVM |
Request pricing |
|
Comscore UVM |
Request pricing |
Recent Articles
Search ArticlesIntune Rules Inside PSScriptAnalyzer
I’m a huge fan of PSScriptAnalyzer and I wanted to integrate my module with it. There are many ci/cd or workflows that involve it, and would rather bundle it in rather than causing someone to learn the IntuneScriptLab commands.
Auditing the Scripts Already in Your Intune Tenant
In round 6 of the validation kit I wanted a remediation that only detected. Graph’s deviceHealthScript assignment has a property for that, runRemediationScript, described as whether to run the detection script only or both. I set it to false and assigned the policy to both test devices. The remediation ran every hour on both of them anyway: detection, remediation, detection, sixteen cycles on the joined device alone.
Reading the Intune Management Extension Logs as Objects
In round 8 of the validation kit I put a fresh VM through Autopilot with an Enrollment Status Page that blocked on three Win32 apps, two for the device and one for the user. AppWorkload.log recorded the page closing at 07:11:22 UTC: 1 ESP completed. Triggering immediate app workload check-in The user’s blocking app was still InProgress at that point. The same log marked it Completed at 07:12:02, forty seconds later, and the check-in the line promised ran at 07:12:22, after the app finished.
Intune Assignment Filters That Never Match
The Microsoft Learn reference for assignment filter properties gives this example for cpuArchitecture: 1 (device.cpuArchitecture -in ["x64", "arm64"]) The property applies to macOS and Windows, and the example sits under both. On macOS the values are x64, arm64 and unknown. On Windows they’re amd64, x86, arm64 and unknown. Paste that example into a filter for the Windows platform and the service saves it without complaint, because validateFilter accepts any string for an enumerated property.
What the Intune Agent Counts as Installed
Say a Win32 app’s whole job is to remove something: a leftover file from an old agent, C:\ProgramData\OldAgent\agent.cfg. Installed means the file is gone, so the detection rule you’d write in the portal is a file rule with the operation “File or folder does not exist”. Graph accepts it too, as a win32LobAppFileSystemRule with operationType set to doesNotExist. The agent can’t evaluate it. Round 5 of the validation kit deployed that rule twice.
Running Intune Scripts Locally the Way the Agent Does
Take a remediation pair, run in user context, that turns off Windows’ feedback requests. Windows keeps that setting in a per-user key that doesn’t exist until somebody changes the setting, HKCU:\Software\Microsoft\Siuf\Rules.
Linting Intune Scripts With Rules Measured on Real Devices
One of the rules in IntuneScriptLab exists because of Microsoft’s own sample scripts. The remediation samples page on Learn has detection scripts for expired certificates. When they find a match, they do this: 1 2 3 Write-Host "Match" Return $results.count exit 1 A comment just above those lines says Intune only remediates on exit code 1, so the script makes sure to exit 1. It doesn’t. A return at script scope ends the script, the returned count becomes output, and the process exits 0.
Testing Intune Scripts Before Intune Does
I went looking for a new module to build after my TestEnvironment module had a reasonable number of providers. I wanted something useful that targets a live tenant, not just test environments, and something I could write about here. My first list was all tenant assessment: an Intune assignment resolver, a license waste finder, a Conditional Access documenter, an app registration hygiene report.
A Role With Nothing but a Name: Seeding OneLogin
Every provider before this one had somewhere to write a marker. Active Directory has adminDescription. Entra has a directory extension. Okta and Authentik have profile fields. FreeIPA has userclass. PingOne had nothing on a user, so the provider created a custom attribute and wrote the tag there. OneLogin gives a role a name. That is the whole object as far as identifying it goes. A group, the same. A security policy, the same. A Smart Hook does not even have a name.
A Directory Full of Question Marks: Seeding PingOne
The first full PingOne seed I ran from Windows PowerShell 5.1 produced a directory where José was Jos<?>, the Han names were rows of question marks, and one surname had lost a character entirely. The same seed from PowerShell 7, against the same environment, stored every name perfectly. The cause is not PingOne’s. Windows PowerShell sends a string request body as ISO-8859-1 when no charset is named, whatever the machine’s code page.