Last active
July 31, 2024 15:31
-
-
Save MrWyss-MSFT/a9401456c32a2ccd3cd1f09b5f2d9a2c to your computer and use it in GitHub Desktop.
This script will upload the Windows Corporate Identifiers for the device to Microsoft Intune
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| param( | |
| [Parameter(Mandatory = $false)] | |
| [string]$CSVPath = "WindowsAutopilotDevices.csv", #TODO: Change back to full path | |
| [Parameter(Mandatory = $false)] | |
| [switch]$Force | |
| ) | |
| #region Variables | |
| $ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path | |
| $LogFilePath = Join-Path $ScriptDirectory "Delete-AutopilotDevices-$(Get-Date -Format yyyy-M-dd).log" | |
| $PSDefaultParameterValues = @{ | |
| "Write-Log:Path" = $LogFilePath | |
| "Write-Log:Component" = "DeleteAutopilotDevices" | |
| "Write-Log:Type" = "Info" | |
| "Write-Log:ConsoleOutput" = $True | |
| } | |
| #endregion | |
| #region Functions | |
| function Invoke-CustomMgGraphRequest { | |
| [cmdletbinding()] | |
| param( | |
| [Parameter()] | |
| [switch]$All, | |
| [Parameter(ValueFromRemainingArguments = $true)] | |
| $RemainingArgs | |
| ) | |
| $GraphRequestParamsArgs = @{} | |
| for ($i = 0; $i -lt $RemainingArgs.count; $i += 2) { | |
| $GraphRequestParamsArgs[($RemainingArgs[$i] -replace '^-+')] = $RemainingArgs[$i + 1] | |
| } | |
| $Result = Invoke-MgGraphRequest @GraphRequestParamsArgs | |
| if ($All.IsPresent) { | |
| #$Result.value | |
| if ($Result.'@odata.nextLink') { | |
| if ($Result.'@odata.nextLink' -match "skip=(.*)") { | |
| [int]$skipValue = $Matches[1] | |
| $totalValue = $Result.'@odata.count' - $Result.'@odata.count' % $skipValue + $skipValue | |
| for ($i = $skipValue; $i -lt $totalValue; $i += $skipValue) { | |
| Write-Progress -id 1 -ParentId 0 -PercentComplete ($i / $totalvalue * 100) -Status "$i of $totalvalue pages" -Activity "Retrieving next page" | |
| $moreObj = Invoke-MgGraphRequest @GraphRequestParamsArgs | |
| $moreObj.value | |
| } | |
| Write-Progress -id 1 -ParentId 0 -Activity "Retrieving next page" -Completed | |
| } | |
| if ($Result.'@odata.nextLink' -match "skiptoken=(.*)") { | |
| #add $count=true to the uri if not present already | |
| if ($GraphRequestParamsArgs.uri -notmatch "\?") { | |
| $TotalCountUri = $GraphRequestParamsArgs.uri + "?`$count=true" | |
| } | |
| else { | |
| $TotalCountUri = $GraphRequestParamsArgs.uri + "&`$count=true" | |
| } | |
| $TotalCountResult = Invoke-MgGraphRequest -uri $TotalCountUri -Method Get | |
| $totalValue = $TotalCountResult.'@odata.count' | |
| $allValues = @() | |
| $currentUri = $GraphRequestParamsArgs.uri | |
| $count = 0 | |
| # Loop through pages until there is no @odata.nextLink | |
| do { | |
| # Request the current page | |
| $pageResult = Invoke-MgGraphRequest -uri $currentUri -Method Get | |
| $allValues += $pageResult.value | |
| $count += $pageResult.value.Count | |
| # Update progress | |
| Write-Progress -id 1 -ParentId 0 -PercentComplete ($count / $totalValue * 100) -Status "$count of $totalValue items" -Activity "Retrieving next page" | |
| # Check for next link | |
| $currentUri = $pageResult.'@odata.nextLink' | |
| } while ($null -ne $currentUri) | |
| # Complete progress | |
| Write-Progress -id 1 -ParentId 0 -Activity "Retrieving next page" -Completed | |
| # Output the total count and all values | |
| Write-Output "Total items retrieved: $count" | |
| $allValues | |
| } | |
| else { | |
| Write-Error "No skiptoken or skip value found in nextLink" | |
| } | |
| } | |
| else { | |
| $Result.value | |
| } | |
| } | |
| else { | |
| $Result.value | |
| } | |
| } | |
| #endregion | |
| Function Write-Log { | |
| <# | |
| .SYNOPSIS | |
| Writes CMTrace log file, customized version of https://janikvonrotz.ch/2017/10/26/powershell-logging-in-cmtrace-format/ | |
| #> | |
| [CmdletBinding()] | |
| Param( | |
| [parameter(Mandatory = $true)] | |
| [String]$Path, | |
| [parameter(Mandatory = $true, ValueFromPipeline)] | |
| [String]$Message, | |
| [parameter(Mandatory = $true)] | |
| [String]$Component, | |
| [Parameter(Mandatory = $true)] | |
| [ValidateSet("Info", "Warning", "Error")] | |
| [String]$Type, | |
| [Parameter(Mandatory = $false)] | |
| [Switch]$ConsoleOutput | |
| ) | |
| switch ($Type) { | |
| "Info" { [int]$Type = 1 } | |
| "Warning" { [int]$Type = 2 } | |
| "Error" { [int]$Type = 3 } | |
| } | |
| if ($ConsoleOutput.IsPresent) { | |
| switch ($Type) { | |
| 1 { $ForgroundColor = "White" } | |
| 2 { $ForgroundColor = "Yellow" } | |
| 3 { $ForgroundColor = "Red" } | |
| } | |
| $OutPut = "{0} : {1}" -f $(Get-Date -Format "MM-d-yyyy HH:mm:ss.ffffff"), $Message | |
| write-host $OutPut -ForegroundColor $ForgroundColor | |
| } | |
| # Create a log entry | |
| $Content = "<![LOG[$Message]LOG]!>" + ` | |
| "<time=`"$(Get-Date -Format "HH:mm:ss.ffffff")`" " + ` | |
| "date=`"$(Get-Date -Format "M-d-yyyy")`" " + ` | |
| "component=`"$Component`" " + ` | |
| "context=`"$([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)`" " + ` | |
| "type=`"$Type`" " + ` | |
| "thread=`"$([Threading.Thread]::CurrentThread.ManagedThreadId)`" " + ` | |
| "file=`"`">" | |
| # Write the line to the log file | |
| $Content | Out-File -FilePath $Path -Append -Encoding UTF8 | |
| } | |
| #endregion | |
| #region Prerequisites Check | |
| if (-not (Get-Module -Name "Microsoft.Graph.Authentication" -ListAvailable)) { | |
| Write-Host "Missing Modules, please run:" -ForegroundColor Yellow | |
| Write-Host @" | |
| Install-Module "Microsoft.Graph.Authentication" -Force | |
| Import-Module "Microsoft.Graph.Authentication" | |
| "@ -ForegroundColor Green | |
| break | |
| } | |
| #endregion | |
| #region Main Code | |
| Write-Log -Message "--- Start $DeleteAutopilotDevices ---" | |
| # Connect to Microsoft Graph | |
| Connect-MgGraph -Scopes "Directory.Read.All, DeviceManagementServiceConfig.Read.All, DeviceManagementServiceConfig.ReadWrite.All" -NoWelcome | |
| # Check the current context | |
| #Get-MgContext | Select-Object -Property Account, TenantId, Environment | |
| # Import CSV | |
| $DevicesToDelete = $null | |
| try { | |
| $DevicesToDelete = Import-Csv -Path $CSVPath | |
| } | |
| catch { | |
| write-Log -Message "Error: $($_.Exception.Message)" -Type Error | |
| Write-Log -Message "--- End $DeleteAutopilotDevices ---" | |
| return | |
| } | |
| # Check if the CSV file is empty | |
| if ($null -eq $DevicesToDelete) { | |
| Write-Log -Message "No devices found in CSV file" -Type Error | |
| Write-Log -Message "--- End $DeleteAutopilotDevices ---" | |
| return | |
| } | |
| # Check if the CSV file contains the required columns | |
| if ($null -eq $DevicesToDelete.'Serial Number') { | |
| Write-Log -Message "CSV file does not contain the required column 'Serial Number'" -Type Error | |
| Write-Log -Message "--- End $DeleteAutopilotDevices ---" | |
| return | |
| } | |
| # Return number of devices to delete | |
| Write-Log -Message "Number of devices to delete: $($DevicesToDelete.Count)" | |
| # Delete devices from the CSV file based on Serial Number | |
| Foreach ($ListDevice in $DevicesToDelete) { | |
| $SerialNumber = $ListDevice.'Serial Number' | |
| # Get device | |
| $AutopilotDeviceIdentityUrl = "https://graph.microsoft.com/v1.0/deviceManagement/windowsAutopilotDeviceIdentities?`$filter=contains(serialNumber,'$SerialNumber')" | |
| $AutopilotDevice = (Invoke-MgGraphRequest -uri $AutopilotDeviceIdentityUrl).value | |
| # Delete device | |
| If ($null -ne $AutopilotDevice -and $AutopilotDevice -ne "") { | |
| Write-Log -Message "Found Autopilot registration for device with Serial Number $SerialNumber :" | |
| $EntraDeviceID = $AutopilotDevice.azureActiveDirectoryDeviceId | |
| $IntuneDeviceID = $AutopilotDevice.managedDeviceId | |
| $AutopilotDeviceID = $AutopilotDevice.id | |
| Write-log -Message " Autopilot Id: $AutopilotDeviceID" | |
| Write-log -Message " Intune Device Id: $IntuneDeviceID" | |
| Write-log -Message " Entra Device Id: $EntraDeviceID" | |
| # Remove Autopilot registration | |
| Write-Log -Message " Removing Autopilot registration for device with Serial Number $SerialNumber" -Type Warning | |
| ## Get Autopilot device infos first | |
| ## Device info already present in $AutopilotDevice | |
| Write-log -Message " Enrollment State: $($AutopilotDevice.enrollmentState)" | |
| Write-log -Message " Last Contact Date: $($AutopilotDevice.lastContactedDateTime)" | |
| ## Log Autopilot device | |
| $AutopilotDeviceDeviceUrl = "https://graph.microsoft.com/v1.0/deviceManagement/windowsAutopilotDeviceIdentities/$AutopilotDeviceID" | |
| $AutopilotDeviceJson = ($AutopilotDevice | ConvertTo-Json) -replace '\s+|\n', ' ' | |
| Write-Log -Message " Autopilot Device = [$AutopilotDeviceJson]" -ConsoleOutput:$false | |
| ## Delete Autopilot device | |
| if ($Force.IsPresent) { | |
| Invoke-MgGraphRequest -Uri $AutopilotDeviceDeviceUrl -Method DELETE | |
| Write-Log -Message " Autopilot device with Serial Number $SerialNumber deleted" -Type Warning | |
| } | |
| else { | |
| Write-Log -Message " Autopilot device with Serial Number $SerialNumber would have been deleted" -Type Warning | |
| } | |
| # Remove Intune device | |
| Write-Log -Message " Removing associated Intune device with Serial Number $SerialNumber" -Type Warning | |
| ## Get Intune device infos first | |
| $IntuneDeviceUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/$IntuneDeviceID" | |
| $IntuneDevice = Invoke-MgGraphRequest -Uri $IntuneDeviceUrl -Method GET | |
| Write-log -Message " Last Sync Date: $($IntuneDevice.lastSyncDateTime)" | |
| Write-log -Message " User: $($IntuneDevice.userDisplayName)" | |
| Write-log -Message " Device Name: $($IntuneDevice.deviceName)" | |
| ## Log Intune device | |
| $IntuneDeviceJson = ($IntuneDevice | ConvertTo-Json) -replace '\s+|\n', ' ' | |
| Write-Log -Message " Intune Device = [$IntuneDeviceJson]" -ConsoleOutput:$false | |
| ## Delete Intune device | |
| if ($Force.IsPresent) { | |
| Invoke-MgGraphRequest -Uri $IntuneDeviceUrl -Method DELETE | |
| Write-Log -Message " Intune device with Serial Number $SerialNumber deleted" -Type Warning | |
| } | |
| else { | |
| Write-Log -Message " Intune device with Serial Number $SerialNumber would have been deleted" -Type Warning | |
| } | |
| # Remove Entra device | |
| Write-Log -Message " Removing associated Entra device with Serial Number $SerialNumber" -Type Warning | |
| ## Get Entra device infos first | |
| $EntraDeviceUrl = "https://graph.microsoft.com/v1.0/devices(deviceId='$EntraDeviceID')" | |
| $EntraDevice = Invoke-MgGraphRequest -Uri $EntraDeviceUrl -Method GET | |
| Write-log -Message " Approx. Last Sign In: $($EntraDevice.approximateLastSignInDateTime)" | |
| Write-log -Message " Device Name: $($EntraDevice.displayName)" | |
| ## Log Entra device | |
| $EntraDeviceJson = ($EntraDevice | ConvertTo-Json) -replace '\s+|\n', ' ' | |
| Write-Log -Message " Entra Device = [$EntraDeviceJson]" -ConsoleOutput:$false | |
| ## Delete Entra device | |
| if ($Force.IsPresent) { | |
| Invoke-MgGraphRequest -Uri $EntraDeviceUrl -Method DELETE | |
| Write-Log -Message " Entra device with Serial Number $SerialNumber deleted" -Type Warning | |
| } | |
| else { | |
| Write-Log -Message " Entra device with Serial Number $SerialNumber would have been deleted" -Type Warning | |
| } | |
| } Else { | |
| Write-Log -Message " Device with Serial Number $SerialNumber not found" -Type Error | |
| } | |
| } | |
| # Device not found | |
| Write-Log -Message " " | |
| Write-Log -Message "--- End $DeleteAutopilotDevices ---" | |
| #endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment