The following is a case study for an automation involving a
web request.
A PowerShell script written to invoke a remote method by
sending a web request works find when executed locally on a PowerShell Terminal
but fails to run the command when the script is part of an automation workflow
aka runbook. The error encountered is “Name or service not known.” even though
the remote method is hosted in an app service. If the app service were denying
the request, a 403 statuscode might have appeared in the error but this is not
the case. The request does not reach the target. The following article explains
how to diagnose this situation.
Before we begin diagnosing the specific cmdlet, it is
important to check that the associated module is imported. This can be done
with `ipmo Microsoft.PowerShell.Utility` directive. It is also necessary to
ensure that the execution policy of the script permits the call. This can be
relaxed with `Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force -Scope
Process` command. Also, the logged in user or identity making the call must
have the necessary permissions to do so or assign the web app contributor role
to the principal.
First, the automation, by its nature, cannot be interactive,
so the parameters must be checked to include an option to progress without
involvement. For example, the $progressPreference = “silentlyContinue” may help
here.
Second, the parameter to debug the call might yield more
information than regular invocation. The ‘-Debug’ parameter, for example, may
indicate that the TLS handshake failed which resulted in the call not going
through. It could also indicate a timeout in getting a response when the
request was valid indicating other reasons why the call could not go through.
When the TLS handshake fails, it might most likely arise
from the certificate validation. A caller making a web request can choose to
skip the validation when the method is to a target that falls under the control
of the owner owning the automation as well as the app service. A PowerShell method to trust all certificates
might be something as simple as:
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srv, X509Certificate
certi,
WebRequest req, int
certificateIssue) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy
= New-Object TrustAllCertsPolicy
A try-catch handler around the request can also indicate not
only the exception but also other modules that might be involved in the request
from the associated stacktrace. For example,
try {
Invoke-RestMethod -Method Get -Uri
APISERVER/api/v1/namespaces/default/pods/ -Headers $headers
}
catch {
$_.Exception | Format-List -Force
}
may indicate the error when it would otherwise be omitted
from the logs.
It is also possible that the target might not be reachable
over the network and this can be diagnosed with:
$DnsCheck = Resolve-DnsName $uri -ErrorAction
SilentlyContinue
Similarly, other parameters to the web-request can also help
here such as –UseBasicParsing to indicate that this is not a web request from a
browser, -Proxy ‘http://w.x.y.z:80’ -ProxyCredential $creds where the
credentials are obtained from $creds = New-AzADSpCredential
-ServicePrincipalName <ServicePrincipalName> and specifying the method
such as with -Method GET.
These are some of the ways in which the web request can be
made to succeed.
No comments:
Post a Comment