Introduction
Dual monitors are becoming more popular among end users who want to increase their productivity, multitask, and enjoy a larger screen space. However, managing dual monitors can pose some issues for IT admins who need to ensure compatibility, security, and performance of the devices. In this document, we will discuss some of the common issues faced by IT admins while managing dual monitors by end users and suggest some possible solutions to overcome them.
Compatibility Issues
One of the main issues faced by IT admins while managing dual monitors by end users is compatibility. Not all monitors are compatible with all devices, operating systems, and applications. For example, some monitors may require specific drivers, adapters, or cables to work with certain devices. Some operating systems may not support dual monitors or may have limited features for configuring them. Some applications may not scale well or may have display issues on dual monitors. These compatibility issues can cause frustration, confusion, and errors for both end users and IT admins.
- A possible solution to compatibility issues is to standardize the hardware and software used by end users and IT admins. This can reduce the variability and complexity of managing dual monitors, and ensure that all devices, operating systems, and applications are compatible with each other.
- Another possible solution is to provide clear and detailed instructions and guidelines for setting up and using dual monitors by end users and IT admins. This can help avoid common mistakes, troubleshoot problems, and optimize the performance of dual monitors.
Security Issues
Another issue faced by IT admins while managing dual monitors by end users is security. Dual monitors can increase the risk of data leakage, unauthorized access, and malware infection. For example, some end users may use dual monitors to access sensitive or confidential information on one screen, while using another screen for personal or non-work-related activities. This can expose the information to unauthorized viewers, hackers, or malicious software. Some end users may also connect their dual monitors to unsecured networks or devices, which can compromise the security of the entire system.
- A possible solution to security issues is to implement strict policies and controls for using dual monitors by end users and IT admins. This can include limiting the access to sensitive or confidential information, enforcing encryption and authentication, and monitoring the activity and performance of dual monitors.
- Another possible solution is to educate and train end users and IT admins on the best practices and risks of using dual monitors. This can help raise awareness, prevent misuse, and detect and report any security incidents.
Performance Issues
A final issue faced by IT admins while managing dual monitors by end users is performance. Dual monitors can consume more resources, bandwidth, and power than single monitors. This can affect the speed, stability, and quality of the system and the applications. For example, some end users may experience lag, flicker, or distortion on their dual monitors, especially when running multiple or high-demand applications. Some IT admins may also face difficulties in managing and updating the drivers, settings, and configurations of dual monitors, which can lead to errors, conflicts, and crashes.
- A possible solution to performance issues is to optimize the hardware and software of the system and the applications for dual monitors. This can include upgrading the devices, operating systems, and applications to support dual monitors, adjusting the resolution, refresh rate, and color settings of the monitors, and using tools and utilities to manage and monitor the performance of dual monitors.
- Another possible solution is to provide adequate support and maintenance for dual monitors by end users and IT admins. This can include providing regular updates, patches, and backups, troubleshooting and resolving any issues, and replacing or repairing any faulty or damaged monitors.
Solution
Before we implement any of these solutions, however, we need to have a clear picture of how many end users are using dual monitors and what kind of devices, operating systems, and applications they are using. This will help us to prioritize our actions, allocate our resources, and measure our outcomes. To manage users with dual monitors, we are planning to first identify machines using dual monitors and upload information about such devices in Log Analytics.
Log Analytics is a service that allows us to collect and analyze data from various sources, such as devices, applications, and services. By using Log Analytics, we can gain insights into the performance, usage, and status of our IT infrastructure and operations. We can also create custom queries, dashboards, and alerts to monitor and report on specific aspects of our IT environment.
To identify machines using dual monitors, we will use a PowerShell script that will scan the devices in WMI and detect the number and type of monitors connected to each device. The script will then upload this information to a Log Analytics workspace, where we can query and visualize the data.
PowerShell Script for Dual Monitor Detection and Log Analytics Upload
The PowerShell script that we will use to identify machines using dual monitors and upload the information to Log Analytics is using the WMI class Win32_DesktopMonitor to query the devices for the availability, device ID, and screen height and width of each monitor. The script also uses the Azure Monitor HTTP Data Collector API to send the data to a Log Analytics workspace. The script requires the following parameters:
– WorkspaceID: The ID of the Log Analytics workspace where the data will be sent.
– SharedKey: The primary or secondary key for the Log Analytics workspace.
– LogType: The name of the custom log table in Log Analytics where the data will be stored.
The script can be run manually or scheduled as a task on each device. Alternatively, we can use Intune Remediation to push the script to the devices and run it automatically. Intune Remediation is a feature that allows us to deploy and execute PowerShell scripts on devices that are enrolled in Intune. By using Intune Remediation, we can ensure that the script runs periodically and consistently on all devices.
# Replace with your Workspace ID
$CustomerId = ""
# Replace with your Primary Key
$SharedKey = ""
#For logging
Function Write-Host()
{
PARAM(
[Parameter(Mandatory=$true)]$Message,
$Info="Information"
)
[System.Diagnostics.EventLog]::WriteEntry("MultipleMonitors", "$Message", $Info, 200)
}
#To check if Module is installed
If((Get-Module -Name OMSIngestionAPI) -eq $null)
{
Write-host "OMSIngestion Module Missing... Installing..."
Try
{
Install-packageProvider -name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name OMSIngestionAPI -Force -ErrorAction Stop
#Import-Module -Name OMSIngestionAPI -Force | Out-null
}
Catch
{
Write-Host "Failed to install Module due to $Error[0]"
Return $Error[0]
Exit 0
}
}
#Capturing Device information
Try
{
$monitors = get-wmiobject Win32_DesktopMonitor -ErrorAction Stop
If($monitors.Count -gt 1)
{
Write-Host "Detected more than 1 monitor, sending data..."
}
else
{
Write-Host "Detected single monitor. Exiting..."
Exit 0
}
}
Catch
{
Write-Host "Failed to get Monitor Information from client machine due to $Error[0]"
Return $Error[0]
Exit 0
}
#Fetching DeviceID for Azure AD.
$DsregCmdStatus = dsregcmd /status
if($DsregCmdStatus -match "DeviceId")
{
$DeviceId = $DsregCmdStatus -match "DeviceID"
$DeviceId = ($DeviceId.Split(":").trim())
$DeviceId = $DeviceId[1]
}
# Specify the name of the record type that you'll be creating
$LogType = "Monitor_Report"
# Specify a field with the created time for the records
$TimeStampField = get-date
$TimeStampField = $TimeStampField.GetDateTimeFormats(115)
$MonitorData =@()
foreach ($bl in $monitors)
{
$property = @{
ComputerName = "$($env:COMPUTERNAME)"
Name = "$($bl.Name)"
Caption = "$($bl.Caption)"
MonitorManufacturer= "$($bl.MonitorManufacturer)"
DeviceID="$($bl.DeviceID)"
Status ="$($bl.Status)"
Availability ="$($bl.Availability)"
AzureADDeviceID ="$DeviceID"
}
$obj=new-Object -TypeName PSObject $property
$MonitorData += $obj
}
#Conversion to JSON
$MonitorDataJSON = $MonitorData | ConvertTo-Json -Depth 10
#Sending to Loganalytics Workspace
Try
{
Send-OMSAPIIngestionFile -customerId $customerId -sharedKey $SharedKey -body $MonitorDataJSON -logType $LogType -TimeStampField $TimeStampField -ErrorAction Stop
Write-Host "Sent BitLocker Details to Log Analytics for reporting..."
exit 0
}
Catch
{
Write-Host "Failed to send BitLocker details... $Error[0]... Will try again in next cycle." -Info "Error"
Return $Error[0]
exit 0
}
#################################################
Runbook to Add Primary Users to a Group
The following script can be used as a runbook to add primary users of devices that match the Log Analytics query to a predefined group in Azure Active Directory. The runbook requires the following parameters:
WorkspaceID: The ID of the Log Analytics workspace where the device data is stored.
Query: The Log Analytics query that filters the devices based on the criteria defined in the previous section.
GroupID: The ID of the group in Azure Active Directory where the primary users will be added.
GraphAppId: The application ID of the Graph app registration that has the permissions to read Intune and write directory data.
GraphAppSecret: The application secret of the Graph app registration.
GraphTenantId: The tenant ID of the Graph app registration.
The script uses the Az.Accounts and Az.OperationalInsights modules to connect to Azure and Log Analytics, and the Invoke-RestMethod cmdlet to make Graph API calls. The script performs the following steps:
Connect to Azure using a service principal account that has the Log Analytics Reader role.
Get the Log Analytics workspace by name and set the current context.
Invoke the Log Analytics query and get the results as an array of objects.
For each object in the array, extract the DeviceId and DeviceName properties.
Use the DeviceId property to make a Graph API call to get the primary user of the device from Intune.
If the primary user is found, use the UserPrincipalName property to make another Graph API call to add the user to the group in Azure Active Directory.
Write the output of the operation to the console, indicating the DeviceName, UserPrincipalName, and GroupName.
The script is shown below:
####################################################
Function Get-AuthToken {
param(
[Parameter(Mandatory=$true)]
$TenantID,
[Parameter(Mandatory=$true)]
$ClientID,
[Parameter(Mandatory=$true)]
$ClientSecret
)
try{
# Define parameters for Microsoft Graph access token retrieval
$resource = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$TenantID"
$tokenEndpointUri = "$authority/oauth2/token"
# Get the access token using grant type client_credentials for Application Permissions
$content = "grant_type=client_credentials&client_id=$ClientID&client_secret=$ClientSecret&resource=$resource"
$response = Invoke-RestMethod -Uri $tokenEndpointUri -Body $content -Method Post -UseBasicParsing
Write-Host "Got new Access Token!"
# If the accesstoken is valid then create the authentication header
if($response.access_token){
# Creating header for Authorization token
$authHeader = @{
'Content-Type'='application/json'
'Authorization'="Bearer " + $response.access_token
'ExpiresOn'=$response.expires_on
}
return $authHeader
}
else{
Write-Error "Authorization Access Token is null, check that the client_id and client_secret is correct..."
break
}
}
catch{
#FatalWebError -Exeption $_.Exception -Function "Get-AuthToken"
}
}
####################################################
Function Validate-AuthToken{
# Checking if authToken exists before running authentication
if($global:authToken){
Write-Host "If global authtoken valid"
# Setting DateTime to Universal time to work in all timezones
#$DateTime = (Get-Date).ToUniversalTime()
$CurrentTimeUnix = $((get-date ([DateTime]::UtcNow) -UFormat +%s)).split((Get-Culture).NumberFormat.NumberDecimalSeparator)[0]
# If the authToken exists checking when it expires
#$TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime).Minutes
$TokenExpires = [MATH]::floor(([int]$authToken.ExpiresOn - [int]$CurrentTimeUnix) / 60)
if($TokenExpires -le 0){
write-host "Authentication Token expired" $TokenExpires "minutes ago"
$global:authToken = Get-AuthToken -TenantID $global:TenantID -ClientID $global:ClientID -ClientSecret $global:ClientSecret
}
}
# Authentication doesn't exist, calling Get-AuthToken function
else {
# Getting the authorization token
Write-Host "now in else... validate token"
$global:authToken = Get-AuthToken -TenantID $global:TenantID -ClientID $global:ClientID -ClientSecret $global:ClientSecret
}
}
###################PLease define the following variables#################################
$global:ClientID = ""
$global:tenantID = ""
$global:ClientSecret = ""
$global:workspace_ID = ""
$GroupID=""
Validate-AuthToken
#############################################
# Log Analytics API URL
$LogAnalytics_API_URL = 'https://api.loganalytics.io'
$oAuthUri = "https://login.microsoftonline.com/$global:tenantID/oauth2/token"
$authBody = [Ordered] @{
resource = "$LogAnalytics_API_URL"
client_id = "$global:ClientID"
client_secret = "$global:ClientSecret"
grant_type = 'client_credentials'
}
$authResponse = Invoke-RestMethod -Method Post -Uri $oAuthUri -Body $authBody -ErrorAction Stop
$token = $authResponse.access_token
$headers = @{
'Content-Type' = 'application/json'
Accept = 'application/json'
Authorization = "Bearer $token"
}
$My_Query = 'Monitor_Report_CL | distinct AzureADDeviceID_g | where AzureADDeviceID_g != ""'
$AdvancedQueries_URL = "https://api.loganalytics.io/v1/workspaces/$global:workspace_ID/query"
$Query_Body = @{query = $My_Query} | ConvertTo-Json
$Query_response = Invoke-WebRequest -Method Post -Uri $AdvancedQueries_URL -Headers $headers -Body $Query_Body
$resultsTable = $Query_response.Content | ConvertFrom-Json
$count = 0
foreach ($table in $resultsTable.Tables)
{
$count += $table.Rows.Count
}
$results = New-Object object[] $count
$i = 0
foreach ($table in $resultsTable.Tables)
{
foreach ($row in $table.Rows)
{
$properties = @{}
for ($columnNum=0; $columnNum -lt $table.Columns.Count; $columnNum++)
{
$properties[$table.Columns[$columnNum].name] = $row[$columnNum]
}
$results[$i] = (New-Object PSObject -Property $properties)
$null = $i++
}
}
Foreach($dID in $results.AzureADDeviceID_g)
{
$PUuri = "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=azureADDeviceId eq '$dID'&`$select=userPrincipalName"
$pu=Invoke-RestMethod -Method Get -Uri $PUuri -Headers $global:authtoken
$global:Priuser=$pu.value.userPrincipalName
$uri2="https://graph.microsoft.com/v1.0/groups/$groupID/members/`$ref"
$body2 = @{
"@odata.id" = "https://graph.microsoft.com/v1.0/users/$global:Priuser"
} | ConvertTo-Json
Invoke-RestMethod -uri $uri2 -Method Post -Headers $global:authToken -Body $body2
}
This script will iterate through all the devices in the Intune tenant and find the primary user of each device. Then, it will add the primary user to a specified group in Azure AD, using the Graph API. This way, the group will contain the primary users of all the devices, and can be used to apply user-based policies or configurations.
Conclusion
This document explained how to use PowerShell and the Graph API to create a group of primary users of all the devices in Intune. This can be useful for managing user-based policies or configurations across different devices. The document provided the prerequisites, the steps to obtain an access token, and the script to perform the task. The script can be modified to suit different scenarios or requirements.
Hope this helps.

Leave a comment