Signing PowerShell Scripts and Modules with a Hardware Token

Nov 2, 2026 · Tutorials · 3 views

You will learn how to configure a Windows environment to sign PowerShell scripts and script modules (.psm1) using a hardware security token, and how to automate that signing process for local development and CI/CD pipelines using OneSigner.

Understanding the Hardware Requirement and Execution Policies

Since the CA/Browser Forum updated its baseline requirements, both Extended Validation (EV) and Organization Validation (OV) code-signing certificates must reside on certified hardware. This means your private key cannot sit as an exported file on a disk; it must remain inside certified hardware, such as a USB token (YubiKey, SafeNet, ePass2003) or a hardware security module.

PowerShell enforces script execution security through execution policies. To run signed scripts in your enterprise or local environment without disabling security controls, you typically set the policy to AllSigned or RemoteSigned:

Set-ExecutionPolicy AllSigned -Scope CurrentUser

When the execution policy is set to AllSigned, PowerShell refuses to run any script unless it bears a valid digital signature from a trusted publisher stored in your local certificate store. If you attempt to execute an unsigned or improperly signed script, PowerShell halts execution and throws a security error.

Preparing Your OneSigner Environment and Hardware Token

Because the private key lives on physical hardware, OneSigner must run on a Windows machine that stays powered on with your USB token plugged into a USB port. If your workflow requires unattended builds on ephemeral cloud runners that lack physical USB ports, you should evaluate whether a hosted cloud service suits your infrastructure better. For on-premises build agents, dedicated developer workstations, or local deployment servers, the OneSigner Windows service and GUI manage the cryptographic operations seamlessly.

First, install OneSigner on your designated Windows signing machine and ensure your hardware token (such as a YubiKey FIPS or SafeNet eToken) is inserted. Open the OneSigner configuration app and map your code-signing certificate to a certificate name in the Azure Key Vault proxy settings (the Cert Name (-kvc) field). OneSigner exposes a REST API and an Azure Key Vault-compatible endpoint, and ships OneSignTool, a command-line client that sends signing requests from your build agents to that endpoint and refers to the certificate by that name.

To verify that your build agent can communicate with the local OneSigner instance, run a quick connectivity test in PowerShell to check the REST API availability:

Invoke-RestMethod -Uri "http://your-onesigner-host:9440/api/signing/status" -Headers @{ Authorization = "Bearer YOUR_ADMIN_TOKEN" }

A successful response returns the status of the signing engine, confirming that your local agent is ready to process signing requests.

Signing PowerShell Scripts Locally Using PowerShell Commands

Before integrating signing into an automated build pipeline, you should test the signing process manually on a target script. Windows provides the native cmdlet Set-AuthenticodeSignature, which interacts with certificates installed in the Windows certificate store or accessed via cryptographic service providers linked to your hardware token.

Locate the thumbprint of your code-signing certificate by inspecting your personal certificate store:

Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert

Copy the resulting thumbprint string. You will pass this thumbprint, along with a timestamp server URL, into the signing command. Timestamping ensures that your script remains valid even after the code-signing certificate eventually expires, because the timestamp authority cryptographically proves the code was signed while the certificate was still active.

Execute the following command to sign your target script named Deploy-Application.ps1:

$cert = Get-ChildItem Cert:\CurrentUser\My\YOUR_CERTIFICATE_THUMBPRINT_HERE
Set-AuthenticodeSignature -FilePath "C:\Scripts\Deploy-Application.ps1" -Certificate $cert -TimestampServer "http://timestamp.digicert.com"

Inspect the output object returned in the console. Verify that the Status property reads Valid and that the SignerCertificate matches your token's certificate details. You can view the embedded signature block at the bottom of your script file in a text editor to confirm the block was appended correctly.

Automating Script and Module Signing in CI/CD Pipelines

When scaling your release pipeline, manual execution is insufficient. For teams building modules packaged as .psm1 files or automation scripts deployed via CI/CD, you can use OneSignTool, which accepts the same core flags as AzureSignTool, allowing your build scripts to request cryptographic signatures from the physical token attached to your OneSigner host machine.

For detailed guidance on structuring automated pipelines without relying on cloud-based hardware security modules, review Automate Code Signing in CI/CD Without Cloud HSM. By routing requests through the local proxy, your build agent executes a standardized command line during the packaging phase.

Here is an example build script snippet that signs all PowerShell module files in a release directory prior to publishing:

$moduleFiles = Get-ChildItem -Path "C:\BuildArtifacts" -Filter "*.psm1" -Recurse
foreach ($file in $moduleFiles) {
    Write-Host "Signing $($file.FullName)..."
    OneSignTool sign -kvu https://signing.example.com -kva $env:SIGNING_TOKEN -kvc your-certificate-name `
      -fd sha256 -tr http://timestamp.sectigo.com -td sha256 $file.FullName
    if ($LASTEXITCODE -ne 0) { throw "Signing failed: $($file.FullName)" }
}

Keep the signing token in your CI system's secret store. If OneSigner rejects the file type, add .ps1 and .psm1 to the File Extensions field of your code-signing profile.

If you manage multiple signing operations or require high-throughput execution across different projects, consult Six Ways to Sign With One OneSigner Machine for other ways to route signing requests to the same token.

Troubleshooting Common Signing Failures

When automating script signing with hardware tokens, several common failure modes can interrupt your build pipeline. Addressing them proactively saves hours of debugging.

  • Token Disconnection or Sleep Mode: If the Windows machine enters a low-power state or the USB token loses connection, the cryptographic provider throws an error indicating the token cannot be found. Ensure your host machine's USB power-saving settings are disabled in the Windows Device Manager.
  • PIN Prompt Blocks: Hardware tokens often require a PIN to authorize signing operations. If your token requires interactive PIN entry on every session and your CI/CD runner runs unattended under a service account, the process will hang. When signing through OneSigner, save the token PIN in the signing profile so the service supplies it without a prompt; for manual signing with Set-AuthenticodeSignature, run it in an interactive session where you can enter the PIN.
  • Untrusted Root Authority: If a target machine fails to validate a freshly signed script, verify that the issuing CA's intermediate and root certificates are installed in the Local Computer's Intermediate Certification Authorities and Trusted Root Certification Authorities stores.

Next Steps

To evaluate OneSigner on your own infrastructure with your hardware token, download the software or start your evaluation at the OneSigner Trial Portal.

Related Posts