Intune

Purpose

This project will follow this YouTube series in a green field setup to help backfill knowledge gaps in Intune as it’s a product I’ve used on an “as needed” basis. Previous experience was incredibly hands-off on employee systems as those employees were old-hat at any/everything PC related. Combine that with legitimate needs for local admin rights and there wasn’t a huge need for management via MDM. The majority of my current experience is around conditional access rules and minor configuration POIs for security and PCI compliance.

The general idea is to start with that Reboot playlist and then backtrack through some of the more recent items. It’s a bit of a backwards approach, however, the entire reason for the reboot is an incredibly valid one for not starting from their first videos - so much has changed they’re no longer relevant.

Notes will not be taken for every process, step, etc. in the videos - I’m not regurgitating their content here. Instead, call outs around special items, points of interest, etc. will be documented in separate sections below. Any repetitive tasks should be automated as well for future reference.

Company Branding

  • Legal disclaimers and notices are needed
  • Company branding around images, custom CSS on the login pages, etc.

License By Group

A licensing strategy that helps standardize user licensing and provisioning.

  1. Establish licensing standards
    • E1 + P2
    • E3 + E5 Security
      • etc.
  2. Create group objects and license them according to the licensing standards
  3. Assign users to the appropriate license group
    1. It can also be assigned to pre-existing groups
    2. IMO I would keep this separate as group memberships can become really entwined. Theoretically conflicts would come up when a user is added to the licensed HR group but they’re already a member of the licensed CLevel group.
      • Solve by fencing of security, license, feature, etc. groups

User Management

Technically managed over in the Entra ID portal but it was created while going through the Intune items - so it wound up here.

User management, especially around onboarding and offboarding, leaves a lot of room for human error when performed manually. Luckily, we have PowerShell scripts and their new Workflows.

User Scripts

############ Section 1 ############
# Check if the Az module is installed and install if not
# Be careful if using the -AllowClobber as it can step on other modules

Write-Host "Checking that the required Az module is installed. If not, we'll try to install it."
$azModule = Get-Module -Name Az -ListAvailable
if (!$azModule) {
    Write-Host "The Az module is not installed, installing it now..."
    Install-Module -Name "Az" -Force
    Import-Module Az
}

# Test if there is an existing Az context
$azContext = Get-AzContext -ErrorAction SilentlyContinue
if (!$azContext) {
    # If the context is null, sign in
    Write-Host "No existing Az context found. Please sign in to your Azure account."
    Connect-AzAccount
}

############ Section 2 ############
# Build the user and UPN

Write-Host "Prompting for required information. Default values will be displayed as (#)"
$firstName = Read-Host "Enter the user's first name." | ForEach-Object { $_ -creplace '\b\w', { $_.Value.ToUpper() } }
$lastName = Read-Host "Enter the user's surname name." | ForEach-Object { $_ -creplace '\b\w', { $_.Value.ToUpper() } }

# Default location is the US - just press enter
# If it needs to be the UK location - press 2
$location = "US"

# Prompt for UK
Clear-Host
$locationCheck = Read-Host "Setting user to United States location by default. Press 2 if their location should be the UK."
if ($locationCheck -eq '2') {
    $location = "UK"
}
Write-Host "Selected location: $location"

# Build UPN
$nickName = "$($lastName.ToLower())$($firstName.ToLower().Substring(0, 1))"
$upn = "$nickName@yourdomain.com"

# Prompt for temporary password (12 digit requirement)
$tempPassword = $null

Clear-Host
Write-Host "Prompting for a secure password now. This must be 12 digits long and include numbers, letters, symbols, etc."
while ($tempPassword -eq $null -or $tempPassword.Length -lt 12) {
    $tempPassword = Read-Host "Enter a 12-digit temporary password" -AsSecureString
    if ($tempPassword.Length -lt 12) {
        Write-Host "Password must be at least 12 digits, try again."
    }
}

############ Section 3 ############
# Prompt for license group
# The E1 group are users with email only
# The E3 Security group is the standard E3 with the E5 security addon
# The E5 group is the full E5 package

do {
    $groupSelection = Read-Host @"
Please select the appropriate license group (2):
Enter for default
1. E1 Users - Email Only
2. E3 Users - Email and Office
3. E5 Users - The kitchen sink
"@

    # Default to 2 on enter
    if ($groupSelection -eq '') {
        $groupSelection = 2
    }

    # Validate and default if invalid
    if ($groupSelection -notin ('1', '2', '3')) {
        Write-Host "Looks like that was an invalid option. Setting default to 2."
        $groupSelection = 2
    }
    else {
        $validSelection = $true
    }
} while (-not $validSelection)

