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_name: "gpo_api"
|
||||||
api_service_folder: "{{ project_folder }}/api"
|
api_service_folder: "{{ project_folder }}/api"
|
||||||
api_service_port: "5000"
|
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"
|
dashboard_web_root: "{{ project_folder }}/dashboard"
|
||||||
container_name: "GPO-Dashboard"
|
container_name: "GPO-Dashboard"
|
||||||
|
|||||||
+55
-28
@@ -29,8 +29,11 @@ function getLinkedOUs(string $gpo): array|false
|
|||||||
//return implode("\n", $decoded);
|
//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>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -42,9 +45,13 @@ function getLinkedOUs(string $gpo): array|false
|
|||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>Query GPOs by Group</h2>
|
<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>
|
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>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
@@ -56,8 +63,9 @@ if (isset($_GET['group'])) {
|
|||||||
<form action="index.php" method="GET">
|
<form action="index.php" method="GET">
|
||||||
<label for="group">Group Name:</label>
|
<label for="group">Group Name:</label>
|
||||||
<input type="text" id="group" name="group" value="'.htmlspecialchars($_GET['group']).'" required>
|
<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>
|
</form><p>
|
||||||
|
Return <a href=/>Home</a><br>
|
||||||
';
|
';
|
||||||
$group = urlencode($_GET['group']);
|
$group = urlencode($_GET['group']);
|
||||||
$url = "http://172.17.0.1:5000/gpo?group=$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);
|
ksort($gpoMap, SORT_STRING | SORT_FLAG_CASE);
|
||||||
if($numResults > 0){
|
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) {
|
foreach ($gpoMap as $gpoName => $cols) {
|
||||||
// Remove duplicates and build comma‑separated lists
|
// Remove duplicates and build comma‑separated lists
|
||||||
$adminGroups = implode('<br>', array_unique($cols['administrators']));
|
$adminGroups = implode('<br>', array_unique($cols['administrators']));
|
||||||
$vncGroups = implode('<br>', array_unique($cols['vnc_admin']));
|
$vncGroups = implode('<br>', array_unique($cols['vnc_admin']));
|
||||||
$linkedOUs = implode("\n", getLinkedOUs($gpoName));
|
$linkedOUs = implode("\n", getLinkedOUs($gpoName));
|
||||||
echo ' <tr>
|
echo "
|
||||||
';
|
<tr>
|
||||||
echo " <td>
|
<td>
|
||||||
<div title='$linkedOUs'>
|
<div title='$linkedOUs'>
|
||||||
<a href=/?gpo='$gpoName'>{$gpoName}</a>
|
<a href=/?gpo=$gpoName>{$gpoName}</a>
|
||||||
</div></td>
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$adminGroups}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$vncGroups}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
";
|
";
|
||||||
echo " <td>{$adminGroups}</td>
|
|
||||||
";
|
|
||||||
echo " <td>{$vncGroups}</td>
|
|
||||||
";
|
|
||||||
echo ' </tr>
|
|
||||||
';
|
|
||||||
}
|
}
|
||||||
echo '</table>
|
echo '</table>
|
||||||
';
|
';
|
||||||
@@ -140,17 +160,20 @@ if (isset($_GET['group'])) {
|
|||||||
echo 'No results found for query <b>'.$_GET['group'].'</b>.<p>';
|
echo 'No results found for query <b>'.$_GET['group'].'</b>.<p>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if you click on a GPO name, print all OUs
|
// if you click on a GPO name, print all OUs
|
||||||
else if (isset($_GET['gpo'])) {
|
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']);
|
$LinkedOUs = getLinkedOUs($_GET['gpo']);
|
||||||
echo implode("<br>", $LinkedOUs);
|
foreach ($LinkedOUs as $OU){
|
||||||
echo '<br>Return <a href=/>Home</a>';
|
echo "<li>".$OU."</li>";
|
||||||
|
}
|
||||||
|
#echo implode("<li>", $LinkedOUs);
|
||||||
|
echo '</ul><p>Return <a href=/>Home</a>';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
echo '
|
echo '
|
||||||
<form action="index.php" method="GET">
|
<form action="index.php" method="GET">
|
||||||
@@ -158,10 +181,14 @@ else {
|
|||||||
<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><p>
|
</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>";
|
//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 */
|
color: #bdc3c7; /* Dimmer text color */
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
color: #bdc3c7; /* Dimmer text color */
|
color: #bdc3c7; /* Dimmer text color */
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ if (Test-Path $OutputFile) {
|
|||||||
Write-Output "Enumerating OUs under '$TargetOU' ..."
|
Write-Output "Enumerating OUs under '$TargetOU' ..."
|
||||||
Add-Content -Path $OutputFile -Value "---"
|
Add-Content -Path $OutputFile -Value "---"
|
||||||
Add-Content -Path $OutputFile -Value "- root_ou: $TargetOU"
|
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 `
|
$ouObjects = Get-ADObject `
|
||||||
-Filter 'ObjectClass -eq "organizationalUnit"' `
|
-Filter 'ObjectClass -eq "organizationalUnit"' `
|
||||||
-SearchBase $TargetOU `
|
-SearchBase $TargetOU `
|
||||||
@@ -69,7 +71,10 @@ Add-Content -Path $OutputFile -Value " gpo_links: $($gpoLinks.Count)"
|
|||||||
|
|
||||||
|
|
||||||
Add-Content -Path $OutputFile -Value " configured_gpos:"
|
Add-Content -Path $OutputFile -Value " configured_gpos:"
|
||||||
|
$ou_counter = 0
|
||||||
foreach ($gpoGuid in $gpoLinks.Keys) {
|
foreach ($gpoGuid in $gpoLinks.Keys) {
|
||||||
|
$ou_counter++
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop
|
$gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop
|
||||||
}
|
}
|
||||||
@@ -77,18 +82,19 @@ foreach ($gpoGuid in $gpoLinks.Keys) {
|
|||||||
Write-Warning "Unable to retrieve GPO $gpoGuid – skipping."
|
Write-Warning "Unable to retrieve GPO $gpoGuid – skipping."
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
Write-Host "GPO: $($gpo.DisplayName)"
|
Write-Host "GPO $ou_counter of $($gpoLinks.Count): $($gpo.DisplayName)"
|
||||||
Add-Content -Path $OutputFile -Value " $($gpo.DisplayName):"
|
Add-Content -Path $OutputFile -Value " $($gpo.DisplayName):"
|
||||||
|
# ok, i need to start generating a variable with all links in it
|
||||||
|
|
||||||
|
|
||||||
# -------- Linked OUs ----------
|
# -------- Linked OUs ----------
|
||||||
$linkedOUs = $gpoLinks[$gpoGuid]
|
$linkedOUs = $gpoLinks[$gpoGuid] # <-- the list we built earlier
|
||||||
Write-Host "Linked OUs:"
|
Add-Content -Path $OutputFile -Value " - Linked_OUs:"
|
||||||
Add-Content -Path $OutputFile -Value " Linked_OUs:"
|
|
||||||
foreach ($ouDn in $linkedOUs) {
|
foreach ($ouDn in $linkedOUs) {
|
||||||
Write-Host "$ouDn"
|
|
||||||
Add-Content -Path $OutputFile -Value " - $ouDn"
|
Add-Content -Path $OutputFile -Value " - $ouDn"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Pull the XML report
|
# Pull the XML report
|
||||||
try {
|
try {
|
||||||
$xmlString = Get-GPOReport -Guid $gpoGuid -ReportType Xml -ErrorAction Stop
|
$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)."
|
Write-Warning "Unable to generate XML report for $($gpo.DisplayName)."
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
$xml = [xml]$xmlString
|
$xml = [xml]$xmlString
|
||||||
# process the XML data
|
|
||||||
$ns = New-Object System.Xml.XmlNamespaceManager ($xml.NameTable)
|
$ns = New-Object System.Xml.XmlNamespaceManager ($xml.NameTable)
|
||||||
$ns.AddNamespace('m', 'http://www.microsoft.com/GroupPolicy/Settings') # default namespace
|
$ns.AddNamespace('m', 'http://www.microsoft.com/GroupPolicy/Settings') # default namespace
|
||||||
$ns.AddNamespace('q1', 'http://www.microsoft.com/GroupPolicy/Settings/Security')
|
$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
|
$adGroupName = ($rg.SelectSingleNode('q1:GroupName/t:Name', $ns)).InnerText
|
||||||
$localGroupName = ($rg.SelectSingleNode('q1:Memberof/t:Name', $ns)).InnerText
|
$localGroupName = ($rg.SelectSingleNode('q1:Memberof/t:Name', $ns)).InnerText
|
||||||
$plainAD_Groupname = ($adGroupName -split '\\')[-1]
|
$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 " - ad_group: $plainAD_Groupname"
|
||||||
Add-Content -Path $OutputFile -Value " local_group: $localGroupName"
|
Add-Content -Path $OutputFile -Value " local_group: $localGroupName"
|
||||||
}
|
}
|
||||||
Add-Content -Path $OutputFile -Value ""
|
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 "..."
|
Add-Content -Path $OutputFile -Value "..."
|
||||||
|
|||||||
+58
-6
@@ -1,5 +1,6 @@
|
|||||||
import yaml
|
import yaml
|
||||||
import re
|
import re
|
||||||
|
from datetime import datetime
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -8,6 +9,23 @@ app = Flask(__name__)
|
|||||||
with open('{{ gpo_yaml_path }}', 'r') as file:
|
with open('{{ gpo_yaml_path }}', 'r') as file:
|
||||||
data = yaml.safe_load(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'])
|
@app.route('/gpo', methods=['GET'])
|
||||||
def get_groups():
|
def get_groups():
|
||||||
group_name = request.args.get('group')
|
group_name = request.args.get('group')
|
||||||
@@ -37,6 +55,33 @@ def get_groups():
|
|||||||
})
|
})
|
||||||
return jsonify(gpos)
|
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"])
|
@app.route("/linked_ous", methods=["GET"])
|
||||||
def linked_ous():
|
def linked_ous():
|
||||||
gpo_name = request.args.get("gpo")
|
gpo_name = request.args.get("gpo")
|
||||||
@@ -55,21 +100,28 @@ def linked_ous():
|
|||||||
if gpo_entry is None:
|
if gpo_entry is None:
|
||||||
continue
|
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
|
# Case 1: direct dict → look for Linked_OUs key
|
||||||
if isinstance(gpo_entry, dict):
|
if isinstance(gpo_entry, dict):
|
||||||
if "Linked_OUs" in gpo_entry:
|
if "Linked_OUs" in gpo_entry:
|
||||||
ous = gpo_entry["Linked_OUs"]
|
_add_ous(gpo_entry["Linked_OUs"])
|
||||||
if isinstance(ous, list):
|
|
||||||
linked.extend(ous)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Case 2: list of dicts → find the dict that has the Linked_OUs key
|
# Case 2: list of dicts → find the dict that has the Linked_OUs key
|
||||||
if isinstance(gpo_entry, list):
|
if isinstance(gpo_entry, list):
|
||||||
for sub in gpo_entry:
|
for sub in gpo_entry:
|
||||||
if isinstance(sub, dict) and "Linked_OUs" in sub:
|
if isinstance(sub, dict) and "Linked_OUs" in sub:
|
||||||
ous = sub["Linked_OUs"]
|
_add_ous(sub["Linked_OUs"])
|
||||||
if isinstance(ous, list):
|
|
||||||
linked.extend(ous)
|
|
||||||
|
|
||||||
return jsonify(linked)
|
return jsonify(linked)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user