Powershell: Using Arguments/Parameters won't work

Hi,

I’m trying to use a powershell post-request script to deploy it to my router.
The script is using parameters like that:

Param(
    [Parameter(Mandatory=$true)]
    [string] $Cert,
    
    [Parameter(Mandatory=$true)]
    [string] $RouterUrl
)

This is then normally called like this:

psscript.ps1 -Cert <path_to_cert> -RouterUrl <url_path>
Now when I’m trying to call that script with a network user (same used for exporting to file share) it won’t work and I’ll get different errors:

  1. Using impersonation type “Network”:

2021-07-15 00:22:32.029 +02:00 [ERR] Error: Fehler beim Erstellen der Pipeline

  1. Using other impersonation types:

2021-07-15 00:22:06.763 +02:00 [ERR] Error: Es wurde kein Parameter gefunden, der dem Parameternamen “Cert “<path_to_cert>” -RouterUrl “””

Interestingly the first dash (-) is also missing.

The script is working on its own with the specific user.

What am I doing wrong here?

Regards
nightmare1942

By default the first parameter passed to the script is a result object with details of the managed certificate. Is your script a wrapper for another script?

Well, I thought the first parameter will only be passed to the script when the checkbox at “Pass Result as First Arg” is checked? Is this not correct?

image

The script is no wrapper.
Inside the script everything is handled what needs to be done.

Looking into this further I can see the Args feature is rarely used and is not well documented, thanks for raising this issue.

You can see if you clear your arguments out of the box that the expected form is not the PowerShell syntax, instead its:
arg1=value;arg2=value;arg3=value;

Note that there is no variable substitution here so there is no way for you to dynamically specify a path to the certificate etc. There are then translated into powershell arguments.

If you want to be able to refer to any information about the managed certificate (certificate path, thumbprint etc) your Powershell scripts must take $result as the first parameter.

Examples are shown here: https://docs.certifytheweb.com/docs/script-hooks

If you didn’t want to change your script you could use a wrapper script designed for Certify (with the param($result)) which then calls your other script with the arguments you need.

So if I understand you correctly the standard named parameter syntax of powershell is not used here.
Rather it’s just the args.
So I need to either rewrite my PowerShell script so it’s accepting args and can be called like:

script.ps1 arg1 arg2 arg3

With this I could use it inside then as arg[i].
e.g. as described here

Or I just use a wrapper script to call the actual one?
Is this what you mean?

Is $result variable also accessible after the renewing of the cert was ok but the deployment task failed?
Or can I access the $result variable afterwards?

Sorry yes I mean just use a wrapper script to call your actual script. Like:

param($result)

C:\Scripts\psscript.ps1 -Cert $result.ManagedItem.CertificatePath -RouterUrl <value>

The arguments are passed programmatically to the powershell script as named arguments (like -Option Value -OtherOption OtherValue) but there is no actual command line, so it’s not quite the same as invoking it manually from a powershell command line.

$result is always available if a request has been attempted previously, it would only be empty if the managed certificate has never been requested before. You can use the following example script to output the current values held in $result to a file so you can see how it works: https://docs.certifytheweb.com/docs/script-hooks#example-output-the-result-properties-to-a-text-file

Okay, I created a wrapper which is calling the actual script.

I tried it with passing the $result var and without but it doesn’t work.

Which impersonation type do I need to use for that?
Network → Pipeline errors
All other → looks like access errors

Maybe also some background:
The servers are hardened and won’t allow anyone to call or execute scripts.
The user in the “Credentials” section has these rights (so these scripts work when calling the wrapper via powershell as this user).
But they seem to fail when Certify is calling it.

How have you hardened the servers? Have you just configured a default execution policy or something else?

You can override the default execution policy the app tries to use: https://docs.certifytheweb.com/docs/script-hooks#troubleshooting

What does your script actually do? Please share as much detail of the exact script as possible. If it spawns new processes it may not work as expected because impersonation is working in-process.

The next release will have an option to execute scripts as a new process (so instead of using a powershell runspace we literally execute powershell.exe). This helps a lot with scripts which required extended impersonation that spans multiple processes.

