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)
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'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);
}