☁️
Tminus365 Docs
  • 🚀Welcome to Tminus365 Docs
  • 🔐Security
    • Azure AD (Entra)
      • MFA Shall Be Required for All Users
      • MFA is enforced on accounts with Highly Privileged Roles
      • MFA is enforced for Azure Management
      • MFA registration and usage shall be periodically reviewed
      • Legacy Authentication shall be blocked
      • High Risk Users Shall Be Blocked
      • High Risk Sign-Ins Shall Be Blocked
      • Browser Sessions shall not be persistent for privileged users
      • MFA shall be required to enroll devices to Azure AD
      • Managed Devices shall be required for authentication
      • Guest User Access Shall be restricted
      • The number of users with highly privileged roles shall be limited
      • Users assigned highly privileged roles shall not have permanent permissions
      • Activation of privileged roles should be monitored and require approval
      • Highly privileged accounts shall be cloud-only
      • Highly privileged role assignments shall be periodically reviewed
      • Passwords shall not expire
      • Azure AD Logs shall be collected
      • Only Admins shall be allowed to register 3rd party applications
      • Non-admin users shall be prevented from providing consent to 3rd party applications
      • Authorized Applications shall be configured for Single Sign-On
      • Inactive accounts shall be blocked or deleted
    • Teams
      • Private Channels shall be utilized to restrict access to sensitive information
      • External Participants SHOULD NOT Be Enabled to Request Control of Shared Desktops or Windows in Meet
      • Anonymous Users SHALL NOT Be Enabled to Start Meetings
      • Automatic Admittance to Meetings SHOULD Be Restricted
      • External User Access SHALL Be Restricted
      • Unmanaged User Access SHALL Be Restricted
      • Contact with Skype Users SHALL Be Blocked
      • Teams Email Integration SHALL Be Disabled
      • Only Approved Apps SHOULD Be Installed
      • File Sharing and File Storage Options shall be blocked
      • Only the Meeting Organizer SHOULD Be Able to Record Live Events
      • Attachments SHOULD Be Scanned for Malware
      • Link Protection SHOULD Be Enabled
      • Restrict Users who can Create Teams Channels
      • Teams Channels shall have an expiration policy
      • Data Loss Prevention Solutions SHALL Be Enabled
    • Exchange
      • Automatic Forwarding to External Domains SHALL Be Disabled
      • Sender Policy Framework SHALL Be Enabled
      • DomainKeys Identified Mail SHOULD Be Enabled
      • Domain-Based Message Authentication, Reporting, and Conformance SHALL Be Enabled
      • Enable Email Encryption
      • Simple Mail Transfer Protocol Authentication SHALL Be Disabled
      • Calendar and Contact Sharing SHALL Be Restricted
      • External Sender Warnings SHALL Be Implemented
      • Data Loss Prevention Solutions SHALL Be Enabled
      • Emails SHALL Be Filtered by Attachment File Type
      • Zero-Hour Auto Purge for Malware SHOULD Be Enabled
      • Phishing Protections SHOULD Be Enabled
      • Inbound Anti-Spam Protections SHALL Be Enabled
      • Safe Link Policies SHOULD Be Enabled
      • Safe Attachments SHALL Be Enabled
      • IP Allow Lists SHOULD NOT be Implemented
      • Mailbox Auditing SHALL Be Enabled
      • Alerts SHALL Be Enabled
      • Audit Logging SHALL Be Enabled
      • Enhanced Filtering Shall be configured if a 3rd party email filtering tool is being used
    • SharePoint
      • File and Folder Links Default Sharing Settings SHALL Be Set to Specific People
      • External Sharing SHOULD be Set to “New and Existing Guests”
      • Sensitive SharePoint Sites SHOULD Adjust Their Default Sharing Settings
      • Expiration Times for Guest Access to a Site SHOULD Be Determined by specific needs
      • Users SHALL Be Prevented from Running Custom Scripts
    • OneDrive
      • Anyone Links SHOULD Be Turned Off
      • Expiration Date SHOULD Be Set for Anyone Links
      • Link Permissions SHOULD Be Set to Enabled Anyone Links to View
      • Windows and MacOS devices should be prevented from syncing the OneDrive Client on personal devices
      • Legacy Authentication SHALL Be Blocked
    • Intune
      • Personal Devices should be restricted from enrolling into the MDM solution
      • Devices shall be deleted that haven’t checked in for over 30 days
      • Devices compliance policies shall be configured for every supported device platform
      • Noncompliant devices shall be blocked from accessing corporate resources
      • MFA Shall be required for Intune Enrollment
      • Security Baselines should be configured for Windows Devices
      • Windows Update Rings shall be configured for Windows Devices
      • Update Policies shall be configured for Apple Devices
      • App Protection policies should be created for mobile devices
      • Mobile devices shall only be able to access corporate data through approved client apps
      • Lockout screen and password settings shall be configured for each device
      • Encryption shall be required on all devices
      • Windows Hello for Business should be configured where applicable
      • Authorized Applications should be deployed to managed devices
      • Device Use Shall be restricted until required applications are installed
      • Devices and Applications shall be wiped when a user leaves the organization or reports a lost/stolen
  • ⚙️Configurations
    • GDAP
      • My Automations Break with GDAP: The Fix!
      • Vendor Integrations Break with GDAP: The Fix!
      • Adding GDAP Relationships
      • Leveraging PIM with GDAP
      • GDAP Migration with Microsoft 365 Lighthouse
    • GoDaddy
      • Defederating GoDaddy 365
  • 🛡️CIS Controls
    • CIS Mapped to M365
  • 🔌Vendor Integrations
    • Pax8
      • Automating NCE subscription renewal notices
      • Leveraging the Pax8 API in Power Automate
    • IT Glue
      • Automating Intune Device Documentation in IT Glue
      • Automating Microsoft Documentation
    • Huntress
      • Leveraging the Huntress API in Power Automate
    • Syncro
      • Automating Microsoft 365 Documentation in Syncro
      • Custom Connector in Power Automate
      • Creating Tickets for Azure AD Risky Users
