Using hooks in windows

Please fill out the fields below so we can help you better. Note: you must provide your domain name to get help. Domain names for issued certificates are all made public in Certificate Transparency logs (e.g. crt.sh | example.com), so withholding your domain name here does not increase secrecy, but only makes it harder for us to provide help.

My domain is: drdoppler.no-ip.biz

I ran this command:
"C:\Program Files\Certbot\bin\certbot.exe" --standalone renew --post-hook 'd:\batch\test.ps1' -v --dry-run
with various quote combinations around d:\batch\test.ps1

It produced this output:
it created the certificate great and it makes my site happy. My problem is I want to schedule the renewal and automate the post cerbot activities using post-hook or post-deploy, Either way I get this error, I have tried many combinations of things and no cigar. I am not a python person,


2023-10-08 19:21:15,783:INFO:certbot.compat.misc:Running post-hook command: d:\batch\test.ps1
2023-10-08 19:21:15,783:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
File "runpy.py", line 197, in _run_module_as_main
File "runpy.py", line 87, in run_code
File "C:\Program Files\Certbot\bin\certbot.exe_main
.py", line 29, in
sys.exit(main())
File "C:\Program Files\Certbot\pkgs\certbot\main.py", line 19, in main
return internal_main.main(cli_args)
File "C:\Program Files\Certbot\pkgs\certbot_internal\main.py", line 1864, in main
return config.func(config, plugins)
File "C:\Program Files\Certbot\pkgs\certbot_internal\main.py", line 1638, in renew
hooks.run_saved_post_hooks()
File "C:\Program Files\Certbot\pkgs\certbot_internal\hooks.py", line 155, in run_saved_post_hooks
_run_hook("post-hook", cmd)
File "C:\Program Files\Certbot\pkgs\certbot_internal\hooks.py", line 240, in _run_hook
returncode, err, out = misc.execute_command_status(
File "C:\Program Files\Certbot\pkgs\certbot\compat\misc.py", line 163, in execute_command_status
proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
File "subprocess.py", line 505, in run
File "subprocess.py", line 951, in init
File "subprocess.py", line 1420, in _execute_child
OSError: [WinError 193] %1 is not a valid Win32 application
2023-10-08 19:21:15,783:ERROR:certbot._internal.log:An unexpected error occurred:
2023-10-08 19:21:15,783:ERROR:certbot._internal.log:OSError: [WinError 193] %1 is not a valid Win32 application``


This is the contents of test.ps1
Write-Host 'Hello, World!'
'Hello, World!' | Write-Host
Write-Output "Press any keyto continue ..."
$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null

My web server is (include version): Netcam studio

The operating system my web server runs on is (include version):

OS Name Microsoft Windows 11 Pro
Version 10.0.22621 Build 22621

My hosting provider, if applicable, is:

I can login to a root shell on my machine (yes or no, or I don't know): admin in windows yes

I'm using a control panel to manage my site (no, or provide the name and version of the control panel): no

The version of my client is (e.g. output of certbot --version or certbot-auto --version if you're using Certbot): certbot 2.6.0

First, I'm guessing you want to use --deploy-hook instead. The --post-hook runs after every time Certbot runs. --deploy-hook only when the cert actually updates.

As to your problem, the hook must be a Windows executable. That is, something you could run directly at a native Windows command prompt.

You are naming a powershell script which can only be run by powershell. You could try something like "powershell d:\batch\test.ps1" as your hook executable.

Also, you won't be able to rely on interacting with a script if it runs in the background as a scheduled task. So, no ReadKey stuff in the actual hook.

Lastly, ...

Shoud be certonly instead of renew

Once you get a cert, Certbot makes a renewal config file for you which remembers these settings. You then just run certbot renew to renew

2 Likes

No #! on Windows? Really?

1 Like

Powershell scripts are not executables (unlike .bat etc) because they are not tied to a single system interpreter. Users can use their own version of the powershell interpreter etc. #! is a convenience mechanism specific to unix/linux etc, using direct file header inspection, because it doesn't have file extension associations to launch default interpreters (at the command line, it does in the various GUIs).

[Note that you could launch the default interpreter for a file using start, e.g. start C:\scripts\example.ps1]

3 Likes

It uses magic bytes. (Which could also work on Windows -- not sure if it's implemented)

Also, stuff doesn't run if you don't set the executable bit. You can do sh somefile, but to do ./somefile you need chmod +x -- shebang or no shebang.

2 Likes

Thanks, I'm veering off-topic, but "magic bytes" are the first few bytes of the file, e.g. "direct file header inspection". As background, I don't use Linux and Unix for many web server tasks, but I do use them, I've variously used Solaris, AIX, Irix, BSD, macOS/Darwin, Linux (lots of flavors since about 1997). Windows actually has really good integration with Linux via WSL.

2 Likes

Thank you all for the help.

I agree that --deploy-hook is the right answer.

The python code that runs the script from misc.py lines 162-164 and is

line = ['powershell.exe', '-Command', shell_cmd]
proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, check=False, env=env)

Thus it assumes powershell all ready. I think I am running a command

powershell.exe -command shell_command

and I need to write shell-command to give something like this

powershell.exe -command & {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File ""d:\batch\test.ps1""' -Verb RunAs}

which, I think, means that I need something like

--post-hook "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File ""d:\batch\test.ps1""' -Verb RunAs}"

I got this idea from

https://www.howtogeek.com/204088/how-to-use-a-batch-file-to-make-powershell-scripts-easier-to-run/

When I do that I get this in the log file

2023-10-09 10:15:59,383:INFO:certbot.compat.misc:Running post-hook command: & {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File d:\batch\test.ps1' -Verb RunAs}
2023-10-09 10:15:59,384:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
File "runpy.py", line 197, in _run_module_as_main
File "runpy.py", line 87, in run_code
File "C:\Program Files\Certbot\bin\certbot.exe_main
.py", line 29, in
sys.exit(main())
File "C:\Program Files\Certbot\pkgs\certbot\main.py", line 19, in main
return internal_main.main(cli_args)
File "C:\Program Files\Certbot\pkgs\certbot_internal\main.py", line 1864, in main
return config.func(config, plugins)
File "C:\Program Files\Certbot\pkgs\certbot_internal\main.py", line 1638, in renew
hooks.run_saved_post_hooks()
File "C:\Program Files\Certbot\pkgs\certbot_internal\hooks.py", line 155, in run_saved_post_hooks
_run_hook("post-hook", cmd)
File "C:\Program Files\Certbot\pkgs\certbot_internal\hooks.py", line 240, in _run_hook
returncode, err, out = misc.execute_command_status(
File "C:\Program Files\Certbot\pkgs\certbot\compat\misc.py", line 163, in execute_command_status
proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
File "subprocess.py", line 505, in run
File "subprocess.py", line 951, in init
File "subprocess.py", line 1420, in _execute_child
OSError: [WinError 193] %1 is not a valid Win32 application
2023-10-09 10:15:59,393:ERROR:certbot._internal.log:An unexpected error occurred:
2023-10-09 10:15:59,393:ERROR:certbot._internal.log:OSError: [WinError 193] %1 is not a valid Win32 application

note that the quotes are being stripped away to my command. How do I add them? I'm going to work on other things for awhile. I have trouble walking away from crap like this.

Kent

1 Like

You might find it easier to use some other client that's more native to Windows. Certbot certainly works fine, but is just a direct port from the Linux version and requires integrations with it to "think" in a Linux-style way. (Which can be helpful, like when integrating with software like Apache on Windows.) But you might want something more like win-acme, Posh-ACME, or Certify the Web. Look at the Windows section of the client list.

3 Likes

Can't you call a .cmd file that contains the call to "powershell ..."?

1 Like

not without changing certbot's code.

Here is the code from misc.py

if POSIX_MODE:
proc = subprocess.run(shell_cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True,
check=False, env=env)
else:
line = ['powershell.exe', '-Command', shell_cmd]
proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, check=False, env=env)

Windows is not POSIX therefor we don't have that option because powershell -command is already there.

Kent

Is this thread useful at all? It seems to cover this case. Ignore the title, look at the post I linked to through the end of the thread which has comments from Certbot dev.

In any case, at this level of detail you'd probably be better off posting on the github for Certbot. We certainly see it a lot here but the devs are more easily found on the github

2 Likes

Hi Mike

So far no. I was hoping that somebody who was into python and powershell would answer. So far, no. I'll check our Github. I usually eventually figure this stuff out. I have trouble leaving it along. When I do, I'll tell you the trick. I know its easy. That is the trouble with coding, when you figure it out, its always easy.

Thank you

Kent

1 Like

I don't want Certbot on my Windows system but in general I have run nested powershell scripts. You can just run cmd.exe from a powershell script to start something else.

Like: cmd.exe /c start /wait notepad

I don't know why you can't start powershell instead of notepad, for example. Or a .bat instead of notepad or whatever

I think that is largely what that github thread says and gives simpler examples

2 Likes

Mike-

Somewhere along the line, things got changed, for better or worse, I don't know. subprocess.call is no longer used and subprocess,run is. This is in the misc.py file. There is one version for POSIX systems (Linux) and another for non-POSIX systems (Windows) thus there are 2 different ways of doing this. How smart this is, I have no idea, but code is code. Here it is.

if POSIX_MODE:
proc = subprocess.run(shell_cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True,
check=False, env=env)
else:
line = ['powershell.exe', '-Command', shell_cmd]
proc = subprocess.run(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, check=False, env=env)

So if you are using Linux, you have more freedom than if you are using windows. Linux users can do as is described in the github description, Windows user are stuck with powershell -comand and adding something after it.

I am tempted to modify misc.py to fix this, but then I'm running none supported code and I don't want to go into that business. I may do that tomorrow to see if I can get more understanding of how this works for learning reasons. It would be nice to talk to whomever wrote this code. They had a reason for doing what they did and I hope they knew more about what they were doing than I do. It shouldn't be hard.

Kent

1 Like

As an aside, you can do this using Certify The Web https://certifytheweb.com (which I develop) using a Deployment Task: Deployment Tasks | Certify The Web Docs it can run powershell tasks etc (including basic impersonation/network credential etc).

Presumably you're specifically using certbot so you can get pem encoded cert files easily, in Certify The Web that would be a Deploy to Generic Server task, then set the output file paths for the components you want under Task Parameters. You can ask for further help over at https://community.certifytheweb.com/

If your main aim is automation of some larger process it's also worth looking at Posh-ACME, which is all powershell.

If you can provide the wider context for what you are trying to achieve we may be able to guide you in the right direction.

3 Likes

That thread was exactly for Windows.

Try the below from a native Windows command prompt. Not a powershell command prompt, native Windows.

powershell -command cmd /c start /wait "powershell testhook.ps1"

Where testhook.ps1 is only:

write-host "I am running"
start-sleep -s 5

On my system, testhook.ps1 starts just fine, displays its message, sleeps, then exits. The Windows command prompt waited for it to exit (due to start /wait). This is pretty standard Windows stuff.

It shouldn't be hard to imagine other things you can do after powershell -command rather than above.

That said, I agree with @webprofusion and @petercooperjr that if you want something better designed for Windows there are better ACME clients. Peter already provided the link of suggestions.

3 Likes

And I fourth the motion.

3 Likes

Ha, well it still depends exactly what @Kent1 is really trying to achieve.

3 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.