Hardening:

  • real strict access permissions
  • supervised folder access
  • execution policy set to remotesigned
  • Core Isolation
  • couple more

The script is calling another .exe and another script.

As said, trying only with powershell.exe as the calling user it work as expected.
Credentials are piped through.

It seems I have to wait for the next release.
Is there any time horizont on when that will be?

Yes we’re trying to get the next version out this week, could be next week though. Calling an exe will definitely spawn a new process so yes that could be a problem for credential impersonation.

Okay, that sound great.
If you could ping me somehow it would be much appreciated.

1 Like

Would you be interesting in trying a beta version? You’d need to use it on a test server, we’re still doing testing so it’s not final.

Here it is if you want to try it out on a desktop or test machine: https://certifytheweb.s3.us-east-1.amazonaws.com/downloads/test/CertifyTheWebSetup_5.5.0-beta1.zip

In the PowerShell task parameters you need to check “Launch New Process”

Thank you.
Unfortunately I only have 1 router which is the productive one.
So in this case I might not be able to test it really, but can check fo PS execution.

1 Like

Thanks, I’d also recommend checking out DNS validation (instead of http validation) as this also allows you to generate certificates independently of the server being http accessible (such as in QA/QC environments).

Okay, today I tested the Beta1 and found a bug:

When I try to just use the wrapper script (as a test) without any arguments I cannot save the task because it says, that it cant find the script.
image

The user I’m configuring with doesn’t have access to this network path but the one used in “Credentials”. This is working in the stable version.

Thanks, I’ll investigate if there has been a regression there but thinking about it the validation has never run under the impersonated credentials, so it would always have failed. We should make that a warning instead of an error for exactly this case.

Keep in mind that the background service won’t have network drive mappings, so you’ll need to use UNC paths.

Okay, I think a warning would be the best option!

Yes, I only use UNC paths (that’s why they are blurried :wink: )

v5.5.1 is out now, the file check has been disabled - the edge cases of permissions checks during impersonation are a little complex!

I updaded the app and tried it but still error:

2021-07-22 20:47:12.344 +02:00 [INF] ---- Performing Task [On-Demand or Manual Execution] :: Install Cert to Router ----
2021-07-22 20:47:12.346 +02:00 [INF] Task [Install Cert to Router] :: Task is being has been forced to run. Normal status would be [Task is enabled but will not run because primary request unsuccessful.]
2021-07-22 20:47:12.346 +02:00 [INF] Executing command via PowerShell
2021-07-22 20:47:12.352 +02:00 [ERR] Launching Process C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe as User: <domain>\<user>
Error Running Script: System.ComponentModel.Win32Exception (0x80004005): Zugriff verweigert
   bei System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
   bei Certify.Management.PowerShellManager.ExecutePowershellAsProcess(CertificateRequestResult result, String executionPolicy, String scriptFile, Dictionary`2 parameters, Dictionary`2 credentials, String scriptContent, PowerShell shell, Boolean autoConvertBoolean, String[] ignoredCommandExceptions, Int32 timeoutMinutes) in D:\a\certify-service\certify-service\src\certify-build\certify\src\Certify.Shared.Compat\PowerShellManager.cs:Zeile 270.
Error: System.InvalidOperationException: Diesem Objekt ist kein Prozess zugeordnet.
   bei System.Diagnostics.Process.EnsureState(State state)
   bei System.Diagnostics.Process.get_HasExited()
   bei Certify.Management.PowerShellManager.ExecutePowershellAsProcess(CertificateRequestResult result, String executionPolicy, String scriptFile, Dictionary`2 parameters, Dictionary`2 credentials, String scriptContent, PowerShell shell, Boolean autoConvertBoolean, String[] ignoredCommandExceptions, Int32 timeoutMinutes) in D:\a\certify-service\certify-service\src\certify-build\certify\src\Certify.Shared.Compat\PowerShellManager.cs:Zeile 283.

This error I get.
I do not know where the access error occurs but what I can say is the path given

D:\a\certify-service\certify-service\src\certify-build\certify\src\Certify.Shared.Compat\PowerShellManager.cs

Does and can not exist (no drive D!).

Maybe an error inside the script?