# Convert the selection to the actual group
switch ($groupSelection) {
    1 { 
        $groupName = "E1License" 
        break
    }
    2 { 
        $groupName = "E3License" 
        break
    }
    3 { 
        $groupName = "E5License"
        break
    }
    default {
        $groupName = $null
        Write-Host "Invalid selection. Please enter 1, 2, or 3."
        break
    }
}

# Display the selection
Write-Host "Selected group: $groupName"

############ Section 4 ############
# Convert password and Create the user

# Convert secure string to plain text for the New-AzADUser cmdlet
$tempPWPlainText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($tempPassword))

$PasswordProfile = @{
    Password                      = $tempPWPlainText
    ForceChangePasswordNextSignIn = $true
}

$newUserParams = @{
    UserPrincipalName  = $upn
    DisplayName        = "$firstName $lastName"
    GivenName          = $firstName
    Surname            = $lastName
    MailNickname       = $nickName
    UsageLocation      = $location
    UserType           = "Member"
    PasswordProfile    = $PasswordProfile
    AccountEnabled     = $true
}

$newUser = New-AzADUser @newUserParams
Import-Module MSOnline
Import-Module AzureAD
# Connect all the things
$yourName = Read-Host "Enter your UPN."

# Connect to Azure Active Directory
Connect-MsolService
#Exchange Online
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName $yourName -ShowProgress $true

# Confirm user input
$userName = Read-Host "Enter the username of the user to offboard"

Clear-Host
# Get user information
$user = Get-AzureADUser -ObjectId $userName
$manager = Get-AzureADUserManager -ObjectId $user.ObjectId
$managerUPN = $manager.UserPrincipalName
Write-Host "Full Name: $($user.DisplayName)"
Write-Host "Manager's UserPrincipalName: $($managerUPN)"

# Confirm offboarding
$confirmation = Read-Host "Enter Yes to offboard this user"
if ($confirmation -ne "Yes") {
    Write-Host "Offboarding cancelled"
    return
}

# Convert the user's mailbox to a shared mailbox
Write-Host "Converting user mailbox to a shared mailbox: $($user.UserPrincipalName)"
Set-Mailbox -Identity $userName -Type Shared
# Assign FullAccess permissions to the manager for the shared mailbox
Add-MailboxPermission -Identity "$($user.UserPrincipalName)\Mailbox" -User "$($manager.UserPrincipalName)\Mailbox" -AccessRights 'FullAccess'
Write-Host "Shared mailbox assigned to manager: $($managerUPN)"

# Get user group memberships
$groups = Get-AzureADUserMembership -ObjectId $user.ObjectId | Where-Object { $_.ObjectType -eq "Group" }

# Get user licenses
$licenses = Get-AzureADUserLicenseDetail -ObjectId $user.ObjectId

# Get user enterprise app assignments
$apps = Get-AzureADUserAppRoleAssignment -ObjectId $user.ObjectId

# Get user distribution list memberships
$distLists = Get-AzureADUserMembership -ObjectId $user.ObjectId | Where-Object { $_.ObjectType -eq "DistributionList" }

# Display user information
Write-Host "Group Memberships:"
foreach ($group in $groups) {
    Write-Host "- $($group.DisplayName)"
}
Write-Host "Licenses:"
foreach ($license in $licenses) {
    Write-Host "- $($license.SkuPartNumber)"
}
Write-Host "Enterprise App Assignments:"
foreach ($app in $apps) {
    Write-Host "- $($app.AppDisplayName) - $($app.DisplayName)"
}
Write-Host "Distribution List Memberships:"
foreach ($distList in $distLists) {
    Write-Host "- $($distList.DisplayName)"
}

# Confirm removal from groups
$removeGroups = Read-Host "Remove user from all groups (except Domain Users)? Enter Yes to confirm"
if ($removeGroups -eq "Yes") {
    foreach ($group in $groups) {
        if ($group.ObjectType -eq "MailEnabledSecurityGroup") {
            Write-Host "Skipping removal from mail-enabled security group: $($group.DisplayName)"
        }
        elseif ($group.ObjectType -eq "DistributionList") {
            # Remove the user from the distribution list
            Remove-DistributionGroupMember -Identity $group.DisplayName -Member $user.UserPrincipalName -Confirm:$false
            Write-Host "User $($user.DisplayName) removed from distribution list $($group.DisplayName)"
        }
        else {
            # Remove the user from other types of groups
            Remove-AzureADGroupMember -ObjectId $group.ObjectId -MemberId $user.ObjectId
            Write-Host "User $($user.DisplayName) removed from group $($group.DisplayName)"
        }
    }
}

if ($removeGroups -eq "Yes")

## Confirm removal of licenses
$removeLicenses = Read-Host "Remove all licenses? Enter Yes to confirm"
if ($removeLicenses -eq "Yes") {
    foreach ($license in $licenses) {
        $license.SkuId | ForEach-Object {
            $licenseDetail = Get-AzADSubscribedSku -SkuId $_
            if ($licenseDetail.AccountSkuId -ne "tenant:ENTERPRISEPACK") {
                Set-AzADUserLicense -ObjectId $user.ObjectId -RemoveLicenses @($licenseDetail.SkuId) -Verbose
                Write-Host "License $($licenseDetail.SkuPartNumber) removed from user $($user.DisplayName)"
            }
        }
    }
}

## Confirm removal from distribution lists
# This shouldnt be necessary anymore as the distribution list is being treated as a group, and removed there.
#$removeDistLists = Read-Host "Remove user from all distribution lists? Enter Yes to confirm"
#if ($removeDistLists -eq "Yes") {
#    foreach ($distList in $distLists) {
#        Remove-AzADGroupMember -ObjectId $distList.ObjectId -MemberId $user.ObjectId -Confirm:$false
#        Write-Host "User $($user.DisplayName) removed from distribution list $($distList.DisplayName)"
#    }
#}

# Log removed items
$logPath = "C:\logs\offboarding.log"
$currentTime = Get-Date
Add-Content $logPath "$currentTime - User $($user.DisplayName) offboarded"
Add-Content $logPath "Removed Groups:"
foreach ($group in $groups) {
    if ($group.DisplayName -ne "Domain Users") {
        Add-Content $logPath "- $($group.DisplayName)"
    }
}

Identity Workflows

Cobbled together Powershell scripts may be a thing of the past if you fork over the money for the Microsoft Entra ID Governance licenses. Looks like Intune grew up and there are now different management tiers with only the top one allowing access to their workflows.

MacOS Enrollment

Unfortunately, a business ID is required to complete these steps. This will be something to pursue in detail at a future date.

  • A very emphatic, “Ah!” around default enrollment restrictions
    • Default policy is assigned to all devices by default
    • User policies are then built on top of the default policy
    • Changing registration for personal devices to block can impact the ability to register devices
  • A separate video specifically around device enrollment will be done around
  • Restriction policies can be specified per type with additional policies layered on top of the default that cover different scopes
  • Prod settings around MDM and MAM called out

Android Provisioning

Managed Google Play

Android is apparently the most problematic registration/provisioning. First prerequisite is the managed play store.

The primary doc for adding apps is, IMO, required reading for anyone spending any time managing these deployments. Especially familiarizing on the app types table, update authority (automatic or manual where you must update it) and the prerequisites for users to use the app.

  1. Intune portal > Devices > Android > Android Enrollment > Managed Google Play
    • Launch and sign in with a Google account
    • Cannot use G-Suite accounts (or at least there are restrictions covered later)
    • Apps can be added/managed once the tenant is associated with the Google Account
  2. Navigate to Intune Portal > Apps > Android and add the “Managed Google Play” app type
    • Other store apps, LOBs, Enterprise, etc. can be added via this process and providing the APK file(s)
    • Find the app, select it, and sync

Corporate Owned - Fully Managed

The first scenario are devices entirely owned by the company for use by a single user. Intune admins manage everything on the device and have complete control. Docs are here.

The shtick with Corporate Owned, fully managed is that admins must install and administer all apps on the device unless they explicitly modify policy to allow users access to the Play Store.

  1. Devices > Enrollment > Android Tab > Corporate-owned, fully managed user devices
  2. On the android device:
    1. Tap on the screen five times to bring up the camera and scan the QR code
    2. The device now belongs to the corporation
      1. Zero-touch enrollment skips this process
    3. Be sure that all users understand the level of visibility corporate has (everything)
  3. Login at the prompt and it will update and install apps automatically
  4. Follow the on-screen prompts to complete the registration process