Skip to content

Instantly share code, notes, and snippets.

@danjpadgett
Created March 13, 2017 09:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danjpadgett/8e03151af999b78e2759c10094666efa to your computer and use it in GitHub Desktop.
Save danjpadgett/8e03151af999b78e2759c10094666efa to your computer and use it in GitHub Desktop.
RemoveObjects.ps1
<#
.NOTES
===========================================================================
Created by: Dan Padgett (C)
Organization: www.execmgr.net
Version: 1.0
===========================================================================
.SYNOPSIS
Removal Tool for SCCM and AD Objects
.NOTES
Script relies on a settings.xml file , the file should look like:
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<Main>
<SCCMServer>sccm.company.group</SCCMServer>
<SearchBase>OU=Workstations,OU=Root,DC=company,DC=group</SearchBase>
<SystemOUName>COMPANY.GROUP/ROOT/WORKSTATIONS<SystemOUName>
<SccmSite>XXX</SccmSite>
<cmrcviewer>C:\Program Files (x86)\ConfigMgrConsole\bin\i386\CmRcViewer.exe</cmrcviewer>
</Main>
</Settings>
.DISCLAIMER
All scripts are provided AS IS without warranty of any kind. The author further disclaims all implied warranties including, without limitation,
any implied warranties of merchantability or of fitness for a particular purpose.
The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
In no event shall the author,or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever
including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss
arising out of the use of or inability to use the sample scripts or documentation, even if the author has been advised of the possibility of such damages.
.LINK
www.execmgr.net
#>
#region Control Helper Functions
function ConvertTo-DataTable
{
[OutputType([System.Data.DataTable])]
param(
[ValidateNotNull()]
$InputObject,
[ValidateNotNull()]
[System.Data.DataTable]$Table,
[switch]$RetainColumns,
[switch]$FilterWMIProperties)
if($Table -eq $null)
{
$Table = New-Object System.Data.DataTable
}
if($InputObject-is [System.Data.DataTable])
{
$table = ConvertTo-DataTable -InputObject $processes –FilterWMIProperties
}
else
{
if(-not $RetainColumns -or $Table.Columns.Count -eq 0)
{
#Clear out the Table Contents
$Table.Clear()
if($InputObject -eq $null){ return } #Empty Data
$object = $null
#find the first non null value
foreach($item in $InputObject)
{
if($item -ne $null)
{
$object = $item
break
}
}
if($object -eq $null) { return } #All null then empty
#Get all the properties in order to create the columns
foreach ($prop in $object.PSObject.Get_Properties())
{
if(-not $FilterWMIProperties -or -not $prop.Name.StartsWith('__'))#filter out WMI properties
{
#Get the type from the Definition string
$type = $null
if($prop.Value -ne $null)
{
try{ $type = $prop.Value.GetType() } catch {}
}
if($type -ne $null) # -and [System.Type]::GetTypeCode($type) -ne 'Object')
{
[void]$table.Columns.Add($prop.Name, $type)
}
else #Type info not found
{
[void]$table.Columns.Add($prop.Name)
}
}
}
if($object -is [System.Data.DataRow])
{
foreach($item in $InputObject)
{
$Table.Rows.Add($item)
}
return @(,$Table)
}
}
else
{
$Table.Rows.Clear()
}
foreach($item in $InputObject)
{
$row = $table.NewRow()
if($item)
{
foreach ($prop in $item.PSObject.Get_Properties())
{
if($table.Columns.Contains($prop.Name))
{
$row.Item($prop.Name) = $prop.Value
}
}
}
[void]$table.Rows.Add($row)
}
}
return @(,$Table)
}
function Load-DataGridView
{
Param (
[ValidateNotNull()]
[Parameter(Mandatory=$true)]
[System.Windows.Forms.DataGridView]$DataGridView,
[ValidateNotNull()]
[Parameter(Mandatory=$true)]
$Item,
[Parameter(Mandatory=$false)]
[string]$DataMember
)
Load-DataGridView -DataGridView $datagridviewResults -Item $table
$DataGridView.SuspendLayout()
$DataGridView.DataMember = $DataMember
if ($Item -is [System.ComponentModel.IListSource]`
-or $Item -is [System.ComponentModel.IBindingList] -or $Item -is [System.ComponentModel.IBindingListView] )
{
$DataGridView.DataSource = $Item
}
else
{
$array = New-Object System.Collections.ArrayList
if ($Item -is [System.Collections.IList])
{
$array.AddRange($Item)
}
else
{
$array.Add($Item)
}
$DataGridView.DataSource = $array
}
$DataGridView.ResumeLayout()
}
#endregion
#region Variables
#Load Settings from setting.xml
[xml]$ConfigFile = Get-Content ".\Settings.xml"
$sccmserver = $ConfigFile.Settings.Main.SCCMServer
$searchbase = $ConfigFile.Settings.Main.SearchBase
$SystemOUName = $ConfigFile.Settings.Main.SystemOUName
$sccmsite = $ConfigFile.Settings.Main.SccmSite
$cmrcviewer = $ConfigFile.Settings.Main.cmrcviewer
#endregion
$textboxSearch.Text = $SystemOUName
function ColorCells
{
$i = -0
foreach ($row in $datagridviewResults.Rows)
{
if ($datagridviewResults.Rows[$i].Cells['SCCMResourceID'].Value -eq $null)
{
$row.defaultcellstyle.backcolor = 'yellow'
}
else
{
##//Do not color cells
}
##//Increment $i
$i++
}
}
$formMain_Load = {
#TODO: Initialize Form Controls here
$UserContextText.Text = "Running As: $env:USERDOMAIN\$env:USERNAME"
#//test for settins.xml file
if (!(Test-Path .\settings.xml))
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Could not find Settings.xml , please create it and try again", "Error", 0)
$formMain.Close()
}
}
function New-ObjectSearch
{
param (
$sccmArr
)
[System.Collections.ArrayList]$computers = Get-ADComputer -Filter * -property name, Description, OperatingSystem, IPv4Address, ms-MCS-AdmPwd -SearchBase $searchbase | select Name, Description, OperatingSystem, IPv4Address, Enabled, @{ Name = "LAPS Password"; Expression = { ($_.'ms-MCS-AdmPwd') } } | sort name
$computers | ForEach {
$compname = $_.Name
$_ | Add-Member -MemberType NoteProperty -Name MACAddresses -Value ($sccmArr | Where-Object { $_.name -eq $compname } | Select-Object -ExpandProperty MACAddresses | Select-Object -First 1)
$_ | Add-Member -MemberType NoteProperty -Name SCCMResourceID -Value ($sccmArr | Where-Object { $_.name -eq $compname } | Select-Object -ExpandProperty ResourceID)
}
return $computers
}
[System.Collections.ArrayList]$sccmQuery = get-wmiobject -query "select * from SMS_R_SYSTEM WHERE Name like '%' " -computername $sccmserver -namespace "ROOT\SMS\site_$sccmsite" | Where-Object { $_.SystemOUName -contains $SystemOUName }
#region Search Function
function SearchGrid()
{
$RowIndex = 0
$ColumnIndex = 0
$seachString = $textboxSearch.Text
if($seachString -eq "")
{
return
}
if($datagridviewResults.SelectedCells.Count -ne 0)
{
$startCell = $datagridviewResults.SelectedCells[0];
$RowIndex = $startCell.RowIndex
$ColumnIndex = $startCell.ColumnIndex + 1
}
$columnCount = $datagridviewResults.ColumnCount
$rowCount = $datagridviewResults.RowCount
for(;$RowIndex -lt $rowCount; $RowIndex++)
{
$Row = $datagridviewResults.Rows[$RowIndex]
for(;$ColumnIndex -lt $columnCount; $ColumnIndex++)
{
$cell = $Row.Cells[$ColumnIndex]
if($cell.Value -ne $null -and $cell.Value.ToString().IndexOf($seachString, [StringComparison]::OrdinalIgnoreCase) -ne -1)
{
$datagridviewResults.CurrentCell = $cell
return
}
}
$ColumnIndex = 0
}
$datagridviewResults.CurrentCell = $null
[void][System.Windows.Forms.MessageBox]::Show("The search has reached the end of the grid.","String not Found")
}
#endregion
#region Events
#//Remote Control
$buttonRemoteControl_Click = {
if ( $($datagridviewResults.CurrentCell.Value.ToString()) -notin $sccmQuery.Name )
{
[System.Windows.Forms.MessageBox]::Show("Please select item from Name column", "Error", 0)
#donothing
}
else
{
& $CmRcViewer $($datagridviewResults.CurrentCell.Value.ToString())
}
}
##//Remove AD Object
$buttonRemoveAD_Click = {
if ($($datagridviewResults.CurrentCell.Value.ToString()) -notin $sccmQuery.Name)
{
[System.Windows.Forms.MessageBox]::Show("Please select item from Name column", "Error", 0)
#donothing
}
else
{
$selecteditem = $($datagridviewResults.CurrentCell.Value.ToString())
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$msgboxwarning = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to remove '$selecteditem' from Active Directory?", "Confirm Removal", 1)
if ($msgboxwarning -eq "OK")
{
Remove-ADComputer -Identity $selecteditem -confirm:$false
}
else
{
#donothing
}
}
}
##//Remove SCCM Object
$buttonRemoveSCCMObject_Click = {
if ($($datagridviewResults.CurrentCell.Value.ToString()) -notin $sccmQuery.Name)
{
[System.Windows.Forms.MessageBox]::Show("Please select item from Name column", "Error", 0)
#donothing
}
else
{
$selecteditem = $($datagridviewResults.CurrentCell.Value.ToString())
$compobject = $sccmQuery | Where-Object { $_.Name -eq $selecteditem }
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$msgboxwarning = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to remove '$selecteditem' - SCCM Resource ID :$($compObject.ResourceID)", "Confirm Removal", 1)
if ($msgboxwarning -eq "OK")
{
$toolstripstatuslabel1.Text = "Removing SCCM Object...."
$compObject.psbase.delete()
timeout 2
##Clear removed SCCM Resource out of Array.
for ($i = 0; $i -lt $sccmQuery.Count; $i++)
{
if ($sccmQuery[$i].Name -eq $selecteditem)
{
Write-Host "$($sccmQuery[$i].Name)"
$sccmQuery.RemoveAt($i)
$toolstripstatuslabel1.Text = "Successfully removed SCCM Object...."
}
}
$datagridviewResults.Refresh()
$computerArr = New-ObjectSearch $sccmQuery
Load-DataGridView -DataGridView $datagridviewResults -Item $computerArr -ErrorAction SilentlyContinue
ColorCells
}
elseif ($msgboxwarning -eq "Cancel")
{
#donothing
}
}
}
##//Remove SCCM and AD Object
$buttonRemoveSCCMADObject_Click = {
if ($($datagridviewResults.CurrentCell.Value.ToString()) -notin $sccmQuery.Name)
{
[System.Windows.Forms.MessageBox]::Show("Please select item from Name column", "Error", 0)
#donothing
}
else
{
$selecteditem = $($datagridviewResults.CurrentCell.Value.ToString())
$compobject = $sccmQuery | Where-Object { $_.Name -eq $selecteditem }
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$msgboxwarning = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to remove '$selecteditem' - SCCM Resource ID : $($compObject.ResourceID) & from AD", "Confirm Removal", 1)
if ($msgboxwarning -eq "OK")
{
##//Remove SCCM Object from DB
$toolstripstatuslabel1.Text = "Removing SCCM & AD Object...."
$compObject.psbase.delete()
timeout 2
##Clear removed SCCM Resource out of Array.
for ($i = 0; $i -lt $sccmQuery.Count; $i++)
{
if ($sccmQuery[$i].Name -eq $selecteditem)
{
Write-Host "$($sccmQuery[$i].Name)"
$sccmQuery.RemoveAt($i)
$toolstripstatuslabel1.Text = "Successfully removed SCCM Object...."
}
}
##/
##//Remove AD Object
Remove-ADComputer -Identity $selecteditem -confirm:$false
##/
$datagridviewResults.Refresh()
$computerArr = New-ObjectSearch $sccmQuery
Load-DataGridView -DataGridView $datagridviewResults -Item $computerArr -ErrorAction SilentlyContinue
ColorCells
}
}
}
##//Search Controls
$textboxSearch_KeyDown = [System.Windows.Forms.KeyEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.KeyEventArgs]
if ($_.KeyCode -eq 'Enter' -and $buttonSearchFilter.Enabled)
{
#ObjectSearch
$computerArr = New-ObjectSearch $sccmQuery
SearchGrid
$_.SuppressKeyPress = $true
}
}
##//Exit Controls
$buttonExit_Click = {
#TODO: Place custom script here
$formMain.Close()
}
##//Search Event
$buttonSearchFilter_Click = {
$datagridviewResults.Refresh()
$computerArr = New-ObjectSearch $sccmQuery
Load-DataGridView -DataGridView $datagridviewResults -Item $computerArr -ErrorAction SilentlyContinue
$toolstripstatuslabel1.Text = "Select Object (From NAME Column)"
SearchGrid
ColorCells
}
$datagridviewResults_ColumnHeaderMouseClick = [System.Windows.Forms.DataGridViewCellMouseEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.DataGridViewCellMouseEventArgs]
if ($datagridviewResults.DataSource -is [System.Data.DataTable])
{
$column = $datagridviewResults.Columns[$_.ColumnIndex]
$direction = [System.ComponentModel.ListSortDirection]::Ascending
if ($column.HeaderCell.SortGlyphDirection -eq 'Descending')
{
$direction = [System.ComponentModel.ListSortDirection]::Descending
}
$datagridviewResults.Sort($datagridviewResults.Columns[$_.ColumnIndex], $direction)
}
}
$formMain_FormClosed = [System.Windows.Forms.FormClosedEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.FormClosedEventArgs]
#Stop any pending jobs
Stop-JobTracker
}
#endregion
#region Job Tracker
$timerJobTracker_Tick = {
Update-JobTracker
}
$JobTrackerList = New-Object System.Collections.ArrayList
function Add-JobTracker
{
Param (
[ValidateNotNull()]
[Parameter(Mandatory = $true)]
[string]$Name,
[ValidateNotNull()]
[Parameter(Mandatory = $true)]
[ScriptBlock]$JobScript,
$ArgumentList = $null,
[ScriptBlock]$CompletedScript,
[ScriptBlock]$UpdateScript)
#Start the Job
$job = Start-Job -Name $Name -ScriptBlock $JobScript -ArgumentList $ArgumentList
if ($job -ne $null)
{
#Create a Custom Object to keep track of the Job & Script Blocks
$members = @{
'Job' = $Job;
'CompleteScript' = $CompletedScript;
'UpdateScript' = $UpdateScript
}
$psObject = New-Object System.Management.Automation.PSObject -Property $members
[void]$JobTrackerList.Add($psObject)
#Start the Timer
if (-not $timerJobTracker.Enabled)
{
$timerJobTracker.Start()
}
}
elseif ($CompletedScript -ne $null)
{
#Failed
Invoke-Command -ScriptBlock $CompletedScript -ArgumentList $null
}
}
function Update-JobTracker
{
<#
.SYNOPSIS
Checks the status of each job on the list.
#>
#Poll the jobs for status updates
$timerJobTracker.Stop() #Freeze the Timer
for ($index = 0; $index -lt $JobTrackerList.Count; $index++)
{
$psObject = $JobTrackerList[$index]
if ($psObject -ne $null)
{
if ($psObject.Job -ne $null)
{
if ($psObject.Job.State -ne "Running")
{
#Call the Complete Script Block
if ($psObject.CompleteScript -ne $null)
{
#$results = Receive-Job -Job $psObject.Job
Invoke-Command -ScriptBlock $psObject.CompleteScript -ArgumentList $psObject.Job
}
$JobTrackerList.RemoveAt($index)
Remove-Job -Job $psObject.Job
$index-- #Step back so we don't skip a job
}
elseif ($psObject.UpdateScript -ne $null)
{
#Call the Update Script Block
Invoke-Command -ScriptBlock $psObject.UpdateScript -ArgumentList $psObject.Job
}
}
}
else
{
$JobTrackerList.RemoveAt($index)
$index-- #Step back so we don't skip a job
}
}
if ($JobTrackerList.Count -gt 0)
{
$timerJobTracker.Start() #Resume the timer
}
}
function Stop-JobTracker
{
<#
.SYNOPSIS
Stops and removes all Jobs from the list.
#>
#Stop the timer
$timerJobTracker.Stop()
#Remove all the jobs
while ($JobTrackerList.Count -gt 0)
{
$job = $JobTrackerList[0].Job
$JobTrackerList.RemoveAt(0)
Stop-Job $job
Remove-Job $job
}
}
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment