220 lines
7.7 KiB
PowerShell
220 lines
7.7 KiB
PowerShell
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
$form = New-Object System.Windows.Forms.Form
|
|
$form.Text = "Haruna's NTFS-ACL Finder"
|
|
$form.Size = New-Object System.Drawing.Size(700, 600)
|
|
$form.StartPosition = "CenterScreen"
|
|
|
|
$global:CancelSearch = $false
|
|
$global:Results = @()
|
|
|
|
$labelUser = New-Object System.Windows.Forms.Label
|
|
$labelUser.Text = "Select group from AD (OU=ZFD):"
|
|
$labelUser.Location = New-Object System.Drawing.Point(10, 20)
|
|
$labelUser.Size = New-Object System.Drawing.Size(680, 20)
|
|
$form.Controls.Add($labelUser)
|
|
|
|
$comboBoxGroups = New-Object System.Windows.Forms.ComboBox
|
|
$comboBoxGroups.Location = New-Object System.Drawing.Point(10, 45)
|
|
$comboBoxGroups.Size = New-Object System.Drawing.Size(660, 20)
|
|
$comboBoxGroups.AutoCompleteMode = 'SuggestAppend'
|
|
$comboBoxGroups.AutoCompleteSource = 'ListItems'
|
|
$comboBoxGroups.Sorted = $true
|
|
$comboBoxGroups.DropDownStyle = 'DropDownList'
|
|
$form.Controls.Add($comboBoxGroups)
|
|
|
|
$groupMap = @{}
|
|
|
|
function Load-ADGroups {
|
|
try {
|
|
$searcher = New-Object System.DirectoryServices.DirectorySearcher
|
|
$searcher.Filter = "(&(objectClass=group)(distinguishedName=*))"
|
|
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://OU=ZFD,DC=zfd,DC=forumzfd,DC=de")
|
|
$searcher.PageSize = 1000
|
|
$searcher.PropertiesToLoad.Add("cn") | Out-Null
|
|
$searcher.PropertiesToLoad.Add("objectSid") | Out-Null
|
|
|
|
$results = $searcher.FindAll()
|
|
$groupInfos = @()
|
|
foreach ($result in $results) {
|
|
$cn = $result.Properties["cn"][0]
|
|
$sidBytes = $result.Properties["objectSid"][0]
|
|
$sid = New-Object System.Security.Principal.SecurityIdentifier($sidBytes, 0)
|
|
$groupInfos += [PSCustomObject]@{ Display = $cn; SID = $sid }
|
|
}
|
|
|
|
$groupInfos = $groupInfos | Sort-Object Display
|
|
foreach ($group in $groupInfos) {
|
|
$comboBoxGroups.Items.Add($group.Display) | Out-Null
|
|
$groupMap[$group.Display] = $group.SID
|
|
}
|
|
} catch {
|
|
[System.Windows.Forms.MessageBox]::Show("Error loading groups: $_", "Error")
|
|
}
|
|
}
|
|
|
|
Load-ADGroups
|
|
|
|
$buttonBrowse = New-Object System.Windows.Forms.Button
|
|
$buttonBrowse.Text = "Select path"
|
|
$buttonBrowse.Location = New-Object System.Drawing.Point(10, 75)
|
|
$form.Controls.Add($buttonBrowse)
|
|
|
|
$labelPath = New-Object System.Windows.Forms.Label
|
|
$labelPath.Text = "No path selected"
|
|
$labelPath.Location = New-Object System.Drawing.Point(110, 80)
|
|
$labelPath.Size = New-Object System.Drawing.Size(560, 20)
|
|
$form.Controls.Add($labelPath)
|
|
|
|
$folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
$buttonBrowse.Add_Click({
|
|
if ($folderBrowser.ShowDialog() -eq "OK") {
|
|
$labelPath.Text = $folderBrowser.SelectedPath
|
|
}
|
|
})
|
|
|
|
$labelDepth = New-Object System.Windows.Forms.Label
|
|
$labelDepth.Text = "Max search depth (0 = unlimited):"
|
|
$labelDepth.Location = New-Object System.Drawing.Point(10, 110)
|
|
$labelDepth.Size = New-Object System.Drawing.Size(250, 20)
|
|
$form.Controls.Add($labelDepth)
|
|
|
|
$textBoxDepth = New-Object System.Windows.Forms.TextBox
|
|
$textBoxDepth.Text = "0"
|
|
$textBoxDepth.Location = New-Object System.Drawing.Point(270, 110)
|
|
$textBoxDepth.Size = New-Object System.Drawing.Size(50, 20)
|
|
$form.Controls.Add($textBoxDepth)
|
|
|
|
$statusLabel = New-Object System.Windows.Forms.Label
|
|
$statusLabel.Text = "Ready."
|
|
$statusLabel.Location = New-Object System.Drawing.Point(10, 140)
|
|
$statusLabel.Size = New-Object System.Drawing.Size(680, 20)
|
|
$form.Controls.Add($statusLabel)
|
|
|
|
$listBox = New-Object System.Windows.Forms.ListBox
|
|
$listBox.Location = New-Object System.Drawing.Point(10, 170)
|
|
$listBox.Size = New-Object System.Drawing.Size(660, 300)
|
|
$listBox.HorizontalScrollbar = $true
|
|
$form.Controls.Add($listBox)
|
|
|
|
$buttonStart = New-Object System.Windows.Forms.Button
|
|
$buttonStart.Text = "Start search"
|
|
$buttonStart.Location = New-Object System.Drawing.Point(10, 490)
|
|
$form.Controls.Add($buttonStart)
|
|
|
|
$buttonCancel = New-Object System.Windows.Forms.Button
|
|
$buttonCancel.Text = "Cancel"
|
|
$buttonCancel.Location = New-Object System.Drawing.Point(130, 490)
|
|
$buttonCancel.Enabled = $false
|
|
$form.Controls.Add($buttonCancel)
|
|
|
|
$buttonExport = New-Object System.Windows.Forms.Button
|
|
$buttonExport.Text = "Export as CSV"
|
|
$buttonExport.Location = New-Object System.Drawing.Point(250, 490)
|
|
$form.Controls.Add($buttonExport)
|
|
|
|
function Search-Folder {
|
|
param (
|
|
[string]$path,
|
|
[System.Security.Principal.SecurityIdentifier]$expectedSID,
|
|
[int]$depth,
|
|
[int]$maxDepth
|
|
)
|
|
if ($global:CancelSearch) { return }
|
|
if ($maxDepth -gt 0 -and $depth -ge $maxDepth) { return }
|
|
|
|
$statusLabel.Text = "Processing: $path"
|
|
[System.Windows.Forms.Application]::DoEvents()
|
|
|
|
try {
|
|
$items = Get-ChildItem -LiteralPath $path -Force -ErrorAction SilentlyContinue
|
|
foreach ($item in $items) {
|
|
if ($global:CancelSearch) { return }
|
|
|
|
$statusLabel.Text = "Processing: $($item.FullName)"
|
|
[System.Windows.Forms.Application]::DoEvents()
|
|
|
|
try {
|
|
$acl = Get-Acl $item.FullName
|
|
foreach ($entry in $acl.Access) {
|
|
try {
|
|
$currentSID = $entry.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier])
|
|
if ($currentSID -eq $expectedSID) {
|
|
$result = [PSCustomObject]@{
|
|
Path = $item.FullName
|
|
Group = $entry.IdentityReference.ToString()
|
|
}
|
|
$global:Results += $result
|
|
$listBox.Items.Add("$($result.Path) -> $($result.Group)")
|
|
}
|
|
} catch {}
|
|
}
|
|
} catch {}
|
|
|
|
if ($item.PSIsContainer) {
|
|
Search-Folder -path $item.FullName -expectedSID $expectedSID -depth ($depth + 1) -maxDepth $maxDepth
|
|
}
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
$buttonStart.Add_Click({
|
|
$listBox.Items.Clear()
|
|
$global:Results = @()
|
|
$global:CancelSearch = $false
|
|
$statusLabel.Text = "Search started..."
|
|
$buttonCancel.Enabled = $true
|
|
|
|
$selectedDisplay = $comboBoxGroups.SelectedItem
|
|
if ([string]::IsNullOrWhiteSpace($selectedDisplay)) {
|
|
[System.Windows.Forms.MessageBox]::Show("Please select a group.", "Notice")
|
|
return
|
|
}
|
|
|
|
$expectedSID = $groupMap[$selectedDisplay]
|
|
|
|
$startPath = $labelPath.Text
|
|
$maxDepth = 0
|
|
if (-not [int]::TryParse($textBoxDepth.Text.Trim(), [ref]$maxDepth)) {
|
|
$maxDepth = 0
|
|
}
|
|
|
|
if (-not (Test-Path $startPath)) {
|
|
[System.Windows.Forms.MessageBox]::Show("Invalid path!", "Error")
|
|
return
|
|
}
|
|
|
|
Search-Folder -path $startPath -expectedSID $expectedSID -depth 0 -maxDepth $maxDepth
|
|
|
|
if ($global:CancelSearch) {
|
|
$statusLabel.Text = "Search canceled."
|
|
} else {
|
|
$statusLabel.Text = "Search completed."
|
|
}
|
|
$buttonCancel.Enabled = $false
|
|
})
|
|
|
|
$buttonCancel.Add_Click({
|
|
$global:CancelSearch = $true
|
|
$statusLabel.Text = "Cancel requested..."
|
|
$buttonCancel.Enabled = $false
|
|
})
|
|
|
|
$buttonExport.Add_Click({
|
|
if ($global:Results.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show("No results to export.", "Notice")
|
|
return
|
|
}
|
|
$saveDialog = New-Object System.Windows.Forms.SaveFileDialog
|
|
$saveDialog.Filter = "CSV files (*.csv)|*.csv"
|
|
$saveDialog.Title = "Save as..."
|
|
$saveDialog.FileName = "ACL-Results.csv"
|
|
if ($saveDialog.ShowDialog() -eq "OK") {
|
|
$global:Results | Export-Csv -Path $saveDialog.FileName -NoTypeInformation -Encoding Default
|
|
[System.Windows.Forms.MessageBox]::Show("Results have been saved.", "Export successful")
|
|
}
|
|
})
|
|
|
|
$form.Topmost = $true
|
|
[void]$form.ShowDialog()
|