A new feature within Intune, currently in Preview is the ability to create a custom compliance policy to give a bit more granular control over what is allowed to connect.
You could require certain apps to be installed (or not installed), a minimum BIOS version, or a particular service needs to be running. If it can be queried with PowerShell, it can be used.
There are plenty of excellent examples on the web so for this post I’m going to run through how it works to hopefully make it easier to understand.
At a top level, there are two files, a powershell script and a JSON file. The PowerShell runs against the device to grab the information you are looking for. The JSON file is the reference point for the script, in the background, the output from the PowerShell (also in JSON format) is compared to the reference file and passes through or flags as non-compliant.
The PowerShell script
Starting with the PowerShell script, the thing to note here is it has to output as a single line JSON file with the last line of the script creating the JSON
return $hash | ConvertTo-Json -Compress
The $hash variable can, however contain an array of values.
As a very basic example, let’s say that you only want to allow Dell computers with 8Gb RAM and you DON’T want any machines with Steam installed
First up, we need to detect the manufacturer and total RAM:
$biosinfo = Get-CimInstance -ClassName Win32_ComputerSystem
$manufacturer = $biosinfo.Manufacturer
$RAM = $biosinfo.TotalPhysicalMemory
Now, clearly we need to pass these back in a reasonable fashion, trim the RAM to exact Gb and make sure the manufacturer is just listed as Dell
#Check if it's a Dell
if ($manufacturer -like "*Dell*") {
$manufacturer = "Dell"
}
else {
$manufacturer = "Unknown"
}
$RAM = ($RAM / 1024 / 1024)
$RAM = [math]::Round($RAM, 0)
Now, let’s check if Steam is installed. Normally I would do a quick get-wmiobject, but for some reason Steam doesn’t display in there so we’ll query the registry instead:
#Look for Steam
$InstalledSoftware = Get-ChildItem "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
if ($InstalledSoftware -like "*Steam*") {
$steam = "Detected"
}
else {
$steam = "Not Detected"
}
Now we have our three variables, we need to put it into a one-liner JSON, we’ll need to remember the headings used for the JSON later:
$hash = @{ Manufacturer = $manufacturer; RAM = $RAM; Steam = $steam}
return $hash | ConvertTo-Json -Compress
The final powershell script looks like this:
##Get BIOS Info
$biosinfo = Get-CimInstance -ClassName Win32_ComputerSystem
#Manufacturer
$manufacturer = $biosinfo.Manufacturer
#Total RAM
$RAM = $biosinfo.TotalPhysicalMemory
#Check if it's a Dell
if ($manufacturer -like "*Dell*") {
$manufacturer = "Dell"
}
else {
$manufacturer = "Unknown"
}
#Tidy the RAM
$RAM = ($RAM / 1024 / 1024)
$RAM = [math]::Round($RAM, 0)
#Look for Steam
$InstalledSoftware = Get-ChildItem "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
if ($InstalledSoftware -like "*Steam*") {
$steam = "Detected"
}
else {
$steam = "Not Detected"
}
$hash = @{ Manufacturer = $manufacturer; RAM = $RAM; Steam = $steam}
return $hash | ConvertTo-Json -Compress
JSON File
Now we have our output on the machine, we need something to compare it to, the JSON file, these are fairly straight forward, give it the heading, what it needs to be an then an error message should it be non-compliant (plus a more info URL if wanted)
For the manufacturer:
{
"SettingName":"Manufacturer",
"Operator":"IsEquals",
"DataType":"String",
"Operand":"Dell",
"MoreInfoUrl":"https://andrewstaylor.com",
"RemediationStrings":[
{
"Language":"en_US",
"Title":"This machine is not a Dell.",
"Description": "We only support Dell devices, please contact us for more information."
}
]
}
As you can see, we use the setting name from the hash and make sure it equals Dell as a string. The JSON uses standard Boolean logic, this link from Microsoft shows the supported types, operators, languages and required settings
Putting our example together:
{
"Rules":[
{
"SettingName":"Manufacturer",
"Operator":"IsEquals",
"DataType":"String",
"Operand":"Dell",
"MoreInfoUrl":"https://andrewstaylor.com",
"RemediationStrings":[
{
"Language":"en_US",
"Title":"This machine is not a Dell.",
"Description": "We only support Dell devices, please contact us for more information."
}
]
},
{
"SettingName":"RAM",
"Operator":"GreaterEquals",
"DataType":"int64",
"Operand":8,
"MoreInfoUrl":"https://andrewstaylor.com",
"RemediationStrings":[
{
"Language": "en_US",
"Title": "Insufficient RAM.",
"Description": "Please arrange for your machine to be replaced, or RAM upgraded to 8Gb Minimum"
}
]
},
{
"SettingName":"Steam",
"Operator":"IsEquals",
"DataType":"String",
"Operand":"Not Detected",
"MoreInfoUrl":"https://andrewstaylor.com",
"RemediationStrings":[
{
"Language": "en_US",
"Title": "Unsupported Application Detected",
"Description": "Steam has been detected on your device, please uninstall and try again."
}
]
}
]
}
Creating the Policy in Intune
Now we have our scripts, we need to create the policy, but first, we have to add the scripts!
Navigate to Endpoint Security – Device Compliance – Scripts
Add the script like you would any PowerShell script:
Paste in the script, in this case it needs to run in the System context and 64-bit:
Navigate to Devices – Compliance Policies – New Policy
Select Windows 10 and give it a name
Select Custom Compliance
Select the Script we just uploaded
Then upload your JSON and it will detect the settings:
Click Next and run through the usual processes you would follow on a compliance policy.
If you want to use my examples, the code is on Github
Hey Andrew,
Wonder if you can help me with this. I am receiving the following error: 65009(Invalid json for the discovered setting)
JSON:
{
“Rules”:[
{
“SettingName”:”Huntress”,
“Operator”:”IsEquals”,
“DataType”:”String”,
“Operand”:”Not Detected”,
“MoreInfoUrl”:”https://twistedfish.com”,
“RemediationStrings”:[
{
“Language”: “en_US”,
“Title”: “Huntress Agent Not Detected”,
“Description”: “Huntress has not been detected on your device, please contact IT support.”
}
]
}
]
}
Discovery script:
#Look for Huntress
$InstalledSoftware = Get-ChildItem “HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall”
if ($InstalledSoftware -like “*Huntress*”) {
$Huntress = “Detected”
}
else {
$Huntress = “Not Detected”
}
$hash = @{Huntress = $Huntress}
return $hash | ConvertTo-Json -Compress
In company portal it does show as Huntress Agent not detected.
When I run the discovery script manually, it does return the correct value.
Is Hunress 32 or 64-bit? It could be PowerShell is running in 32-bit from Intune
It’s 64-but. I have turned on 64-bit powershell.
If anyone else comes across this, I fixed it by adding the not detected variable first:
Discovery script:
#Look for Huntress
$huntress = “Not Detected”
$InstalledSoftware = Get-ChildItem “HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall”
if ($InstalledSoftware -like “*Huntress*”) {
$Huntress = “Detected”
}
else {
$Huntress = “Not Detected”
}
$hash = @{Huntress = $Huntress}
return $hash | ConvertTo-Json -Compress
Hi,
I’ve followed this exactly but am getting the errors:
Manufacturer
Error
65007(Script returned failure)
RAM
Error
65007(Script returned failure)
Steam
Error
65007(Script returned failure)
I cannot figure out why this is happening?
If you run the PowerShell part directly on your machine, does it give you output?
You can use {ActualValue} to pull down resulting value. I’m using it with Linux custom compliance, but it should work for Windows. e.g.:
{
“Language”: “en_US”,
“Title”: “Manufacturer: {ActualValue}”,
“Description”: “We only support Dell devices, but you are using {ActualValue}.”
}
Good spot, thank you!
Hi Andrew, thanks for this. This is great
How can I add a variable from PowerShell to the description in json? something like below. Is the syntax correct?
“Description”: “We only support Dell devices, but you are using $manufacturer.”
Hi Anup,
The JSON is static data only, you could pass the variable to it, but as the JSON just does a pass/fail, it wouldn’t be able to display it
Worth feeding back to Microsoft though as a feature request
I’d there a cost associated with this or am I getting confused with something else?
It should be included in M365 E3/E5 licensing when out of preview