generated from MrSphay/codex-agent-repository-kit
105 lines
3.3 KiB
PowerShell
105 lines
3.3 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string[]]$Path,
|
|
[string]$PfxPath,
|
|
[string]$CertificateThumbprint,
|
|
[string]$TimestampServer = "http://timestamp.digicert.com",
|
|
[switch]$NoTimestamp,
|
|
[switch]$AllowUntrustedRoot
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Resolve-FullPath {
|
|
param([Parameter(Mandatory)][string]$Path)
|
|
|
|
$executionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
|
|
}
|
|
|
|
function Get-CodeSigningCertificateFromStore {
|
|
param([Parameter(Mandatory)][string]$Thumbprint)
|
|
|
|
$normalizedThumbprint = $Thumbprint -replace "\s", ""
|
|
$certificate = Get-ChildItem "Cert:\CurrentUser\My", "Cert:\LocalMachine\My" |
|
|
Where-Object { $_.Thumbprint -eq $normalizedThumbprint } |
|
|
Select-Object -First 1
|
|
|
|
if (-not $certificate) {
|
|
throw "No code-signing certificate found with thumbprint $Thumbprint."
|
|
}
|
|
|
|
$certificate
|
|
}
|
|
|
|
if (-not $PfxPath -and -not $CertificateThumbprint) {
|
|
throw "Provide either -PfxPath or -CertificateThumbprint."
|
|
}
|
|
|
|
if ($PfxPath -and $CertificateThumbprint) {
|
|
throw "Use either -PfxPath or -CertificateThumbprint, not both."
|
|
}
|
|
|
|
if ($PfxPath) {
|
|
$resolvedPfxPath = Resolve-FullPath $PfxPath
|
|
if (-not (Test-Path -LiteralPath $resolvedPfxPath)) {
|
|
throw "PFX file not found: $resolvedPfxPath"
|
|
}
|
|
|
|
$password = Read-Host "Enter PFX password" -AsSecureString
|
|
$storageFlags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable -bor
|
|
[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
|
|
$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($resolvedPfxPath, $password, $storageFlags)
|
|
}
|
|
else {
|
|
$certificate = Get-CodeSigningCertificateFromStore -Thumbprint $CertificateThumbprint
|
|
}
|
|
|
|
if (-not $certificate.HasPrivateKey) {
|
|
throw "The selected certificate does not include a private key and cannot sign files."
|
|
}
|
|
|
|
$targets = foreach ($item in $Path) {
|
|
$resolvedPath = Resolve-FullPath $item
|
|
if (Test-Path -LiteralPath $resolvedPath -PathType Container) {
|
|
Get-ChildItem -LiteralPath $resolvedPath -Recurse -File |
|
|
Where-Object { $_.Extension -in ".exe", ".msi", ".dll", ".ps1", ".psm1", ".psd1", ".cat" }
|
|
}
|
|
elseif (Test-Path -LiteralPath $resolvedPath -PathType Leaf) {
|
|
Get-Item -LiteralPath $resolvedPath
|
|
}
|
|
else {
|
|
throw "Path not found: $resolvedPath"
|
|
}
|
|
}
|
|
|
|
if (-not $targets) {
|
|
throw "No files found to sign."
|
|
}
|
|
|
|
foreach ($target in $targets) {
|
|
Write-Host "Signing $($target.FullName)"
|
|
$signatureArguments = @{
|
|
FilePath = $target.FullName
|
|
Certificate = $certificate
|
|
HashAlgorithm = "SHA256"
|
|
}
|
|
|
|
if (-not $NoTimestamp -and $TimestampServer) {
|
|
$signatureArguments.TimestampServer = $TimestampServer
|
|
}
|
|
|
|
$signature = Set-AuthenticodeSignature @signatureArguments
|
|
|
|
if ($signature.Status -eq "UnknownError" -and $AllowUntrustedRoot -and $signature.SignerCertificate) {
|
|
Write-Warning "Signed $($target.FullName), but the local machine does not trust the signing root yet."
|
|
continue
|
|
}
|
|
|
|
if ($signature.Status -ne "Valid") {
|
|
throw "Signing failed for $($target.FullName): $($signature.StatusMessage)"
|
|
}
|
|
}
|
|
|
|
Write-Host "Signed $($targets.Count) file(s)."
|