What I am trying to do:
Use a .bat file to call a .ps1 file (don't ask) that generates a self-signed certificate and key pair (.pem), then the .bat file will move each .pem to a new directory.
What I have done:
I have the .ps1 file working correctly, it generates both files, but it does require PowerShell to be run as administrator. I have the .bat file calling the .ps1 file when it should. Within the batch file, I am opening PowerShell, which then opens another PowerShell instance as administrator (because there is no way to run PS as admin from the command line, correct me if I'm wrong). Here is the line of code:
PowerShell -Command "& {Start-Process PowerShell -ArgumentList '-NoExit -File ""cert-gen.ps1""' -Verb RunAs}"
What is happening:
When this line is run, I see a PS window pop up and immediately close and it does not generate my cert and key. Since it is closing immediately, I cannot see if there any error within that window, and the command line does show any errors. I am pretty sure I have -NoExit in the correct place.
Bonus:
This needs to be fully automated with no user interaction, so the prompting for UAC elevation is not going to work. I eventually need to figure out a way around this as well, so if there is a solution that fixes all of these problems in one go, that is even better!
The primary problem was that when
powershell.exe, the Windows PowerShell CLI, is invoked with elevation, it invariably usesC:\Windows\System32as the working directory. Thus, it wasn't able to find yourcert-gen.ps1script there.%CD%\cert-gen.ps1ensures that the script is passed by its full path, which solves that problem.%CD%is expanded bycmd.exeup front, to the full path of the current directory.Note that your script must be prepared to handle running with
C:\Windows\System32as the working directory; if needed, it can use the automatic$PSScriptRootvariable to refer to its own directory, for instance.As an aside: It is unfortunate that a CLI session invoked via
-NoExitautomatically closes if the script targeted with-Fileisn't found (when using-Commandwith a failing command, the session stays open); GitHub issue #10471 proposes changing this behavior.The unnecessary
& { ... }enclosure was removed:"& { ... }"in order to invoke code passed to PowerShell's CLI via the-Command(-c) parameter - just use"..."directly. Older versions of the CLI documentation erroneously suggested that& { ... }is required, but this has since been corrected.While
""for escaping embedded"chars. happens to work in this case, it doesn't work robustly, so\"is used instead:pwsh.exe, the PowerShell (Core) 7+,""does work robustly, and is preferable to\", because it avoids edge cases wherecmd.exe's parsing can break a command - see this answer for details.As for the UAC part of the question:
The only secure way to prevent the batch file from triggering a UAC prompt is to run it from an already elevated session - but note that starting such a session itself will trigger a UAC prompt.
If you ensure that your batch file therefore as a whole runs with elevation (which itself could be considered a security risk, if not all operations in it actually require elevation), you can simplify your PowerShell CLI call to (if
-NoExitwas just for troubleshooting, consider removing it):That is, direct invocation is then possible, because child processes launched from an elevated process are elevated too.
Insecure alternatives are discussed in this answer.