add reload button
This commit is contained in:
1 parent
910555f363
commit
b642f2af7d
4 files changed
+217
-9
No files matched your search
@@ -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
|
||||
@@ -29,6 +29,28 @@ function getLinkedOUs(string $gpo): array|false
|
||||
//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);
|
||||
$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);
|
||||
@@ -180,6 +202,10 @@ else {
|
||||
<label for="group">Group Name:</label>
|
||||
<input type="text" id="group" name="group" required>
|
||||
<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>
|
||||
Data indexed at '.$yaml_timestamp['timestamp'].' after '.$index_duration['duration'].' minutes<br>
|
||||
Total Linked GPOs: '.$gpo_links['gpo_links'].'<p>
|
||||
|
||||
+12
-5
@@ -11,6 +11,13 @@
|
||||
group: "{{ service_user }}"
|
||||
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
|
||||
template:
|
||||
src: app.py
|
||||
@@ -46,11 +53,11 @@
|
||||
- name: API Service - api service handler
|
||||
block:
|
||||
|
||||
- name: "API Service - {{ api_service_name }} - stop service if running"
|
||||
ignore_errors: yes
|
||||
systemd:
|
||||
name: "{{ api_service_name }}.service"
|
||||
state: stopped
|
||||
# - name: "API Service - {{ api_service_name }} - stop service if running"
|
||||
# ignore_errors: yes
|
||||
# systemd:
|
||||
# name: "{{ api_service_name }}.service"
|
||||
# state: stopped
|
||||
|
||||
- name: "API Service - template {{ api_service_name }}.service"
|
||||
vars:
|
||||
|
||||
+42
-4
@@ -1,13 +1,27 @@
|
||||
import yaml
|
||||
import re
|
||||
from datetime import datetime
|
||||
from flask import Flask, request, jsonify
|
||||
from flask import Flask, request, jsonify, abort
|
||||
import threading
|
||||
|
||||
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
|
||||
with open('{{ gpo_yaml_path }}', 'r') as file:
|
||||
data = yaml.safe_load(file)
|
||||
with _data_lock:
|
||||
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:
|
||||
suffix = base_suffix.strip()
|
||||
@@ -126,6 +140,30 @@ def linked_ous():
|
||||
|
||||
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
|
||||
@app.route('/test', methods=['GET'])
|
||||
def test():
|
||||
@@ -137,7 +175,7 @@ def test():
|
||||
except TypeError:
|
||||
# Handle cases where data might be of a different type than expected
|
||||
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__':
|
||||
app.run(debug=False, host='{{ api_service_bind_ip }}', port={{ api_service_port }})
|
||||
Reference in new issue
Block a user