0

I am building an application that interacts with Active Directory using System.Management.Automation (Not using Directory Services because currently new to that library and learning it). To update the group membership of for a group in the active directory I am creating a JSON object on my view and invoking a function to pass the object & the URI from front end to back end via a function in my controller.

The basic idea is to allow removal of AD group members in bulk by passing the JSON object as a parameter to the shell script which will be executed in an instance of PowerShell created in the function. I am using .ajax call to invoke the controller function and passing the JSON object that I generated as an argument along with the current URI. The shell.commands.AddParameter() function accepts argument in only string format. So, I typecasted it with ToString() and converting it to JSON in the PowerShell script. I am passing the URL from code behind as the URL is subject to change. I am not getting any errors However, I am also not able to see any update in membership in the AD. Json Object is getting generated from HTML Table.

My shell script

param($objMemberUpdate, $uri)
$body = $objMemberUpdate | ConvertTo-JSON
Invoke-WebRequest -Uri $uri -Method Post -Body $objMemberUpdate

My Controller Function to Invoke PowerShell Instance and executing Shell Script file from specified location.

private string UpdateMemberList(JsonResult objMemberUpdate)
    {
        var uri = HttpContext.Request.Url.AbsoluteUri;
        var shell = PowerShell.Create();
        shell.Commands.AddCommand(AppDomain.CurrentDomain.BaseDirectory + "Shell\\Set-ADGroupMembership.ps1").AddParameter(objMemberUpdate.ToString(), uri);
        var results = shell.Invoke();
        shell.Dispose();
        return results.ToString();
    }

The Ajax Call that I am calling on a button click on my HTML page.

//Make Array Object to pass in the API For Membership Update
    $("#btnUpdate").click(function () {
        var RemoveMembers = [];
        var RemoveAfter = [];
        var MemberUpdate = {};
        var GroupGUID = "";
        $("table [id*=ddlReqdAdjustment]").each(function () {
            if ($(this).val() != "Keep") {
                GroupGUID = $(this).parent().parent().children().eq(4)[0].innerText;
                var date = $(this).parent().parent().children().eq(8)[0].firstElementChild.value;
                var ObjectGUID = $(this).parent().parent().children().eq(3)[0].innerText + "@@" + $('#ddlDirectory').val();

                if ($(this).val() == "Remove") {
                    var format = ObjectGUID;
                    RemoveMembers.push(format);
                } else {
                    var format = date + "|" + ObjectGUID;
                    RemoveAfter.push(format);
                }
            }
        });
        MemberUpdate = {
            "Directory": $('#ddlDirectory').val(),
            "Group": GroupGUID,
            "Remove": RemoveMembers,
            "RemoveAfter": RemoveAfter,
            "ResultFormat": "json",
            "OnBehalfOf": "11112201"            
        };
        console.log(MemberUpdate);
        $.ajax({
            type: "POST",
            url: "/Group/UpdateMemberList",
            data: { objMemberUpdate: MemberUpdate },
            success: function (response) {
                alert(response.message);
            }
        });

The selected member in the table is supposed to get removed from the Group whose GroupGUID (ObjectGUID attribute in AD) is mentioned from the AD. However, no compile time or no runtime error is encountered and nit even any changes are reflected and I think this must be due to problem with my JSON Object?

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84

1 Answers1

0

The first problem is here:

private string UpdateMemberList(JsonResult objMemberUpdate)

The JsonResult class is designed to be used in a response (returned from a controller action), not as a parameter.

Instead, create your own class with the properties you need, and use that. Something like this:

public class MemberUpdate {
    public string Directory { get; set; }
    public Guid Group { get; set; }
    public List<string> Remove { get; set; }
    public List<string> RemoveAfter { get; set; }
    public string ResultFormat { get; set; }
    public string OnBehalfOf { get; set; }
}

And your action definition will then be like this:

public string UpdateMemberList(MemberUpdate objMemberUpdate)

ASP.NET will deserialize the JSON sent from the browser into an instance of your class automatically.

That said, I want to address something you said:

using System.Management.Automation (Not using Directory Services because currently new to that library and learning it)

Regardless of how you implement this, you will have to learn something. You may as well learn the better way :)

Calling PowerShell from C# is awful. I've done it several times, and it always gives me a headache. It means more prerequisites (you need the AD module installed), more things to break, and just slower performance (since you're communicating with a separate powershell.exe process).

There are lots of examples online about how to add and remove members from groups in C#, like here - both the code in the question itself (using System.DirectoryServices), and the code in the accepted answer (using System.DirectoryServices.AccountManagement) will work. But using System.DirectoryServices directly, while a little more complicated, always performs faster than System.DirectoryServices.AccountManagement. (I talked about why in an article I wrote).

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Yes for Sure Gabriel thanks for the response, also the another issue I found was I used private for the function which is why it was not being invoked and when I made it public I got the parse error as follow : System.Management.Automation.ParseException HResult=0x80131501 Message=System error. Source= StackTrace: –  Jul 02 '19 at 19:19
  • Yes, that's true. Making your action private will make it just do nothing - I didn't catch that (but it's happened to me before). – Gabriel Luci Jul 02 '19 at 19:23
  • 1
    The exception you're getting now is the reason I recommend you don't call PowerShell from C# :) – Gabriel Luci Jul 02 '19 at 19:24
  • So, I realize the reason behind this happening is because my JSON Object is giving null values but the ajax call is already passing the values to the argument. https://imgur.com/LDdbjTW this is what I am getting. –  Jul 02 '19 at 19:57
  • Oh I think that's because of this in your JavaScript: `data: { objMemberUpdate: MemberUpdate }`. Change that to just `data: MemberUpdate` – Gabriel Luci Jul 02 '19 at 23:17