For over 20 years I was a mildly successful Configuration Manager Architect without ever learning to write scripts. When I needed something that required a script, I could usually find something online that was close to what I needed, and I could modify well enough to work.

And then came Intune! The amount of work I do with ConfigMgr has dwindled over the past 5 or 6 years to the point where, for the past year and a half, I have done almost 100% Intune work. An experienced ConfigMgr person who makes the move to managing devices with Intune will quickly realize that, without PowerShell, accomplishing tasks that are considered basic functionality in ConfigMgr are virtually impossible using Intune. I have begrudgingly been trying to learn more about PowerShell for about a year and a half now. Fortunately, I have an amazing friend, Kaido Järvemets, who is great with PowerShell and has a lot of patience. He’s been super helpful to me. Thanks Kaido!

People have various learning styles, mine is to learn by doing. I prefer a real-world problem, that I care enough about to spend my time to solve, as a way to learn.

Several times I’ve needed a script to set properties such as the primary user, device category, or ownership for Intune devices. Then I had a couple of other people who I know needing the same thing. There are some scripts out there to do this, but I didn’t like any of them. None of the ones I was able to find could do everything that I needed in one single script. Most of them are using outdated cmdlets. Some have dozens of lines of code to simply authenticate to Graph, while others require and Azure AD app registration to authenticate. Don’t get me wrong, I am not knocking anyone else’s work, but I do not like using scripts if I don’t fully understand how they work and many of the ones out there seemed overly complicated to me. So, I decided that I had done enough basic scripting that I felt like could tackle this. Please note that I do not claim to be a PowerShell expert, I hope you figured that out from the first two paraphs here. I wrote them to make that point, I despise “blog fluff”. I am certain that some people will grab this script and then comment on how I could have done XYZ better. Please do! I am still learning.

I should also give some credit to Timmy Andersson who helped me solve several problems that I just could not figure out in this script. Without him I probably would not have completed it.

I had fun creating this, I hope you find it useful.

For those who, like myself, despise blog fluff, this is the part you want to read…

This script allows you to set the device category, ownership, and primary user of a single, or many Intune devices. You can set any combination of those items and you can get the list of devices and the user that you’d like to set as the primary user in as many ways as I could possibly imagine. For example, you can select devices based upon a device name prefix, from a .csv file, or input it on the command line when executing the script. You can select the primary user based on the last logged on user, from a .csv file, or on the command line. There’s error checking on everything, for example if the computer or user is not found the script will simply skip that device if you are setting the primary user. If you enter an invalid category name, you will be alerted to that. If you chose to select device based on a naming prefix you will get a big scary warning asking if you REALLY want to do that. All of this in less than 450 lines of code. I feel like I did a decent job of documenting how to use the script within the script but if you need help, don’t understand what I was thinking, or have an idea how I could have done this better feel free to ping me on Twitter @MEM_MVP 

Get the Script

PowerShell
<#
.SYNOPSIS
	Batch update Intune device category and/or primary user
    Batch update ownership to corporate.
	Batch update Intune device an input file or using a naming prefix ,
	or direct names via the -ComputerName, -CategoryName, and/or -UserName parameter(s).
.PARAMETER ComputerName
	Name of one or more computers
.PARAMETER IntputFile
	Path and name of .CSV input file
	CSV file must have a column named "ComputerName"
    Must have column named "UserName" if CSV is used also for primary user.
.PARAMETER SetCategory
    True/False value to determine whether the device category is being set.
.PARAMETER CategoryName
	A valid category name. If the name does not exist in the
	Intune subscription, it will return an error.
    Required is SetCategory is $True.
.PARAMETER SetPrimaryUser
    True/False value to determine whether the primary user is being set.
.PARAMETER LastLogonUser
    True/False value whether to use the last logon user as primary user.
.PARAMETER UserName
    Name of one or more users. Required if PrimaryUser is $True.
    Cannot be used with LastLogonUser
    Can be provided in .CSV
.PARAMETER ComputerPrefix
    Specify the prefix of computer names to set category
    Cannot be used with InputFile nor ComputerName

.NOTES
    Requires modules AzureADPreview,Microsoft.Graph.Intune,Microsoft.Graph

    7.0 - 3-21-2023 - John Marcum - csv import and last logged on user tested and confirmed to work.
#>

[CmdletBinding()]
param (
        [parameter(Mandatory = $False)][string]$ComputerName = "",
        [parameter(Mandatory = $False)][string]$ComputerPrefix = "",
        [parameter(Mandatory = $False)][string]$InputFile = "",
        [parameter(Mandatory = $False)][bool]$SetCategory = $True,
        [parameter(Mandatory = $False)][string]$CategoryName = '',
        [parameter(Mandatory = $False)][bool]$SetPrimaryUser = $True,
        [parameter(Mandatory = $False)][bool]$LastLogonUser = $False,    
        [parameter(Mandatory = $False)][string]$UserName = "",
        [parameter(Mandatory = $False)][bool]$SetOwner = $True,
        [parameter(Mandatory = $False)][string]$Owner = "company"
    
)

