Get/Set Signature (CTP2) (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/749"></script>download | new post
VERSION 1.5 for CTP3 — The default cert should be put in the ModuleInfo file.
Description: Wrappers for the Get-AuthenticodeSignature and Set-AuthenticodeSignature which properly parse paths and don’t kill your pipeline and script when you hit a folder by accident…
- #Requires -version 2.0
- ## Authenticode.psm1 updated for CTP 3
- ####################################################################################################
- ## Wrappers for the Get-AuthenticodeSignature and Set-AuthenticodeSignature cmdlets
- ## These properly parse paths, so they don't kill your pipeline and script if you include a folder
- ##
- ## Usage:
- ## ls | Get-AuthenticodeSignature
- ## Get all the signatures
- ##
- ## ls | Select-Signed -Mine -Broken | Set-AuthenticodeSignature
- ## Re-sign anything you signed before that has changed
- ##
- ## ls | Select-Signed -NotMine -ValidOnly | Set-AuthenticodeSignature
- ## Re-sign scripts that are hash-correct but not signed by me or by someone trusted
- ##
- ####################################################################################################
- ## History:
- ## 1.5 - Moved the default certificate setting into the module info Authenticode.psd1 file
- ## Note: If you get this off PoshCode, you'll have to create it yourself, see below:
- ## 1.4 - Moved the default certificate setting into an external psd1 file.
- ## 1.3 - Fixed some bugs in If-Signed and renamed it to Select-Signed
- ## - Added -MineOnly and -NotMineOnly switches to Select-Signed
- ## 1.2 - Added a hack workaround to make it appear as though we can sign and check PSM1 files
- ## It's important to remember that the signatures are NOT checked by PowerShell yet...
- ## 1.1 - Added a filter "If-Signed" that can be used like: ls | If-Signed
- ## - With optional switches: ValidOnly, InvalidOnly, BrokenOnly, TrustedOnly, UnsignedOnly
- ## - commented out the default Certificate which won't work for "you"
- ## 1.0 - first working version, includes wrappers for Get and Set
- ##
- ####################################################################################################
- ## README! README! README! README! #################################################################
- ## README! README! README! README! #################################################################
- ##
- ## You should set the location to your default signing certificate. The permanent way to do that is
- ## to modify (or create) the .psd1 file to set the PrivateData member variable. Otherwise you'll be
- ## prompted to provide a cert path whenever you try to sign a script without passing a certificate.
- ##
- ## The PrivateData variable should point at your code-signing certificate either with a full path
- ## or with the THUMBPRINT of a certificate you have available in your Cert:\CurrentUser\My\ provider
- ##
- ## EG:
- ## F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5
- ## OR:
- ## "Cert:\CurrentUser\My\F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5"
- ## OR a file name:
- ## "C:\Users\Joel\Documents\WindowsPowerShell\PoshCerts\Joel-Bennett_Code-Signing.pfx"
- ##
- ## The simplest thing is to just create a new PSD1
- ##
- ## New-ModuleManifest .\Authenticode.psd1 -Nested .\Authenticode.psm1 `
- ## -Author "" -COmpany "" -Copy "" -Desc "" `
- ## -Types @() -Formats @() -RequiredMod @() -RequiredAs @() -Other @() `
- ## -PrivateData F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5
- ##
- ####################################################################################################
- function Get-UserCertificate {
- [CmdletBinding()]
- PARAM ()
- PROCESS {
- trap {
- Write-Host "The authenticode script module requires configuration to function fully!"
- Write-Host
- Write-Host "You must put the path to your default signing certificate in the module metadata"`
- "file before you can use the module's Set-Authenticode cmdlet or to the 'mine'"`
- "feature of the Select-Signed or Test-Signature. To set it up, you can do this:"
- Write-Host
- Write-Host "PrivateData = 'C:\Users\${Env:UserName}\Documents\WindowsPowerShell\PoshCerts\Code-Signing.pfx'"
- Write-Host
- Write-Host "If you load your certificate into your 'CurrentUser\My' store, or put the .pfx file"`
- "into the folder with the Authenthenticode module script, you can just specify it's"`
- "thumprint or filename, respectively. Otherwise, it should be a full path."
- Write-Error $_
- return
- }
- # Import-LocalizedData -bindingVariable CertificatePath -EA "STOP"
- if(!$ExecutionContext.SessionState.Module.PrivateData) {
- $ExecutionContext.SessionState.Module.PrivateData = $(Read-Host "Please specify a user certificate")
- }
- # Write-Host "CertificatePath: $ExecutionContext.SessionState.Module.PrivateData" -fore cyan
- $ResolvedPath = $Null
- $ResolvedPath = Resolve-Path $ExecutionContext.SessionState.Module.PrivateData -ErrorAction "SilentlyContinue"
- if(!$ResolvedPath -or !(Test-Path $ResolvedPath -ErrorAction "SilentlyContinue")) {
- # Write-Host "ResolvedPath: $ResolvedPath" -fore green
- $ResolvedPath = Resolve-Path (Join-Path $PsScriptRoot $ExecutionContext.SessionState.Module.PrivateData -ErrorAction "SilentlyContinue") -ErrorAction "SilentlyContinue"
- }
- if(!$ResolvedPath -or !(Test-Path $ResolvedPath -ErrorAction "SilentlyContinue")) {
- # Write-Host "ResolvedPath: $ResolvedPath" -fore yellow
- $ResolvedPath = Resolve-Path (Join-Path "Cert:\CurrentUser\My" $ExecutionContext.SessionState.Module.PrivateData -ErrorAction "SilentlyContinue") -ErrorAction "SilentlyContinue"
- }
- $Certificate = get-item $ResolvedPath -ErrorAction "SilentlyContinue"
- if($Certificate -is [System.IO.FileInfo]) {
- $Certificate = Get-PfxCertificate $Certificate -ErrorAction "SilentlyContinue"
- }
- Write-Verbose "Certificate: $($Certificate | Out-String)"
- return $Certificate
- }
- }
- function Test-Signature {
- [CmdletBinding()]
- PARAM (
- [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
- # We can't actually require the type, or we won't be able to check the fake ones
- # [System.Management.Automation.Signature]
- $Signature
- ,
- [Alias("Valid")]
- [Switch]$ForceValid
- )
- return ( $Signature.Status -eq "Valid" -or
- ( !$ForceValid -and
- ($Signature.Status -eq "UnknownError") -and
- ($_.SignerCertificate.Thumbprint -eq $(Get-UserCertificate).Thumbprint)
- ) )
- }
- function Set-AuthenticodeSignature{
- [CmdletBinding()]
- PARAM (
- [Parameter(Position=1, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
- [Alias("FullName")]
- [ValidateScript({
- if((resolve-path $_).Provider.Name -ne "FileSystem") {
- throw "Specified Path is not in the FileSystem: '$_'"
- }
- if(!(Test-Path -PathType Leaf $_)) {
- throw "Specified Path is not a File: '$_'"
- }
- return $true
- })]
- [string]
- $Path
- , ## TODO: you should CHANGE THIS to a method which gets *your* default certificate
- [Parameter(Position=2, Mandatory=$false)]
- $Certificate = $(Get-UserCertificate)
- )
- PROCESS {
- Write-Verbose "Set Authenticode Signature on $Path with $($Certificate | Out-String)"
- Microsoft.PowerShell.Security\Set-AuthenticodeSignature -Certificate $Certificate -FilePath $Path
- }
- }
- New-Alias sign Set-AuthenticodeSignature
- function Get-AuthenticodeSignature {
- [CmdletBinding()]
- PARAM (
- [Parameter(Position=1, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
- [Alias("FullName")]
- [ValidateScript({
- if((resolve-path $_).Provider.Name -ne "FileSystem") {
- throw "Specified Path is not in the FileSystem: '$_'"
- }
- if(!(Test-Path -PathType Leaf $_)) {
- throw "Specified Path is not a File: '$_'"
- }
- return $true
- })]
- [string]
- $Path
- )
- PROCESS {
- Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $Path
- }
- }
- function Select-Signed {
- [CmdletBinding()]
- PARAM (
- [Parameter(Position=1, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
- [Alias("FullName")]
- [ValidateScript({
- if((resolve-path $_).Provider.Name -ne "FileSystem") {
- throw "Specified Path is not in the FileSystem: '$_'"
- }
- return $true
- })]
- [string]
- $Path
- ,
- [Parameter()]
- [switch]$MineOnly
- ,
- [Parameter()]
- [switch]$NotMineOnly
- ,
- [Parameter()]
- [switch]$BrokenOnly
- ,
- [Parameter()]
- [switch]$TrustedOnly
- ,
- [Parameter()]
- [switch]$ValidOnly
- ,
- [Parameter()]
- [switch]$InvalidOnly
- ,
- [Parameter()]
- [switch]$UnsignedOnly
- )
- if(!(Test-Path -PathType Leaf $Path)) {
- # if($ErrorAction -ne "SilentlyContinue") {
- # Write-Error "Specified Path is not a File: '$Path'"
- # }
- } else {
- $sig = Get-AuthenticodeSignature $Path
- # Broken only returns ONLY things which are HashMismatch
- if($BrokenOnly -and $sig.Status -ne "HashMismatch")
- {
- Write-Debug "$($sig.Status) - Not Broken: $Path"
- return
- }
- # Trusted only returns ONLY things which are Valid
- if($TrustedOnly -and $sig.Status -ne "Valid")
- {
- Write-Debug "$($sig.Status) - Not Trusted: $Path"
- return
- }
- # AllValid returns only things that are SIGNED and not HashMismatch
- if($ValidOnly -and (($sig.Status -ne "HashMismatch") -or !$sig.SignerCertificate) )
- {
- Write-Debug "$($sig.Status) - Not Valid: $Path"
- return
- }
- # NOTValid returns only things that are SIGNED and not HashMismatch
- if($InvalidOnly -and ($sig.Status -eq "Valid"))
- {
- Write-Debug "$($sig.Status) - Valid: $Path"
- return
- }
- # Unsigned returns only things that aren't signed
- # NOTE: we don't test using NotSigned, because that's only set for .ps1 or .exe files??
- if($UnsignedOnly -and $sig.SignerCertificate )
- {
- Write-Debug "$($sig.Status) - Signed: $Path"
- return
- }
- # Mine returns only things that were signed by MY CertificateThumbprint
- if($MineOnly -and (!($sig.SignerCertificate) -or ($sig.SignerCertificate.Thumbprint -ne $((Get-UserCertificate).Thumbprint))))
- {
- Write-Debug "Originally signed by someone else, thumbprint: $($sig.SignerCertificate.Thumbprint)"
- Write-Debug "Does not match your default certificate print: $((Get-UserCertificate).Thumbprint)"
- Write-Debug " $Path"
- return
- }
- # NotMine returns only things that were signed by MY CertificateThumbprint
- if($NotMineOnly -and (!($sig.SignerCertificate) -or ($sig.SignerCertificate.Thumbprint -eq $((Get-UserCertificate).Thumbprint))))
- {
- if($sig.SignerCertificate) {
- Write-Debug "Originally signed by you, thumbprint: $($sig.SignerCertificate.Thumbprint)"
- Write-Debug "Matches your default certificate print: $((Get-UserCertificate).Thumbprint)"
- Write-Debug " $Path"
- }
- return
- }
- if(!$BrokenOnly -and !$TrustedOnly -and !$ValidOnly -and !$InvalidOnly -and !$UnsignedOnly -and !($sig.SignerCertificate) )
- {
- Write-Debug "$($sig.Status) - Not Signed: $Path"
- return
- }
- get-childItem $sig.Path
- }
- }
- Export-ModuleMember Set-AuthenticodeSignature, Get-AuthenticodeSignature, Test-Signature, Select-Signed, Get-UserCertificate
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
PowerShell Code Repository