Skip to content

Instantly share code, notes, and snippets.

@MrWyss-MSFT
Created August 5, 2024 15:04
Show Gist options
  • Select an option

  • Save MrWyss-MSFT/980f43ecaa74df26627b84b359e0ac15 to your computer and use it in GitHub Desktop.

Select an option

Save MrWyss-MSFT/980f43ecaa74df26627b84b359e0ac15 to your computer and use it in GitHub Desktop.
Bulk wipe Intune devices based on a txt file
<#
.SYNOPSIS
Wipes Intune Devices from a given computers.txt List.
.DESCRIPTION
Searches the DeviceID from a given computers.txt list in Intune.
Found Devices will be wiped. There is standard output as well as a
CMTrace compatible Logfile (Wipe-IntuneDevices-yyyy-m-dd.log)
will be created in the ScriptRoot.
Requires
- Modules Microsoft.Graph.Intune and Microsoft.Graph.Authentication
- Install-Module Microsoft.Graph.Authentication -Force
- Access to MSGraph with Consent (DeviceManagementManagedDevices.PrivilegedOperations.All)
- Tested with PowerShell 7.4
.EXAMPLE
PS> .\Wipe-IntuneDevices.ps1
Default Validation Mode
.EXAMPLE
PS> .\Wipe-IntuneDevices.ps1 -Force
With Force Mode devices will get wiped
#>
#Requires -Modules @{ ModuleName="Microsoft.Graph.Authentication"; ModuleVersion="2.20.0" }
[CmdletBinding()]
Param(
[Parameter(Mandatory = $false)]
[Switch]
$Force
)
Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes "Directory.Read.All, DeviceManagementServiceConfig.Read.All, DeviceManagementManagedDevices.PrivilegedOperations.All" -NoWelcome #TBC
Write-Host "Connected to MSGraph with Scopes: " -NoNewline
$Context = Get-MgContext
#Connect-MSGraph -AdminConsent | out-null #Connect and grant permissions
#region Variables
$ComputerListFile = ".\computers.txt"
$ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path
$LogFilePath = Join-Path $ScriptDirectory "Wipe-IntuneDevices-$(Get-Date -Format yyyy-M-dd).log"
$LogComponent = "IntuneDeviceWipe"
$PSDefaultParameterValues = @{
"Write-Log:Path" = $LogFilePath
"Write-Log:Component" = $LogComponent
"Write-Log:Type" = "Info"
"Write-Log:ConsoleOutput" = $True
}
#endregion
#region Functions
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
}
function Get-IntuneDeviceID {
[CmdletBinding()]
param
(
[Parameter(
Position = 0,
Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true)
]
[Alias('ComputerName')]
[String[]]
$ComputerList
)
begin {}
process {
foreach ($ComputerName in $ComputerList) {
$IntuneDeviceUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/?`$filter=deviceName eq '$ComputerName'&select=id, deviceName"
$IntuneDevice = Invoke-MgGraphRequest -Uri $IntuneDeviceUrl -Method Get
If ($IntuneDevice.'@odata.count' -gt 1) {
Write-Log -Message "More than one Device found for $ComputerName in Intune, device will be excluded " -Type "Error"
}
If ($IntuneDevice.'@odata.count' -eq 0) {
Write-Log -Message "No Device found for $ComputerName in Intune, device will be excluded " -Type "Error"
}
else {
[pscustomobject]@{ComputerName = $IntuneDevice.value.deviceName; DeviceID = $IntuneDevice.value.id }
}
}
}
end {
}
}
function Wipe-IntuneDevice {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param(
[Parameter(Mandatory = $true, HelpMessage = "ComputerName, DeviceID List", ValueFromPipeline)]
[pscustomobject[]]$ComputerNameDeviceIDList
)
[int]$TotalCount = $Input.count
[int]$Count = 0
Write-Log -Message "--- Start Wipe Intune Devices ---"
Write-Log -Message "Number of Devices to Wipe: $TotalCount" -Type Warning
$Input | ForEach-Object {
$Count++
[int]$PercentComplete = ($Count / $TotalCount * 100)
$DeviceText = "ComputerName: $($_.ComputerName) DeviceID: $($_.DeviceID)"
Write-Progress -id 1 -ParentId 0 -Activity "Delete Devices " -Status "Process: $DeviceText ( $Count of $TotalCount )" -PercentComplete $PercentComplete
#Write-Log -Message "Current $_ ($i/$($ComputerNameDeviceIDList.count))"
if ($PSCmdlet.ShouldProcess("$DeviceText", 'WIPE')) {
try {
Write-Log -Message "Try to Wipe $DeviceText" -Type Warning
if ($Force.IsPresent) {
$IntuneDeviceUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/$($_.DeviceID)/wipe"
Invoke-MgGraphRequest -Uri $IntuneDeviceUrl -Method POST
Write-Log -Message "Wiped : $DeviceText" -Type Warning
}
else {
Write-Log -Message "Validation Mode (Wipe): $DeviceText" -Type Warning
}
}
catch {
#Write-Error ($_ | Out-String)
Write-Log -Message ($_ | Out-String) -Type Error
Write-Log -Message "Failed to Wipe $DeviceText" -Type Warning
}
}
else {
Write-Log -Message "Cancelled Wipe of $DeviceText" -Type Warning
}
}
# Complete progress
Write-Progress -id 1 -ParentId 0 -Activity "Delete Devices " -Completed
Write-Log -Message "--- End Wipe Intune Devices ---"
}
#endregion
#region Business Logic
Write-Log -Message "Connected as $($Context.Account) MSGraph" -Type "Info"
## Read input file
Write-Log -Message "----- Start Wipe-IntuneDevices Script -----"
$ComputersList = Get-Content -Path $ComputerListFile
#region Validate Input File
## Check if File is empty
if ($ComputersList.count -eq 0) {
Write-Log -Message "No ComputerNames found in File" -Type "Error"
Write-Log -Message "Script will exit" -Type "Error"
Write-Log -Message "----- End Wipe-IntuneDevices Script -----" -Type "Error"
Exit
}
## Check if there are emtpy Lines in File and print line number
$lineNumber = 0
$EmptyOrWhitespaceLines = $ComputersList | ForEach-Object {
$lineNumber++
if ($_ -match '^\s*$') {
[PSCustomObject]@{
LineNumber = $lineNumber
LineContent = $_
}
}
} | Where-Object { $_ -ne $null }
if ($EmptyOrWhitespaceLines) {
Write-Log -Message "Empty or whitespace lines found in file" -Type "Error"
$EmptyOrWhitespaceLines | ForEach-Object {
Write-Log -Message "Line $($_.LineNumber)" -Type "Error"
}
Write-Log -Message "Script will exit" -Type "Error"
Write-Log -Message "----- End Wipe-IntuneDevices Script -----" -Type "Error"
Exit
}
## Check if duplicate ComputerNames in File
$Duplicates = $ComputersList | Group-Object | Where-Object { $_.Count -gt 1 }
if ($Duplicates) {
Write-Log -Message "Duplicate ComputerNames found in File" -Type "Error"
$Duplicates | ForEach-Object {
Write-Log -Message "Duplicate ComputerName: $($_.Name)" -Type "Error"
}
Write-Log -Message "Script will exit" -Type "Error"
Write-Log -Message "----- End Wipe-IntuneDevices Script -----" -Type "Error"
Exit
}
## Validate computer names
$lineNumber = 0
$InvalidComputerNames = $ComputersList | ForEach-Object {
$lineNumber++
if ($_ -match '^[0-9]+$' -or $_.Length -gt 15 -or $_ -match '[`~!@#$%^&*()=+_\[\]{}\\|;:.]') {
[PSCustomObject]@{
LineNumber = $lineNumber
ComputerName = $_
}
}
} | Where-Object { $_ -ne $null }
if ($InvalidComputerNames) {
Write-Log -Message "Invalid computer names found in file" -Type "Error"
$InvalidComputerNames | ForEach-Object {
Write-Log -Message "Line $($_.LineNumber): '$($_.ComputerName)'" -Type "Error"
}
Write-Log -Message "Script will exit" -Type "Error"
Write-Log -Message "----- End Wipe-IntuneDevices Script -----" -Type "Error"
Exit
}
#endregion
Write-Log -Message "Number of Devices in File: $($ComputersList.count)"
## Search for Devices in Intune
Write-Log -Message "Start Searching for Devices in Intune"
$IntuneDevices = Get-IntuneDeviceID -ComputerList $ComputersList
Write-Log -Message "Number of Devices to Wipe: $($IntuneDevices.count)"
## Wipe Devices
Write-Log -Message "Start Searching for Devices in Intune"
$IntuneDevices | Wipe-IntuneDevice
Write-Log -Message "----- End Wipe-IntuneDevices Script -----"
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment