How to get an report with all new enrolled devices

How to Get a Report of All New Enrolled Devices

Keeping track of newly enrolled devices in your organization can be a challenging task when relying solely on the Intune console. Wouldn’t it be awesome to receive a comprehensive report automatically via email? As you know, I love automating things. In this blog post, we’ll explore a simple and efficient way to generate a weekly report for all newly enrolled devices using PowerShell, Azure Automation Runbooks, and Microsoft Graph API. This automated solution will save you time and effort, allowing you to focus on more important tasks in managing your organization’s devices. So, let’s dive in and learn how to create this valuable report!

How to get an report with all new enrolled devices

How can you get the Script?

You can find the script in my GitHub repository, before running the script you have to adapt the from and to email address:

How to get an report with all new enrolled devices

What is the purpose of the script?

This PowerShell script retrieves all devices enrolled in the last 7 days, creates a CSV from them, and attaches the CSV to an email.

How can I schedule the Report?

To schedule the report, you can create an Azure Automation Runbook and authenticate via an App Registration. The only thing that you have to do is to paste the content of the script into the runbook.

How to create the Automation?

Create an App Registration

  • Search for Microsoft Entra ID
How to get an report with all new enrolled devices
  • Select App registration
How to get an report with all new enrolled devices
  • Select +New registration
How to get an report with all new enrolled devices
  • Enter a Name and click Register
How to get an report with all new enrolled devices
  • Click API permissions and +Add a permission
How to get an report with all new enrolled devices
  • Select Microsoft Graph
How to get an report with all new enrolled devices
  • Select Application permissions
How to get an report with all new enrolled devices
  • Search for DeviceManagementApps.Read.All & Mail.Send
How to get an report with all new enrolled devices
  • Click Grant admin consent for *** and approve with Yes
How to get an report with all new enrolled devices
  • Select Certificates & secrets and click +New client secret
How to get an report with all new enrolled devices
  • Enter a Description and select a Expires time
  • Click Add
How to get an report with all new enrolled devices
  • Copy and save the Value and the Secret ID
How to get an report with all new enrolled devices

Create Automation Account

  • Search for Automation Accounts
How to get an report with all new enrolled devices
  • Click + Create
How to get an report with all new enrolled devices
  • Select a Subscription and a Resource group
  • Enter an account name and select a Region
  • Click Next
How to get an report with all new enrolled devices
  • Click Next
How to get an report with all new enrolled devices
  • Click Next -> Next -> Create
How to get an report with all new enrolled devices

Create the Runbook

  • Open the Automation Account
  • Navigate to Variables and click + Add a variable
  • Add the Secret ValueTenantId, and the App ID as Variable
  • How to get an report with all new enrolled devices
  • How to get an report with all new enrolled devices
  • How to get an report with all new enrolled devices
  • How to get an report with all new enrolled devices
  • How to get an report with all new enrolled devices
  • How to get an report with all new enrolled devices
  • Select Runbooks
  • Click + Create a runbook
How to get an report with all new enrolled devices
  • Enter a Name
  • Select PowerShell as Runbook type
  • Select 5.1 as Runtime version
  • Click Create
How to get an report with all new enrolled devices
  • Insert the Script from my Github repository
  • Add the sender and receiver email, in the script
How to get an report with all new enrolled devices
  • Save and test the script
How to get an report with all new enrolled devices
How to get an report with all new enrolled devices
  • Click Publish
How to get an report with all new enrolled devices
  • Navigate to Schedules and click + Add a schedule
How to get an report with all new enrolled devices
How to get an report with all new enrolled devices
  • Click Link to schedule and add the created schedule
How to get an report with all new enrolled devices
How to get an report with all new enrolled devices

Script

<#
Version: 1.0
Author: Jannik Reinhard (jannikreinhard.com)
Script: Get-NewEnrolledDevicesReport
Description:
Get Email with new enrolled devices
Release notes:
Version 1.0: Init
#> 


function Get-AuthHeader{
    param (
        [parameter(Mandatory=$true)]$tenantId,
        [parameter(Mandatory=$true)]$clientId,
        [parameter(Mandatory=$true)]$clientSecret
       )
    
    $authBody=@{
        client_id=$clientId
        client_secret=$clientSecret
        scope="https://graph.microsoft.com/.default"
        grant_type="client_credentials"
    }

    $uri="https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
    $accessToken=Invoke-WebRequest -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $authBody -Method Post -ErrorAction Stop -UseBasicParsing
    $accessToken=$accessToken.content | ConvertFrom-Json

    $authHeader = @{
        'Content-Type'='application/json'
        'Authorization'="Bearer " + $accessToken.access_token
        'ExpiresOn'=$accessToken.expires_in
    }
    
    return $authHeader
}

