Code signing practices question

5 views
Skip to first unread message

Mike Leone

unread,
Feb 25, 2026, 11:58:13 AMFeb 25
to NTPowershell Mailing List
(this one's gonna be stupid, get ready ...)

So I'm trying to get us all (me included) into the habit of ONLY running SIGNED scripts, and NOT to change the execution policy to Bypass ...LOL

So here's my question. I've issued myself (well, my privileged account) a personal code signing cert from our internal CA. I know it works, I've tried it ...

Extension OID: 1.3.6.1.4.1.311.21.7
Extension Value (Formatted): Template=PHA_2025_CodeSigning(1.3.6.1.4.1.311.21.8.10369535.12142142.11356553.3523258.15422597.205.14820783.14282570), Major Version Number=100, Minor Version Number=4
---
Extension OID: 2.5.29.37
Extension Value (Formatted): Code Signing (1.3.6.1.5.5.7.3.3)
---
Extension OID: 2.5.29.15
Extension Value (Formatted): Digital Signature (80)
---
Extension OID: 1.3.6.1.4.1.311.21.10
Extension Value (Formatted): [1]Application Certificate Policy:Policy Identifier=Code Signing

SignerCertificate      Status 
-----------------      ------ 
<thumbprint>            Valid

So I'm set for the signing cert, anyway.

So here's my stupid question ... how do you sign/re-sign your scripts?  Workflow wise, I mean.

At the moment, I'm doing all this from my priv access workstation, 

I write the scripts on this workstation.. My local execution policy is set to BYPASS, so I don't have to re-sign every script 900 times for each small change I make when writing/debugging/testing it. 

When I have the script working, what I do is: 
I have a separate script that I use to JUST sign other scripts with; in this, I import my code signing cert above, and use it to sign whatever script I've just finished creating/testiing. Now it's signed.

---------------------------
$SigningCert = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object {$_.Thumbprint -eq "<thumbprint>"}

$FileName = "The-important-Script.PS1"

Set-AuthenticodeSignature -FilePath $FileName  -Certificate $SigningCert
---------------------------

(there's actually a whole bunch more to the signing script, where I check to see if it's already signed, and if so, is it valid (no need to do anything) or used to be signed but has been changed "HashMismatch" and so needs to be signed again, etc)

And I then I go over to the host where this script is supposed to eventually run from (sometimes that's a central script host that runs many diverse scripts, sometimes that's a specific host). And there I set the execution policy to REMOTESIGNED. And either run the newly signed script manually/interactively, or set it as a scheduled task, whatever it needs to be.

Comments so far?

At the moment, when I import my code signing script, I filter it by the specific thumbprint of that code signing script.

$SigningCert = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object {$_.Thumbprint -eq "<thumbprint>"}

That's a bit clunky. Is there a better way to do that? Filter the import, I mean, so it only uses the cert that has the Code Signing entitlement?

I'm sure this workflow, etc can be massively improved. Please, tell me how. This is acceptable, more or less, for just me working. But when you start having 2-3 people who might be writing/running scrripts, then it needs to be more structured and formalized.

Thanks for any insights.
--

Mike. Leone, <mailto:tur...@mike-leone.com>

PGP Fingerprint: 0AA8 DC47 CB63 AE3F C739 6BF9 9AB4 1EF6 5AA5 BCDF
Photo Gallery: <http://www.flickr.com/photos/mikeleonephotos>

Solodow, Damien

unread,
Feb 25, 2026, 12:02:01 PMFeb 25
to ntpowe...@googlegroups.com

$SigningCert = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object {$_.Thumbprint -eq "<thumbprint>"}

 

That's a bit clunky. Is there a better way to do that? Filter the import, I mean, so it only uses the cert that has the Code Signing entitlement?

 

$SigningCert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert

 

It might return multiple results, so you may need to filter based on subject or NotAfter

 

Gaylor Electric logo

Facebook logo

Instagram logo

LinkedIn logo

X logo

YouTube logo

Damien Solodow
IT Senior Systems Engineer
Gaylor Electric, Inc.
10405 Crosspoint Blvd
Indianapolis, IN. 46256
O: 317.815.3103 | M: 317.506.8521

--
You received this message because you are subscribed to the Google Groups "ntpowershell" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ntpowershell...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/ntpowershell/CAHBr%2B%2BiVnoWpXRb%3DGaJG-3onUDphPZxor5PNiUGUE6LtGHg7MQ%40mail.gmail.com.

Wright, John M

unread,
Feb 25, 2026, 12:11:27 PMFeb 25
to ntpowe...@googlegroups.com

FWIW, I set execution policy via GPO, domain-wide, not on individual hosts.

 

Also (and this may not matter at all), when I sign the script, I add a time stamp server parameter.  I’m not even sure why I added that.

 

Set-AuthenticodeSignature -TimestampServer http://timestamp.sectigo.com?td=sha256 -FilePath $PathToScript -Certificate $CodeSignCert

 

--

John Wright

IT Support Specialist

1800 Old Bluegrass Avenue, Louisville, KY 40215

502.708.9953

Please submit IT requests to Hazelwoo...@bluegrass.org

24 Hour Helpline 1.800.928.8000

  

CONFIDENTIALITY NOTICE: This message contains confidential information and is intended only for the individual(s) addressed in the message. If you are not the named addressee, you should not disseminate, distribute, or copy this e-mail. If you are not the intended recipient, you are notified that disclosing, distributing, or copying this e-mail is strictly prohibited.

 

From: ntpowe...@googlegroups.com <ntpowe...@googlegroups.com> On Behalf Of Mike Leone
Sent: Wednesday, February 25, 2026 11:58 AM
To: NTPowershell Mailing List <ntpowe...@googlegroups.com>
Subject: [ntpowershell] Code signing practices question

 

EXTERNAL EMAIL - This email was sent by a person from outside your organization. Exercise caution when clicking links, opening attachments or taking further action, before validating its authenticity.

--

Mike Leone

unread,
Feb 25, 2026, 12:22:35 PMFeb 25
to ntpowe...@googlegroups.com
On Wed, Feb 25, 2026 at 12:02 PM Solodow, Damien <dsol...@gaylor.com> wrote:

$SigningCert = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object {$_.Thumbprint -eq "<thumbprint>"}

 

That's a bit clunky. Is there a better way to do that? Filter the import, I mean, so it only uses the cert that has the Code Signing entitlement?

 

$SigningCert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert

 

It might return multiple results, so you may need to filter based on subject or NotAfter


DUH. I dunno how I missed that ... yeah, I had an older cert, which has expired. Luckily, I can delete that one. But I'll add in some logic to test for validity of the cert ...

Thanks!

 

Mike Leone

unread,
Feb 26, 2026, 12:51:52 PMFeb 26
to ntpowe...@googlegroups.com
So ... my code signing cert needs to be in the "Trusted Publishers" cert store, right? 

I set a VM to be execution policy "RemoteSigned". And then it complained it wouldn't load my profile, because it was unsigned. :-) Ok, fine, I signed the profile. Then I went to run a (signed) script.
And it asked if I wanted to run a script signed by an Untrusted Publisher". I said no, imported my signing cert into the Trusted Publishers, and then it ran.

It's odd, I have a domain wildcard cert (don't judge me) that's already in the Trusted Publisher's store, I would have thought that would cover my code signing cert. But it apparently didn't, not in my case.

So will I need to be pushing my (and any co-workers) code signing certs to all hosts Trusted Publisher's store, before signed scripts will run ?

Wright, John M

unread,
Feb 26, 2026, 2:47:47 PMFeb 26
to ntpowe...@googlegroups.com

AFAIK, yes, you’ll need to push the certificate to the store.  I use a GPO that’s set at computer config>policies>windows settings>security settings>public key policies.  Right-click on the key, import, browse to the cert.

Reply all
Reply to author
Forward
0 new messages