Public/Set-FileSignature.ps1

function Set-FileSignature {
<#
.SYNOPSIS
    Sets Authenticode signature on PowerShell files.
 
.DESCRIPTION
    Signs files using a code signing certificate from the CurrentUser certificate store.
    Automatically selects the valid certificate with the longest time before expiration
    and determines the appropriate timestamp server based on the certificate issuer
    (Digicert or Sectigo).
 
.PARAMETER MyCert
    Code signing certificate to use. If not specified, automatically selects the valid
    codesign certificate with the longest time before expiration from the CurrentUser store.
 
.PARAMETER TimeStampServer
    URL of the timestamp server. If not specified, automatically determined based on the
    certificate issuer (Digicert or Sectigo).
 
.PARAMETER Path
    Path(s) to the file(s) to sign. Accepts pipeline input and the FullName property
    from Get-ChildItem output.
 
.INPUTS
    System.String[] - File paths to sign (via pipeline or parameter).
 
.OUTPUTS
    System.Management.Automation.Signature - The signature result for each file.
 
.EXAMPLE
    Set-FileSignature -Path .\MyScript.ps1
    Signs a single file using the auto-detected certificate.
 
.EXAMPLE
    Get-ChildItem .\Modules\*.psm1 | Set-FileSignature
    Signs all .psm1 files in the Modules directory via pipeline.
 
.EXAMPLE
    Set-FileSignature -Path .\MyScript.ps1 -TimeStampServer 'http://timestamp.digicert.com'
    Signs a file using an explicitly specified timestamp server.
#>

  [CmdletBinding()]
  param (
    [Parameter()]
    $MyCert = (Get-ChildItem cert:\currentuser\my -CodesigningCert |
        Where-Object { ($_.NotAfter -gt (Get-Date) ) -and ($_.HasPrivateKey -eq $true) }
      | Sort-Object -Descending NotAfter | Select-Object -First 1),

    [Parameter()]
    [String]$TimeStampServer = '',

    [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
    [Alias('FullName')]
    [String[]]
    $Path
  )

  begin {
    if ($null -eq $MyCert) {
      throw 'No valid codesign certificate found'
    }
    Write-Verbose $($MyCert.Issuer)

    if ($TimeStampServer -eq '') {
      Write-Verbose "have a CN? $($MyCert.Issuer.StartsWith('CN'))"
      if ($MyCert.Issuer.StartsWith('CN=Digicert')) {
        Write-Verbose 'Digicert cert found'
        $TimeStampServer = 'http://timestamp.digicert.com'
      } elseif ($MyCert.Issuer.StartsWith('CN=Sect') ) {
        Write-Verbose 'Sectigo cert found'
        $TimeStampServer = 'http://timestamp.sectigo.com'
      } else {
        Write-Verbose "Issuer: $($MyCert.Issuer)"
        Write-Verbose "Digicert? $($MyCert.Issuer.StartsWith('CN=Digicert'))"
        Write-Verbose "Sectigo? $($MyCert.Issuer.StartsWith('CN=Sect'))"
        throw 'No Timestamp server could be set, aborting.'
      }
    } else {
      Write-Verbose "Timestamp server entered $($TimeStampServer)"
    }
    Write-Verbose "Mycert: $($MyCert)"
    Write-Verbose "Timestamp server: $($TimeStampServer)"
  }

  process {
    foreach ($file in $Path) {
      Write-Verbose "Signing: $file"
      Set-AuthenticodeSignature -FilePath $file -TimestampServer $TimeStampServer -Certificate $MyCert
    }
  }
}