add reload button

This commit is contained in:
matt committed 2026-11-03 03:01:00 -08:00
1 parent 910555f363
commit b642f2af7d
4 files changed
+217 -9

No files matched your search

+137
View File
@@ -0,0 +1,137 @@
# ------------------------------------------------------------------
# 1. Set up environment
# ------------------------------------------------------------------
$ComputerName = "FRRF1LLC1103011"
$printDebug = $false
Import-Module GroupPolicy -ErrorAction Stop
Import-Module ActiveDirectory -ErrorAction Stop
# ------------------------------------------------------------------
# 2. Resolve the computer’s DN and build the OU chain (leaf → root)
# ------------------------------------------------------------------
try {
$comp = Get-ADComputer -Identity $ComputerName -Properties DistinguishedName
}
catch {
Write-Error "Cannot find computer '$ComputerName' in AD: $_"
exit 1
}
$ouDN = $comp.DistinguishedName -replace '^CN=.*?,', ''
$ouChain = @()
$currentDN = $ouDN
while ($currentDN -match '^OU=') {
$ouChain += $currentDN
$currentDN = $currentDN.Substring($currentDN.IndexOf(',') + 1)
}
$ouChain += $currentDN # root
if ($printDebug) {
Write-Host "OU chain (leaf → root):" -ForegroundColor Cyan
$ouChain | ForEach-Object { Write-Host $_ }
}
# ------------------------------------------------------------------
# 3. Gather GPO links for each OU in the chain
# ------------------------------------------------------------------
$gpoLinks = @{} # Hashtable: GPO_GUID => array of OU DNs
foreach ($ouDN in $ouChain) {
try {
$ouObj = Get-ADObject -Identity $ouDN -Properties gPLink -ErrorAction Stop
}
catch {
Write-Warning "Could not read OU '$ouDN': $_"
continue
}
if ($ouObj.gPLink) {
foreach ($link in ($ouObj.gPLink -split ';')) {
$clean = $link.Trim(' ', '[', ']')
if ($clean -match '\{(?<guid>[0-9a-fA-F-]+)\}') {
$guid = $Matches.guid
if (-not $gpoLinks.ContainsKey($guid)) { $gpoLinks[$guid] = @() }
$gpoLinks[$guid] += $ouDN
}
}
}
}
if (-not $gpoLinks.Count) {
Write-Host "No GPOs linked to any OU in the hierarchy." -ForegroundColor Yellow
exit
}
Write-Host "Found $($gpoLinks.Count) distinct GPO(s) linked in this OU tree." -ForegroundColor Green
# ------------------------------------------------------------------
# 4. Collect all restricted‑group entries into an array
# ------------------------------------------------------------------
$results = @() # Will hold objects: @{ADGroup=; LocalGroup=; GPO=}
$uniqueGpoGuids = $gpoLinks.Keys | Sort-Object -Unique
$ou_counter = 0
$totalItems = $uniqueGpoGuids.Count
$startTime = Get-Date
foreach ($gpoGuid in $uniqueGpoGuids) {
$ou_counter++
try { $gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop }
catch { Write-Warning "Unable to retrieve GPO $gpoGuid – skipping."; continue }
$percentComplete = [int]( ($ou_counter / $gpoLinks.Count) * 100 )
if ($ou_counter -gt 0) {
$elapsed = (Get-Date) - $startTime
$averagePerItem = $elapsed.TotalSeconds / $ou_counter
$remainingItems = $totalItems - $ou_counter
$secondsRemaining = [int]($averagePerItem * $remainingItems)
} else { $secondsRemaining = -1 }
Write-Progress -Activity "Processing GPOs" `
-Status $gpo.DisplayName `
-PercentComplete $percentComplete `
-SecondsRemaining $secondsRemaining `
-CurrentOperation "GPO $ou_counter of $totalItems"
# Grab XML report
try { $xmlString = Get-GPOReport -Guid $gpoGuid -ReportType Xml -ErrorAction Stop }
catch { Write-Warning "Unable to generate XML report for $($gpo.DisplayName)."; continue }
$xml = [xml]$xmlString
$ns = New-Object System.Xml.XmlNamespaceManager ($xml.NameTable)
$ns.AddNamespace('m', 'http://www.microsoft.com/GroupPolicy/Settings')
$ns.AddNamespace('q1', 'http://www.microsoft.com/GroupPolicy/Settings/Security')
$ns.AddNamespace('t', 'http://www.microsoft.com/GroupPolicy/Types')
$ns.AddNamespace('xsi','http://www.w3.org/2001/XMLSchema-instance')
$restrictedGroups = $xml.SelectNodes('//q1:RestrictedGroups', $ns)
foreach ($rg in $restrictedGroups) {
$adGroupName = ($rg.SelectSingleNode('q1:GroupName/t:Name', $ns)).InnerText
$localGroupName = ($rg.SelectSingleNode('q1:Memberof/t:Name', $ns)).InnerText
$results += [pscustomobject]@{
ADGroup = $adGroupName
LocalGroup = $localGroupName
GPO = $gpo.DisplayName
}
}
}
$elapsed = (Get-Date) - $startTime
$elapsedSeconds = [math]::Round($elapsed.TotalSeconds, 2)
Write-Host "`nFinished processing $totalItems GPO(s) after $elapsedSeconds seconds." -ForegroundColor Green
# ------------------------------------------------------------------
# 5. Print two separate lists
# ------------------------------------------------------------------
Write-Host "`n=== AD groups that are members of BUILTIN\Administrators ===" -ForegroundColor Yellow
$results | Where-Object {$_.LocalGroup -eq 'BUILTIN\Administrators'} |
Select-Object -ExpandProperty ADGroup | Sort-Object | Get-Unique
Write-Host "`n=== AD groups that are members of vnc_admin ===" -ForegroundColor Yellow
$results | Where-Object {$_.LocalGroup -eq 'vnc_admin'} |
Select-Object -ExpandProperty ADGroup | Sort-Object | Get-Unique
+26
View File
@@ -29,6 +29,28 @@ function getLinkedOUs(string $gpo): array|false
//return implode("\n", $decoded); //return implode("\n", $decoded);
} }
# helper to reload OUs
if (isset($_GET['reload'])) {
// Call the Flask endpoint that reloads the YAML index
$reloadUrl = "http://172.17.0.1:5000/reload_index";
$ch = curl_init($reloadUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 10‑second timeout
$rawResponse = curl_exec($ch);
if ($rawResponse === false) {
error_log('cURL error [' . curl_errno($ch) . ']: ' . curl_error($ch));
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode !== 200) {
error_log("API returned HTTP {$httpCode} for reload_index");
}
// Optionally inspect $rawResponse if you want to show a message
}
curl_close($ch);
}
$yaml_timestamp = json_decode(file_get_contents('http://172.17.0.1:5000/timestamp'), true); $yaml_timestamp = json_decode(file_get_contents('http://172.17.0.1:5000/timestamp'), true);
$gpo_links = json_decode(file_get_contents('http://172.17.0.1:5000/gpo_links'), true); $gpo_links = json_decode(file_get_contents('http://172.17.0.1:5000/gpo_links'), true);
$index_duration = json_decode(file_get_contents('http://172.17.0.1:5000/index_duration'), true); $index_duration = json_decode(file_get_contents('http://172.17.0.1:5000/index_duration'), true);
@@ -180,6 +202,10 @@ else {
<label for="group">Group Name:</label> <label for="group">Group Name:</label>
<input type="text" id="group" name="group" required> <input type="text" id="group" name="group" required>
<button type="submit">Query</button> <button type="submit">Query</button>
</form>
<form action="index.php" method="GET" style="display:inline;">
<input type="hidden" name="reload" value="1">
<button type="submit">Reload Index</button>
</form><p> </form><p>
Data indexed at '.$yaml_timestamp['timestamp'].' after '.$index_duration['duration'].' minutes<br> Data indexed at '.$yaml_timestamp['timestamp'].' after '.$index_duration['duration'].' minutes<br>
Total Linked GPOs: '.$gpo_links['gpo_links'].'<p> Total Linked GPOs: '.$gpo_links['gpo_links'].'<p>
+12 -5
View File
@@ -11,6 +11,13 @@
group: "{{ service_user }}" group: "{{ service_user }}"
mode: '0755' mode: '0755'
- name: "API Service - {{ api_service_name }} - stop service"
systemd:
name: "{{ api_service_name }}.service"
state: stopped
ignore_errors: yes
- name: API Service - template app.py - name: API Service - template app.py
template: template:
src: app.py src: app.py
@@ -46,11 +53,11 @@
- name: API Service - api service handler - name: API Service - api service handler
block: block:
- name: "API Service - {{ api_service_name }} - stop service if running" # - name: "API Service - {{ api_service_name }} - stop service if running"
ignore_errors: yes # ignore_errors: yes
systemd: # systemd:
name: "{{ api_service_name }}.service" # name: "{{ api_service_name }}.service"
state: stopped # state: stopped
- name: "API Service - template {{ api_service_name }}.service" - name: "API Service - template {{ api_service_name }}.service"
vars: vars:
+42 -4
View File
@@ -1,13 +1,27 @@
import yaml import yaml
import re import re
from datetime import datetime from datetime import datetime
from flask import Flask, request, jsonify from flask import Flask, request, jsonify, abort
import threading
app = Flask(__name__) app = Flask(__name__)
### adding reload route
# Global cache and lock
data = None
_data_lock = threading.Lock()
def load_yaml():
"""Load the YAML file and return its contents."""
with open('{{ gpo_yaml_path }}', 'r', encoding='utf-8') as f:
return yaml.safe_load(f)
# Load GPO data # Load GPO data
with open('{{ gpo_yaml_path }}', 'r') as file: with _data_lock:
data = yaml.safe_load(file) data = load_yaml()
# O.G. method
#with open('{{ gpo_yaml_path }}', 'r') as file:
# data = yaml.safe_load(file)
def strip_dn(dn: str, base_suffix: str = ",OU=Manufacturing,OU=Tesla Systems,DC=teslamotors,DC=com") -> str: def strip_dn(dn: str, base_suffix: str = ",OU=Manufacturing,OU=Tesla Systems,DC=teslamotors,DC=com") -> str:
suffix = base_suffix.strip() suffix = base_suffix.strip()
@@ -126,6 +140,30 @@ def linked_ous():
return jsonify(linked) return jsonify(linked)
# reload index route
@app.route('/reload_index', methods=['GET'])
def reload_index():
try:
new_data = load_yaml()
except Exception as exc:
# Log the exception if you have a logger; here we just abort
abort(500, description=f'Failed to load YAML: {exc}')
# Thread‑safe write to the global cache
with _data_lock:
global data
data = new_data
# Return the re‑loaded data (or some confirmation)
return jsonify({
'status': 'reloaded',
'gpo_links': data[0]['gpo_links']
})
# with open('{{ gpo_yaml_path }}', 'r') as file:
# data = yaml.safe_load(file)
# return jsonify({'status': 'reloaded', 'data': data})
# test route # test route
@app.route('/test', methods=['GET']) @app.route('/test', methods=['GET'])
def test(): def test():
@@ -137,7 +175,7 @@ def test():
except TypeError: except TypeError:
# Handle cases where data might be of a different type than expected # Handle cases where data might be of a different type than expected
return jsonify({"error": "TypeError: Data is not a dictionary"}), 400 return jsonify({"error": "TypeError: Data is not a dictionary"}), 400
return jsonify({"result": "test", "OU_Root": root_ou}) return jsonify({"result": "test", "OU_Root": root_ou, "gpo_links": data[0]['gpo_links']})
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=False, host='{{ api_service_bind_ip }}', port={{ api_service_port }}) app.run(debug=False, host='{{ api_service_bind_ip }}', port={{ api_service_port }})