######## Begin Functions ########

####################################################

# Check for required modules, install if not present
function Assert-ModuleExists([string]$ModuleName) {
        $module = Get-Module $ModuleName -ListAvailable -ErrorAction SilentlyContinue
        if (!$module) {
                Write-Host "Installing module $ModuleName ..."
                Install-Module -Name $ModuleName -Force -Scope Allusers
                Write-Host "Module installed"
        }
        elseif ($module.Version -ne '1.0.0' -and $module.Version -le '1.0.410') {
                Write-Host "Updating module $ModuleName ..."
                Update-Module -Name $ModuleName -Force -ErrorAction Stop
                Write-Host "Module updated"
        }
}


####################################################

# Get device info from Intune
function Get-DeviceInfo {
        Get-IntuneManagedDevice -Filter "startswith(DeviceName, '$Computer') and operatingSystem eq 'Windows'" -Top 1000 `
        | Get-MSGraphAllPages `
        | Select-Object DeviceName, UserPrincipalName, id, userId, DeviceCategoryDisplayName, ManagedDeviceOwnerType, chassisType, usersLoggedOn
}


####################################################

# Set the device categories
function Set-DeviceCategory {
        [CmdletBinding()]
        param (
                [parameter(Mandatory)][string] $DeviceID,
                [parameter(Mandatory)][string] $CategoryID
        )
        Write-Host "Updating device category for $Computer"
        $requestBody = @{
                "@odata.id" = "$baseUrl/deviceManagement/deviceCategories/$CategoryID" # $CategoryName
        }
        $url = "$baseUrl/deviceManagement/managedDevices/$DeviceID/deviceCategory/`$ref"
        Write-Host "request-url: $url"
        
        $null = Invoke-MSGraphRequest -HttpMethod PUT -Url $url -Content $requestBody
        Write-Host "Device category for $Computer updated"
}
        

####################################################

# Set the device ownership
function Set-Owner {
        [CmdletBinding()]
        param (
                [parameter(Mandatory)][string] $DeviceID,
                [parameter(Mandatory)][string] $Owner       
        )
        Write-Host "Updating owner for $Computer"

      
                
        $JSON = @"
{
ownerType:"$Owner"
}
"@

        $uri = "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$deviceId')"
        Invoke-MSGraphRequest -Url $uri -HttpMethod PATCH -Content $Json
}
        

####################################################

# Get Intune Primary User
function Get-IntuneDevicePrimaryUser {

        [CmdletBinding()]
        param (
                [parameter(Mandatory)][string] $DeviceID   
        )

     
        $graphApiVersion = "beta"
        $Resource = "deviceManagement/managedDevices"
        $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)" + "/" + $deviceId + "/users"

        try {
        
                $primaryUser = Invoke-MSGraphRequest -Url $uri -HTTPMethod Get

                return $primaryUser.value."id"
        
        }
        catch {
                $ex = $_.Exception
                $errorResponse = $ex.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($errorResponse)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd();
                Write-Host "Response content:`n$responseBody" -f Red
                Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
                throw "Get-IntuneDevicePrimaryUser error"
        }
        
}


####################################################

# Set the Intune primary user
function Set-IntuneDevicePrimaryUser {
        [cmdletbinding()]
        param

        (
                [parameter(Mandatory = $true)]
                [ValidateNotNullOrEmpty()]
                $DeviceId,
                [parameter(Mandatory = $true)]
                [ValidateNotNullOrEmpty()]
                $userId
        )

        $graphApiVersion = "beta"
        $Resource = "deviceManagement/managedDevices('$DeviceId')/users/`$ref"     

        $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
        $userUri = "https://graph.microsoft.com/$graphApiVersion/users/" + $userId
        

        $JSON = @"

{"@odata.id":"$userUri"}

"@
     

        Invoke-MSGraphRequest -HttpMethod POST -Url $uri -Content $JSON  
}


####################################################

# Set the primary user of the device to the last logged on user if it they are not already the same user

function Set-LastLogon {    
        $IntuneDevicePrimaryUser = Get-IntuneDevicePrimaryUser -deviceId $DeviceID
        #Check if there is a Primary user set on the device already
        if ($IntuneDevicePrimaryUser -eq $null) {
                Write-Host "No Intune Primary User Id set for Intune Managed Device" $Device.deviceName
        }
        else {
                $PrimaryAADUser = Get-AzureADUser -ObjectId $IntuneDevicePrimaryUser
                Write-Host "Intune Device Primary User:" $PrimaryAADUser.displayName
        }
        #Get the objectID of the last logged in user for the device, which is the last object in the list of usersLoggedOn
        $LastLoggedInUser = ($Device.usersLoggedOn[-1]).userId
        #Using the objectID, get the user from the Microsoft Graph for logging purposes
        $User = Get-AzureADUser -ObjectId $LastLoggedInUser
        #Check if the current primary user of the device is the same as the last logged in user
        if ($IntuneDevicePrimaryUser -notmatch $User.id) {
                #If the user does not match, then set the last logged in user as the new Primary User
                $SetIntuneDevicePrimaryUser = Set-IntuneDevicePrimaryUser -IntuneDeviceId $Device.id -userId $User.id
                if ($SetIntuneDevicePrimaryUser -eq "") {
                        Write-Host "User"$User.displayName"set as Primary User for device '$($Device.deviceName)'..." 
                }
        }
        else {
                #If the user is the same, then write to host that the primary user is already correct.
                Write-Host "The user '$($User.displayName)' is already the Primary User on the device..."
        }
}

####################################################


######## End Functions ########


######## Script Entry Point ########

# Install required modules
if ($SetPrimaryUser) {
        Assert-ModuleExists -ModuleName "AzureAD"
}
Assert-ModuleExists -ModuleName "Microsoft.Graph.Intune"
Assert-ModuleExists -ModuleName "MSGraph"

# Import modules
if ($SetPrimaryUser) {
        Import-Module "AzureAD"
}
Import-Module "Microsoft.Graph.Intune"
Import-Module "MSGraph"

# Connect to Azure to get user ID's
if ($SetPrimaryUser) {
        Write-Host "connecting to: azure ad"
        if (!($azconn)) { 
                $azconn = Connect-AzureAD
                Write-Host "connected to $azconn.TenantDomain"
        }
}

# Connect to Graph API
Write-Host "connecting to: msgraph"
[string]$baseUrl = "https://graph.microsoft.com/beta"
if (!($GraphCon )) {
        $GraphCon = Connect-MSGraph -ForceInteractive
}
Update-MSGraphEnvironment -SchemaVersion beta



# Get the computers that we want to work onE
if (($ComputerPrefix) -and ($InputFile)) {
        $Msg = @'
Prefix And InputFile Cannot
    Used Together!
        EXITING!
'@
        [System.Windows.MessageBox]::Show($Msg, 'Error!', 'Ok', 'Error')
        # Exit 1
}

if ([string]::IsNullOrEmpty($ComputerName)) {
        if ($InputFile) {
                Write-Host "computername was not provided, checking intputfile parameter"
                if (-not(Test-Path $InputFile)) {
                        throw "file not found: $InputFile"
                }
                else {
                        if ($InputFile.EndsWith(".csv")) {
                                [array]$computers = Import-Csv -Path $InputFile | Select-Object ComputerName, UserName
                                Write-Host "Found $($Computers.Count) devices in file"             

                        }
                        else {
                                throw "Only .csv files are supported"
                        }
                }
        } 
        if ($ComputerPrefix) {
                Write-Host "Getting computers with the prefix from Intune"
                # Confirm that you really want to run against all computers!
                $Msg = @'
Seleting all devices with prefix!
ARE YOU SURE YOU WANT TO DO THIS?
THIS HAS POTENTIAL TO DO DAMAGE! 
'@
                $Result = [System.Windows.MessageBox]::Show($Msg, 'CAUTION!', 'YesNo', 'Warning')
                Write-Host "Your choice is $Result"
                if ($Result -eq 'No') {
                        throw 'Exiting to prevent a disater!'
                        Exit 1
                }
                $Computers = Get-MgDeviceManagementManagedDevice -Filter "startswith(DeviceName, '$ComputerPrefix') and operatingSystem eq 'Windows'" -Top 1000 | Get-MSGraphAllPages | Select-Object DeviceName, UserPrincipalName, id, userId, DeviceCategoryDisplayName, ManagedDeviceOwnerType
                Write-Host "Found $($Computers.Count) devices in Intune"
   
        }
}
else {
        Write-Host "computer name was provided via command line"
        $Computers = $ComputerName -split ','
}


