Private/Get-DigitalSignature.ps1

Function Get-DigitalSignature {
    <#
        .SYNOPSIS
            Get digital signatures from files in a target folder.
        
        .DESCRIPTION
            Gets digital signatures from .exe and .dll files from a specified path and sub-folders.
            Retreives the certificate thumbprint, certificate name, certificate expiry, certificate validity and file path and outputs the results.
            Output includes files that are not signed.

        .NOTES
            Author: Aaron Parker
            Twitter: @stealthpuppy
        
        .LINK
            https://github.com/Insentra/ApplicationControl

        .OUTPUTS
            [System.Array]

        .PARAMETER Path
            A target path in which to scan files for digital signatures.

        .PARAMETER Include
            Gets only the specified items.

        .PARAMETER Unique
            By default the script will return all files and their certificate details. Use -Unique to return the first listing for each unique certificate.

        .EXAMPLE
            Get-AcDigitalSignatures -Path "C:\Users\aaron\AppData\Local\GitHubDesktop"

            Description:
            Scans the folder specified in the Path variable and returns the digital signatures for each file.

        .EXAMPLE
            Get-DigitalSignatures -Path "C:\Users\aaron\AppData\Local\GitHubDesktop" -Unique

            Description:
            Scans the folder specified in the Path variable and returns the digital signatures for only the first file with a unique certificate.
    #>

    [CmdletBinding(SupportsShouldProcess = $False)]
    [OutputType([Array])]
    Param (
        [Parameter(Mandatory = $False, Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True, `
                HelpMessage = 'Specify a target path in which to scan files for digital signatures.')]
        [Alias('FullName', 'PSPath')]
        [System.String[]] $Path,

        [Parameter(Mandatory = $False, Position = 1, ValueFromPipeline = $False, `
                HelpMessage = 'Gets only the specified items.')]
        [Alias('Filter')]
        [System.String[]] $Include = @('*.exe', '*.dll', '*.ocx', '*.msi', '*.ps1', '*.vbs', '*.js'),

        [Parameter(ParameterSetName = 'Base', Mandatory = $False)]
        [System.Management.Automation.SwitchParameter] $Unique
    )
    Begin {        
        # Initialise $Signatures as an array
        $Signatures = @()
    }
    Process {
        # For each path in $Path, check that the path exists
        ForEach ($Loc in $Path) {
            If (Test-Path -Path $Loc -IsValid -ErrorAction "SilentlyContinue") {

                # Get the item to determine whether it's a file or folder
                If ((Get-Item -Path $Loc -Force).PSIsContainer) {

                    # Target is a folder, so trawl the folder for .exe and .dll files in the target and sub-folders
                    Write-Verbose -Message "$($MyInvocation.MyCommand): Scanning files in folder: $Loc"
                    $items = Get-ChildItem -Path $Loc -Recurse -File -Include $Include
                }
                Else {

                    # Target is a file, so just get metadata for the file
                    Write-Verbose -Message "$($MyInvocation.MyCommand): Scanning file: $Loc"
                    $items = Get-Item -Path $Loc
                }

                # Get Exe and Dll files from the target path (inc. subfolders), find signatures and return certain properties in a grid view
                Write-Verbose -Message "$($MyInvocation.MyCommand): Getting digital signatures for: $Loc"
                $Signatures += $items | Get-AuthenticodeSignature | `
                    Select-Object @{Name = "Thumbprint"; Expression = { $_.SignerCertificate.Thumbprint } }, `
                @{Name = "Subject"; Expression = { $_.SignerCertificate.Subject } }, `
                @{Name = "Expiry"; Expression = { $_.SignerCertificate.NotAfter } }, `
                    Status, `
                    Path
            }
            Else {
                Write-Error "Path does not exist: $Loc"
            }
        }
    }
    End {
        # If -Unique is specified, filter the signatures list and return the first item of each unique certificate
        # If -Export is specified, we also only want unique certificate files
        If ($Export -or $Unique) { 
            Write-Verbose -Message "$($MyInvocation.MyCommand): Filtering for unique signatures."
            $Signatures = $Signatures | Where-Object { $_.Status -eq "Valid" -or $_.Status -eq "UnknownError" } | `
                Group-Object -Property Thumbprint | `
                ForEach-Object { $_.Group | Select-Object -First 1 }
            Write-Verbose -Message "$($MyInvocation.MyCommand): $($Signatures.Count) unique signature/s found in $Path"
        }

        # Return output
        Write-Verbose -Message "$($MyInvocation.MyCommand): Digital signature trawling complete."
        Write-Object -InputObject $Signatures
    }
}