Search code examples
c#powershellrestsharp

Powershell not invoking method in a c# object


I have a bunch of libraries in C# that are written by me and are supposed to be used by PowerShell scripts to perform various devops tasks in our environment. The strangest thing is happening and I think it has something to do with external loading of libraries in my PowerShell script.

Working example

First of all, I will demonstrate the workings of the general code and one class like this so you can understand how I work with it: We start by loading the external libraries for my API

$binpath = "$PSScriptRoot\bin"
#Reads credentials
Add-Type -Path "$binpath\CredentialHandling.dll"
#Is used for logging
Add-Type -Path "$binpath\OperationLogging.dll"
#Is used to handle the different dev environments (we have a lot of them!)
Add-Type -Path "$binpath\IdmEnvironmentHandling.dll"
#Is used to perform operations in LDAP
Add-Type -Path "$binpath\IdmLdapInteractions.dll"
#Is used to perform operations with a specific REST API service
#The base library that contains general methods and binds it all together
Add-Type -Path "$binpath\IdmApi.dll"

I set up my objects that should call on the constructors in the C# code, and proceed to perform a method on one of the connectors

#The IdmApiOperator contains multiple connectors to different platforms to perform unified tasks
$idm = [IdmApi.IdmApiOperator]::new($environment)
$searchbase = 'ou=OrganizationalUnit,o=SYSTEM'
$ldapFilter = '(cn=CommonNameExample)'
#This will return some sort of ldap search response, which works
$search = $idm.LdapOperator.Search($searchbase, ldapFilter)

The Ldap operator in the context of this code uses the standard .NET library System.DirectoryServices.Protocols, it works like a charm and all the actual code is working in C# and in PowerShell.

Members of IdmApiConnector (the base class for the operator, which is kind of like an interface) Members of IdmApiConnector (the base class for the operator, which is kind of like an interface)

The example that won't work

We start by loading the external libraries for my API, this time including one used for a REST API, this call on the RestOperator class will fail and I do not understand why

$binpath = "$PSScriptRoot\bin"
#Reads credentials
Add-Type -Path "$binpath\CredentialHandling.dll"
#Is used for logging
Add-Type -Path "$binpath\OperationLogging.dll"
#Is used to handle the different dev environments (we have a lot of them!)
Add-Type -Path "$binpath\IdmEnvironmentHandling.dll"
#Is used to perform operations in LDAP
Add-Type -Path "$binpath\IdmLdapInteractions.dll"
#Is used to perform operations with a specific REST API service
Add-Type -Path "$binpath\IdmRestInteractions.dll"
#Used by IdmRestInteractions, put in here just to be safe
Add-Type -Path "$binpath\RestSharp.dll"
#The base library that contains general methods and binds it all together
Add-Type -Path "$binpath\IdmApi.dll"

$idm = [IdmApi.IdmApiOperator]::new($environment)
#Purely a test, this method will return an Oauth token for the specified connection, this method is a derivative of the actual method that will set a token property in the base class.
$token = $idm.RestOperator.GetToken()
#Will return null, not even an error is thrown

Code for the GetToken() method, which returns an IdmToken, defined in the same namespace under IdmRestInteractions.Objects:

public IdmToken GetToken()
        {
            string path = MethodPaths["OAuthUri"];
            RestRequest request = new RestRequest()
            {
                Method = Method.POST,
                Resource = path,
            };
            string authstring = GetOAuthString();
            request.AddHeader("Authorization", authstring);
            string body = ""//here it creates the body, removed in this version
            request.AddParameter("application/x-www-form-urlencoded", body, ParameterType.RequestBody);
            IRestResponse response = Client.Post(request); //Client here being an IRestClient object from the library RestSharp
            return JsonConvert.DeserializeObject<IdmToken>(response.Content);
        }

Looking at the tomcat host, the method does not seem to go through or something, as the server does not receive any requests. Changing the output of the method to giberish will make it return giberish, so it's not that the method is not triggered. I've also tried adding Newtonsoft.Json to my PowerShell code, that did not change anything either. Then of course when I use the token later on in my programs it will give a nullref exception...

To summarize

  • I use libraries I wrote myself in .dll format in PowerShell scripts.
  • One works, one does not, the issue does not lie in the usage or implementation of the libraries
  • The Rest Api connector uses an external library, RestSharp (that might be the cause?)
  • The method gets triggered, but does not perform an API request to the service
  • Most importantly, the code does work natively in C#, it's not like i'm not authenticated

Solution

  • I've had a quick look at the docs and this answer. The client will not throw exceptions by default. Content will just be empty and your method will silently fail and return null. Possible solutions include checking the ErrorException property or setting ThrowOnAnyError:

    # option 1
    Client.ThrowOnAnyError = true;
    
    # option 2
    if (response.ErrorException != null)
    {
        throw new Exception("Request failed.", response.ErrorException);
    }