OrphanedAutoPilot.psm1
if(-not (Get-Module Microsoft.Graph -ListAvailable)){ Install-Module Microsoft.Graph -AllowClobber -Scope CurrentUser -Force -SkipPublisherCheck } Import-Module Microsoft.Graph.Identity.DirectoryManagement Import-Module Microsoft.Graph.DeviceManagement.Enrollment Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName PresentationFramework function Get-AutoPilotDevices { param( [Parameter(ParameterSetName="ShowAll")] [bool] $ShowAll = $false ) if($ShowAll -eq $true) { return Get-MgDeviceManagementWindowsAutopilotDeviceIdentity } else { return Get-MgDeviceManagementWindowsAutopilotDeviceIdentity | Where-Object { $_.ManagedDeviceId -eq "00000000-0000-0000-0000-000000000000" } } } function Remove-AutoPilotDevice { [CmdletBinding()] param( [Parameter(Mandatory=$true, ParameterSetName="id")] [guid] $AutoPilotId ) Process { return Remove-MgDeviceManagementWindowsAutopilotDeviceIdentity -WindowsAutopilotDeviceIdentityId $AutoPilotId -PassThru } } function ConvertTo-DataTable { <# .Synopsis Creates a DataTable from an object .Description Creates a DataTable from an object, containing all properties (except built-in properties from a database) .Example Get-ChildItem| Select Name, LastWriteTime | ConvertTo-DataTable .Link Select-DataTable .Link Import-DataTable .Link Export-Datatable #> [OutputType([Data.DataTable])] param( # The input objects [Parameter(Position=0, Mandatory=$true, ValueFromPipeline = $true)] [PSObject[]] $InputObject ) begin { $outputDataTable = new-object Data.datatable $knownColumns = @{} } process { foreach ($In in $InputObject) { $DataRow = $outputDataTable.NewRow() $isDataRow = $in.psobject.TypeNames -like "*.DataRow*" -as [bool] $simpleTypes = ('System.Boolean', 'System.Byte[]', 'System.Byte', 'System.Char', 'System.Datetime', 'System.Decimal', 'System.Double', 'System.Guid', 'System.Int16', 'System.Int32', 'System.Int64', 'System.Single', 'System.UInt16', 'System.UInt32', 'System.UInt64') $SimpletypeLookup = @{} foreach ($s in $simpleTypes) { $SimpletypeLookup[$s] = $s } foreach($property in $In.PsObject.properties) { if ($isDataRow -and 'RowError', 'RowState', 'Table', 'ItemArray', 'HasErrors' -contains $property.Name) { continue } $propName = $property.Name $propValue = $property.Value $IsSimpleType = $SimpletypeLookup.ContainsKey($property.TypeNameOfValue) if (-not $outputDataTable.Columns.Contains($propName)) { $outputDataTable.Columns.Add(( New-Object Data.DataColumn -Property @{ ColumnName = $propName DataType = if ($issimpleType) { $property.TypeNameOfValue } else { 'System.Object' } } )) } $DataRow.Item($propName) = if ($isSimpleType -and $propValue) { $propValue } elseif ($propValue) { [PSObject]$propValue } else { [DBNull]::Value } } $outputDataTable.Rows.Add($DataRow) } } end { ,$outputDataTable } } function Show-Devices { param ( [Parameter(Mandatory = $true)] [System.Collections.IEnumerable]$Data ) # Create the form $form = New-Object System.Windows.Forms.Form $form.Text = "Ophaned AutoPilot Devices" $form.Size = New-Object System.Drawing.Size(800, 450) $form.StartPosition = "CenterScreen" #$form.AutoSize = $true; #$form.AutoSizeMode = 'GrowAndShrink' # Create the filter TextBox $textBox = New-Object System.Windows.Forms.TextBox $textBox.Location = New-Object System.Drawing.Point(10, 10) $textBox.Size = New-Object System.Drawing.Size(300, 20) $form.Controls.Add($textBox) # Create the filter Button $filterButton = New-Object System.Windows.Forms.Button $filterButton.Location = New-Object System.Drawing.Point(310, 10) $filterButton.Size = New-Object System.Drawing.Size(75, 20) $filterButton.Text = "Filter" $form.Controls.Add($filterButton) # Create the refresh Button $refreshButton = New-Object System.Windows.Forms.Button $refreshButton.Location = New-Object System.Drawing.Point(390, 10) $refreshButton.Size = New-Object System.Drawing.Size(75, 20) $refreshButton.Text = "Refresh" $form.Controls.Add($refreshButton) # Create the azure Button $azureButton = New-Object System.Windows.Forms.Button $azureButton.Location = New-Object System.Drawing.Point(470, 10) $azureButton.Size = New-Object System.Drawing.Size(100, 20) $azureButton.Text = "Show in Azure" $azureButton.Enabled = $false $form.Controls.Add($azureButton) # Create the delete Button $deleteButton = New-Object System.Windows.Forms.Button $deleteButton.Location = New-Object System.Drawing.Point(575, 10) $deleteButton.Size = New-Object System.Drawing.Size(100, 20) $deleteButton.Text = "Delete Device" $deleteButton.Enabled = $false $form.Controls.Add($deleteButton) # Create checkbox $showAllCb = New-Object System.Windows.Forms.Checkbox $showAllCb.Location = New-Object System.Drawing.Point(685, 10) $showAllCb.Size = New-Object System.Drawing.Size(100, 20) $showAllCb.Text = "Show All" $form.Controls.Add($showAllCb) # Create the DataGridView $dataGridView = New-Object System.Windows.Forms.DataGridView $dataGridView.Location = New-Object System.Drawing.Point(10, 40) $dataGridView.Size = New-Object System.Drawing.Size(760, 360) $dataGridView.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor ` [System.Windows.Forms.AnchorStyles]::Bottom -bor ` [System.Windows.Forms.AnchorStyles]::Left -bor ` [System.Windows.Forms.AnchorStyles]::Right $dataGridView.ScrollBars = 'Both' $dataGridView.AutoSizeColumnsMode = "AllCells" $dataGridView.ReadOnly = $true $dataGridView.SelectionMode = 'FullRowSelect' $dataGridView.DataBindings.DefaultDataSourceUpdateMode = 0 $form.Controls.Add($dataGridView) $dataGridView.DataSource = $data | ConvertTo-Datatable $dataGridView.Refresh() # Handle the Resize event to adjust DataGridView size $form.Add_Shown({$form.Activate()}) $form.add_ResizeEnd({ #$dataGridView.Size = New-Object System.Drawing.Size(($form.ClientSize.Width - 20), ($form.ClientSize.Height - 50)) }) $filterButton.Add_Click({ $filter = $textBox.Text if($filter -ne "") { $filteredData = $Data | Where-Object { $match = $false foreach ($column in $columns) { if ($_.PSObject.Properties[$column].Value -like "*$filter*") { $match = $true } } $match } } else { $filteredData = $Data } $dataGridView.DataSource = $filteredData | ConvertTo-Datatable $dataGridView.Refresh() }) $refreshButton.Add_Click({ $dataGridView.DataSource = Get-AutoPilotDevices -ShowAll $showAllCb.Checked | Select-Object | ConvertTo-Datatable $dataGridView.Refresh() }) $azureButton.Add_Click({ try { $device = $Data[$dataGridView.CurrentCell.RowIndex] $azureDevice = Get-MgDevice -Search "deviceId:$($device.AzureActiveDirectoryDeviceId)" -ConsistencyLevel eventual if($azureDevice -ne $null) { Start-Process "https://portal.azure.com/#view/Microsoft_AAD_Devices/DeviceDetailsMenuBlade/~/Properties/objectId/$($azureDevice.Id)" } } catch { [System.Windows.MessageBox]::Show("An error occured fetching Azure device info" + $_,"Azure Device","Ok","Error") } }) $deleteButton.Add_Click({ $deleteButton.Enabled = $false try { $device = $Data[$dataGridView.CurrentCell.RowIndex] $confirmDialog = [System.Windows.MessageBox]::Show("Confirm deletion of $($device.Id) ($($device.SerialNumber))","Delete Device","YesNo","Error") if($confirmDialog -eq 'Yes') { if((Remove-AutoPilotDevice -AutoPilotId $device.Id) -eq $true) { [System.Windows.MessageBox]::Show("Delete request submitted, it may take up to 30 minutes to process...","Device Deleted","Ok","Information") $dataGridView.DataSource = Get-AutoPilotDevices -ShowAll $showAllCb.Checked | Select-Object | ConvertTo-Datatable $dataGridView.Refresh() } else { [System.Windows.MessageBox]::Show("Failed to delete device, does it still exist?","Delete Failed","Ok","Error") } } } catch { [System.Windows.MessageBox]::Show("An error occured deleting the device: " + $_,"Delete Device","Ok","Error") } finally { $deleteButton.Enabled = $true } }) $showAllCb.Add_CheckStateChanged({ $dataGridView.DataSource = Get-AutoPilotDevices -ShowAll $showAllCb.Checked | Select-Object | ConvertTo-Datatable $dataGridView.Refresh() }) $dataGridView.add_selectionChanged({ if($dataGridView.CurrentCell.RowIndex -ge 0) { $azureButton.Enabled = $true $deleteButton.Enabled = $true } else { $azureButton.Enabled = $false $deleteButton.Enabled = $false } }) # Show the form [void] $form.ShowDialog() } function Get-MissingAutoPilotDevices { Connect-MgGraph -NoWelcome Show-Devices -Data (Get-AutoPilotDevices | Select-Object) } |