Fix missing properties

This commit is contained in:
2024-07-03 09:29:28 +02:00
parent f0db61b7e9
commit a37fdf783f
2 changed files with 568 additions and 197 deletions

View File

@@ -53,18 +53,17 @@
#region ---------------------------------------------------[Modifiable Parameters and defaults]------------------------------------
# Customizations
[System.Object]$Enrollmentaccounts = @("install@tbone.se", "wds@tbone.se") # @() = No Enrollment accounts. @("wds@tbone.se","wds2@tbone.se") = will filter them out and not assign them as primary users.
[int]$SigninsTimeSpan = 30 # Number of days back in time to look back for Sign-In logs (Default 30 days)
[int]$DeviceTimeSpan = 30 # Number of days back in time to look back for active devices (Default 30 days)
[Bool]$TestMode = $False # $True = No changes will be made on Primary owner, $False = Primary Owner will be changed
[Bool]$Verboselogging = $False # $Ture = Enable verbose logging for t-shoot. $False = Disable Verbose Logging
[Bool]$ReturnReport = $True # $True = Will return a report with all devices and primary users. $False = No report will be returned
[System.Object]$Enrollmentaccounts = @("install@tbone.se","wds@tbone.se") # @() = No Enrollment accounts. @("wds@tbone.se","wds2@tbone.se") = will filter them out and not assign them as primary users.
[int]$SigninsTimeSpan = 30 # Number of days back in time to look back for Sign-In logs (Default 30 days)
[int]$DeviceTimeSpan = 30 # Number of days back in time to look back for active devices (Default 30 days)
[Bool]$TestMode = $False # $True = No changes will be made on Primary owner, $False = Primary Owner will be changed
[Bool]$Verboselogging = $False # $Ture = Enable verbose logging for t-shoot. $False = Disable Verbose Logging
[Bool]$ReturnReport = $True # $True = Will return a report with all devices and primary users. $False = No report will be returned
#Batch Runtime settings
[Bool]$RunBatchMode = $true #Run the script in batch mode, faster but uses more memory, recommended for large environments
[int]$Batchsize = 20 #How many objects to process in each batch
[int]$waittime = 0 #How many seconds to wait between Batches to avoid throttling
[int]$MaxRetry = 50 #How many retries of trottled requests before error
[string[]]$DeviceGroups = @("Group1", "Group2") # Add your desired groups here
[Bool]$RunBatchMode = $true #Run the script in batch mode, faster but uses more memory, recommended for large environments
[int]$Batchsize = 20 #How many objects to process in each batch
[int]$waittime = 0 #How many seconds to wait between Batches to avoid throttling
[int]$MaxRetry = 50 #How many retries of trottled requests before error
#endregion
#region ---------------------------------------------------[Set global script settings]--------------------------------------------
@@ -78,17 +77,17 @@ import-Module Microsoft.Graph.Reports
#endregion
#region ---------------------------------------------------[Static Variables]------------------------------------------------------
[Int64]$MemoryUsage = 0
[System.Object]$report = @()
[System.Object]$IntuneDevices = @()
[System.Object]$SignInLogs = @()
[System.Object]$AllPrimaryUsersHash = @()
[System.Object]$RequiredScopes = ("DeviceManagementManagedDevices.ReadWrite.All", "AuditLog.Read.All", "User.Read.All")
[datetime]$scriptStartTime = Get-Date
[datetime]$SignInsStartTime = (Get-Date).AddDays(-$SigninsTimeSpan )
[datetime]$DeviceStartTime = (Get-Date).AddDays(-$DeviceTimeSpan )
if ($Verboselogging) { $VerbosePreference = "Continue" }
else { $VerbosePreference = "SilentlyContinue" }
[Int64]$MemoryUsage = 0
[System.Object]$report = @()
[System.Object]$IntuneDevices = @()
[System.Object]$SignInLogs = @()
[System.Object]$AllPrimaryUsersHash = @()
[System.Object]$RequiredScopes = ("DeviceManagementManagedDevices.ReadWrite.All", "AuditLog.Read.All", "User.Read.All")
[datetime]$scriptStartTime = Get-Date
[datetime]$SignInsStartTime = (Get-Date).AddDays(-$SigninsTimeSpan )
[datetime]$DeviceStartTime = (Get-Date).AddDays(-$DeviceTimeSpan )
if ($Verboselogging){$VerbosePreference = "Continue"}
else{$VerbosePreference = "SilentlyContinue"}
#endregion
#region ---------------------------------------------------[Functions]------------------------------------------------------------
@@ -100,50 +99,40 @@ function ConnectTo-MgGraph {
$ErrorActionPreference = 'stop'
[String]$resourceURL = "https://graph.microsoft.com/"
$GraphAccessToken = $null
if ($env:AUTOMATION_ASSET_ACCOUNTID) { [Bool]$ManagedIdentity = $true } # Check if running in Azure Automation
else { [Bool]$ManagedIdentity = $false } # Otherwise running in Local PowerShell
}
if ($env:AUTOMATION_ASSET_ACCOUNTID) { [Bool]$ManagedIdentity = $true} # Check if running in Azure Automation
else { [Bool]$ManagedIdentity = $false} # Otherwise running in Local PowerShell
}
Process {
if ($ManagedIdentity) {
#Connect to the Microsoft Graph using the ManagedIdentity and get the AccessToken
Try {
$response = [System.Text.Encoding]::Default.GetString((Invoke-WebRequest -UseBasicParsing -Uri "$($env:IDENTITY_ENDPOINT)?resource=$resourceURL" -Method 'GET' -Headers @{'X-IDENTITY-HEADER' = "$env:IDENTITY_HEADER"; 'Metadata' = 'True' }).RawContentStream.ToArray()) | ConvertFrom-Json
if ($ManagedIdentity){ #Connect to the Microsoft Graph using the ManagedIdentity and get the AccessToken
Try{$response = [System.Text.Encoding]::Default.GetString((Invoke-WebRequest -UseBasicParsing -Uri "$($env:IDENTITY_ENDPOINT)?resource=$resourceURL" -Method 'GET' -Headers @{'X-IDENTITY-HEADER' = "$env:IDENTITY_HEADER"; 'Metadata' = 'True'}).RawContentStream.ToArray()) | ConvertFrom-Json
$GraphAccessToken = $response.access_token
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get an Access Token to Graph for managed identity"
}
Catch { Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get an Access Token to Graph for managed identity, with error: $_" }
}
Catch{Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get an Access Token to Graph for managed identity, with error: $_"}
$GraphVersion = ($GraphVersion = (Get-Module -Name 'Microsoft.Graph.Authentication' -ErrorAction SilentlyContinue).Version | Sort-Object -Desc | Select-Object -First 1)
if ('2.0.0' -le $GraphVersion) {
Try {
Connect-MgGraph -ManagedIdentity -Nowelcome
Try{Connect-MgGraph -ManagedIdentity -Nowelcome
$GraphAccessToken = convertto-securestring($response.access_token) -AsPlainText -Force
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph with module 2.x and Managedidentity"
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph with module 2.x and Managedidentity"}
Catch{Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph with module 2.x and Managedidentity, with error: $_"}
}
Catch { Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph with module 2.x and Managedidentity, with error: $_" }
}
else {
#Connect to the Microsoft Graph using the AccessToken
Try {
Connect-mgGraph -AccessToken $GraphAccessToken
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph with module 1.x and Managedidentity"
else {#Connect to the Microsoft Graph using the AccessToken
Try{Connect-mgGraph -AccessToken $GraphAccessToken
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph with module 1.x and Managedidentity"}
Catch{Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph with module 1.x and Managedidentity, with error: $_"}
}
Catch { Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph with module 1.x and Managedidentity, with error: $_" }
}
}
else {
Try {
Connect-MgGraph -Scope $RequiredScopes -NoWelcome
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph manually"
else{
Try{Connect-MgGraph -Scope $RequiredScopes -NoWelcome
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph manually"}
Catch{Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph manually, with error: $_"}
}
Catch { Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph manually, with error: $_" }
}
#Check and cleanup memory after connecting to Graph
return $GraphAccessToken
}
End {
$MemoryUsage = [System.GC]::GetTotalMemory($true)
}
End {$MemoryUsage = [System.GC]::GetTotalMemory($true)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to cleanup Memory usage after connect to Graph to: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
}
}
}
function get-mggraphrequestbatch {
Param(
@@ -155,78 +144,70 @@ function get-mggraphrequestbatch {
[int]$BatchSize,
[int]$WaitTime,
[int]$MaxRetry
)
)
Begin {
$Retrycount = 0
$CollectedObjects = [System.Collections.ArrayList]@()
$LookupHash = @{}
if ($env:AUTOMATION_ASSET_ACCOUNTID) { $ManagedIdentity = $true } # Check if running in Azure Automation
else { $ManagedIdentity = $false } # Otherwise running in Local PowerShell
}
if ($env:AUTOMATION_ASSET_ACCOUNTID) {$ManagedIdentity = $true} # Check if running in Azure Automation
else {$ManagedIdentity = $false} # Otherwise running in Local PowerShell
}
Process {
do {
$TotalObjects = $objects.count
[int]$i = 0
$currentObject = 0
$RetryObjects = [System.Collections.ArrayList]@()
#Start looping all objects and run batches
for ($i = 0; $i -lt $TotalObjects; $i += $BatchSize) {
#Start looping all objects and run batches
for($i=0;$i -lt $TotalObjects;$i+=$BatchSize){
# Create Requests of id, method and url
[System.Object]$req = @()
if ($i + ($BatchSize - 1) -lt $TotalObjects) {
$req += ($objects[$i..($i + ($BatchSize - 1))] | Select-Object @{n = 'id'; e = { $_.id } }, @{n = 'method'; e = { 'GET' } }, @{n = 'url'; e = { "/$($Object)/$($_.id)$($uri)" } })
}
elseif ($TotalObjects -eq 1) {
$req += ($objects[$i] | Select-Object @{n = 'id'; e = { $_.id } }, @{n = 'method'; e = { 'GET' } }, @{n = 'url'; e = { "/$($Object)/$($_.id)$($uri)" } })
}
else {
$req += ($objects[$i..($TotalObjects - 1)] | Select-Object @{n = 'id'; e = { $_.id } }, @{n = 'method'; e = { 'GET' } }, @{n = 'url'; e = { "/$($Object)/$($_.id)$($uri)" } })
if($i + ($BatchSize-1) -lt $TotalObjects){
$req += ($objects[$i..($i+($BatchSize-1))] | Select-Object @{n='id';e={$_.id}},@{n='method';e={'GET'}},@{n='url';e={"/$($Object)/$($_.id)$($uri)"}})
} elseif ($TotalObjects -eq 1) {
$req += ($objects[$i] | Select-Object @{n='id';e={$_.id}},@{n='method';e={'GET'}},@{n='url';e={"/$($Object)/$($_.id)$($uri)"}})
} else {
$req += ($objects[$i..($TotalObjects-1)] | Select-Object @{n='id';e={$_.id}},@{n='method';e={'GET'}},@{n='url';e={"/$($Object)/$($_.id)$($uri)"}})
}
#Send the requests in a batch
$responses = invoke-mggraphrequest -Method POST `
-URI "https://graph.microsoft.com/$($RunProfile)/`$batch" `
-body (@{'requests' = $req } | convertto-json)
#Process the responses and verify status
-body (@{'requests' = $req} | convertto-json)
#Process the responses and verify status
foreach ($respons in $responses.responses) {
$CurrentObject++
switch ($respons.status) {
200 {
[void] $CollectedObjects.Add($respons)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get object $($respons.id) from Graph batches"
}
403 { write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Access denied during Graph batches - Status: $($respons.status)" }
404 { write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Result not found during Graph batches- Status: $($respons.status)" }
429 {
[void] $RetryObjects.Add($respons)
write-warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning, Throttling occured during Graph batches- Status: $($respons.status)"
}
default {
[void] $RetryObjects.Add($respons)
write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Other error occured during Graph batches - Status: $($respons.status)"
}
200 {[void] $CollectedObjects.Add($respons)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get object $($respons.id) from Graph batches" }
403 {write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Access denied during Graph batches - Status: $($respons.status)"}
404 {write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Result not found during Graph batches- Status: $($respons.status)"}
429 {[void] $RetryObjects.Add($respons)
write-warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning, Throttling occured during Graph batches- Status: $($respons.status)"}
default {[void] $RetryObjects.Add($respons)
write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Other error occured during Graph batches - Status: $($respons.status)"}
}
}
#progressbar
$Elapsedtime = (get-date) - $starttime
$timeLeft = [TimeSpan]::FromMilliseconds((($ElapsedTime.TotalMilliseconds / $CurrentObject) * ($TotalObjects - $CurrentObject)))
if (!$ManagedIdentity) {
if (!$ManagedIdentity){
Write-Progress -Activity "Get $($uri) $($CurrentObject) of $($TotalObjects)" `
-Status "Est Time Left: $($timeLeft.Hours) Hour, $($timeLeft.Minutes) Min, $($timeLeft.Seconds) Sek - Throttled $($retryObjects.count) - Retry $($Retrycount) of $($MaxRetry)" `
-PercentComplete $([math]::ceiling($($CurrentObject / $TotalObjects) * 100))
}
$throttledResponses = $responses.responses | Select-Object -last 20 | Where-Object { $_.status -eq "429" }
$throttledResponse = $throttledResponses | Select-Object -last 1
# | Select-Object -Property *,@{Name='HasDelay';Expression={$null -ne $_.headers."retry-after"}} | Where-Object HasDelay -eq $true
$throttledResponses = $responses.responses | Select-Object -last 20 | Where-Object {$_.status -eq "429"}
$throttledResponse = $throttledResponses |select -last 1
# | Select-Object -Property *,@{Name='HasDelay';Expression={$null -ne $_.headers."retry-after"}} | Where-Object HasDelay -eq $true
if ($throttledResponse) {
[int]$recommendedWait = ($throttledResponses.headers.'retry-after' | Measure-object -Maximum).maximum
write-warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning Throttling occured during Graph batches, Will wait the recommended $($recommendedWait+1) seconds"
Start-Sleep -Seconds ($recommendedWait + 1)
}
else { Start-Sleep -Milliseconds $WaitTime } #to avoid throttling
else{Start-Sleep -Milliseconds $WaitTime} #to avoid throttling
}
if ($RetryObjects.Count -gt 0 -and $MaxRetry -gt 0) {
if ($RetryObjects.Count -gt 0 -and $MaxRetry -gt 0){
$Retrycount++
$MaxRetry--
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to start rerun batches with $($RetryObjects.Count) collected a total of $($CollectedObjects.count))"
@@ -234,14 +215,13 @@ function get-mggraphrequestbatch {
$objects = $RetryObjects
}
}While ($RetryObjects.Count -gt 0 -and $MaxRetry -gt 0)
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success returning $($CollectedObjects.count) objects from Graph batching"
foreach ($CollectedObject in $CollectedObjects) { $LookupHash[$CollectedObject.id] = $CollectedObject }
return $LookupHash
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success returning $($CollectedObjects.count) objects from Graph batching"
foreach ($CollectedObject in $CollectedObjects) {$LookupHash[$CollectedObject.id] = $CollectedObject}
return $LookupHash
}
End {
$MemoryUsage = [System.GC]::GetTotalMemory($true)
End {$MemoryUsage = [System.GC]::GetTotalMemory($true)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to cleanup Memory usage after Graph batching to: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
}
}
}
function Set-IntunePrimaryUsers {
param (
@@ -254,93 +234,78 @@ function Set-IntunePrimaryUsers {
)
Begin {
$ErrorActionPreference = 'stop'
[int]$i = 0
[String]$EnrollmentaccountsFilter = ($Enrollmentaccounts | ForEach-Object { [regex]::escape($_) }) -join '|'
}
[int]$i=0
[String]$EnrollmentaccountsFilter = ($Enrollmentaccounts|ForEach-Object{[regex]::escape($_)}) -join '|'
}
Process {
[System.Object]$report = @()
Foreach ($IntuneDevice in $IntuneDevices) {
[System.Object]$SignInLogsOnDevice = $null
[System.Object]$MostFrequentUser = $null
[hashtable]$primaryuserHash = @{}
[String]$MostFrequentUserPrincipalname = $null
[String]$MostFrequentUserID = $null
[String]$primaryUser = $null
[System.Object]$report = @()
Foreach ($IntuneDevice in $IntuneDevices){
[System.Object]$SignInLogsOnDevice = $null
[System.Object]$MostFrequentUser = $null
[hashtable]$primaryuserHash = @{}
[String]$MostFrequentUserPrincipalname = $null
[String]$MostFrequentUserID = $null
[String]$primaryUser = $null
$i++
#Get current Primary User
if ($AllPrimaryUsersHash.count -gt 0) {
$PrimaryuserHash = $AllPrimaryUsersHash[$IntuneDevice.id]
$primaryUserJson = ($primaryuserHash.body.value | ConvertTo-Json -Depth 9 | ConvertFrom-Json -Depth 9)
if ($AllPrimaryUsersHash.count -gt 0){$PrimaryuserHash = $AllPrimaryUsersHash[$IntuneDevice.id]
$primaryUserJson = ($primaryuserHash.body.value | ConvertTo-Json -Depth 9 | ConvertFrom-Json)
if ($primaryUserJson -and $primaryUserJson.PSObject.Properties.Name -contains 'userprincipalname') {
$primaryuser = $primaryUserJson.userprincipalname
}
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get Primary User $($Primaryuser) for $($IntuneDevice.DeviceName) from batch lookup"
}
$primaryuser = $primaryUserJson.userprincipalname}
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get Primary User $($Primaryuser) for $($IntuneDevice.DeviceName) from batch lookup"}
else {
try {
$primaryUser = (Get-MgDeviceManagementManagedDeviceUser -ManagedDeviceId $IntuneDevice.ID -property "UserPrincipalName").UserPrincipalName
try {$primaryUser = (Get-MgDeviceManagementManagedDeviceUser -ManagedDeviceId $IntuneDevice.ID -property "UserPrincipalName").UserPrincipalName
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get Primary User $($Primaryuser) for device $($IntuneDevice.DeviceName) from Graph"
}
catch{write-Warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Primary User $($Primaryuser) for device $($IntuneDevice.DeviceName) from Graph with error: $_"
}
}
catch {
write-Warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Primary User $($Primaryuser) for device $($IntuneDevice.DeviceName) from Graph with error: $_"
}
}
if (!$primaryUser) { $primaryUser = ""; write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success getting Primary user for device $($IntuneDevice.DeviceName) but device has no Primary User" }
if (!$primaryUser){$primaryUser = "";write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success getting Primary user for device $($IntuneDevice.DeviceName) but device has no Primary User"}
# Get sign in logs for the device
if ($enrollmentaccounts.count -ge 1) { $SignInLogsOnDevice = $SignInLogs | Where-Object { $_.deviceid -eq $IntuneDevice.AzureAdDeviceId -and $_.userprincipalname -notmatch $EnrollmentaccountsFilter } }
else { $SignInLogsOnDevice = $SignInLogs | Where-Object { $_.deviceid -eq $IntuneDevice.AzureAdDeviceId } }
if ($SignInLogsOnDevice) { $SignInUsers = $SignInLogsOnDevice | Select-Object userprincipalname, UserId | Group-Object userprincipalname }
else {
if ($enrollmentaccounts.count -ge 1){$SignInLogsOnDevice = $SignInLogs | Where-Object {$_.deviceid -eq $IntuneDevice.AzureAdDeviceId -and $_.userprincipalname -notmatch $EnrollmentaccountsFilter}}
else {$SignInLogsOnDevice = $SignInLogs | Where-Object {$_.deviceid -eq $IntuneDevice.AzureAdDeviceId}}
if ($SignInLogsOnDevice){$SignInUsers = $SignInLogsOnDevice | Select-Object userprincipalname, UserId | Group-Object userprincipalname}
else{
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning Device $($IntuneDevice.DeviceName) is skipped due to failing to find Sign-In logs"
if ($ReturnReport) { $report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning Device $($IntuneDevice.DeviceName) is skipped due to failing to find Sign-In logs" }
continue
}
if ($ReturnReport){$report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning Device $($IntuneDevice.DeviceName) is skipped due to failing to find Sign-In logs"}
continue}
$MostFrequentUser = $SignInUsers | Sort-Object count | Select-Object -Last 1
$MostFrequentUserPrincipalname = $MostFrequentUser.group[0].UserPrincipalName
$MostFrequentUserID = $MostFrequentUser.group[0].UserID
$IntuneDeviceID = $IntuneDevice.id
#Set primary User if needed
if (($MostFrequentUserPrincipalname) -and ($MostFrequentUserid) -and ($MostFrequentUserPrincipalname -ne $PrimaryUser)) {
if (($MostFrequentUserPrincipalname) -and ($MostFrequentUserid) -and ($MostFrequentUserPrincipalname -ne $PrimaryUser))
{
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine change needed on Device $($IntuneDevice.DeviceName) primaryuser from $($PrimaryUser) to $($MostFrequentUserPrincipalname)"
$uri = "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$IntuneDeviceID')/users/`$ref"
$Body = @{ "@odata.id" = "https://graph.microsoft.com/beta/users/$MostFrequentUserid" } | ConvertTo-Json
$Method = "POST"
if (!$TestMode) {
try {
Invoke-MgGraphRequest -Method $Method -uri $uri -body $Body
if (!$TestMode){
try{Invoke-MgGraphRequest -Method $Method -uri $uri -body $Body
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)"
if ($ReturnReport) { $report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)" }
}
catch {
write-Warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName) with error: $_"
if ($ReturnReport) { $report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName) with error: $_" }
if ($ReturnReport){$report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)"}}
catch{write-Warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName) with error: $_"
if ($ReturnReport){$report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName) with error: $_"}}
}
else{write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Testmode - Will not set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)"
if ($ReturnReport){$report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Testmode - Will not set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)"}}
}
else {
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Testmode - Will not set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)"
if ($ReturnReport) { $report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Testmode - Will not set Primary User $($MostFrequentUserPrincipalname) for device $($IntuneDevice.DeviceName)" }
}
}
else {
if (!$MostFrequentUserPrincipalname) {
else{
if (!$MostFrequentUserPrincipalname){
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) has no logins in collected logs"
if ($ReturnReport) { $report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) has no logins in collected logs" }
}
else {
write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) have correct Primary User $($PrimaryUser)"
if ($ReturnReport) { $report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) have correct Primary User $($PrimaryUser)" }
if ($ReturnReport){$report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) has no logins in collected logs"}}
else {write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) have correct Primary User $($PrimaryUser)"
if ($ReturnReport){$report += "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to determine that Device $($IntuneDevice.DeviceName) have correct Primary User $($PrimaryUser)"}}
}
}
}
return $report
}
End {
$MemoryUsage = [System.GC]::GetTotalMemory($true)
}
End {$MemoryUsage = [System.GC]::GetTotalMemory($true)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to cleanup Memory usage after set Primary Users to: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
}
}
}
#endregion
@@ -348,35 +313,14 @@ function Set-IntunePrimaryUsers {
$StartTime = Get-Date
$MgGraphAccessToken = ConnectTo-MgGraph -RequiredScopes $RequiredScopes
# Get Intune Devices
try {
$IntuneDevices = Get-MgDeviceManagementManagedDevice -Filter "operatingSystem eq 'Windows' and LastSyncDateTime gt $($DeviceStartTime.ToString('yyyy-MM-ddTHH:mm:ssZ'))" -All -Property "AzureAdDeviceId,DeviceName,Id"
if ($DeviceGroups.Count -gt 0) {
$GroupIds = @()
foreach ($group in $DeviceGroups) {
$groupObj = Get-MgGroup -Filter "displayName eq '$group'" -Property id
if ($groupObj) {
$GroupIds += $groupObj.id
}
else {
Write-Warning "Group $group not found."
}
}
$DeviceIdsInGroups = @()
foreach ($groupId in $GroupIds) {
$devicesInGroup = Get-MgGroupMember -GroupId $groupId -All -Property id | Where-Object { $_.'@odata.type' -eq '#microsoft.graph.device' }
$DeviceIdsInGroups += $devicesInGroup.id
}
$IntuneDevices = $IntuneDevices | Where-Object { $DeviceIdsInGroups -contains $_.Id }
}
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get $($IntuneDevices.Count) Devices with selected properties for devices synced last $($DeviceTimeSpan) days"
#Get Intune Devices
try{
$IntuneDevices = @(Get-MgDeviceManagementManagedDevice -filter "operatingSystem eq 'Windows'and LastSyncDateTime gt $($DeviceStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"))" -all -Property "AzureAdDeviceId,DeviceName,Id")
$IntuneDeviceCount = $IntuneDevices | Measure-Object | Select-Object -ExpandProperty Count
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get $($IntuneDeviceCount) Devices with selected properties for devices synced last $($DeviceTimeSpan) days"
}
catch {
Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Devices with error: $_"
catch{
write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Devices with error: $_"
}
#Memory Garbage collection
@@ -384,38 +328,45 @@ $MemoryUsage = [System.GC]::GetTotalMemory($true)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to cleanup Memory usage after get devices to: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
#Get Sign-In logs
try {
$SignInLogs = Get-MgAuditLogSignIn -Filter "appDisplayName eq 'Windows Sign In' and CreatedDateTime gt $($SignInsStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"))" -All | Select-Object devicedetail.deviceid, userprincipalname, UserId -ExpandProperty devicedetail
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get $($SignInLogs.count) Sign-In logs with selected properties for last $($SigninsTimeSpan) days"
try{
$SignInLogs = Get-MgAuditLogSignIn -Filter "appDisplayName eq 'Windows Sign In' and CreatedDateTime gt $($SignInsStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"))" -All | select devicedetail.deviceid,userprincipalname, UserId -ExpandProperty devicedetail
$SignInLogCount = $SignInLogs | Measure-Object | Select-Object -ExpandProperty Count
write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get $($SignInLogCount) Sign-In logs with selected properties for last $($SigninsTimeSpan) days"
}
catch{
write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Sign-In logs with error: $_"
}
catch { write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Sign-In logs with error: $_" }
#Memory Garbage collection
$MemoryUsage = [System.GC]::GetTotalMemory($true)
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to cleanup Memory usage after get Sign-In logs to: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
if (($IntuneDevices) -and ($SignInLogs)) {
If ($RunBatchMode) {
#Getting Primary Users in batch mode
try {
if (($IntuneDevices) -and ($SignInLogs)){
If ($RunBatchMode){ #Getting Primary Users in batch mode
try{
$AllPrimaryUsersHash = get-mggraphrequestbatch -RunProfile "beta" -method GET -Object "deviceManagement/managedDevices" -objects $IntuneDevices -uri "/users" -BatchSize $Batchsize -WaitTime $waittime -MaxRetry $MaxRetry
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get Primary Users for $($AllPrimaryUsersHash.count) Devices"
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get Primary Users for $($AllPrimaryUsersHash.count) Devices"
}
catch{
write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Primary Users for Devices with error: $_"
}
catch { Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Primary Users for Devices with error: $_" }
$report = Set-IntunePrimaryUsers -IntuneDevices $IntuneDevices -SignInLogs $SignInLogs -AllPrimaryUsersHash $AllPrimaryUsersHash -Enrollmentaccounts $Enrollmentaccounts -TestMode $TestMode -ReturnReport $ReturnReport
}
else {
#Getting Primary Users in foreach mode
else{ #Getting Primary Users in foreach mode
$report = Set-IntunePrimaryUsers -IntuneDevices $IntuneDevices -SignInLogs $SignInLogs -AllPrimaryUsersHash $AllPrimaryUsersHash -Enrollmentaccounts $Enrollmentaccounts -TestMode $TestMode -ReturnReport $ReturnReport
}
}
else { write-Warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),No Devices or Sign-In logs found, exiting script" }
else{
write-Warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),No Devices or Sign-In logs found, exiting script"
}
if ($ReturnReport) { write-Output -InputObject $report }
if ($ReturnReport){
write-Output -InputObject $report
}
disconnect-mggraph | out-null
[datetime]$scriptEndTime = Get-Date
$MemoryUsage = [System.GC]::GetTotalMemory($false)
[datetime]$scriptEndTime = Get-Date
$MemoryUsage = [System.GC]::GetTotalMemory($false)
write-Output "Script execution time: $(($scriptEndTime-$scriptStartTime).ToString('hh\:mm\:ss'))"
Write-Output "Memory Usage at the end of script execution: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
$VerbosePreference = "SilentlyContinue"