Powered by GitBook
On this page
  • Prerequisites
  • The Script
  • Final Thoughts
  1. Vendor Integrations
  2. IT Glue

Automating Intune Device Documentation in IT Glue

PreviousIT GlueNextAutomating Microsoft Documentation

Last updated 1 year ago

As we continue to shift the management of devices to Intune, I wanted an easy way to see all of the devices across all customers. I wanted to include metadata at a multi-tenant level such as device compliance and autopilot enrollment. I created a script that creates a new flexible asset in IT Glue and populates it with all enrolled devices per company. The script creates new devices or updates existing devices. You will be able to document the following:

  • Device Name

  • Ownership (Corporate or Personal)

  • OS

  • OS Version

  • Compliance State

  • User

  • Autopilot Enrolled

  • Encrypted

  • Serial Number

  • Configurations(if existing)

Prerequisites

In Microsoft, you will need to make sure you add the following permissions from the ap that was created with the Secure Application model if they are not already there:

  • DeviceManagementConfiguration.Read.All

  • DeviceManagementManagedDevices.Read.All

The Script

Param
(

[cmdletbinding()]
    [Parameter(Mandatory= $true, HelpMessage="Enter your ApplicationId from the Secure Application Model https://github.com/KelvinTegelaar/SecureAppModel/blob/master/Create-SecureAppModel.ps1")]
    [string]$ApplicationId,
    [Parameter(Mandatory= $true, HelpMessage="Enter your ApplicationSecret from the Secure Application Model")]
    [string]$ApplicationSecret,
    [Parameter(Mandatory= $true, HelpMessage="Enter your Partner Tenantid")]
    [string]$tenantID,
    [Parameter(Mandatory= $true, HelpMessage="Enter your refreshToken from the Secure Application Model")]
    [string]$refreshToken,
    [Parameter(Mandatory= $true, HelpMessage="Enter your IT Glue API Key")]
    [string]$APIKey,
    [Parameter(Mandatory= $true, HelpMessage="Enter your IT Glue URL, ex: https://api.itglue.com")]
    [string]$APIEndpoint

)


###Additional API Permissions Need for App in Azure AD ####

####DeviceManagementConfiguration.Read.All
####DeviceManagementManagedDevices.Read.All


