Skip to content
Merged
2 changes: 1 addition & 1 deletion Private/Assert-CloudDeviceCleanupSettings.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function Assert-CloudDeviceCleanupSettings {
return $false
}

$minimumVersion = [version] '0.0.58'
$minimumVersion = [version] '0.0.59'
if ($moduleAvailable.Version -lt $minimumVersion) {
Write-Color -Text '[e] ', "'GraphEssentials' module is outdated for cloud-device cleanup. Please update to minimum version '$minimumVersion'. Terminating." -Color Yellow, Red
return $false
Expand Down
28 changes: 27 additions & 1 deletion Private/Get-CloudDeviceSelectionReason.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function Get-CloudDeviceSelectionReason {
[PSObject] $Device,

[Parameter(Mandatory)]
[ValidateSet('Retire', 'Disable', 'Delete')]
[ValidateSet('Retire', 'Disable', 'Delete', 'RemoveAutopilotIdentity')]
[string] $Type,

[Parameter(Mandatory)]
Expand All @@ -18,6 +18,14 @@ function Get-CloudDeviceSelectionReason {

$reasons.Add("RecordState=$($Device.RecordState)")

if ($Device.PSObject.Properties['IntuneLinkState'] -and $Device.IntuneLinkState) {
$reasons.Add("IntuneLinkState=$($Device.IntuneLinkState)")
}

if ($ActionIf.IntuneLinkState -and $ActionIf.IntuneLinkState -ne 'Any') {
$reasons.Add("RequiredIntuneLinkState=$($ActionIf.IntuneLinkState)")
}

if ($null -ne $ActionIf.LastSeenEntraMoreThan -and $null -ne $Device.EntraLastSeenDays) {
$reasons.Add("EntraLastSeenDays=$($Device.EntraLastSeenDays) > $($ActionIf.LastSeenEntraMoreThan)")
} elseif ($null -ne $ActionIf.LastSeenEntraMoreThan -and $ActionIf.IncludeUnknownActivity -and $null -eq $Device.EntraLastSeenDays) {
Expand All @@ -42,6 +50,20 @@ function Get-CloudDeviceSelectionReason {
$reasons.Add("AutopilotState=$($ActionIf.AutopilotState)")
}

if ($null -ne $ActionIf.AutopilotLastContactMoreThan -and $null -ne $Device.AutopilotLastContactedDays) {
$reasons.Add("AutopilotLastContactedDays=$($Device.AutopilotLastContactedDays) > $($ActionIf.AutopilotLastContactMoreThan)")
} elseif ($null -ne $ActionIf.AutopilotLastContactMoreThan -and $ActionIf.IncludeUnknownActivity -and $null -eq $Device.AutopilotLastContactedDays) {
$reasons.Add("AutopilotLastContactedDays=Unknown allowed")
}

if ($ActionIf.AutopilotIntuneAssociationState -and $ActionIf.AutopilotIntuneAssociationState -ne 'Any') {
$reasons.Add("AutopilotIntuneAssociationState=$($ActionIf.AutopilotIntuneAssociationState)")
}

if ($ActionIf.AutopilotEntraAssociationState -and $ActionIf.AutopilotEntraAssociationState -ne 'Any') {
$reasons.Add("AutopilotEntraAssociationState=$($ActionIf.AutopilotEntraAssociationState)")
}

if ($ActionIf.OwnerState -and $ActionIf.OwnerState -ne 'Any') {
$reasons.Add("OwnerState=$($ActionIf.OwnerState)")
}
Expand Down Expand Up @@ -100,5 +122,9 @@ function Get-CloudDeviceSelectionReason {
}
}

if ($Type -eq 'RemoveAutopilotIdentity') {
$reasons.Add('Remove Windows Autopilot device identity only')
}

$reasons -join '; '
}
78 changes: 77 additions & 1 deletion Private/Get-CloudDevicesToProcess.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function Get-CloudDevicesToProcess {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[ValidateSet('Retire', 'Disable', 'Delete')]
[ValidateSet('Retire', 'Disable', 'Delete', 'RemoveAutopilotIdentity')]
[string] $Type,

[Parameter(Mandatory)]
Expand Down Expand Up @@ -115,6 +115,56 @@ function Get-CloudDevicesToProcess {
'Unknown'
}

function Test-CloudDeviceAutopilotIntuneAssociationState {
param(
[Parameter(Mandatory)] [object] $Device,
[string] $State
)

if (-not $State -or $State -eq 'Any') {
return $true
}

$hasAssociation = -not [string]::IsNullOrWhiteSpace([string] $Device.AutopilotManagedDeviceId)
if ($State -eq 'Missing') {
return -not $hasAssociation
}
if ($State -eq 'Present') {
return $hasAssociation
}

$true
}

function Test-CloudDeviceAutopilotEntraAssociationState {
param(
[Parameter(Mandatory)] [object] $Device,
[string] $State
)

if (-not $State -or $State -eq 'Any') {
return $true
}

$associationValue = [string] $Device.AutopilotResourceName
$hasAssociation = -not [string]::IsNullOrWhiteSpace([string] $Device.AutopilotAzureAdDeviceId)
$serialNumber = [string] $Device.AutopilotSerialNumber
if ($State -eq 'Missing') {
return -not $hasAssociation
}
if ($State -eq 'Present') {
return $hasAssociation
}
if ($State -eq 'EqualsSerialNumber') {
return -not [string]::IsNullOrWhiteSpace($associationValue) -and -not [string]::IsNullOrWhiteSpace($serialNumber) -and $associationValue -eq $serialNumber
}
if ($State -eq 'NotEqualsSerialNumber') {
return -not [string]::IsNullOrWhiteSpace($associationValue) -and -not [string]::IsNullOrWhiteSpace($serialNumber) -and $associationValue -ne $serialNumber
}

$true
}

Write-Color -Text '[i] ', "Applying following rules to $Type action:" -Color Yellow, Cyan, Green
foreach ($key in $ActionIf.Keys) {
if ($null -eq $ActionIf[$key] -or ($ActionIf[$key] -is [System.Array] -and $ActionIf[$key].Count -eq 0)) {
Expand Down Expand Up @@ -142,6 +192,10 @@ function Get-CloudDevicesToProcess {
continue
}

if ($ActionIf.IntuneLinkState -and $ActionIf.IntuneLinkState -ne 'Any' -and $device.IntuneLinkState -ne $ActionIf.IntuneLinkState) {
continue
}

if ($Type -eq 'Retire') {
if (-not $device.HasIntuneRecord) {
continue
Expand Down Expand Up @@ -175,6 +229,10 @@ function Get-CloudDevicesToProcess {
if ($device.RecordState -eq 'IntuneOnly' -and -not $ActionIf.IncludeIntuneOnly) {
continue
}
} elseif ($Type -eq 'RemoveAutopilotIdentity') {
if ($device.AutopilotOnboarded -ne $true -or [string]::IsNullOrWhiteSpace([string] $device.AutopilotDeviceId)) {
continue
}
}

if ($null -ne $ActionIf.ListProcessedMoreThan) {
Expand Down Expand Up @@ -220,6 +278,24 @@ function Get-CloudDevicesToProcess {
}
}

if ($null -ne $ActionIf.AutopilotLastContactMoreThan) {
if ($null -eq $device.AutopilotLastContactedDays) {
if (-not $ActionIf.IncludeUnknownActivity) {
continue
}
} elseif ($device.AutopilotLastContactedDays -le $ActionIf.AutopilotLastContactMoreThan) {
continue
}
}

if (-not (Test-CloudDeviceAutopilotIntuneAssociationState -Device $device -State $ActionIf.AutopilotIntuneAssociationState)) {
continue
}

if (-not (Test-CloudDeviceAutopilotEntraAssociationState -Device $device -State $ActionIf.AutopilotEntraAssociationState)) {
continue
}

if ($ActionIf.EnabledState -and $ActionIf.EnabledState -ne 'Any') {
if ($ActionIf.EnabledState -eq 'Enabled' -and $device.Enabled -ne $true) {
continue
Expand Down
55 changes: 53 additions & 2 deletions Private/Get-InitialCloudDevices.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ function Get-InitialCloudDevices {
$null
}

$testIntuneManagementClaim = {
param([AllowNull()] $Device)

if (-not $Device) {
return $false
}

$managementValues = @(
Get-CloudDevicePropertyValue -InputObject $Device -Name 'ManagementType'
Get-CloudDevicePropertyValue -InputObject $Device -Name 'ManagementAgent'
) | Where-Object { -not [string]::IsNullOrWhiteSpace([string] $_) }
Comment thread
PrzemyslawKlys marked this conversation as resolved.
Resolved

foreach ($managementValue in $managementValues) {
if ([string] $managementValue -like '*mdm*' -or [string] $managementValue -like '*intune*') {
return $true
Comment thread
PrzemyslawKlys marked this conversation as resolved.
Resolved
}
}

$false
}

[Array] $entraJoinType = @($IncludeJoinType | Where-Object { $_ -ne 'Not available' })
[Array] $entraDevices = @()
if ($entraJoinType.Count -gt 0) {
Expand Down Expand Up @@ -160,6 +181,19 @@ function Get-InitialCloudDevices {
$intuneRegisteredDays = if ($intuneDevice) { & $getAgeDays $intuneDevice.FirstSeen } else { $null }
$autopilotInventoryLoaded = & $getFirstNonNullPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotInventoryLoaded'
$autopilotOnboarded = & $getFirstNonNullPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotOnboarded'
$autopilotLastContacted = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotLastContacted'
$autopilotLastContactedDays = & $getFirstNonNullPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotLastContactedDays'
if ($null -eq $autopilotLastContactedDays -and $autopilotLastContacted) {
$autopilotLastContactedDays = & $getAgeDays $autopilotLastContacted
}
$claimsIntuneManagement = & $testIntuneManagementClaim $entraDevice
$intuneLinkState = if ($intuneDevice) {
'Healthy'
} elseif ($claimsIntuneManagement) {
'Broken'
} else {
'NotClaimed'
}

$outputDevices.Add([PSCustomObject] [ordered] @{
Name = $entraDevice.Name
Expand All @@ -170,6 +204,8 @@ function Get-InitialCloudDevices {
HasIntuneRecord = [bool] $intuneDevice
RecordState = if ($intuneDevice) { 'Matched' } else { 'EntraOnly' }
RecordSource = if ($intuneDevice) { 'Microsoft Entra ID + Intune' } else { 'Microsoft Entra ID only' }
IntuneLinkState = $intuneLinkState
ClaimsIntuneManagement = $claimsIntuneManagement
Enabled = $entraDevice.Enabled
OperatingSystem = if ($intuneDevice -and $intuneDevice.OperatingSystem) { $intuneDevice.OperatingSystem } else { $entraDevice.OperatingSystem }
OperatingSystemVersion = $operatingSystemVersion
Expand Down Expand Up @@ -200,10 +236,14 @@ function Get-InitialCloudDevices {
AutopilotInventoryLoaded = $autopilotInventoryLoaded
AutopilotOnboarded = $autopilotOnboarded
AutopilotDeviceId = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotDeviceId'
AutopilotManagedDeviceId = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotManagedDeviceId'
AutopilotAzureAdDeviceId = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotAzureAdDeviceId'
AutopilotResourceName = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotResourceName'
AutopilotGroupTag = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotGroupTag'
AutopilotSerialNumber = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotSerialNumber'
AutopilotEnrollmentState = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotEnrollmentState'
AutopilotLastContacted = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotLastContacted'
AutopilotLastContacted = $autopilotLastContacted
AutopilotLastContactedDays = $autopilotLastContactedDays
AutopilotUserPrincipalName = & $getFirstPropertyValue -InputObject @($intuneDevice, $entraDevice) -Name 'AutopilotUserPrincipalName'
SelectionReason = $null
})
Expand All @@ -225,6 +265,11 @@ function Get-InitialCloudDevices {
}

$intuneRegisteredDays = & $getAgeDays $intuneDevice.FirstSeen
$autopilotLastContacted = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotLastContacted'
$autopilotLastContactedDays = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotLastContactedDays'
if ($null -eq $autopilotLastContactedDays -and $autopilotLastContacted) {
$autopilotLastContactedDays = & $getAgeDays $autopilotLastContacted
}

$outputDevices.Add([PSCustomObject] [ordered] @{
Name = $intuneDevice.Name
Expand All @@ -235,6 +280,8 @@ function Get-InitialCloudDevices {
HasIntuneRecord = $true
RecordState = 'IntuneOnly'
RecordSource = 'Intune only'
IntuneLinkState = 'IntuneOnly'
ClaimsIntuneManagement = $true
Enabled = $null
OperatingSystem = $intuneDevice.OperatingSystem
OperatingSystemVersion = $intuneDevice.OperatingSystemVersion
Expand Down Expand Up @@ -265,10 +312,14 @@ function Get-InitialCloudDevices {
AutopilotInventoryLoaded = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotInventoryLoaded'
AutopilotOnboarded = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotOnboarded'
AutopilotDeviceId = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotDeviceId'
AutopilotManagedDeviceId = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotManagedDeviceId'
AutopilotAzureAdDeviceId = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotAzureAdDeviceId'
AutopilotResourceName = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotResourceName'
AutopilotGroupTag = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotGroupTag'
AutopilotSerialNumber = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotSerialNumber'
AutopilotEnrollmentState = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotEnrollmentState'
AutopilotLastContacted = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotLastContacted'
AutopilotLastContacted = $autopilotLastContacted
AutopilotLastContactedDays = $autopilotLastContactedDays
AutopilotUserPrincipalName = Get-CloudDevicePropertyValue -InputObject $intuneDevice -Name 'AutopilotUserPrincipalName'
SelectionReason = $null
})
Expand Down
2 changes: 2 additions & 0 deletions Private/New-EmailBodyCloudDevices.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function New-EmailBodyCloudDevices {
[Array] $retiredDevices = $CurrentRun | Where-Object { $_.Action -eq 'Retire' }
[Array] $disabledDevices = $CurrentRun | Where-Object { $_.Action -eq 'Disable' }
[Array] $deletedDevices = $CurrentRun | Where-Object { $_.Action -eq 'Delete' }
[Array] $autopilotIdentitiesRemoved = $CurrentRun | Where-Object { $_.Action -eq 'RemoveAutopilotIdentity' }

$emailBody = EmailBody -EmailBody {
EmailText -Text 'Hello,'
Expand All @@ -20,6 +21,7 @@ function New-EmailBodyCloudDevices {
EmailListItem -Text 'Objects retired: ', $retiredDevices.Count -Color None, Orange -FontWeight normal, bold
EmailListItem -Text 'Objects disabled: ', $disabledDevices.Count -Color None, Orange -FontWeight normal, bold
EmailListItem -Text 'Objects deleted: ', $deletedDevices.Count -Color None, Salmon -FontWeight normal, bold
EmailListItem -Text 'Autopilot identities removed: ', $autopilotIdentitiesRemoved.Count -Color None, Salmon -FontWeight normal, bold
}
EmailTable -DataTable $CurrentRun -HideFooter
EmailText -LineBreak
Expand Down
Loading
Loading