The script signXades.ps1 creates XAdES signatures from Windows PowerShell 5.1: an enveloped signature inside an XML document, or a detached signature (a separate XML file) for a file of any type. It supports the baseline levels XAdES-B-B, B-T, B-LT and B-LTA.

How to run it

powershell -ExecutionPolicy Bypass -File signXades.ps1 test.xml test[signed].xml
powershell -ExecutionPolicy Bypass -File signXades.ps1 invoice.xml -Level XadesLTA -TimestampUrl https://ca.signfiles.com/TSAServer.aspx
powershell -ExecutionPolicy Bypass -File signXades.ps1 contract.pdf -Detached -Commitment ProofOfApproval

Options: -Level (XadesB, XadesT, XadesLT, XadesLTA; T, LT and LTA need -TimestampUrl), -Detached, -Commitment, -City, -Country, -LtvLevel, -HashAlgorithm, and the certificate options -PfxFile, -PfxPassword, -Thumbprint, -SmartCardPin. To add a second signer, sign the signed document again.

The signing code of the script

Initialize-SignLib

if (-not $OutputFile)
{
    if ($Detached)
    {
        $full = Get-FullPath $InputFile
        $OutputFile = Join-Path ([System.IO.Path]::GetDirectoryName($full)) ([System.IO.Path]::GetFileName($full) + '[signature].xml')
    }
    else { $OutputFile = Get-DefaultOutputFile $InputFile }
}

$sign = New-Object SignLib.Xml.XadesSignature (Get-SerialNumber $SerialNumber)
$sign.DigitalSignatureCertificate = Get-SigningCertificate -PfxFile $PfxFile -PfxPassword $PfxPassword -Thumbprint $Thumbprint -LocalMachine:$LocalMachine
$sign.SignatureStandard = [System.Enum]::Parse([SignLib.Xml.XadesSignatureStandard], $Level)
$sign.HashAlgorithm = Get-HashAlgorithm $HashAlgorithm
$sign.LtvLevel = [System.Enum]::Parse([SignLib.Xml.XadesLtvLevel], $LtvLevel)
$sign.CommitmentType = [System.Enum]::Parse([SignLib.Xml.XadesCommitmentType], $Commitment)

if ($Detached) { $sign.SignaturePackaging = [SignLib.Xml.XadesSignaturePackaging]::Detached }
else { $sign.SignaturePackaging = [SignLib.Xml.XadesSignaturePackaging]::Enveloped }

if ($City -or $Country)
{
    $place = New-Object SignLib.Xml.XadesProductionPlace
    if ($City) { $place.City = $City }
    if ($Country) { $place.CountryName = $Country }
    $sign.SignatureProductionPlace = $place
}

if ($TimestampUrl) { $sign.TimeStamping.ServerUrl = [Uri]$TimestampUrl }
if (($Level -ne 'XadesB') -and (-not $TimestampUrl)) { throw "The level $Level needs a time-stamping server (-TimestampUrl)." }

Write-Host "Perform the digital signature ($Level)..."
Set-SmartCardPin $SmartCardPin
$sign.ApplyDigitalSignature((Get-FullPath $InputFile), (Get-FullPath $OutputFile))

Write-Host "Signed file: $OutputFile"

Run the full sample. The script signXades.ps1 is in the folder PowerShell Scripts of the library download, with SignLib.dll, a test certificate and test documents. It runs in Windows PowerShell 5.1. Without a serial number the library runs in demo mode. Download the library and the samples · User manual

Frequently asked questions

How do I verify the XAdES signature from PowerShell?

With verifySignature.ps1 of the same folder; a detached signature also needs -OriginalFile.