3

I'm trying to better understand Add-Type in PowerShell after running into an issue of trying to do a REST API call and avoiding a self-signed cert issue. Code is as follows.

add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;

    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("InternalApiKey", "d472f0e9-23c9-4fff-aec9-cc1f2d5d6a85")

$response = Invoke-RestMethod 'https://localhost:9443/api/GetStats/' -Method 'GET' -Headers $headers
$response | ConvertTo-Json

When I run this it breaks with the error.

"New-Object: Cannot find type [TrustAllCertsPolicy]: verify that the assembly containing this type is loaded." And then, because that failed I get the error, "Invoke-RestMethod: The remote certificate is invalid because of errors in the certificate chain: PartialChain"

Just stumbled upon the fact it works as expected in PowerShell 5.1.22000.282 and does not in PowerShell 7.2.1. What changes can I make to make it work in both version of PowerShell?

Update: this link has some code to get it running in both versions of PowerShell. I accepted the answer I did because it was the most helpful and because I'm sharing this other answer. https://github.com/PowerShell/PowerShell/issues/7092

BuddyJoe
  • 69,735
  • 114
  • 291
  • 466

1 Answers1

6

In PowerShell 7.x, the web cmdlets have a -SkipCertificateCheck switch you can use instead:

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("InternalApiKey", "d472f0e9-23c9-4fff-aec9-cc1f2d5d6a85")

$response = Invoke-RestMethod 'https://localhost:9443/api/GetStats/' -SkipCertificateCheck -Method 'GET' -Headers $headers

If the endpoint is already sending JSON, you might as well use Invoke-WebRequest instead (rather than letting Invoke-RestMethod convert from JSON to objects and then back again with ConvertTo-Json):

$response = Invoke-WebRequest 'https://localhost:9443/api/GetStats/' -SkipCertificateCheck -Method 'GET' -Headers $headers
$response.Content # this now contains the body of the raw response from the API, eg. JSON/XML/whatever
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • thank you for this great info. Great to know that switch exists. I'd really like to better understand Add-Type and maybe how it has changed in Powershell 7.x ... Is there a way to get this working so it would be compatible with 7 and 5 using the Add-Type? – BuddyJoe Jan 26 '22 at 15:42
  • I stumbled upon this - https://github.com/PowerShell/PowerShell/issues/7092 - guess I should have copied C# over to Core project and tried it out. Seems like a lot of effort. guess I'm going to make this thing 7.x only. Thanks again. – BuddyJoe Jan 26 '22 at 15:53
  • @BuddyJoe Happy to hear it helps! FWIW It's not a problem with `Add-Type` per se, the problem is that the whole `ServicePointManager` API which governs these settings for .NET Framework has been completely re-designed for .NET Core – Mathias R. Jessen Jan 26 '22 at 15:59