###MICROSOFT SECRETS#####

$ApplicationId = $ApplicationId
$ApplicationSecret = $ApplicationSecret
$tenantID = $tenantID
$refreshToken = $refreshToken
$secPas = $ApplicationSecret| ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $secPas)

########################## IT-Glue Information ############################
$APIKey = $APIKey
$APIEndpoint = $APIEndpoint
$FlexAssetName = "Intune Devices"
$Description = "Documentation for all devices enrolled into Intune"

write-host "Getting IT-Glue module" -ForegroundColor Green
 
If (Get-Module -ListAvailable -Name "ITGlueAPI") { 
    Import-module ITGlueAPI 
}
Else { 
    Install-Module ITGlueAPI -Force
    Import-Module ITGlueAPI
}
#Settings IT-Glue logon information
Add-ITGlueBaseURI -base_uri $APIEndpoint
Add-ITGlueAPIKey $APIKEy

write-host "Checking if Flexible Asset exists in IT-Glue." -foregroundColor green
$FilterID = (Get-ITGlueFlexibleAssetTypes -filter_name $FlexAssetName).data
if (!$FilterID) { 
    write-host "Does not exist, creating new." -foregroundColor green
    $NewFlexAssetData = 
    @{
        type          = 'flexible-asset-types'
        attributes    = @{
            name        = $FlexAssetName
            icon        = 'laptop'
            description = $description
        }
        relationships = @{
            "flexible-asset-fields" = @{
                data = @(
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order           = 1
                            name            = "Device Name"
                            kind            = "Text"
                            required        = $true
                            "show-in-list"  = $true
                            "use-for-title" = $true
                        }
                    },

                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 2
                            name           = "Ownership"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 3
                            name           = "OS"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 4
                            name           = "OS Version"
                            kind           = "Text"
                            required       = $false
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 5
                            name           = "Compliance State"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 6
                            name           = "User"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 7
                            name           = "Autopilot Enrolled"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 8
                            name           = "Encrypted"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 9
                            name           = "Serial Number"
                            kind           = "Text"
                            required       = $true
                            "show-in-list" = $true
                        }
                    }
                    @{
                        type       = "flexible_asset_fields"
                        attributes = @{
                            order          = 10
                            name           = "Configurations"
                            'tag-type'     = "Configurations"
                            kind           = "Tag"
                            required       = $false
                            "show-in-list" = $true
                        }
                    }
                     
                )
            }
        }
    }
    New-ITGlueFlexibleAssetTypes -Data $NewFlexAssetData
    $FilterID = (Get-ITGlueFlexibleAssetTypes -filter_name $FlexAssetName).data
}


#Grab all IT-Glue contacts to match the domain name.
write-host "Getting IT-Glue contact list" -foregroundColor green
$i = 1
$AllITGlueContacts = do {
    $Contacts = (Get-ITGlueContacts -page_size 1000 -page_number $i).data.attributes
    $i++
    $Contacts
    Write-Host "Retrieved $($Contacts.count) Contacts" -ForegroundColor Yellow
}while ($Contacts.count % 1000 -eq 0 -and $Contacts.count -ne 0) 


$i=1
$AllITGlueConfigurations = do {
    $Configs = (Get-ITGlueConfigurations -page_size 1000 -page_number $i).data
    $i++
    $Configs
    Write-Host "Retrieved $($Configs.count) Configurations" -ForegroundColor Yellow
}while ($Configs.count % 1000 -eq 0 -and $Configs.count -ne 0) 

$DomainList = foreach ($Contact in $AllITGlueContacts) {
    $ITGDomain = ($contact.'contact-emails'.value -split "@")[1]
    [PSCustomObject]@{
        Domain   = $ITGDomain
        OrgID    = $Contact.'organization-id'
        Combined = "$($ITGDomain)$($Contact.'organization-id')"
    }
} 


###Connect to your Own Partner Center to get a list of customers/tenantIDs #########
$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID


Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken

$customers = Get-MsolPartnerContract -All
 
Write-Host "Found $($customers.Count) customers in Partner Center." -ForegroundColor DarkGreen