#################################################################################################
########################################### Start ###############################################
#################################################################################################
# Variables
$MailSender = "mail@abc.onmicrosoft.com"
$MailTo = "mail@abc.onmicrosoft.com"

# Automation Secrets
$tenantId = Get-AutomationVariable -Name 'TenantId'
$clientId = Get-AutomationVariable -Name 'AppId'
$clientSecret = Get-AutomationVariable -Name 'AppSecret'


$global:authToken = Get-AuthHeader -tenantId $tenantId -clientId $clientId -clientSecret $clientSecret

# Define the time range
$endDate = Get-Date
$startDate = $endDate.AddDays(-7)
$filter = "enrolledDateTime gt $($startDate.ToString("yyyy-MM-ddTHH:mm:ssZ"))&enrolledDateTime le $($endDate.ToString("yyyy-MM-ddTHH:mm:ssZ"))"

# Query Intune devices enrolled in the past week
$graphApiUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices"
$graphApiQuery = "?`$filter=$filter&`$select=id,deviceName,operatingSystem,enrolledDateTime,userPrincipalName,model"
$uri = $graphApiUrl + $graphApiQuery
$response = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:authToken

# Generate CSV report
$reportPath = "NewEnrolledDevicesReport.csv"
$response.value | Select-Object id,deviceName,operatingSystem,enrolledDateTime,userPrincipalName,model | Export-Csv -Path $reportPath -NoTypeInformation
$csv = [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\$reportPath"))

#Send Mail    
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
{
    "message": {
      "subject": "New enrolled devices",
      "body": {
        "contentType": "Text",
        "content": "Dear Admin, this Mail contains the enrolled devices from the previous 7 days"
      },
      "toRecipients": [
        {
          "emailAddress": {
            "address": "$MailTo"
          }
        }
      ],
      "attachments": [
        {
          "@odata.type": "#microsoft.graph.fileAttachment",
          "name": "newEnrolledDevicesReport.csv",
          "contentType": "text/plain",
          "contentBytes": "$csv"
        }
      ]
    }
  }
"@


Invoke-RestMethod -Method POST -Uri $URLsend -Headers $global:authToken -Body $BodyJsonsend

Conclusion

In conclusion, automating the process of generating and emailing reports for newly enrolled devices can save time and effort, ensuring that you stay up-to-date with device management. By following the steps outlined in this post, you can easily set up an automated report that keeps you informed about device enrollment in your organization. Give it a try and experience the benefits of automation firsthand.

Feel free to modify the conclusion as you see fit or let me know if you would like further assistance.

4 thoughts on “How to Get a Report of All New Enrolled Devices

  1. Hi Jannik, thank you for this!
    I am experiencing this error after testing the Runbook,.
    The csv file does exist but it is empty.

    Completed

    The remote server returned an error: (401) Unauthorized.
    Cannot bind argument to parameter ‘InputObject’ because it is null.
    Object reference not set to an instance of an object.
    System.Management.Automation.MethodInvocationException: Exception calling “ReadAllBytes” with “1” argument(s): “Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.” —> System.IO.FileNotFoundException: Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
    at System.IO.File.InternalReadAllBytes(String path, Boolean checkHost)
    at CallSite.Target(Closure , CallSite , Type , String )
    — End of inner exception stack trace —
    at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo)
    at CallSite.Target(Closure , CallSite , Type , String )
    at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
    at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
    Object reference not set to an instance of an object.

    • Looks like an bug in the script could it be that there was no enrollments in the last week that no device is in the object and no csv was generated?

    • Same here: The remote server returned an error: (403) Forbidden.
      System.Management.Automation.MethodInvocationException: Exception calling “ReadAllBytes” with “1” argument(s): “Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.” —> System.IO.FileNotFoundException: Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.
      at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
      at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      at System.IO.File.InternalReadAllBytes(String path, Boolean checkHost)
      at CallSite.Target(Closure , CallSite , Type , String )
      — End of inner exception stack trace —
      at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo)
      at CallSite.Target(Closure , CallSite , Type , String )
      at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
      at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
      at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
      The remote server returned an error: (400) Bad Request.

  2. Hi Jannik, for some reason i’m receiving a related error
    I know there are multiple entries but the .csv ca’nt be found, any ideas?

Comments are closed.