none
Casting Returned objects from PowerShell with C# RRS feed

  • Question

  • Good afternoon.

    We are attempting to pull AD changes for a given time span and writing the updates into a database.  The original code uses very old C# code (pre version 3) and takes hours to complete.  I have been provided with a PoweShell script that pulls the changes in about a minute

    $dte = [datetime]'{0}'
    Get-ADObject -Filter {((WhenChanged -gt $dte) -or (WhenCreated -gt $dte)) -and (ObjectClass -eq 'User' -and ObjectCategory -eq 'Person') } | Group-Object objectclass -eq 'user' -properties
    Get-ADObject -Filter {((WhenChanged -gt $dte) -or (WhenCreated -gt $dte)) -and (ObjectClass -eq 'Group') } | Group-Object objectclass

    Get-ADObject -Filter {((WhenChanged -gt $dte) -or (WhenCreated -gt $dte)) -and ((ObjectCategory -eq 'publicfolder') -or (ObjectCategory -eq 'contact')) } | Group-Object objectclass
    Get-ADObject -Filter {(WhenCreated -gt $dte) -and ((ObjectCategory -eq 'publicfolder') -or (ObjectCategory -eq 'contact')) } | Group-Object objectclass

    I am calling the script via C# code 

     

    System.IO.StreamReader reader = new System.IO.StreamReader(System.IO.File.OpenRead(@"D:\Prototypes\ConsoleADPowershell\ConsoleADPowershell\Script.ps1"));
    string script = reader.ReadToEnd();
    script.Replace("{0}", "05/18/2018");

    PowerShell _powerShell;
    _powerShell = PowerShell.Create().AddScript(script);

    Collection<PSObject> resultsList = _powerShell.Invoke();

                if(resultsList !=null)
                {                 resultsList.ToList().ForEach(delegate (PSObject item)
                    {

                        if(item.Properties["Group"].Value != null)
                        {
                            ICollection<PSObject> groupResults = (ICollection<PSObject>)item.Properties["Group"].Value;

                            IEnumerator<PSObject> e = groupResults.GetEnumerator();

                            PSObject p;

                            while(e.MoveNext())
                            {
                                p = e.Current;

                                MyData data = new MyData();

                                data.DistinguishedName = p.Properties["DistinguishedName"].Value.ToString();
                                data.Name = p.Properties["Name"].Value.ToString();
                                data.ObjectClass = p.Properties["ObjectClass"].Value.ToString();
                                data.ObjectGUID = p.Properties["ObjectGUID"].Value.ToString();

                                data.PropertyCount = int.Parse(p.Properties["PropertyCount"].Value.ToString());

                                //Add Properties
                                if (p.Properties["AddProperties"].Value != null)
                                {

                                    var x = p.Properties["AddProperties"].Value;}   

    I cannot seem to pull the "AddProperties" value and get a {"Unable to cast object of type 'Microsoft.ActiveDirectory.Management.ADPropertyValueCollection' to type 'System.Collections.Generic.ICollection`1[System.String]'."} System.InvalidCastException

    when I try.  I cannot seem to find the Microsoft.ActiveDirectory.Management dll to import into VS2017.  I feel that i must be doing either something very wrong on the hardest way possible.  I am not sure why the libraries which seem to be known to the runtime (as seen through the quickwatch) are inaccessable to me at runtime.  Any help would be appreciated.  Thank you.

                                                                   
    Wednesday, May 23, 2018 6:07 PM

All replies

  • var x = p.Properties["AddProperties"].Value;}   

    I cannot seem to pull the "AddProperties" value and get a {"Unable to cast object of type 'Microsoft.ActiveDirectory.Management.ADPropertyValueCollection' to type 'System.Collections.Generic.ICollection`1[System.String]'."}
    System.InvalidCastException

    You must not be showing all the code, becuase a var used in the above statement is not going to cause a casting error. You must be trying to add 'x' as/is to a generic.ICollection and the cast cannot be made. You can't tell one object that it's going to be different object and that's what is happening that is causing the exception.

    Wednesday, May 23, 2018 6:50 PM
  • That is true.  The code was set up like this

     ICollection<string> addPropertiesCollection = (ICollection<string>)p.Properties["AddProperties"].Value;

    based on the fact the quickwatch window stated that the AddProperties is of a type System.Collections.Generic.IColliection(string).  However if I let it run I get the exception stating that it cannot casta Microsoft.ActiveDirectory.Management.ADPropertyValueCollection to a System.collections.Generic.ICollection(string)

    In short what I see and what the error states seem to be different.  So if I could find a way to import the Microsoft.ActiveDirectory.Management.dll and get access to the object type I might be fine but I can't seem to find documentation on how to add it in VS.  Of course generally when there isn't any instructions online anywhere, you are doing it wrong so I am open to other suggestions.  Thank you.

    Essentially.  How can I reference Microsoft.ActiveDirectory.Management.ADPropertyValueCollection in visual Studio
    • Edited by Cheesebread Wednesday, May 23, 2018 7:59 PM
    Wednesday, May 23, 2018 7:01 PM
  • The adding of a DLL is not going to correct the problem. You don't understand the error message.

    A class is the blueprint for an object instance. 

    ICollection<string> addPropertiesCollection = (ICollection<string>)p.Properties["AddProperties"].Value;

    Microsoft.ActiveDirectory.Management.ADPropertyValueCollection' to type

    It is a type that was defined by its class.

    'System.Collections.Generic.ICollection`1[System.String]'."}
    System.InvalidCastException

    And the above is a type defined by its class.

    They are two different classes or two different blueprints. You can't tell one object based on its class that it's going to be a different object based on its class, becuase classes have different properties and methods/behaviors.

    And besides,  .NET is not going to allow you to cast objects across two different named namespaces, even if it is a string object you are working with on both sides. Yes, there is the String class for string data. 

    https://msdn.microsoft.com/en-us/library/system.string%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    Microsoft.ActiveDirectory.Management.ADPropertyValueCollection

    You have to use Quickwatch and look inside the object to see what needs to be extracted out of it, make it a string value, and then manually add to it the System.Collections.Generic.ICollection defined as a collection using that is defined as primitive type string.

    Wednesday, May 23, 2018 7:58 PM