foreach ($customer in $customers) {
    Write-Host "Found $($customer.Name) in Partner Center" -ForegroundColor Green

    ###Get Access Token########
    $CustomerToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -Tenant $customer.TenantID
    $headers = @{ "Authorization" = "Bearer $($CustomerToken.AccessToken)" }
    $Devices = ""

    #####Get Intune information if it is available####
    try{
    $Devices = (Invoke-RestMethod -Uri 'https://graph.microsoft.com/beta/deviceManagement/managedDevices' -Headers $headers -Method Get -ContentType "application/json").value | Select-Object deviceName, ownerType, operatingSystem, osVersion, complianceState,userPrincipalName, autopilotEnrolled,isEncrypted, serialNumber
    }catch{('This tenant either does not have intune licensing or you have not added the correct permissions to the which are listed in the begining of this script')} 

    if($Devices){
       forEach($device in $Devices){
        forEach($configuration in $AllITGlueConfigurations){
            if($configuration.attributes.'serial-number' -eq $device.serialNumber){
                $configExist = $configuration
                Write-Host "Existing Configuration Found in ITGlue" -ForegroundColor Cyan
            } else {
                $configExist = ""
            }
        }
        $FlexAssetBody =
        @{
        type       = 'flexible-assets'
        attributes = @{
            traits = @{
             'device-name'              = $device.deviceName
             'ownership'                = $device.ownertype
             'os'                       = $device.operatingSystem
             'os-version'               = $device.osVersion
             'compliance-state'         = $device.complianceState
             'user'                     = $device.userPrincipalName
             'autopilot-enrolled'       = $device.autopilotEnrolled | Out-String
             'encrypted'                = $device.isEncrypted | Out-String
             'serial-number'            = $device.serialNumber
             'configurations'           = $configExist.id
            }
        }
    }
    Write-Host "Finding $($customer.name) in IT-Glue" -ForegroundColor Green
    $CustomerDomains = Get-MsolDomain -TenantId $Customer.TenantId
    $orgid = foreach ($customerDomain in $customerdomains) {
        ($domainList | Where-Object { $_.domain -eq $customerDomain.name }).'OrgID'
    }

    $orgID = $orgid | Select-Object -Unique
    if(!$orgID){
       Write-Host "$($customer.name) does not exist in IT-Glue" -ForegroundColor Red
    }
    if($orgID){
    $ExistingFlexAsset = (Get-ITGlueFlexibleAssets -filter_flexible_asset_type_id $($filterID.id) -filter_organization_id $orgID).data | Where-Object { $_.attributes.traits.'serial-number' -eq $device.serialNumber}
        #If the Asset does not exist, we edit the body to be in the form of a new asset, if not, we just update.
        if (!$ExistingFlexAsset) {
            $FlexAssetBody.attributes.add('organization-id', $orgID)
            $FlexAssetBody.attributes.add('flexible-asset-type-id', $($filterID.ID))
            write-host "Creating Intune Device $($device.deviceName) for $($customer.name) into IT-Glue organisation $org" -ForegroundColor Green
            New-ITGlueFlexibleAssets -data $FlexAssetBody
        }
        else {
            write-host "Updating Intune Device $($device.deviceName) for $($customer.name) into IT-Glue organisation $org"  -ForegroundColor Yellow
            $ExistingFlexAsset = $ExistingFlexAsset | select-object -last 1
            Set-ITGlueFlexibleAssets -id $ExistingFlexAsset.id -data $FlexAssetBody
        }
    }
    }}}

Final Thoughts

The script is looking for Serial Numbers to soft match an Intune enrolled device to an existing configuration and add them as a tag to the asset. I did have the thought of creating Intune devices as new configurations if they didn’t perform that soft match of the serial number but would want some feedback on that! Additionally, if you think there would be more metadata you would like to see that is part of the device, please comment that below.

You will need to garner tokens and GUIDs from both the Secure Application Model and Syncro. The secure application model allows for a headless connection into all of your customer environments. The script to run that can be found from Kelvin over at CyberDrain.

In IT Glue you will need to create a new API Key. .

Reference for steps on adding permission to your app registration.

🔌
Click here to go to that page in Github.
Click Here for IT Glue’s Documentation on generating a new API key
the following documentation