# Set Device Category
if ($SetCategory) {
        # Get the categories from Intune so we have the ID
        Write-Host "Getting List of Categories from Intune"
        $Categories = Get-DeviceManagement_DeviceCategories
        $CatNames = $Categories.DisplayName
        Write-host "Found $($Categories.Count) Categories in Intune"  
        
        if ($CategoryName) {
                # Validate category name is valid        
                Write-Host "validating requested category: $CategoryName"
                $Category = $Categories | Where-Object { $_.displayName -eq $CategoryName }
                if (!($Category)) { 
                        Write-Warning  "Category name $CategoryName not valid" 
                }
                $CategoryID = $Category.id
                Write-Host "$CategoryName is $CategoryID"
        }
        else {
                Write-Warning  "No category name specified"
       
        } 

        # Set the device categories
        foreach ($Computer in $Computers) {
                if ($InputFile) {
                        $Computer = $Computer.ComputerName
                }
                $Device = Get-DeviceInfo
                Write-Host "Found $($Device.Count) devices in Intune"
                if (!($device)) {
                        Write-Warning "$Computer not found in Intune"
                }
                else {
                        $DeviceID = $Device.id
                        if ($Device.deviceCategoryDisplayName -ne $CategoryName) {
                                Write-Progress -Status "Updating Device Category" -Activity "$computer ($deviceId) --> $($device.deviceCategoryDisplayName)"
                                Write-Host "Device Name = $Computer"
                                Write-Host "Device ID = $DeviceID"
                                Write-Host "Current category is $($Device.deviceCategoryDisplayName)"
                                Write-Host "Setting category to $CategoryName"
                                Set-DeviceCategory -DeviceID $DeviceID -category $CategoryID
                        }
                        else {
                                write-host "$Computer is already in $CategoryName"
                        }
                }
        }
}



# Set Device Ownership
if ($SetOwner) {
        foreach ($Computer in $Computers) {
                if ($InputFile) {
                        $Computer = $Computer.ComputerName
                }
                $Device = Get-DeviceInfo
                Write-Host "Found $($Device.Count) devices in Intune"
                if (!($device)) {
                        Write-Warning "$Computer not found in Intune"
                }
                else {
                        $DeviceID = $Device.id
                        if ($Device.ManagedDeviceOwnerType -ne $Owner) {
                                Write-Progress -Status "Updating Device Owner" -Activity "$computer ($deviceId) --> $($device.ManagedDeviceOwnerType)"
                                Write-Host "Device Name = $Computer"
                                Write-Host "Device ID = $DeviceID"
                                Write-Host "Current ownership is $($Device.ManagedDeviceOwnerType)"
                                Write-Host "Setting ownership to $Owner"
                                Set-Owner -DeviceID $DeviceID -owner $Owner
                        }
                        else {
                                write-host "$Computer is already set to $Owner"
                        }
                }
        }
}


# Set Primary User
if ($SetPrimaryUser) {        
        if ([string]::IsNullOrEmpty($UserName)) {
                if ($LastLogonUser) {
                        foreach ($computer in $computers) {
                                $Device = Get-DeviceInfo
                                Write-Host "Found $($Device.Count) devices in Intune"
                                $Userid = ($Device.usersLoggedOn[-1]).userId
                                Write-Host "Found $User $Userid"
                                if (!($device -and $Userid)) {
                                        Write-Warning "$Computer and/or $User not found"
                                }
                                else {
                                        $DeviceID = $Device.id                                              
                                        Set-LastLogon
                                }
                        }
                }
                if (!($LastLogonUser)) {
                        if ($Inputfile) {
                               
                                foreach ($Row in $computers) {
                                        $Computer = $Row.ComputerName
                                        $User = $Row.UserName
                                        $Device = Get-DeviceInfo
                                        Write-Host "Found $Device in Intune"
                                        $Userid = Get-AzureADUser -Filter "userPrincipalName eq '$User'" | Select -ExpandProperty ObjectId
                                        Write-Host "Found $User $Userid"
                                        if (!($device -and $Userid)) {
                                                Write-Warning "$Computer and/or $User not found"
                                        }
                                        else {
                                                $DeviceID = $Device.id
                                                $CurrentUser = Get-IntuneDevicePrimaryUser -DeviceId $deviceID
                                                if ($CurrentUser -ne $Userid) {
                                                        Set-IntuneDevicePrimaryUser -DeviceId $deviceID -userId $userID 
                                                }
                                                else {
                                                        Write-Host "No change in user is needed"
                                                }
                                        }
                                }
                        }
                }
        }
        else {
                foreach ($computer in $computers) {
                        write-host "UserName was specified on the command line"
                        $Device = Get-DeviceInfo
                        Write-Host "Found $($Device.Count) devices in Intune"
                        $Userid = Get-AzureADUser -Filter "userPrincipalName eq '$Username'" | Select -ExpandProperty ObjectId
                        Write-Host "Found $User $Userid"
                        if (!($device -and $Userid)) {
                                Write-Warning "$Computer and/or $User not found"
                        }
                        else {
                                $DeviceID = $Device.id
                                $CurrentUser = Get-IntuneDevicePrimaryUser -DeviceId $deviceID
                                if ($CurrentUser -ne $Userid) {
                                        Set-IntuneDevicePrimaryUser -DeviceId $deviceID -userId $userID
                                }
                                else {
                                        Write-Host "No change in user is needed"
                                }
                        }
                }
        }
}