Custom Compliance PowerShell script for detecting additional local Administrators

One of our customers wanted to be sure that there were no additional accounts in the local Administrators group on their Intune devices, and… That’s where Custom Compliance policies come in 🙂 In this blog post, I will show you how to automatically check the Administrators group and mark the device as non-compliant if needed.

How the script works

On an Intune device, you will always find three standard members of the Administrators group, the default local Administrator account, the Global Admin, and the Azure AD Joined Device Local Administrator role. If there are more members present, then there might be a security issue on that device.

The script reads all the members, excludes the three standard ones, and if there are more… Then it will return that to the Custom Compliance policy, and the device will be marked as Non-Compliant. When the device is Non-Compliant, the Conditional Access Rules will stop it from using all services in your tenant until remediated.

Note: For this to work, you need a Microsoft 365 E3/E5 license

How to add this to Intune?

To add this solution to Intune, you can follow the steps in the chapters below.

Customizing the script for your tenant

You will first need to find the IDs for the Global Admin and Azure AD Joined Device Local Administrator roles, and I used this blog post for that: https://oliverkieselbach.com/2020/05/13/powershell-helpers-to-convert-azure-ad-object-ids-and-sids/. You first retrieve all the roles, get the ObjectID and convert that to a sid. Below is my example (In which I changed the SIDs 😉 )

#Retrieve all members of local Administrator group using ADSI
$admins = { ([ADSI]"WinNT://./Administrators").psbase.Invoke('Members')  | ForEach-Object {
    ([ADSI]$_).InvokeGet('AdsPath')
    }
}.Invoke()

#Remove all defaults accounts and groups from the $admins variable
#Use https://oliverkieselbach.com/2020/05/13/powershell-helpers-to-convert-azure-ad-object-ids-and-sids/ to get the corresponding Role/Group
$defaultAdmins = `
"WinNT://$($env:COMPUTERNAME)/Administrator",               # Default local administrator `
"WinNT://S-1-12-1-1234567890-1234567890-1234567890-1234567890",  # Global Administrator Role `
"WinNT://S-1-12-1-0987654321-0987654321-0987654321-0987654321"  # Azure AD Joined Device Local Administrator Role

foreach ($defaultAdmin in $defaultAdmins) {
    $admins.Remove($defaultAdmin)
}

$hash = @{ numberOfExtraAdmins = $admins.count }
return $hash | ConvertTo-Json -Compress

Create a JSON file for the Custom Compliance Policy

The script will gather the results and return a JSON-formatted output. The Custom Compliance Script needs a JSON to compare those results and take action if the check fails. Create an admins.json text file, insert the lines below, and save it afterward. (You can customize the Title and Description to your liking)

More information about formatting the JSON file is here.

{
    "Rules": [
        {
            "SettingName": "numberOfExtraAdmins",
            "Operator": "IsEquals",
            "DataType": "Int64",
            "Operand": "0",
            "MoreInfoUrl": "https://powershellisfun.com",
            "RemediationStrings": [
                {
                    "Language": "en_US",
                    "Title": "Additional admins found!",
                    "Description": "There are too many members of the Administrators on this system. Please get in touch with IT Support. The device is now marked as non-compliant."
                }
            ]
        }
    ]
}

Adding the script to Intune

Once the script is adjusted to your tenant, then you can follow these steps to upload it into Intune:

  • Go to Compliance policies – Microsoft Intune admin center
  • Select Add, and select Windows 10 and later
  • Enter a Name (Local Administrators check, for example) and choose Next
  • Insert the script’s contents in the Detection Script pane and choose Next.
  • Review the values and choose Create.

You should now return to the Compliance Policies/Scripts pane and see the script is listed.

Creating a Custom Compliance Script

Now that the script is available in Intune, the Custom Compliance Script can be created. Follow these steps to create one:

  • Go to Compliance policies – Microsoft Intune admin center
  • Select Create Policy
  • Select Windows 10 and later as Platform and select Create
  • Enter a Name (Local Administrator Compliance, for example) and choose Next
  • Expand Custom Compliance and select Require
  • Select Click to select, select the Local Administrators check from the list, and click Select.
  • Click on Select a file, browse, and open the admins.json file you saved earlier. When uploaded, it will check the format and display an error if it’s not correctly formatted.
  • Click Next
  • Select the noncompliance actions you want, Mark device noncompliant is mandatory in this case, but you can email the end user if you have created a template for that here.
  • Click Next and assign the correct device group for this Custom Compliance Script.
  • Click Next
  • Review the settings and select Create.

Note: The script will run every 8 hours after it runs the first time and will also check for updated versions every 8 hours.

Results on a non-compliant Intune Device

