class/SigningTimeGetter.psm1

Function Get-AuthenticodeSigningTime {
    [CmdletBinding(HelpUri = 'https://www.sysadmins.lv/blog-en/retrieve-timestamp-attribute-from-digital-signature.aspx')]
    Param(
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [string[]] $FilePath
    )
    Begin {
        $Signature = @"
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool CryptQueryObject(
                int dwObjectType,
                [MarshalAs(UnmanagedType.LPWStr)]string pvObject,
                int dwExpectedContentTypeFlags,
                int dwExpectedFormatTypeFlags,
                int dwFlags,
                ref int PdwMsgAndCertEncodingType,
                ref int PdwContentType,
                ref int PdwFormatType,
                ref IntPtr phCertStore,
                ref IntPtr phMsg,
                ref IntPtr ppvContext
            );
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool CryptMsgGetParam(
                IntPtr hCryptMsg,
                int dwParamType,
                int dwIndex,
                byte[] pvData,
                ref int pcbData
            );
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool CryptMsgClose(IntPtr hCryptMsg);
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool CertCloseStore(IntPtr hCertStore, int dwFlags);
"@

        Add-Type -AssemblyName System.Security
        Add-Type -MemberDefinition $Signature -Namespace PKI -Name Crypt32
    }
    Process {
        (Get-AuthenticodeSignature @PSBoundParameters).Where({ $_.SignerCertificate }) |
        ForEach-Object {
            $PdwMsgAndCertEncodingType =  0
            $PdwContentType =  0
            $PdwFormatType =  0
            [IntPtr] $PhCertStore = [IntPtr]::Zero
            [IntPtr] $PhMsg = [IntPtr]::Zero
            [IntPtr] $PpvContext = [IntPtr]::Zero
            [void] [PKI.Crypt32]::CryptQueryObject(
                1,
                $_.Path,
                16382,
                14,
                $Null,
                [ref] $PdwMsgAndCertEncodingType,
                [ref] $PdwContentType,
                [ref] $PdwFormatType,
                [ref] $PhCertStore,
                [ref] $PhMsg,
                [ref] $PpvContext
            )
            $PcbData = 0
            [void] [PKI.Crypt32]::CryptMsgGetParam($PhMsg, 29, 0, $Null, [ref] $PcbData)
            $PvData = New-Object byte[] -ArgumentList $PcbData
            [void] [PKI.Crypt32]::CryptMsgGetParam($PhMsg, 29, 0, $PvData, [ref] $PcbData)
            $SignedCms = New-Object Security.Cryptography.Pkcs.SignedCms
            $SignedCms.Decode($PvData)
            Foreach ($Infos In $SignedCms.SignerInfos) {
                Foreach ($CounterSignerInfos In $Infos.CounterSignerInfos) {
                    $STime = ($CounterSignerInfos.SignedAttributes |
                    Where-Object { $_.Oid.Value -eq '1.2.840.113549.1.9.5' }).Values |
                    Where-Object { $Null -ne $_.SigningTime }
                }
            }
            $STime.SigningTime
            [void][PKI.Crypt32]::CryptMsgClose($PhMsg)
            [void][PKI.Crypt32]::CertCloseStore($PhCertStore, 0)
        }
    }
    End { }
}