Fix missing properties
This commit is contained in:
@@ -53,18 +53,17 @@
|
|||||||
|
|
||||||
#region ---------------------------------------------------[Modifiable Parameters and defaults]------------------------------------
|
#region ---------------------------------------------------[Modifiable Parameters and defaults]------------------------------------
|
||||||
# Customizations
|
# 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.
|
[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]$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)
|
[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]$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]$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
|
[Bool]$ReturnReport = $True # $True = Will return a report with all devices and primary users. $False = No report will be returned
|
||||||
#Batch Runtime settings
|
#Batch Runtime settings
|
||||||
[Bool]$RunBatchMode = $true #Run the script in batch mode, faster but uses more memory, recommended for large environments
|
[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]$Batchsize = 20 #How many objects to process in each batch
|
||||||
[int]$waittime = 0 #How many seconds to wait between Batches to avoid throttling
|
[int]$waittime = 0 #How many seconds to wait between Batches to avoid throttling
|
||||||
[int]$MaxRetry = 50 #How many retries of trottled requests before error
|
[int]$MaxRetry = 50 #How many retries of trottled requests before error
|
||||||
[string[]]$DeviceGroups = @("Group1", "Group2") # Add your desired groups here
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ---------------------------------------------------[Set global script settings]--------------------------------------------
|
#region ---------------------------------------------------[Set global script settings]--------------------------------------------
|
||||||
@@ -78,17 +77,17 @@ import-Module Microsoft.Graph.Reports
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ---------------------------------------------------[Static Variables]------------------------------------------------------
|
#region ---------------------------------------------------[Static Variables]------------------------------------------------------
|
||||||
[Int64]$MemoryUsage = 0
|
[Int64]$MemoryUsage = 0
|
||||||
[System.Object]$report = @()
|
[System.Object]$report = @()
|
||||||
[System.Object]$IntuneDevices = @()
|
[System.Object]$IntuneDevices = @()
|
||||||
[System.Object]$SignInLogs = @()
|
[System.Object]$SignInLogs = @()
|
||||||
[System.Object]$AllPrimaryUsersHash = @()
|
[System.Object]$AllPrimaryUsersHash = @()
|
||||||
[System.Object]$RequiredScopes = ("DeviceManagementManagedDevices.ReadWrite.All", "AuditLog.Read.All", "User.Read.All")
|
[System.Object]$RequiredScopes = ("DeviceManagementManagedDevices.ReadWrite.All", "AuditLog.Read.All", "User.Read.All")
|
||||||
[datetime]$scriptStartTime = Get-Date
|
[datetime]$scriptStartTime = Get-Date
|
||||||
[datetime]$SignInsStartTime = (Get-Date).AddDays(-$SigninsTimeSpan )
|
[datetime]$SignInsStartTime = (Get-Date).AddDays(-$SigninsTimeSpan )
|
||||||
[datetime]$DeviceStartTime = (Get-Date).AddDays(-$DeviceTimeSpan )
|
[datetime]$DeviceStartTime = (Get-Date).AddDays(-$DeviceTimeSpan )
|
||||||
if ($Verboselogging) { $VerbosePreference = "Continue" }
|
if ($Verboselogging){$VerbosePreference = "Continue"}
|
||||||
else { $VerbosePreference = "SilentlyContinue" }
|
else{$VerbosePreference = "SilentlyContinue"}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ---------------------------------------------------[Functions]------------------------------------------------------------
|
#region ---------------------------------------------------[Functions]------------------------------------------------------------
|
||||||
@@ -100,50 +99,40 @@ function ConnectTo-MgGraph {
|
|||||||
$ErrorActionPreference = 'stop'
|
$ErrorActionPreference = 'stop'
|
||||||
[String]$resourceURL = "https://graph.microsoft.com/"
|
[String]$resourceURL = "https://graph.microsoft.com/"
|
||||||
$GraphAccessToken = $null
|
$GraphAccessToken = $null
|
||||||
if ($env:AUTOMATION_ASSET_ACCOUNTID) { [Bool]$ManagedIdentity = $true } # Check if running in Azure Automation
|
if ($env:AUTOMATION_ASSET_ACCOUNTID) { [Bool]$ManagedIdentity = $true} # Check if running in Azure Automation
|
||||||
else { [Bool]$ManagedIdentity = $false } # Otherwise running in Local PowerShell
|
else { [Bool]$ManagedIdentity = $false} # Otherwise running in Local PowerShell
|
||||||
}
|
}
|
||||||
Process {
|
Process {
|
||||||
if ($ManagedIdentity) {
|
if ($ManagedIdentity){ #Connect to the Microsoft Graph using the ManagedIdentity and get the AccessToken
|
||||||
#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
|
||||||
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
|
$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"
|
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)
|
$GraphVersion = ($GraphVersion = (Get-Module -Name 'Microsoft.Graph.Authentication' -ErrorAction SilentlyContinue).Version | Sort-Object -Desc | Select-Object -First 1)
|
||||||
if ('2.0.0' -le $GraphVersion) {
|
if ('2.0.0' -le $GraphVersion) {
|
||||||
Try {
|
Try{Connect-MgGraph -ManagedIdentity -Nowelcome
|
||||||
Connect-MgGraph -ManagedIdentity -Nowelcome
|
|
||||||
$GraphAccessToken = convertto-securestring($response.access_token) -AsPlainText -Force
|
$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
|
||||||
else {
|
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"}
|
||||||
#Connect to the Microsoft Graph using the AccessToken
|
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: $_"}
|
||||||
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: $_" }
|
|
||||||
}
|
}
|
||||||
}
|
else{
|
||||||
else {
|
Try{Connect-MgGraph -Scope $RequiredScopes -NoWelcome
|
||||||
Try {
|
Write-verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to connect to Graph manually"}
|
||||||
Connect-MgGraph -Scope $RequiredScopes -NoWelcome
|
Catch{Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to connect to Graph manually, with error: $_"}
|
||||||
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: $_" }
|
|
||||||
}
|
|
||||||
#Check and cleanup memory after connecting to Graph
|
#Check and cleanup memory after connecting to Graph
|
||||||
return $GraphAccessToken
|
return $GraphAccessToken
|
||||||
}
|
}
|
||||||
End {
|
End {$MemoryUsage = [System.GC]::GetTotalMemory($true)
|
||||||
$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"
|
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 {
|
function get-mggraphrequestbatch {
|
||||||
Param(
|
Param(
|
||||||
@@ -155,78 +144,70 @@ function get-mggraphrequestbatch {
|
|||||||
[int]$BatchSize,
|
[int]$BatchSize,
|
||||||
[int]$WaitTime,
|
[int]$WaitTime,
|
||||||
[int]$MaxRetry
|
[int]$MaxRetry
|
||||||
)
|
)
|
||||||
Begin {
|
Begin {
|
||||||
$Retrycount = 0
|
$Retrycount = 0
|
||||||
$CollectedObjects = [System.Collections.ArrayList]@()
|
$CollectedObjects = [System.Collections.ArrayList]@()
|
||||||
$LookupHash = @{}
|
$LookupHash = @{}
|
||||||
if ($env:AUTOMATION_ASSET_ACCOUNTID) { $ManagedIdentity = $true } # Check if running in Azure Automation
|
if ($env:AUTOMATION_ASSET_ACCOUNTID) {$ManagedIdentity = $true} # Check if running in Azure Automation
|
||||||
else { $ManagedIdentity = $false } # Otherwise running in Local PowerShell
|
else {$ManagedIdentity = $false} # Otherwise running in Local PowerShell
|
||||||
}
|
}
|
||||||
Process {
|
Process {
|
||||||
do {
|
do {
|
||||||
$TotalObjects = $objects.count
|
$TotalObjects = $objects.count
|
||||||
[int]$i = 0
|
[int]$i = 0
|
||||||
$currentObject = 0
|
$currentObject = 0
|
||||||
$RetryObjects = [System.Collections.ArrayList]@()
|
$RetryObjects = [System.Collections.ArrayList]@()
|
||||||
#Start looping all objects and run batches
|
#Start looping all objects and run batches
|
||||||
for ($i = 0; $i -lt $TotalObjects; $i += $BatchSize) {
|
for($i=0;$i -lt $TotalObjects;$i+=$BatchSize){
|
||||||
# Create Requests of id, method and url
|
# Create Requests of id, method and url
|
||||||
[System.Object]$req = @()
|
[System.Object]$req = @()
|
||||||
if ($i + ($BatchSize - 1) -lt $TotalObjects) {
|
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)" } })
|
$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) {
|
||||||
elseif ($TotalObjects -eq 1) {
|
$req += ($objects[$i] | Select-Object @{n='id';e={$_.id}},@{n='method';e={'GET'}},@{n='url';e={"/$($Object)/$($_.id)$($uri)"}})
|
||||||
$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)"}})
|
||||||
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
|
#Send the requests in a batch
|
||||||
$responses = invoke-mggraphrequest -Method POST `
|
$responses = invoke-mggraphrequest -Method POST `
|
||||||
-URI "https://graph.microsoft.com/$($RunProfile)/`$batch" `
|
-URI "https://graph.microsoft.com/$($RunProfile)/`$batch" `
|
||||||
-body (@{'requests' = $req } | convertto-json)
|
-body (@{'requests' = $req} | convertto-json)
|
||||||
#Process the responses and verify status
|
#Process the responses and verify status
|
||||||
foreach ($respons in $responses.responses) {
|
foreach ($respons in $responses.responses) {
|
||||||
$CurrentObject++
|
$CurrentObject++
|
||||||
switch ($respons.status) {
|
switch ($respons.status) {
|
||||||
200 {
|
200 {[void] $CollectedObjects.Add($respons)
|
||||||
[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" }
|
||||||
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)"}
|
||||||
403 { write-error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Error Access denied during Graph batches - Status: $($respons.status)" }
|
429 {[void] $RetryObjects.Add($respons)
|
||||||
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)" }
|
write-warning "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Warning, Throttling occured during Graph batches- Status: $($respons.status)"}
|
||||||
429 {
|
default {[void] $RetryObjects.Add($respons)
|
||||||
[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)"}
|
||||||
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
|
#progressbar
|
||||||
$Elapsedtime = (get-date) - $starttime
|
$Elapsedtime = (get-date) - $starttime
|
||||||
$timeLeft = [TimeSpan]::FromMilliseconds((($ElapsedTime.TotalMilliseconds / $CurrentObject) * ($TotalObjects - $CurrentObject)))
|
$timeLeft = [TimeSpan]::FromMilliseconds((($ElapsedTime.TotalMilliseconds / $CurrentObject) * ($TotalObjects - $CurrentObject)))
|
||||||
if (!$ManagedIdentity) {
|
if (!$ManagedIdentity){
|
||||||
Write-Progress -Activity "Get $($uri) $($CurrentObject) of $($TotalObjects)" `
|
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)" `
|
-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))
|
-PercentComplete $([math]::ceiling($($CurrentObject / $TotalObjects) * 100))
|
||||||
}
|
}
|
||||||
$throttledResponses = $responses.responses | Select-Object -last 20 | Where-Object { $_.status -eq "429" }
|
$throttledResponses = $responses.responses | Select-Object -last 20 | Where-Object {$_.status -eq "429"}
|
||||||
$throttledResponse = $throttledResponses | Select-Object -last 1
|
$throttledResponse = $throttledResponses |select -last 1
|
||||||
# | Select-Object -Property *,@{Name='HasDelay';Expression={$null -ne $_.headers."retry-after"}} | Where-Object HasDelay -eq $true
|
# | Select-Object -Property *,@{Name='HasDelay';Expression={$null -ne $_.headers."retry-after"}} | Where-Object HasDelay -eq $true
|
||||||
if ($throttledResponse) {
|
if ($throttledResponse) {
|
||||||
[int]$recommendedWait = ($throttledResponses.headers.'retry-after' | Measure-object -Maximum).maximum
|
[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"
|
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)
|
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++
|
$Retrycount++
|
||||||
$MaxRetry--
|
$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))"
|
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
|
$objects = $RetryObjects
|
||||||
}
|
}
|
||||||
}While ($RetryObjects.Count -gt 0 -and $MaxRetry -gt 0)
|
}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"
|
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 }
|
foreach ($CollectedObject in $CollectedObjects) {$LookupHash[$CollectedObject.id] = $CollectedObject}
|
||||||
return $LookupHash
|
return $LookupHash
|
||||||
}
|
}
|
||||||
End {
|
End {$MemoryUsage = [System.GC]::GetTotalMemory($true)
|
||||||
$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"
|
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 {
|
function Set-IntunePrimaryUsers {
|
||||||
param (
|
param (
|
||||||
@@ -254,93 +234,78 @@ function Set-IntunePrimaryUsers {
|
|||||||
)
|
)
|
||||||
Begin {
|
Begin {
|
||||||
$ErrorActionPreference = 'stop'
|
$ErrorActionPreference = 'stop'
|
||||||
[int]$i = 0
|
[int]$i=0
|
||||||
[String]$EnrollmentaccountsFilter = ($Enrollmentaccounts | ForEach-Object { [regex]::escape($_) }) -join '|'
|
[String]$EnrollmentaccountsFilter = ($Enrollmentaccounts|ForEach-Object{[regex]::escape($_)}) -join '|'
|
||||||
}
|
}
|
||||||
Process {
|
Process {
|
||||||
[System.Object]$report = @()
|
[System.Object]$report = @()
|
||||||
Foreach ($IntuneDevice in $IntuneDevices) {
|
Foreach ($IntuneDevice in $IntuneDevices){
|
||||||
[System.Object]$SignInLogsOnDevice = $null
|
[System.Object]$SignInLogsOnDevice = $null
|
||||||
[System.Object]$MostFrequentUser = $null
|
[System.Object]$MostFrequentUser = $null
|
||||||
[hashtable]$primaryuserHash = @{}
|
[hashtable]$primaryuserHash = @{}
|
||||||
[String]$MostFrequentUserPrincipalname = $null
|
[String]$MostFrequentUserPrincipalname = $null
|
||||||
[String]$MostFrequentUserID = $null
|
[String]$MostFrequentUserID = $null
|
||||||
[String]$primaryUser = $null
|
[String]$primaryUser = $null
|
||||||
$i++
|
$i++
|
||||||
#Get current Primary User
|
#Get current Primary User
|
||||||
if ($AllPrimaryUsersHash.count -gt 0) {
|
if ($AllPrimaryUsersHash.count -gt 0){$PrimaryuserHash = $AllPrimaryUsersHash[$IntuneDevice.id]
|
||||||
$PrimaryuserHash = $AllPrimaryUsersHash[$IntuneDevice.id]
|
$primaryUserJson = ($primaryuserHash.body.value | ConvertTo-Json -Depth 9 | ConvertFrom-Json)
|
||||||
$primaryUserJson = ($primaryuserHash.body.value | ConvertTo-Json -Depth 9 | ConvertFrom-Json -Depth 9)
|
|
||||||
if ($primaryUserJson -and $primaryUserJson.PSObject.Properties.Name -contains 'userprincipalname') {
|
if ($primaryUserJson -and $primaryUserJson.PSObject.Properties.Name -contains 'userprincipalname') {
|
||||||
$primaryuser = $primaryUserJson.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"}
|
||||||
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 {
|
else {
|
||||||
try {
|
try {$primaryUser = (Get-MgDeviceManagementManagedDeviceUser -ManagedDeviceId $IntuneDevice.ID -property "UserPrincipalName").UserPrincipalName
|
||||||
$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"
|
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 {
|
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"}
|
||||||
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" }
|
|
||||||
|
|
||||||
# Get sign in logs for the device
|
# Get sign in logs for the device
|
||||||
if ($enrollmentaccounts.count -ge 1) { $SignInLogsOnDevice = $SignInLogs | Where-Object { $_.deviceid -eq $IntuneDevice.AzureAdDeviceId -and $_.userprincipalname -notmatch $EnrollmentaccountsFilter } }
|
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 } }
|
else {$SignInLogsOnDevice = $SignInLogs | Where-Object {$_.deviceid -eq $IntuneDevice.AzureAdDeviceId}}
|
||||||
if ($SignInLogsOnDevice) { $SignInUsers = $SignInLogsOnDevice | Select-Object userprincipalname, UserId | Group-Object userprincipalname }
|
if ($SignInLogsOnDevice){$SignInUsers = $SignInLogsOnDevice | Select-Object userprincipalname, UserId | Group-Object userprincipalname}
|
||||||
else {
|
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"
|
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" }
|
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
|
continue}
|
||||||
}
|
|
||||||
$MostFrequentUser = $SignInUsers | Sort-Object count | Select-Object -Last 1
|
$MostFrequentUser = $SignInUsers | Sort-Object count | Select-Object -Last 1
|
||||||
$MostFrequentUserPrincipalname = $MostFrequentUser.group[0].UserPrincipalName
|
$MostFrequentUserPrincipalname = $MostFrequentUser.group[0].UserPrincipalName
|
||||||
$MostFrequentUserID = $MostFrequentUser.group[0].UserID
|
$MostFrequentUserID = $MostFrequentUser.group[0].UserID
|
||||||
$IntuneDeviceID = $IntuneDevice.id
|
$IntuneDeviceID = $IntuneDevice.id
|
||||||
|
|
||||||
#Set primary User if needed
|
#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)"
|
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"
|
$uri = "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$IntuneDeviceID')/users/`$ref"
|
||||||
$Body = @{ "@odata.id" = "https://graph.microsoft.com/beta/users/$MostFrequentUserid" } | ConvertTo-Json
|
$Body = @{ "@odata.id" = "https://graph.microsoft.com/beta/users/$MostFrequentUserid" } | ConvertTo-Json
|
||||||
$Method = "POST"
|
$Method = "POST"
|
||||||
if (!$TestMode) {
|
if (!$TestMode){
|
||||||
try {
|
try{Invoke-MgGraphRequest -Method $Method -uri $uri -body $Body
|
||||||
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)"
|
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)" }
|
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: $_"
|
||||||
catch {
|
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: $_"}}
|
||||||
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 {
|
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 (!$MostFrequentUserPrincipalname){
|
||||||
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) {
|
|
||||||
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"
|
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" }
|
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)"
|
||||||
else {
|
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)"}}
|
||||||
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
|
return $report
|
||||||
}
|
}
|
||||||
End {
|
End {$MemoryUsage = [System.GC]::GetTotalMemory($true)
|
||||||
$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"
|
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
|
#endregion
|
||||||
|
|
||||||
@@ -348,35 +313,14 @@ function Set-IntunePrimaryUsers {
|
|||||||
$StartTime = Get-Date
|
$StartTime = Get-Date
|
||||||
$MgGraphAccessToken = ConnectTo-MgGraph -RequiredScopes $RequiredScopes
|
$MgGraphAccessToken = ConnectTo-MgGraph -RequiredScopes $RequiredScopes
|
||||||
|
|
||||||
# Get Intune Devices
|
#Get Intune Devices
|
||||||
try {
|
try{
|
||||||
$IntuneDevices = Get-MgDeviceManagementManagedDevice -Filter "operatingSystem eq 'Windows' and LastSyncDateTime gt $($DeviceStartTime.ToString('yyyy-MM-ddTHH:mm:ssZ'))" -All -Property "AzureAdDeviceId,DeviceName,Id"
|
$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
|
||||||
if ($DeviceGroups.Count -gt 0) {
|
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"
|
||||||
$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"
|
|
||||||
}
|
}
|
||||||
catch {
|
catch{
|
||||||
Write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Devices with error: $_"
|
write-Error "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Failed to get Devices with error: $_"
|
||||||
}
|
}
|
||||||
|
|
||||||
#Memory Garbage collection
|
#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"
|
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
|
#Get Sign-In logs
|
||||||
try {
|
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
|
$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
|
||||||
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"
|
$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
|
#Memory Garbage collection
|
||||||
$MemoryUsage = [System.GC]::GetTotalMemory($true)
|
$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"
|
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 (($IntuneDevices) -and ($SignInLogs)){
|
||||||
If ($RunBatchMode) {
|
If ($RunBatchMode){ #Getting Primary Users in batch mode
|
||||||
#Getting Primary Users in batch mode
|
try{
|
||||||
try {
|
|
||||||
$AllPrimaryUsersHash = get-mggraphrequestbatch -RunProfile "beta" -method GET -Object "deviceManagement/managedDevices" -objects $IntuneDevices -uri "/users" -BatchSize $Batchsize -WaitTime $waittime -MaxRetry $MaxRetry
|
$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
|
$report = Set-IntunePrimaryUsers -IntuneDevices $IntuneDevices -SignInLogs $SignInLogs -AllPrimaryUsersHash $AllPrimaryUsersHash -Enrollmentaccounts $Enrollmentaccounts -TestMode $TestMode -ReturnReport $ReturnReport
|
||||||
}
|
}
|
||||||
else {
|
else{ #Getting Primary Users in foreach mode
|
||||||
#Getting Primary Users in foreach mode
|
|
||||||
$report = Set-IntunePrimaryUsers -IntuneDevices $IntuneDevices -SignInLogs $SignInLogs -AllPrimaryUsersHash $AllPrimaryUsersHash -Enrollmentaccounts $Enrollmentaccounts -TestMode $TestMode -ReturnReport $ReturnReport
|
$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
|
disconnect-mggraph | out-null
|
||||||
[datetime]$scriptEndTime = Get-Date
|
[datetime]$scriptEndTime = Get-Date
|
||||||
$MemoryUsage = [System.GC]::GetTotalMemory($false)
|
$MemoryUsage = [System.GC]::GetTotalMemory($false)
|
||||||
write-Output "Script execution time: $(($scriptEndTime-$scriptStartTime).ToString('hh\:mm\:ss'))"
|
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"
|
Write-Output "Memory Usage at the end of script execution: $(($MemoryUsage/1024/1024).ToString('N2')) MB"
|
||||||
$VerbosePreference = "SilentlyContinue"
|
$VerbosePreference = "SilentlyContinue"
|
||||||
|
420
Intune-Set-PrimaryUserGroups.ps1
Normal file
420
Intune-Set-PrimaryUserGroups.ps1
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
<#PSScriptInfo
|
||||||
|
.SYNOPSIS
|
||||||
|
Script for Intune to set Primary User on Device
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script will get the Entra Sign in logs for Windows Sign ins
|
||||||
|
The script then determine who has logged on to the device the most times in the last 30 days and set the Primary user to that user
|
||||||
|
The script uses Ms Graph with MGGraph modules
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\Intune-Set-PrimaryUser.ps1
|
||||||
|
Will set the primary user for devices in Intune
|
||||||
|
|
||||||
|
.NOTES
|
||||||
|
Written by Mr-Tbone (Tbone Granheden) Coligo AB
|
||||||
|
torbjorn.granheden@coligo.se
|
||||||
|
|
||||||
|
.VERSION
|
||||||
|
2.0
|
||||||
|
|
||||||
|
.RELEASENOTES
|
||||||
|
1.0 2023-02-14 Initial Build
|
||||||
|
2.0 2021-03-01 Large update to use Graph batching and reduce runtime
|
||||||
|
|
||||||
|
.AUTHOR
|
||||||
|
Tbone Granheden
|
||||||
|
@MrTbone_se
|
||||||
|
|
||||||
|
.COMPANYNAME
|
||||||
|
Coligo AB
|
||||||
|
|
||||||
|
.GUID
|
||||||
|
00000000-0000-0000-0000-000000000000
|
||||||
|
|
||||||
|
.COPYRIGHT
|
||||||
|
Feel free to use this, But would be grateful if My name is mentioned in Notes
|
||||||
|
|
||||||
|
.CHANGELOG
|
||||||
|
1.0.2202.1 - Initial Version
|
||||||
|
2.0.2312.1 - Large update to use Graph batching and reduce runtime
|
||||||
|
#>
|
||||||
|
|
||||||
|
#region ---------------------------------------------------[Set script requirements]-----------------------------------------------
|
||||||
|
#
|
||||||
|
#Requires -Modules Microsoft.Graph.Authentication
|
||||||
|
#Requires -Modules Microsoft.Graph.DeviceManagement
|
||||||
|
#Requires -Modules Microsoft.Graph.Reports
|
||||||
|
#
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ---------------------------------------------------[Script Parameters]-----------------------------------------------
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#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 = $True # $True = No changes will be made on Primary owner, $False = Primary Owner will be changed
|
||||||
|
[Bool]$Verboselogging = $True # $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
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ---------------------------------------------------[Set global script settings]--------------------------------------------
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ---------------------------------------------------[Import Modules and Extensions]-----------------------------------------
|
||||||
|
import-Module Microsoft.Graph.Authentication
|
||||||
|
import-Module Microsoft.Graph.DeviceManagement
|
||||||
|
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" }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ---------------------------------------------------[Functions]------------------------------------------------------------
|
||||||
|
function ConnectTo-MgGraph {
|
||||||
|
param (
|
||||||
|
[System.Object]$RequiredScopes
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
$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: $_" }
|
||||||
|
$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
|
||||||
|
$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"
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
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(
|
||||||
|
[string]$RunProfile,
|
||||||
|
[string]$Object,
|
||||||
|
[String]$Method,
|
||||||
|
[system.object]$Objects,
|
||||||
|
[string]$Uri,
|
||||||
|
[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
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
# 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)" } })
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
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)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#progressbar
|
||||||
|
$Elapsedtime = (get-date) - $starttime
|
||||||
|
$timeLeft = [TimeSpan]::FromMilliseconds((($ElapsedTime.TotalMilliseconds / $CurrentObject) * ($TotalObjects - $CurrentObject)))
|
||||||
|
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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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))"
|
||||||
|
$objects = @()
|
||||||
|
$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
|
||||||
|
}
|
||||||
|
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 (
|
||||||
|
[System.Object]$IntuneDevices,
|
||||||
|
[System.Object]$SignInLogs,
|
||||||
|
[System.Object]$AllPrimaryUsersHash,
|
||||||
|
[System.Object]$Enrollmentaccounts,
|
||||||
|
[Bool]$Testmode,
|
||||||
|
[Bool]$ReturnReport
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
$ErrorActionPreference = 'stop'
|
||||||
|
[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
|
||||||
|
$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 ($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"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
$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)) {
|
||||||
|
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
|
||||||
|
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: $_" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
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)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $report
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
#region ---------------------------------------------------[[Script Execution]------------------------------------------------------
|
||||||
|
$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 { $_.id -ne $null }
|
||||||
|
$DeviceIdsInGroups += $devicesInGroup.id
|
||||||
|
}
|
||||||
|
|
||||||
|
$IntuneDevices = $IntuneDevices | Where-Object { $DeviceIdsInGroups -contains $_.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: $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
$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: $_" }
|
||||||
|
|
||||||
|
# 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 {
|
||||||
|
$AllPrimaryUsersHash = get-mggraphrequestbatch -RunProfile "beta" -method GET -Object "deviceManagement/managedDevices" -objects $IntuneDevices -uri "/users" -BatchSize $Batchsize -WaitTime $waittime -MaxRetry $MaxRetry
|
||||||
|
$AllPrimaryUsersHashCount = $AllPrimaryUsersHash.Keys.Count
|
||||||
|
Write-Verbose "$(Get-Date -Format 'yyyy-MM-dd'),$(Get-Date -format 'HH:mm:ss'),Success to get Primary Users for $($AllPrimaryUsersHashCount) 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: $_" }
|
||||||
|
$report = Set-IntunePrimaryUsers -IntuneDevices $IntuneDevices -SignInLogs $SignInLogs -AllPrimaryUsersHash $AllPrimaryUsersHash -Enrollmentaccounts $Enrollmentaccounts -TestMode $TestMode -ReturnReport $ReturnReport
|
||||||
|
}
|
||||||
|
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" }
|
||||||
|
|
||||||
|
if ($ReturnReport) { write-Output -InputObject $report }
|
||||||
|
|
||||||
|
disconnect-mggraph | out-null
|
||||||
|
[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"
|
Reference in New Issue
Block a user