add linked GPOs functionality
This commit is contained in:
+82
-27
@@ -1,7 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
# helper function for linked OUs
|
||||||
|
function getLinkedOUs(string $gpo): array|false
|
||||||
|
{
|
||||||
|
$encodedGpo = rawurlencode($gpo);
|
||||||
|
$requestUrl = "http://172.17.0.1:5000/linked_ous?gpo={$encodedGpo}";
|
||||||
|
$ch = curl_init($requestUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
|
$rawResponse = curl_exec($ch);
|
||||||
|
if ($rawResponse === false) {
|
||||||
|
error_log('cURL error [' . curl_errno($ch) . ']: ' . curl_error($ch));
|
||||||
|
curl_close($ch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
if ($httpCode !== 200) {
|
||||||
|
error_log("API returned HTTP {$httpCode} for GPO '{$gpo}'");
|
||||||
|
curl_close($ch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
curl_close($ch);
|
||||||
|
$decoded = json_decode($rawResponse, true);
|
||||||
|
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
error_log('JSON decode error: ' . json_last_error_msg());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $decoded;
|
||||||
|
//return implode("\n", $decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@@ -16,24 +47,20 @@
|
|||||||
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>
|
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>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<?php if (isset($_GET['group'])) : ?>
|
|
||||||
<form action="index.php" method="GET">
|
|
||||||
<label for="group">Group Name:</label>
|
|
||||||
<input type="text" id="group" name="group" value="<?php echo htmlspecialchars($_GET['group']); ?>" required>
|
|
||||||
<button type="submit">Query</button>
|
|
||||||
</form><p>
|
|
||||||
<?php else : ?>
|
|
||||||
<form action="index.php" method="GET">
|
|
||||||
<label for="group">Group Name:</label>
|
|
||||||
<input type="text" id="group" name="group" required>
|
|
||||||
<button type="submit">Query</button>
|
|
||||||
</form><p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
// populating the info div
|
||||||
|
// if the group var is set, show the GPOs with the search term
|
||||||
if (isset($_GET['group'])) {
|
if (isset($_GET['group'])) {
|
||||||
|
echo '
|
||||||
|
<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>
|
||||||
|
</form><p>
|
||||||
|
';
|
||||||
$group = urlencode($_GET['group']);
|
$group = urlencode($_GET['group']);
|
||||||
$url = "http://10.34.115.140:5000/gpo?group=$group";
|
$url = "http://172.17.0.1:5000/gpo?group=$group";
|
||||||
// query API
|
// query API
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
@@ -80,30 +107,58 @@ 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>
|
||||||
echo '<table border="1" cellpadding="4" cellspacing="0">';
|
';
|
||||||
echo '<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));
|
||||||
echo '<tr>';
|
echo ' <tr>
|
||||||
echo "<td>{$gpoName}</td>";
|
';
|
||||||
echo "<td>{$adminGroups}</td>";
|
echo " <td>
|
||||||
echo "<td>{$vncGroups}</td>";
|
<div title='$linkedOUs'>
|
||||||
echo '</tr>';
|
<a href=/?gpo='$gpoName'>{$gpoName}</a>
|
||||||
|
</div></td>
|
||||||
|
";
|
||||||
|
echo " <td>{$adminGroups}</td>
|
||||||
|
";
|
||||||
|
echo " <td>{$vncGroups}</td>
|
||||||
|
";
|
||||||
|
echo ' </tr>
|
||||||
|
';
|
||||||
}
|
}
|
||||||
echo '</table>';
|
echo '</table>
|
||||||
|
';
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
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
|
||||||
|
else if (isset($_GET['gpo'])) {
|
||||||
|
echo 'OUs linked to GPO <b>'.$_GET['gpo'].':</b><p>';
|
||||||
|
$LinkedOUs = getLinkedOUs($_GET['gpo']);
|
||||||
|
echo implode("<br>", $LinkedOUs);
|
||||||
|
echo '<br>Return <a href=/>Home</a>';
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
echo '
|
||||||
|
<form action="index.php" method="GET">
|
||||||
|
<label for="group">Group Name:</label>
|
||||||
|
<input type="text" id="group" name="group" required>
|
||||||
|
<button type="submit">Query</button>
|
||||||
|
</form><p>
|
||||||
|
';
|
||||||
echo "<p>No group specified.</p>";
|
echo "<p>No group specified.</p>";
|
||||||
}
|
}
|
||||||
echo "</div>";
|
echo "</div>";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
Import-Module GroupPolicy -ErrorAction Stop
|
Import-Module GroupPolicy -ErrorAction Stop
|
||||||
Import-Module ActiveDirectory -ErrorAction Stop
|
Import-Module ActiveDirectory -ErrorAction Stop
|
||||||
$TargetOU = "OU=NA,OU=Manufacturing,OU=Tesla Systems,DC=teslamotors,DC=com"
|
$TargetOU = "OU=NA,OU=Manufacturing,OU=Tesla Systems,DC=teslamotors,DC=com"
|
||||||
$OutputFile = "C:\Users\matanderson\gpo.yaml"
|
$OutputFile = "C:\Users\matanderson\gpo\gpo-update.yaml"
|
||||||
# Add-Content -Path $OutputFile -Value $line
|
# Add-Content -Path $OutputFile -Value $line
|
||||||
if (Test-Path $OutputFile) {
|
if (Test-Path $OutputFile) {
|
||||||
Remove-Item -Path $OutputFile -Force
|
Remove-Item -Path $OutputFile -Force
|
||||||
@@ -34,7 +34,6 @@ if ($targetOUObj) {
|
|||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# 2. Build a hashtable: GPO_GUID => list of OU DNs it is linked to
|
# 2. Build a hashtable: GPO_GUID => list of OU DNs it is linked to
|
||||||
# This is entirely opaque voodoo, i have no idea what's going on
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
$gpoLinks = @{}
|
$gpoLinks = @{}
|
||||||
@@ -59,6 +58,8 @@ if (-not $gpoLinks.Count) {
|
|||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Write-Host "Found $($gpoLinks.Count) distinct GPO(s) linked in the OU tree."
|
Write-Host "Found $($gpoLinks.Count) distinct GPO(s) linked in the OU tree."
|
||||||
Add-Content -Path $OutputFile -Value " gpo_links: $($gpoLinks.Count)"
|
Add-Content -Path $OutputFile -Value " gpo_links: $($gpoLinks.Count)"
|
||||||
|
|
||||||
@@ -66,18 +67,28 @@ Add-Content -Path $OutputFile -Value " gpo_links: $($gpoLinks.Count)"
|
|||||||
# 3. For each GPO, get an XML report and pull RestrictedGroup nodes
|
# 3. For each GPO, get an XML report and pull RestrictedGroup nodes
|
||||||
# ----------------------------------------------------
|
# ----------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
Add-Content -Path $OutputFile -Value " configured_gpos:"
|
Add-Content -Path $OutputFile -Value " configured_gpos:"
|
||||||
foreach ($gpoGuid in $gpoLinks.Keys) {
|
foreach ($gpoGuid in $gpoLinks.Keys) {
|
||||||
try {
|
try {
|
||||||
$gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop
|
$gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
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: $($gpo.DisplayName)"
|
||||||
Add-Content -Path $OutputFile -Value " $($gpo.DisplayName):"
|
Add-Content -Path $OutputFile -Value " $($gpo.DisplayName):"
|
||||||
|
|
||||||
|
# -------- Linked OUs ----------
|
||||||
|
$linkedOUs = $gpoLinks[$gpoGuid]
|
||||||
|
Write-Host "Linked OUs:"
|
||||||
|
Add-Content -Path $OutputFile -Value " Linked_OUs:"
|
||||||
|
foreach ($ouDn in $linkedOUs) {
|
||||||
|
Write-Host "$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
|
||||||
@@ -86,9 +97,8 @@ 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')
|
||||||
|
|||||||
@@ -37,6 +37,42 @@ def get_groups():
|
|||||||
})
|
})
|
||||||
return jsonify(gpos)
|
return jsonify(gpos)
|
||||||
|
|
||||||
|
@app.route("/linked_ous", methods=["GET"])
|
||||||
|
def linked_ous():
|
||||||
|
gpo_name = request.args.get("gpo")
|
||||||
|
if not gpo_name:
|
||||||
|
return jsonify({"error": "Missing 'gpo' query parameter"}), 400
|
||||||
|
linked = []
|
||||||
|
# The YAML is a list of dictionaries – iterate over them
|
||||||
|
|
||||||
|
for top in data or []:
|
||||||
|
cfg = top.get("configured_gpos", {})
|
||||||
|
if not isinstance(cfg, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Grab the value for the requested GPO – it can be a dict *or* a list
|
||||||
|
gpo_entry = cfg.get(gpo_name)
|
||||||
|
if gpo_entry is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
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)
|
||||||
|
|
||||||
|
return jsonify(linked)
|
||||||
|
|
||||||
# test route
|
# test route
|
||||||
@app.route('/test', methods=['GET'])
|
@app.route('/test', methods=['GET'])
|
||||||
def test():
|
def test():
|
||||||
|
|||||||
Reference in New Issue
Block a user