After assigning the script (And waiting for about 15 minutes), this is how it will look when a device is not compliant:

Logs

In c:\ProgramData\Microsoft\IntuneManagementExtension\Logs you can view the AgentExecutor.log or IntuneManagementExtension.log file and search for the “HealthSchript” keyword. Somewhere near those lines, you should see:

]LOG]!><time="19:44:39.6940524" date="4-18-2023" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell script is successfully executed.]LOG]!><time="19:44:39.6940524" date="4-18-2023" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[write output done. output = True
False
False
{"numberOfExtraAdmins":2}

or

<![LOG[[HS] err output = ]LOG]!><time="19:44:44.7258239" date="4-18-2023" component="IntuneManagementExtension" context="" type="1" thread="38" file="">
<![LOG[[HS] std output = {"numberOfExtraAdmins":2}]LOG]!><time="19:44:44.7258239" date="4-18-2023" component="IntuneManagementExtension" context="" type="1" thread="38" file="">
<![LOG[[HS] PreDetectScript parsing result is done ]LOG]!><time="19:44:44.7258239" date="4-18-2023" component="IntuneManagementExtension" context="" type="1" thread="38" file="">

Company Portal

The Company Portal will show an event like this:

(Clicking on the “How to resolve this” link will redirect your browser to the address specified in the JSON file, in my case https://powershellisfun.com 😉 )

Results on a compliant Intune Device

Logs

In c:\ProgramData\Microsoft\IntuneManagementExtension\Logs you can view the AgentExecutor.log or IntuneManagementExtension.log file and search for the “HealthSchript” keyword. Somewhere near those lines, you should see:

<![LOG[Powershell script is successfully executed.]LOG]!><time="20:37:52.2049168" date="4-18-2023" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[write output done. output = True
True
True
{"numberOfExtraAdmins":0}

or

<![LOG[[HS] std output = {"numberOfExtraAdmins":0}]LOG]!><time="20:37:57.2299454" date="4-18-2023" component="IntuneManagementExtension" context="" type="1" thread="43" file="">
<![LOG[[HS] PreDetectScript parsing result is done ]LOG]!><time="20:37:57.2299454" date="4-18-2023" component="IntuneManagementExtension" context="" type="1" thread="43" file="">
<![LOG[[HS] Returned exitcode from child process is 0]LOG]!><time="20:37:57.2299454" date="4-18-2023" component="IntuneManagementExtension" context="" type="1" thread="43" file="">

Company Portal

When opening the Company Portal, the device status will look like this:

8 thoughts on “Custom Compliance PowerShell script for detecting additional local Administrators

  1. Pingback: Intune Newsletter - 23rd April 2023 - Andrew Taylor

      • I need to create a custom compliance policy to make sure 3 services are detected on our machines. if they are running would be a plus, but mainly that they exist.

      • this is what I have so far but its coming back null

        $Service = Get-Service -Name ‘crowdstrike falcon sensor Service’

        $hash = @{ ServicePresent = $Service.ServicePresent}
        return $hash | ConvertTo-Json -Compress

    • Ah, ok… Welll You could try this, add them to Intune like mentioned above and use this PowerShell script for detecting and this JSON for compliance check. Note: Not tested, just tested the script for three services..

      PowerShell script:

      $services = @(“Cryptographic Service”, “DHCP Client”, “DNS Client”)
      $badcount = 0
      foreach ($service in $services) {
      if (Get-Service -DisplayName $service -ErrorAction SilentlyContinue | Where-Object StartType -eq ‘Automatic’) {
      Write-Host (“{0} was found and running” -f $service)
      }
      else {
      $badcount++
      }
      }

      $hash = @{ MissingOrNotRunningServices = $badcount }
      return $hash | ConvertTo-Json -Compress

      JSON File:

      {
      “Rules”: [
      {
      “SettingName”: “MissingOrNotRunningServices”,
      “Operator”: “IsEquals”,
      “DataType”: “Int64”,
      “Operand”: “0”,
      “MoreInfoUrl”: “https://powershellisfun.com”,
      “RemediationStrings”: [
      {
      “Language”: “en_US”,
      “Title”: “Missing or not running services found!”,
      “Description”: “There are services on your system that were not detected or not running. Please get in touch with IT Support. The device is now marked as non-compliant.”
      }
      ]
      }
      ]
      }

      You can replace the text in the JSON File, just an example 🙂 You can adjust the PowerShell script and remove ” | Where-Object StartType -eq ‘Automatic’ ” if you don’t want to test the Automatic state… Change the write-host in that case too, remove “and running” and “and/or running” and change MissingOrNotRunningServices to MissingServices in both files.

      Let me know if it works 🙂

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.