Files
disco-ad-compare-plugin/WebHandler/ADCompareWebHandler.cs
T

137 lines
7.3 KiB
C#

using Disco.Plugins.ADCompare.Features;
using Disco.Services.Plugins;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace Disco.Plugins.ADCompare.WebHandler
{
public class ADCompareWebHandler : PluginWebHandler
{
public override ActionResult ExecuteAction(string ActionName)
{
switch (ActionName?.ToLower())
{
case null:
case "":
case "index":
return Index();
case "compare":
return Compare();
case "export":
return ExportCsv();
default:
return new HttpNotFoundResult();
}
}
private ActionResult Index()
{
return new ContentResult
{
Content = BuildDashboardHtml(),
ContentType = "text/html",
ContentEncoding = Encoding.UTF8
};
}
private ActionResult Compare()
{
var service = new DeviceCompareService(Database);
var summary = service.CompareAllDevices();
return new ContentResult
{
Content = JsonConvert.SerializeObject(summary, Formatting.Indented),
ContentType = "application/json",
ContentEncoding = Encoding.UTF8
};
}
private ActionResult ExportCsv()
{
var service = new DeviceCompareService(Database);
var summary = service.CompareAllDevices();
var sb = new StringBuilder();
sb.AppendLine("SerialNumber,ComputerName,DiscoAssignedUser,DiscoAssignedUserName,ADManagedByUser,ADManagedByName,Match,Reason");
foreach (var r in summary.Results.Where(r => !r.IsMatch))
{
sb.AppendLine(string.Join(",",
Csv(r.SerialNumber), Csv(r.ComputerName),
Csv(r.DiscoAssignedUserId), Csv(r.DiscoAssignedUserDisplayName),
Csv(r.ADManagedByUserId), Csv(r.ADManagedByDisplayName),
r.IsMatch.ToString(), Csv(r.MismatchReason)));
}
HostController.Response.Headers.Add("Content-Disposition",
$"attachment; filename=\"AD_ManagedBy_Compare_{DateTime.Now:yyyyMMdd_HHmmss}.csv\"");
return new ContentResult { Content = sb.ToString(), ContentType = "text/csv", ContentEncoding = Encoding.UTF8 };
}
private string Csv(string v) => $"\"{(v ?? "").Replace("\"", "\"\"")}\"";
private string BuildDashboardHtml()
{
var pluginUrl = Url.Action(MVC.API.Disco.Plugin.PluginWebAction(Manifest.Id, null));
return $@"
<div id='adcompare'>
<h2><i class='fa fa-exchange'></i> AD Compare &mdash; Device Managed By</h2>
<p>Compares the AD computer <strong>Managed By</strong> field against the Disco <strong>Assigned User</strong>.</p>
<div style='margin:15px 0;'>
<button id='btnRun' class='btn btn-primary' onclick='runCompare()'><i class='fa fa-refresh'></i> Run Comparison</button>
<button id='btnExport' class='btn btn-default' onclick='location.href=""{pluginUrl}/Export""' style='margin-left:10px;' disabled><i class='fa fa-download'></i> Export Mismatches CSV</button>
<span id='loading' style='display:none;margin-left:15px;'><i class='fa fa-spinner fa-spin'></i> Querying AD for all devices&hellip;</span>
</div>
<div id='summary' style='display:none;margin:15px 0;padding:15px;background:#f5f5f5;border-radius:4px;'>
<div class='row'>
<div class='col-md-2'><strong>Total Devices</strong><br/><span id='sTotal' style='font-size:24px;'>-</span></div>
<div class='col-md-2 text-success'><strong>Matched</strong><br/><span id='sMatch' style='font-size:24px;'>-</span></div>
<div class='col-md-2 text-warning'><strong>Mismatched</strong><br/><span id='sMismatch' style='font-size:24px;'>-</span></div>
<div class='col-md-2 text-danger'><strong>Not in AD</strong><br/><span id='sNotAD' style='font-size:24px;'>-</span></div>
<div class='col-md-2 text-info'><strong>No ManagedBy</strong><br/><span id='sNoMgr' style='font-size:24px;'>-</span></div>
<div class='col-md-2 text-muted'><strong>No Assignment</strong><br/><span id='sNoAssign' style='font-size:24px;'>-</span></div>
</div>
</div>
<div style='margin:10px 0;'>
<label><input type='checkbox' id='chkMismatchOnly' checked onchange='renderTable()'> Show mismatches only</label>
<input type='text' id='txtFilter' placeholder='Filter by serial, computer name, or user...' style='margin-left:15px;padding:4px 8px;width:350px;' oninput='renderTable()'>
</div>
<table id='tbl' class='table table-striped table-condensed' style='display:none;'>
<thead><tr>
<th></th><th>Serial Number</th><th>Computer Name</th>
<th>Disco Assigned User</th><th>AD Managed By</th><th>Reason</th>
</tr></thead>
<tbody id='tbody'></tbody>
</table>
</div>
<script>
var data=[];
function runCompare(){{
$('#loading').show();$('#btnRun').prop('disabled',true);$('#tbl').hide();
$.getJSON('{pluginUrl}/Compare',function(d){{
data=d.Results;
$('#sTotal').text(d.TotalDevices);$('#sMatch').text(d.DevicesMatched);
$('#sMismatch').text(d.DevicesMismatched);$('#sNotAD').text(d.DevicesNotInAD);
$('#sNoMgr').text(d.DevicesNoManagedBy);$('#sNoAssign').text(d.DevicesNoAssignment);
$('#summary').show();$('#btnExport').prop('disabled',false);
renderTable();$('#tbl').show();
}}).fail(function(x){{alert('Error: '+x.statusText);}})
.always(function(){{$('#loading').hide();$('#btnRun').prop('disabled',false);}});
}}
function renderTable(){{
var mo=$('#chkMismatchOnly').is(':checked'),q=$('#txtFilter').val().toLowerCase(),tb=$('#tbody');tb.empty();
data.forEach(function(r){{
if(mo&&r.IsMatch)return;
if(q){{var hay=(r.SerialNumber+' '+r.ComputerName+' '+r.DiscoAssignedUserId+' '+r.ADManagedByUserId+' '+(r.DiscoAssignedUserDisplayName||'')+' '+(r.ADManagedByDisplayName||'')).toLowerCase();if(hay.indexOf(q)<0)return;}}
var icon=r.IsMatch?'<i class=""fa fa-check text-success""></i>':(!r.FoundInAD?'<i class=""fa fa-times text-danger""></i>':'<i class=""fa fa-exclamation-triangle text-warning""></i>');
var discoUser=r.DiscoAssignedUserId?(esc(r.DiscoAssignedUserId)+(r.DiscoAssignedUserDisplayName?'<br/><small class=""text-muted"">'+esc(r.DiscoAssignedUserDisplayName)+'</small>':'')):'<em class=""text-muted"">Not assigned</em>';
var adUser=r.ADManagedByUserId?(esc(r.ADManagedByUserId)+(r.ADManagedByDisplayName?'<br/><small class=""text-muted"">'+esc(r.ADManagedByDisplayName)+'</small>':'')):(r.FoundInAD?'<em class=""text-muted"">Empty</em>':'<em class=""text-muted"">N/A</em>');
tb.append('<tr class=""'+(r.IsMatch?'':'warning')+'"">'+'<td>'+icon+'</td><td>'+esc(r.SerialNumber)+'</td><td>'+esc(r.ComputerName||'')+'</td><td>'+discoUser+'</td><td>'+adUser+'</td><td>'+esc(r.MismatchReason||'')+'</td></tr>');
}});
}}
function esc(t){{if(!t)return'';var d=document.createElement('div');d.appendChild(document.createTextNode(t));return d.innerHTML;}}
</script>";
}
}
}