add gpo counter variable to powershell script for visbility
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@ project_folder: "/opt/cosmos/gpo_site"
|
||||
api_service_name: "gpo_api"
|
||||
api_service_folder: "{{ project_folder }}/api"
|
||||
api_service_port: "5000"
|
||||
api_service_bind_ip: "0.0.0.0"
|
||||
api_service_bind_ip: "172.17.0.1"
|
||||
|
||||
dashboard_web_root: "{{ project_folder }}/dashboard"
|
||||
container_name: "GPO-Dashboard"
|
||||
|
||||
+55
-28
@@ -29,8 +29,11 @@ function getLinkedOUs(string $gpo): array|false
|
||||
//return implode("\n", $decoded);
|
||||
}
|
||||
|
||||
?>
|
||||
$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);
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -42,9 +45,13 @@ function getLinkedOUs(string $gpo): array|false
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Query GPOs by Group</h2>
|
||||
This tool allows you to query Group Policy Objects in Active Directory by Restricted Group.<br>
|
||||
This tool is intended to help determine what OU to use for a specific group.<br>
|
||||
Users often request systems with a certain security group assigned.<br>
|
||||
Since AD has no way to look this up, this makes it challenging to match groups to OUs.<p>
|
||||
This site has all restricted groups indexed by GPO and OU.<br>
|
||||
Search is case insensitive and supports partial match. <br>
|
||||
Once you have the GPO name, you can locate this in the GPO management snap-in and find what OUs it links to.<br><p>
|
||||
The OUs liked to the GPOs will show up as a hover tooltip on the GPO name.<br>
|
||||
Clicking on the GPO name will list all linked OUs.<br><p>
|
||||
</div>
|
||||
<div class="container">
|
||||
|
||||
@@ -56,8 +63,9 @@ if (isset($_GET['group'])) {
|
||||
<form action="index.php" method="GET">
|
||||
<label for="group">Group Name:</label>
|
||||
<input type="text" id="group" name="group" value="'.htmlspecialchars($_GET['group']).'" required>
|
||||
<button type="submit">Query</button>
|
||||
<button type="submit">Query</button><br>
|
||||
</form><p>
|
||||
Return <a href=/>Home</a><br>
|
||||
';
|
||||
$group = urlencode($_GET['group']);
|
||||
$url = "http://172.17.0.1:5000/gpo?group=$group";
|
||||
@@ -107,31 +115,43 @@ if (isset($_GET['group'])) {
|
||||
}
|
||||
ksort($gpoMap, SORT_STRING | SORT_FLAG_CASE);
|
||||
if($numResults > 0){
|
||||
echo 'Total results: '.$numResults.'<br>
|
||||
echo '
|
||||
Total results: '.$numResults.'<br>
|
||||
Data indexed at '.$yaml_timestamp['timestamp'].' after '.$index_duration['duration'].' minutes<br>
|
||||
Total Linked GPOs: '.$gpo_links['gpo_links'].'<p>
|
||||
<table border="1" cellpadding="4" cellspacing="0">
|
||||
<tr>
|
||||
<th>
|
||||
GPO
|
||||
</th>
|
||||
<th>
|
||||
Administrators
|
||||
</th>
|
||||
<th>
|
||||
vnc_admin
|
||||
</th>
|
||||
</tr>
|
||||
';
|
||||
echo '<table border="1" cellpadding="4" cellspacing="0">
|
||||
';
|
||||
echo '<tr><th>GPO</th><th>Administrators</th><th>vnc_admin</th></tr>
|
||||
';
|
||||
|
||||
foreach ($gpoMap as $gpoName => $cols) {
|
||||
// Remove duplicates and build comma‑separated lists
|
||||
$adminGroups = implode('<br>', array_unique($cols['administrators']));
|
||||
$vncGroups = implode('<br>', array_unique($cols['vnc_admin']));
|
||||
$linkedOUs = implode("\n", getLinkedOUs($gpoName));
|
||||
echo ' <tr>
|
||||
';
|
||||
echo " <td>
|
||||
<div title='$linkedOUs'>
|
||||
<a href=/?gpo='$gpoName'>{$gpoName}</a>
|
||||
</div></td>
|
||||
echo "
|
||||
<tr>
|
||||
<td>
|
||||
<div title='$linkedOUs'>
|
||||
<a href=/?gpo=$gpoName>{$gpoName}</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{$adminGroups}
|
||||
</td>
|
||||
<td>
|
||||
{$vncGroups}
|
||||
</td>
|
||||
</tr>
|
||||
";
|
||||
echo " <td>{$adminGroups}</td>
|
||||
";
|
||||
echo " <td>{$vncGroups}</td>
|
||||
";
|
||||
echo ' </tr>
|
||||
';
|
||||
}
|
||||
echo '</table>
|
||||
';
|
||||
@@ -140,17 +160,20 @@ if (isset($_GET['group'])) {
|
||||
echo 'No results found for query <b>'.$_GET['group'].'</b>.<p>';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if you click on a GPO name, print all OUs
|
||||
else if (isset($_GET['gpo'])) {
|
||||
echo 'OUs linked to GPO <b>'.$_GET['gpo'].':</b><p>';
|
||||
echo 'OUs linked to GPO <b>'.$_GET['gpo'].':</b><p><ul>';
|
||||
$LinkedOUs = getLinkedOUs($_GET['gpo']);
|
||||
echo implode("<br>", $LinkedOUs);
|
||||
echo '<br>Return <a href=/>Home</a>';
|
||||
foreach ($LinkedOUs as $OU){
|
||||
echo "<li>".$OU."</li>";
|
||||
}
|
||||
#echo implode("<li>", $LinkedOUs);
|
||||
echo '</ul><p>Return <a href=/>Home</a>';
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
echo '
|
||||
<form action="index.php" method="GET">
|
||||
@@ -158,10 +181,14 @@ else {
|
||||
<input type="text" id="group" name="group" required>
|
||||
<button type="submit">Query</button>
|
||||
</form><p>
|
||||
Data indexed at '.$yaml_timestamp['timestamp'].' after '.$index_duration['duration'].' minutes<br>
|
||||
Total Linked GPOs: '.$gpo_links['gpo_links'].'<p>
|
||||
No group specified.</p>
|
||||
';
|
||||
echo "<p>No group specified.</p>";
|
||||
|
||||
}
|
||||
echo "</div>";
|
||||
echo "</div>
|
||||
";
|
||||
//echo "<p>Source code can be found <a target='_blank' rel='noopener noreferrer' href='https://gitea.matt-cloud.com/matt/gpo_lookup'>here</a>.<p>";
|
||||
?>
|
||||
|
||||
|
||||
@@ -67,11 +67,6 @@ h1, h2, h3, h4 {
|
||||
color: #bdc3c7; /* Dimmer text color */
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 10px;
|
||||
color: #bdc3c7; /* Dimmer text color */
|
||||
|
||||
@@ -18,6 +18,8 @@ if (Test-Path $OutputFile) {
|
||||
Write-Output "Enumerating OUs under '$TargetOU' ..."
|
||||
Add-Content -Path $OutputFile -Value "---"
|
||||
Add-Content -Path $OutputFile -Value "- root_ou: $TargetOU"
|
||||
$Start_Date = (Get-Date).ToString('MM/dd/yyyy hh:mm:ss tt')
|
||||
Add-Content -Path $OutputFile -Value " init_timestamp: $Start_Date"
|
||||
$ouObjects = Get-ADObject `
|
||||
-Filter 'ObjectClass -eq "organizationalUnit"' `
|
||||
-SearchBase $TargetOU `
|
||||
@@ -69,7 +71,10 @@ Add-Content -Path $OutputFile -Value " gpo_links: $($gpoLinks.Count)"
|
||||
|
||||
|
||||
Add-Content -Path $OutputFile -Value " configured_gpos:"
|
||||
$ou_counter = 0
|
||||
foreach ($gpoGuid in $gpoLinks.Keys) {
|
||||
$ou_counter++
|
||||
|
||||
try {
|
||||
$gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop
|
||||
}
|
||||
@@ -77,18 +82,19 @@ foreach ($gpoGuid in $gpoLinks.Keys) {
|
||||
Write-Warning "Unable to retrieve GPO $gpoGuid – skipping."
|
||||
continue
|
||||
}
|
||||
Write-Host "GPO: $($gpo.DisplayName)"
|
||||
Write-Host "GPO $ou_counter of $($gpoLinks.Count): $($gpo.DisplayName)"
|
||||
Add-Content -Path $OutputFile -Value " $($gpo.DisplayName):"
|
||||
# ok, i need to start generating a variable with all links in it
|
||||
|
||||
|
||||
# -------- Linked OUs ----------
|
||||
$linkedOUs = $gpoLinks[$gpoGuid]
|
||||
Write-Host "Linked OUs:"
|
||||
Add-Content -Path $OutputFile -Value " Linked_OUs:"
|
||||
$linkedOUs = $gpoLinks[$gpoGuid] # <-- the list we built earlier
|
||||
Add-Content -Path $OutputFile -Value " - Linked_OUs:"
|
||||
foreach ($ouDn in $linkedOUs) {
|
||||
Write-Host "$ouDn"
|
||||
Add-Content -Path $OutputFile -Value " - $ouDn"
|
||||
}
|
||||
|
||||
|
||||
# Pull the XML report
|
||||
try {
|
||||
$xmlString = Get-GPOReport -Guid $gpoGuid -ReportType Xml -ErrorAction Stop
|
||||
@@ -97,8 +103,9 @@ foreach ($gpoGuid in $gpoLinks.Keys) {
|
||||
Write-Warning "Unable to generate XML report for $($gpo.DisplayName)."
|
||||
continue
|
||||
}
|
||||
|
||||
$xml = [xml]$xmlString
|
||||
# process the XML data
|
||||
|
||||
$ns = New-Object System.Xml.XmlNamespaceManager ($xml.NameTable)
|
||||
$ns.AddNamespace('m', 'http://www.microsoft.com/GroupPolicy/Settings') # default namespace
|
||||
$ns.AddNamespace('q1', 'http://www.microsoft.com/GroupPolicy/Settings/Security')
|
||||
@@ -113,10 +120,12 @@ foreach ($gpoGuid in $gpoLinks.Keys) {
|
||||
$adGroupName = ($rg.SelectSingleNode('q1:GroupName/t:Name', $ns)).InnerText
|
||||
$localGroupName = ($rg.SelectSingleNode('q1:Memberof/t:Name', $ns)).InnerText
|
||||
$plainAD_Groupname = ($adGroupName -split '\\')[-1]
|
||||
Write-Output "AD Group: $adGroupName - Local Group: $localGroupName"
|
||||
#Write-Output "AD Group: $adGroupName - Local Group: $localGroupName"
|
||||
Add-Content -Path $OutputFile -Value " - ad_group: $plainAD_Groupname"
|
||||
Add-Content -Path $OutputFile -Value " local_group: $localGroupName"
|
||||
}
|
||||
Add-Content -Path $OutputFile -Value ""
|
||||
}
|
||||
$Current_Date = (Get-Date).ToString('MM/dd/yyyy hh:mm:ss tt')
|
||||
Add-Content -Path $OutputFile -Value " timestamp: $Current_Date"
|
||||
Add-Content -Path $OutputFile -Value "..."
|
||||
|
||||
+58
-6
@@ -1,5 +1,6 @@
|
||||
import yaml
|
||||
import re
|
||||
from datetime import datetime
|
||||
from flask import Flask, request, jsonify
|
||||
|
||||
app = Flask(__name__)
|
||||
@@ -8,6 +9,23 @@ app = Flask(__name__)
|
||||
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()
|
||||
dn_clean = dn.strip()
|
||||
lowered_dn = dn_clean.lower()
|
||||
lowered_suffix = suffix.lower()
|
||||
idx = lowered_dn.rfind(lowered_suffix)
|
||||
if idx != -1:
|
||||
dn_clean = dn_clean[:idx].rstrip(',')
|
||||
|
||||
# Pull all OU=… values (leaf → root order)
|
||||
ou_values: List[str] = re.findall(r'OU=([^,]+)', dn_clean, flags=re.IGNORECASE)
|
||||
|
||||
if not ou_values:
|
||||
return ''
|
||||
ou_values = [v.strip() for v in reversed(ou_values)]
|
||||
return '\\'.join(ou_values)
|
||||
|
||||
@app.route('/gpo', methods=['GET'])
|
||||
def get_groups():
|
||||
group_name = request.args.get('group')
|
||||
@@ -37,6 +55,33 @@ def get_groups():
|
||||
})
|
||||
return jsonify(gpos)
|
||||
|
||||
@app.route("/gpo_links", methods=["GET"])
|
||||
def gpo_links():
|
||||
try:
|
||||
gpo_link_count = data[0]['gpo_links']
|
||||
except:
|
||||
gpo_link_count = "whoops"
|
||||
return jsonify({"gpo_links": gpo_link_count})
|
||||
|
||||
@app.route("/timestamp", methods=["GET"])
|
||||
def timestamp():
|
||||
try:
|
||||
yaml_timestamp = data[0]['timestamp']
|
||||
except:
|
||||
yaml_timestamp = "whoops"
|
||||
return jsonify({"timestamp": yaml_timestamp})
|
||||
|
||||
@app.route("/index_duration", methods=["GET"])
|
||||
def index_duration():
|
||||
fmt="%m/%d/%Y %I:%M:%S %p"
|
||||
try:
|
||||
start_timestamp = data[0]['init_timestamp']
|
||||
end_timestamp = data[0]['timestamp']
|
||||
duration = (datetime.strptime(end_timestamp, fmt) - datetime.strptime(start_timestamp, fmt)).total_seconds() / 60
|
||||
return jsonify({"duration": duration, "start_timestamp": start_timestamp, "end_timestamp": end_timestamp})
|
||||
except:
|
||||
return jsonify({'duration': "whoops"})
|
||||
|
||||
@app.route("/linked_ous", methods=["GET"])
|
||||
def linked_ous():
|
||||
gpo_name = request.args.get("gpo")
|
||||
@@ -55,21 +100,28 @@ def linked_ous():
|
||||
if gpo_entry is None:
|
||||
continue
|
||||
|
||||
def _add_ous(ous):
|
||||
if not isinstance(ous, list):
|
||||
return
|
||||
for dn in ous:
|
||||
if isinstance(dn, str):
|
||||
# 1. strip out OU/ DC components
|
||||
# 2. keep the *leaf* and its *parent* (e.g. NA\SJC18)
|
||||
stripped = strip_dn(dn)
|
||||
if stripped:
|
||||
linked.append(stripped)
|
||||
|
||||
# Case 1: direct dict → look for Linked_OUs key
|
||||
if isinstance(gpo_entry, dict):
|
||||
if "Linked_OUs" in gpo_entry:
|
||||
ous = gpo_entry["Linked_OUs"]
|
||||
if isinstance(ous, list):
|
||||
linked.extend(ous)
|
||||
_add_ous(gpo_entry["Linked_OUs"])
|
||||
continue
|
||||
|
||||
# Case 2: list of dicts → find the dict that has the Linked_OUs key
|
||||
if isinstance(gpo_entry, list):
|
||||
for sub in gpo_entry:
|
||||
if isinstance(sub, dict) and "Linked_OUs" in sub:
|
||||
ous = sub["Linked_OUs"]
|
||||
if isinstance(ous, list):
|
||||
linked.extend(ous)
|
||||
_add_ous(sub["Linked_OUs"])
|
||||
|
||||
return jsonify(linked)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user