Get-IntuneOffboardingTool.ps1
<#PSScriptInfo
.VERSION 2.0.2 .GUID ed2ff5a9-a163-4caa-a0b2-caf77cb3f92f .AUTHOR Ugur Koc .COMPANYNAME .COPYRIGHT .TAGS AutoPilot, Intune, AzureAD, Powershell, Windows, MacOS, Android, iOS, Offboarding, GraphAPI, Microsoft .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Version 2.0: Initial Release. Version 2.0.1: Fixes with Authentication. Version 2.0.2: Added Check Permissions button and fixed some bugs. #> <# .DESCRIPTION This PowerShell script provides a WPF GUI-based tool that facilitates the offboarding of devices from Microsoft's #Intune, #AutoPilot, and #AzureAD services. The tool leverages Microsoft Graph APIs to authenticate, search, and remove devices. #> Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System.Windows.Forms # Define WPF XAML [xml]$xaml = @" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Intune Offboarding Tool" Height="500" Width="570" ResizeMode="NoResize"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="5*"/> <RowDefinition Height="212*"/> </Grid.RowDefinitions> <Button x:Name="SearchButton" Content="Search" HorizontalAlignment="Left" Margin="393,100,0,0" VerticalAlignment="Top" Width="92" Grid.Row="1" Height="22"/> <Button x:Name="AuthenticateButton" Content="Connect to MS Graph" HorizontalAlignment="Left" Margin="76,42,0,0" VerticalAlignment="Top" Width="131" Grid.Row="1"/> <Button x:Name="InstallModulesButton" Content="Install/Update Modules" HorizontalAlignment="Left" Margin="318,42,0,0" VerticalAlignment="Top" Width="167" Height="20" Grid.Row="1"/> <TextBox x:Name="SearchInputText" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="176,73,0,0" VerticalAlignment="Top" Width="213" Height="22" Grid.Row="1" FontSize="12"/> <Button x:Name="OffboardButton" Content="Offboard device(s) from Intune, AutoPilot and Azure AD" HorizontalAlignment="Left" Margin="78,333,0,0" VerticalAlignment="Top" Width="308" Grid.Row="1"/> <Label Content="Intune Offboarding Tool" HorizontalAlignment="Left" VerticalAlignment="Top" Height="49" Width="264" FontSize="24" Grid.Row="1" Margin="160,0,0,0"/> <TextBlock x:Name="intune_status" HorizontalAlignment="Left" Margin="79,251,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="154"><Run Language="de-de" Text="Intune Status"/></TextBlock> <TextBlock x:Name="autopilot_status" HorizontalAlignment="Left" Margin="79,272,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="154"><Run Language="de-de" Text="Autopilot"/><Run Text=" Status"/></TextBlock> <TextBlock x:Name="aad_status" HorizontalAlignment="Left" Margin="79,293,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="154"><Run Language="de-de" Text="Azure AD"/><Run Text=" Status"/></TextBlock> <ComboBox x:Name="dropdown" HorizontalAlignment="Left" Margin="76,73,0,0" Grid.Row="1" VerticalAlignment="Top" Width="95"/> <DataGrid x:Name="SearchResultsDataGrid" Grid.Row="1" Margin="78,127,71,210"/> <Button x:Name="logs_button" Content="Logs" HorizontalAlignment="Left" Margin="504,422,0,0" VerticalAlignment="Top" Grid.Row="1"/> <Button x:Name="export_button" Content="Export results" HorizontalAlignment="Left" Margin="409,252,0,0" Grid.Row="1" VerticalAlignment="Top"/> <Button x:Name="bulk_import_button" Content="Bulk Import" HorizontalAlignment="Left" Margin="392,73,0,0" VerticalAlignment="Top" Width="93" Grid.Row="1" Height="22"/> <ComboBox x:Name="dropdown_lastsync_days" HorizontalAlignment="Left" Margin="79,367,0,0" Grid.Row="1" VerticalAlignment="Top" Width="94"/> <Button x:Name="export_stale_devices_button" Content="Export Stale devices" HorizontalAlignment="Left" Margin="195,367,0,0" VerticalAlignment="Top" Width="118" Grid.Row="1" Height="23"/> <ComboBox x:Name="dropdown_lastsync_platform" HorizontalAlignment="Left" Margin="79,396,0,0" Grid.Row="1" VerticalAlignment="Top" Width="94"/> <Button x:Name="disconnect_button" Content="Disconnect" Width="80" HorizontalAlignment="Left" Margin="419,422,0,0" VerticalAlignment="Top" Grid.Row="1"/> <Button x:Name="check_permissions_button" Content="Check Permissions" HorizontalAlignment="Left" Margin="212,42,0,0" Grid.Row="1" VerticalAlignment="Top" /> </Grid> </Window> "@ # Parse XAML $reader = (New-Object System.Xml.XmlNodeReader $xaml) $Window = [Windows.Markup.XamlReader]::Load( $reader ) $script:LogFilePath = [System.IO.Path]::Combine([Environment]::GetFolderPath("Desktop"), "IntuneOffboardingTool_Log.txt") function Write-Log { param( [Parameter(Mandatory = $true)] [string] $Message ) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logMessage = "$timestamp - $Message" Add-Content -Path $script:LogFilePath -Value $logMessage } # Connect to Controls $SearchButton = $Window.FindName("SearchButton") $OffboardButton = $Window.FindName("OffboardButton") $AuthenticateButton = $Window.FindName("AuthenticateButton") $SearchInputText = $Window.FindName("SearchInputText") $InstallModulesButton = $Window.FindName("InstallModulesButton") $bulk_import_button = $Window.FindName('bulk_import_button') $Dropdown = $Window.FindName("dropdown") $Disconnect = $Window.FindName('disconnect_button') $Export_Button = $Window.FindName('export_button') $logs_button = $Window.FindName('logs_button') $CheckPermissionsButton = $Window.FindName('check_permissions_button') $Dropdown_LastSync_Platform = $Window.FindName('dropdown_lastsync_platform') $Dropdown_LastSync_Days = $Window.FindName('dropdown_lastsync_days') $Export_Stale_Devices = $Window.FindName('export_stale_devices_button') $SearchInputText.Add_GotFocus({ $SearchInputText.Height = 50 $SearchInputText.Width = 213 }) $SearchInputText.Add_LostFocus({ $SearchInputText.Height = 22 $SearchInputText.Width = 213 }) $Window.Add_Loaded({ $Dropdown.Items.Add("Devicename") $Dropdown.Items.Add("Serialnumber") $Dropdown.SelectedIndex = 0 $Dropdown_LastSync_Platform.Items.Add("Windows") $Dropdown_LastSync_Platform.Items.Add("Android") $Dropdown_LastSync_Platform.Items.Add("iOS") $Dropdown_LastSync_Platform.Items.Add("macOS") $Dropdown_LastSync_Platform.SelectedIndex = 0 $Dropdown_LastSync_Days.Items.Add("30 days") $Dropdown_LastSync_Days.Items.Add("60 days") $Dropdown_LastSync_Days.Items.Add("90 days") $Dropdown_LastSync_Days.Items.Add("120 days") $Dropdown_LastSync_Days.Items.Add("150 days") $Dropdown_LastSync_Days.Items.Add("180 days") $Dropdown_LastSync_Days.Items.Add("210 days") $Dropdown_LastSync_Days.Items.Add("240 days") $Dropdown_LastSync_Days.Items.Add("270 days") $Dropdown_LastSync_Days.Items.Add("300 days") $Dropdown_LastSync_Days.Items.Add("330 days") $Dropdown_LastSync_Days.Items.Add("365 days") $Dropdown_LastSync_Days.SelectedIndex = 0 }) $Window.Add_Loaded({ try { Write-Log "Window is loading..." $context = Get-MgContext if ($null -eq $context) { Write-Log "Not connected to MS Graph" $AuthenticateButton.Content = "Connect to MS Graph" $AuthenticateButton.IsEnabled = $true $Disconnect.IsEnabled = $false } else { Write-Log "Successfully connected to MS Graph" $AuthenticateButton.Content = "Successfully connected" $AuthenticateButton.IsEnabled = $false $Disconnect.IsEnabled = $true } } catch { Write-Log "Error occurred: $_" $AuthenticateButton.Content = "Not Connected to MS Graph" $AuthenticateButton.IsEnabled = $true } }) $Disconnect.Add_Click({ try { Write-Log "Attempting to disconnect from MS Graph..." Disconnect-MgGraph $Disconnect.Content = "Disconnected" $Disconnect.IsEnabled = $false # Disable Disconnect button after disconnect $AuthenticateButton.Content = "Connect to MS Graph" $AuthenticateButton.IsEnabled = $true $CheckPermissionsButton.IsEnabled = $false # Disable CheckPermissionsButton after disconnect } catch { Write-Log "Error occurred while attempting to disconnect from MS Graph: $_" [System.Windows.MessageBox]::Show("Error in disconnect operation.") } }) $AuthenticateButton.Add_Click({ try { Connect-MgGraph -Scopes "DeviceManagementManagedDevices.ReadWrite.All", "DeviceManagementServiceConfig.ReadWrite.All" -ErrorAction Stop $context = Get-MgContext if ($null -eq $context) { Write-Log "Authentication Failed" $AuthenticateButton.Content = "Authentication Failed" $AuthenticateButton.IsEnabled = $true $Disconnect.Content = "Disconnected" $Disconnect.IsEnabled = $false $CheckPermissionsButton.IsEnabled = $false } else { Write-Log "Authentication Successful" $AuthenticateButton.Content = "Authentication Successful" $AuthenticateButton.IsEnabled = $false $Disconnect.Content = "Disconnect" $Disconnect.IsEnabled = $true $CheckPermissionsButton.IsEnabled = $true } } catch { Write-Log "Error occurred during authentication. Exception: $_" $AuthenticateButton.Content = "Authentication Failed" $AuthenticateButton.IsEnabled = $true $Disconnect.Content = "Disconnected" $Disconnect.IsEnabled = $false $CheckPermissionsButton.IsEnabled = $false } }) $CheckPermissionsButton.Add_Click({ try { Write-Log "Check Permissions button clicked, attempting to retrieve user context..." $context = Get-MGContext if ($context) { $username = $context.Account # Check if the required scopes are present $requiredScopes = @("DeviceManagementManagedDevices.ReadWrite.All", "DeviceManagementServiceConfig.ReadWrite.All") $missingScopes = $requiredScopes | Where-Object { $_ -notin $context.Scopes } if ($missingScopes) { $missingScopesList = $missingScopes -join ', ' $message = "WARNING: The following required permissions are missing for $username : $missingScopesList" } else { $message = "All required permissions are granted for $username." } [System.Windows.MessageBox]::Show($message) } else { [System.Windows.MessageBox]::Show("No user context found. Please authenticate first.") } } catch { Write-Log "Error in retrieving user context: $_" [System.Windows.MessageBox]::Show("Error in retrieving user context.") } }) $Export_Button.Add_Click({ try { Write-Log "Export button clicked, attempting to export data..." $data = $Window.FindName('SearchResultsDataGrid').ItemsSource if ($data -ne $null -and $data.Count -gt 0) { $outputPath = [System.IO.Path]::Combine([Environment]::GetFolderPath("Desktop"), "SearchResults.csv") $data | Export-Csv -Path $outputPath -NoTypeInformation Write-Log "Search results exported successfully to SearchResults.csv on your Desktop." [System.Windows.MessageBox]::Show("Search results exported successfully to SearchResults.csv on your Desktop.") } else { Write-Log "No search results to export." [System.Windows.MessageBox]::Show("No search results to export.") } } catch { Write-Log "Error occurred during the export operation: $_" [System.Windows.MessageBox]::Show("Error in export operation.") } }) $Export_Stale_Devices.Add_Click({ try { Write-Log "Export stale devices button clicked, attempting to export data..." $daysRaw = $Window.FindName('dropdown_lastsync_days').SelectedItem $OS = $Window.FindName('dropdown_lastsync_platform').SelectedItem $days = [int]($daysRaw -replace " days", "") if (![string]::IsNullOrEmpty($days) -and ![string]::IsNullOrEmpty($OS)) { $pastDate = (Get-Date).AddDays(-$days).ToString('yyyy-MM-ddTHH:mm:ssZ') $StaleDevices = Get-MgDeviceManagementManagedDevice -Filter "lastSyncDateTime le $pastDate and OperatingSystem eq '$OS'" if ($StaleDevices) { $deviceNames = $StaleDevices | ForEach-Object { $_.DeviceName } | Out-String $outputPath = [System.IO.Path]::Combine([Environment]::GetFolderPath("Desktop"), "StaleDevices.txt") Set-Content -Path $outputPath -Value $deviceNames Write-Log "Stale devices exported successfully to StaleDevices.txt on your Desktop." [System.Windows.MessageBox]::Show("Stale devices exported successfully to StaleDevices.txt on your Desktop.") } else { Write-Log "No stale devices found." [System.Windows.MessageBox]::Show("No stale devices found.") } } else { Write-Log "Number of days and platform not selected." [System.Windows.MessageBox]::Show("Please select the number of days and platform.") } } catch { Write-Log "Error in export operation. Please ensure you have selected the correct number of days and platform: $_" [System.Windows.MessageBox]::Show("Error in export operation. Please ensure you have selected the correct number of days and platform.") } }) $Window.Add_Loaded({ try { Write-Log "Window is loading..." $modules = @( "Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.DeviceManagement", "Microsoft.Graph.DeviceManagement.Enrollment" ) if ($modules | ForEach-Object { Get-Module -ListAvailable -Name $_ }) { $InstallModulesButton.Content = "Modules Installed" $InstallModulesButton.IsEnabled = $false Write-Log "Modules already installed." } } catch { Write-Log "Error occurred while checking if modules are installed: $_" $AuthenticateButton.Content = "Not Connected to MS Graph" $AuthenticateButton.IsEnabled = $true } }) $InstallModulesButton.Add_Click({ try { Write-Log "Install Modules button clicked, attempting to install modules..." $modules = @( "Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.DeviceManagement", "Microsoft.Graph.DeviceManagement.Enrollment" ) $InstallModulesButton.Content = "Installing..." $InstallModulesButton.IsEnabled = $false $job = Start-Job -ScriptBlock { param($modules) foreach ($module in $modules) { if (!(Get-Module -ListAvailable -Name $module)) { Write-Host "Installing module: $module..." Install-Module $module -Scope CurrentUser -Force -ErrorAction Stop } } } -ArgumentList $modules # Register event to capture installation completion and update GUI accordingly Register-ObjectEvent -InputObject $job -EventName StateChanged -Action { if ($event.SourceEventArgs.JobStateInfo.State -eq 'Completed') { if ($modules | ForEach-Object { Get-Module -ListAvailable -Name $_ }) { $InstallModulesButton.Dispatcher.Invoke({ $InstallModulesButton.Content = "Modules Installed" }) Write-Log "All modules installed successfully." } } elseif ($event.SourceEventArgs.JobStateInfo.State -eq 'Failed') { $InstallModulesButton.Dispatcher.Invoke({ $InstallModulesButton.Content = "Install Modules" $InstallModulesButton.IsEnabled = $true }) Write-Log "Error in installing modules. Please ensure you have administrative permissions: $_" [System.Windows.MessageBox]::Show("Error in installing modules. Please ensure you have administrative permissions.") } } } catch { Write-Log "Exception: $_" [System.Windows.MessageBox]::Show("Error in installing modules. Please ensure you have administrative permissions.") } }) $SearchButton.Add_Click({ if ($AuthenticateButton.IsEnabled) { Write-Log "User is not connected to MS Graph. Attempted search operation." [System.Windows.MessageBox]::Show("You are not connected to MS Graph. Please connect first.") return } try { $SearchTexts = $SearchInputText.Text -split ', ' Write-Log "$SearchTexts" $searchOption = $Dropdown.SelectedItem $searchResults = New-Object 'System.Collections.Generic.List[System.Object]' $AADCount = 0 $IntuneCount = 0 $AutopilotCount = 0 foreach ($SearchText in $SearchTexts) { if (![string]::IsNullOrEmpty($SearchText)) { if ($searchOption -eq "Devicename") { $AADDevices = Get-MgDevice -Search "displayName:$SearchText" -CountVariable CountVar -ConsistencyLevel eventual -ErrorAction Stop | Select-Object -Property displayName, ApproximateLastSignInDateTime, IsManaged, OperatingSystem $IntuneDevices = Get-MgDeviceManagementManagedDevice -Filter "deviceName eq '$SearchText'" -ErrorAction Stop | Select-Object -Property UserDisplayName, OperatingSystem, SerialNumber, DeviceName, LastSyncDateTime foreach ($AADDevice in $AADDevices) { foreach ($IntuneDevice in $IntuneDevices) { if ($IntuneDevice.DeviceName -eq $AADDevice.displayName) { $AutopilotDevice = Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -Filter "contains(serialNumber,'$($IntuneDevice.SerialNumber)')" -ErrorAction Stop | Select-Object -Property GroupTag, SerialNumber, LastContactedDateTime $CombinedDevice = New-Object PSObject -Property @{ "DeviceName" = $IntuneDevice.DeviceName "SerialNumber" = $IntuneDevice.SerialNumber "OperatingSystem" = $AADDevice.OperatingSystem "Primary User" = $IntuneDevice.UserDisplayName "AzureAD Last Contact" = $AADDevice.ApproximateLastSignInDateTime "Intune Last Contact" = $IntuneDevice.LastSyncDateTime "Autopilot Last Contact" = $AutopilotDevice.LastContactedDateTime } $searchResults.Add($CombinedDevice) | Select-Object "DeviceName", "SerialNumber", "OperatingSystem", "Primary User", "AzureAD Last Contact", "Intune Last Contact", "Autopilot Last Contact" if ($AADDevice) { $AADCount++ } if ($IntuneDevice) { $IntuneCount++ } if ($AutopilotDevice) { $AutopilotCount++ } } } } } elseif ($searchOption -eq "Serialnumber") { $IntuneDevices = Get-MgDeviceManagementManagedDevice -Filter "SerialNumber eq '$SearchText'" -ErrorAction Stop | Select-Object -Property UserDisplayName, OperatingSystem, SerialNumber, DeviceName, LastSyncDateTime $displayName = $IntuneDevices.DeviceName $AADDevices = Get-MgDevice -Search "displayName:$displayName" -CountVariable CountVar -ConsistencyLevel eventual -ErrorAction Stop | Select-Object -Property displayName, ApproximateLastSignInDateTime, IsManaged, OperatingSystem foreach ($AADDevice in $AADDevices) { foreach ($IntuneDevice in $IntuneDevices) { if ($IntuneDevice.DeviceName -eq $AADDevice.displayName) { $AutopilotDevice = Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -Filter "contains(serialNumber,'$SearchText')" -ErrorAction Stop | Select-Object -Property GroupTag, SerialNumber, LastContactedDateTime $CombinedDevice = New-Object PSObject -Property @{ "DeviceName" = $IntuneDevice.DeviceName "SerialNumber" = $IntuneDevice.SerialNumber "OperatingSystem" = $AADDevice.OperatingSystem "Primary User" = $IntuneDevice.UserDisplayName "AzureAD Last Contact" = $AADDevice.ApproximateLastSignInDateTime "Intune Last Contact" = $IntuneDevice.LastSyncDateTime "Autopilot Last Contact" = $AutopilotDevice.LastContactedDateTime } $searchResults.Add($CombinedDevice) | Select-Object "DeviceName", "SerialNumber", "OperatingSystem", "Primary User", "AzureAD Last Contact", "Intune Last Contact", "Autopilot Last Contact" if ($AADDevice) { $AADCount++ } if ($IntuneDevice) { $IntuneCount++ } if ($AutopilotDevice) { $AutopilotCount++ } } } } } } } $Window.FindName('intune_status').Text = "Intune: $IntuneCount Available" $Window.FindName('intune_status').Foreground = if ($IntuneCount -gt 0) { 'Green' } else { 'Red' } $Window.FindName('autopilot_status').Text = "Autopilot: $AutopilotCount Available" $Window.FindName('autopilot_status').Foreground = if ($AutopilotCount -gt 0) { 'Green' } else { 'Red' } $Window.FindName('aad_status').Text = "AzureAD: $AADCount Available" $Window.FindName('aad_status').Foreground = if ($AADCount -gt 0) { 'Green' } else { 'Red' } $Window.FindName('SearchResultsDataGrid').ItemsSource = $searchResults } catch { Write-Log "Error occurred during search operation. Exception: $_" [System.Windows.MessageBox]::Show("Error in search operation. Please ensure the Serialnumber or Devicename is valid.") } }) $bulk_import_button.Add_Click({ try { $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.filter = "CSV files (*.csv)|*.csv|TXT files (*.txt)|*.txt" $OpenFileDialog.ShowDialog() | Out-Null $filePath = $OpenFileDialog.FileName if (Test-Path $filePath) { $devices = Get-Content -Path $filePath $deviceNames = $devices $deviceNamesString = $deviceNames -join ", " $SearchInputText.Text = $deviceNamesString } } catch { Write-Log "Exception: $_" [System.Windows.MessageBox]::Show("Error in bulk import operation. Please ensure the file is valid and try again.") } }) $OffboardButton.Add_Click({ if ($AuthenticateButton.IsEnabled) { Write-Log "User is not connected to MS Graph. Attempted offboarding operation." [System.Windows.MessageBox]::Show("You are not connected to MS Graph. Please connect first.") return } $confirmationResult = [System.Windows.MessageBox]::Show("Are you sure you want to proceed with offboarding? This action cannot be undone.", "Confirm Offboarding", [System.Windows.MessageBoxButton]::YesNo) if ($confirmationResult -eq 'No') { Write-Log "User canceled offboarding operation." return } try { $SearchTexts = $SearchInputText.Text -split ', ' foreach ($SearchText in $SearchTexts) { if (![string]::IsNullOrEmpty($SearchText)) { $AADDevice = Get-MgDevice -Search "displayName:$SearchText" -CountVariable CountVar -ConsistencyLevel eventual -ErrorAction Stop $IntuneDevice = Get-MgDeviceManagementManagedDevice -Filter "deviceName eq '$SearchText'" -ErrorAction Stop $AutopilotDevice = Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -Filter "contains(serialNumber,'$($IntuneDevice.SerialNumber)')" -ErrorAction Stop if ($AADDevice) { Remove-MgDevice -DeviceId $AADDevice.Id -ErrorAction Stop [System.Windows.MessageBox]::Show("Successfully removed device $SearchText from AzureAD.") $Window.FindName('aad_status').Text = "AzureAD: Unavailable" Write-Log "Successfully removed device $SearchText from Azure AD." } else { [System.Windows.MessageBox]::Show("Device $SearchText not found in AzureAD.") } if ($IntuneDevice) { Remove-MgDeviceManagementManagedDevice -ManagedDeviceId $IntuneDevice.Id -PassThru -ErrorAction Stop [System.Windows.MessageBox]::Show("Successfully removed device $SearchText from Intune.") $Window.FindName('intune_status').Text = "Intune: Unavailable" Write-Log "Successfully removed device $SearchText from Intune." } else { [System.Windows.MessageBox]::Show("Device $SearchText not found in Intune.") } if ($AutopilotDevice) { Remove-MgDeviceManagementWindowsAutopilotDeviceIdentity -WindowsAutopilotDeviceIdentityId $AutopilotDevice.Id -PassThru -ErrorAction Stop [System.Windows.MessageBox]::Show("Successfully removed device $SearchText from Autopilot.") $Window.FindName('autopilot_status').Text = "Autopilot: Unavailable" Write-Log "Successfully removed device $SearchText from Autopilot." } else { [System.Windows.MessageBox]::Show("Device $SearchText not found in Autopilot.") } } else { [System.Windows.MessageBox]::Show("Please provide a valid device name.") } } } catch { Write-Log "Error in offboarding operation. Exception: $_" [System.Windows.MessageBox]::Show("Error in offboarding operation. Please ensure device names are valid.") } }) $logs_button.Add_Click({ $logFilePath = [System.IO.Path]::Combine([Environment]::GetFolderPath("Desktop"), "IntuneOffboardingTool_Log.txt") if (Test-Path $logFilePath) { Invoke-Item $logFilePath } else { Write-Host "Log file not found." } }) # Show Window $Window.ShowDialog() | Out-Null |