{"id":86114,"date":"2019-07-24T10:32:34","date_gmt":"2019-07-24T18:32:34","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/scripting\/?p=86114"},"modified":"2019-10-29T06:49:52","modified_gmt":"2019-10-29T14:49:52","slug":"reporting-on-digitally-signed-files-with-powershell","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/reporting-on-digitally-signed-files-with-powershell\/","title":{"rendered":"Reporting on Digitally Signed Files with PowerShell"},"content":{"rendered":"<p><strong>Summary<\/strong>: Using the Get-AuthenticodeSignature cmdlet to show if a file is Digitally Signed<\/p>\n<p>Q: Hey, Doctor Scripto!<\/p>\n<p>I was curious, since many new files are Digitally signed with a certificate if there was an easy way to see the status of the Digital Signatures of many files easily?<\/p>\n<p>\u2014SH<\/p>\n<p>A: Hello SH your good friend Doctor Scripto is here today to help you along.<\/p>\n<p>One of the things which changed with PowerShell in version 3.0 was a beautiful little Cmdlet called Get-AuthenticodeSignature<\/p>\n<p>This Cmdlets task was very simple, examine a file and show the properties of the Digital Certificate on a file. Here\u2019s an example of it in action<\/p>\n<p><img decoding=\"async\" width=\"1770\" height=\"388\" class=\"wp-image-86120\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-8.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-8.png 1770w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-8-300x66.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-8-768x168.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-8-1024x224.png 1024w\" sizes=\"(max-width: 1770px) 100vw, 1770px\" \/><\/p>\n<p>A quick glance shows us the file has a Valid digital signature. If you would like to see more details you can pipe the results into Format-List<\/p>\n<p><img decoding=\"async\" width=\"2253\" height=\"1806\" class=\"wp-image-86122\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-10.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-10.png 2253w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-10-300x240.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-10-768x616.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-10-1024x821.png 1024w\" sizes=\"(max-width: 2253px) 100vw, 2253px\" \/><\/p>\n<p>Visually this is a nice way of trying to determine if the content you downloaded is at least signed with a current certificate from a vendor.<\/p>\n<p>I can even take a list of files, pipe them in to see their status!<\/p>\n<p><img decoding=\"async\" width=\"2145\" height=\"719\" class=\"wp-image-86125\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-13.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-13.png 2145w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-13-300x101.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-13-768x257.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-13-1024x343.png 1024w\" sizes=\"(max-width: 2145px) 100vw, 2145px\" \/><\/p>\n<p>However the Cmdlet does have a Snag. If I wish to take this information and try to Export it as a list to a CSV to report on a list of files, it produces some unexpected results.<\/p>\n<p>Instead of seeing a nicely formatting CSV file in columns and perhaps the odd Object reference, it looks more like a regular text file<\/p>\n<p><img decoding=\"async\" width=\"1882\" height=\"702\" class=\"wp-image-86126\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-14.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-14.png 1882w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-14-300x112.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-14-768x286.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-14-1024x382.png 1024w\" sizes=\"(max-width: 1882px) 100vw, 1882px\" \/><\/p>\n<p>This had the good Doctor doing some head scratching. How could this be fixed? Something in the way the part of the object had parsed did not show up the way we wanted. I was expecting individual columns on data.<\/p>\n<p>I could just hear myself shouting out, \u201cThis is a job for \u2026 Select-Object!\u201d<\/p>\n<p>First let\u2019s see what was exposed using Get-Member to decide where the problem might be.<\/p>\n<p><img decoding=\"async\" width=\"1142\" height=\"366\" class=\"wp-image-86127\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-15.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-15.png 1142w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-15-300x96.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-15-768x246.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-15-1024x328.png 1024w\" sizes=\"(max-width: 1142px) 100vw, 1142px\" \/><\/p>\n<p>I could see a total of seven properties to view. The bool and string properties were probably straight forward and not causing an issue. System.Management.Automation as it was accessing a single property within itself was probably ok. \u00a0 I could be wrong, but sometimes a good honest guest works.<\/p>\n<p>But those X509Certificate2 objects? I foresaw them containing a lot of information such as Expiry, Issue, signatures. They could have been the problem.<\/p>\n<p>A simple test I did was to Run the Get-AuthenticodeSignature and only take the ones I guessed were ok and output them to a CSV file.<\/p>\n<p><span style=\"color: #ff0000; font-size: 12pt;\">Get-ChildItem c:\\windows\\notepad*.exe | Get-AuthenticodeSignature | `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">Select-Object -Property Path,ISOSBinary,SignatureType,Status,StatusMessage | `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">Export-CSV C:\\report\\Signature.csv -NoTypeInformation<\/span><\/p>\n<p><img decoding=\"async\" width=\"1189\" height=\"367\" class=\"wp-image-86128\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-16.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-16.png 1189w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-16-300x93.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-16-768x237.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-16-1024x316.png 1024w\" sizes=\"(max-width: 1189px) 100vw, 1189px\" \/><\/p>\n<p>This time the results were much nicer. So the challenge was to pull out the objects from WITHIN the object in X509Certificate2. Again a task designed for Select-Object and Get-Member.<\/p>\n<p>The first we needed to do was to see the properties *IN* that X509Certificate2 object.<\/p>\n<p><img decoding=\"async\" width=\"1437\" height=\"566\" class=\"wp-image-86129\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-17.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-17.png 1437w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-17-300x118.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-17-768x302.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-17-1024x403.png 1024w\" sizes=\"(max-width: 1437px) 100vw, 1437px\" \/><\/p>\n<p>Now we can see a myriad of additional properties that were in that object. To obtain a property such as the SerialNumber, we need to leverage a feature of Select-Object called a \u201cCalculated Property\u201d. This feature has been around PowerShell for a VERY long time and is quite useful in these situations.<\/p>\n<p><span style=\"color: #ff0000; font-size: 12pt;\">Get-ChildItem C:\\Windows\\notepad.exe | Get-AuthenticodeSignature | `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">Select-Object -Property @{Name=&#8217;SignerSerialNumber&#8217;;Expression={($_.SignerCertificate.SerialNumber)}}<\/span><\/p>\n<p><span style=\"color: #000000;\">Using this in PowerShell produced the following result<\/span><\/p>\n<p><span style=\"color: #ff0000;\">SignerSerialNumber<\/span>\n<span style=\"color: #ff0000;\">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span>\n<span style=\"color: #ff0000;\">33000001C422B2F79B793DACB20000000001C4<\/span><\/p>\n<p><span style=\"color: #000000;\">A much more desirable output. At this point it was a matter of producing a Calculated Property for each of the individual items from the X509Certificate2 object.<\/span><\/p>\n<p><span style=\"color: #ff0000; font-size: 12pt;\">Get-ChildItem C:\\Windows\\notepad.exe | Get-AuthenticodeSignature | `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">Select-object -Property Path, Status,StatusMessage,SignatureType, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectName&#8217;;Expression={($_.SignerCertificate.Subject)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectIssuer&#8217;;Expression={($_.SignerCertificate.Issuer)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectSerialNumber&#8217;;Expression={($_.SignerCertificate.SerialNumber)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectNotBefore&#8217;;Expression={($_.SignerCertificate.NotBefore)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectNotAfter&#8217;;Expression={($_.SignerCertificate.NotAfter)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectThumbprint&#8217;;Expression={($_.SignerCertificate.ThumbPrint)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperName&#8217;;Expression={($_.SignerCertificate.Subject)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperIssuer&#8217;;Expression={($_.SignerCertificate.Issuer)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperSerialNumber&#8217;;Expression={($_.SignerCertificate.SerialNumber)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperNotBefore&#8217;;Expression={($_.SignerCertificate.NotBefore)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperNotAfter&#8217;;Expression={($_.SignerCertificate.NotAfter)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperThumbprint&#8217;;Expression={($_.SignerCertificate.ThumbPrint)}}<\/span><\/p>\n<p>With this we now had an object that would export directly to a CSV.<\/p>\n<p>As a simple way to consume it, we could even write it up as a function.<\/p>\n<p><span style=\"color: #ff0000; font-size: 12pt;\">Function Expand-AuthenticodeSignature($AuthenticodeSignature)<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">{<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">$AuthenticodeSignature | Select-object -Property Path, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">Status,StatusMessage,SignatureType, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectName&#8217;;Expression={($_.SignerCertificate.Subject)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectIssuer&#8217;;Expression={($_.SignerCertificate.Issuer)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectSerialNumber&#8217;;Expression={($_.SignerCertificate.SerialNumber)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectNotBefore&#8217;;Expression={($_.SignerCertificate.NotBefore)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectNotAfter&#8217;;Expression={($_.SignerCertificate.NotAfter)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;SubjectThumbprint&#8217;;Expression={($_.SignerCertificate.ThumbPrint)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperName&#8217;;Expression={($_.SignerCertificate.Subject)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperIssuer&#8217;;Expression={($_.SignerCertificate.Issuer)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperSerialNumber&#8217;;Expression={($_.SignerCertificate.SerialNumber)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperNotBefore&#8217;;Expression={($_.SignerCertificate.NotBefore)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperNotAfter&#8217;;Expression={($_.SignerCertificate.NotAfter)}}, `<\/span>\n<span style=\"color: #ff0000; font-size: 12pt;\">@{Name=&#8217;TimeStamperThumbprint&#8217;;Expression={($_.SignerCertificate.ThumbPrint)}}}<\/span><\/p>\n<p>Now that we have the data in a more consumable and exportable fashion. We can even grab a list of files with their Digital Certificate status<\/p>\n<p>$List=Get-ChildItem C:\\Windows\\*.exe | Get-AuthenticodeSignature<\/p>\n<p>\u2026.then produce the new output in a script with our function and Export it directly to a CSV file<\/p>\n<p>Expand-AuthenticodeSignature -AuthenticodeSignature $List | Export-Csv C:\\report\\working.csv<\/p>\n<p>As you can see, the results are much more useful.<\/p>\n<p><img decoding=\"async\" width=\"1997\" height=\"359\" class=\"wp-image-86130\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-18.png\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-18.png 1997w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-18-300x54.png 300w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-18-768x138.png 768w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/07\/word-image-18-1024x184.png 1024w\" sizes=\"(max-width: 1997px) 100vw, 1997px\" \/><\/p>\n<p>SH that is all there is to seeing how to report on Digitally Signed files with Get-AuthenticodeSigntature<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\">Official Scripting Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Your good friend, Doctor Scripto<\/strong><\/p>\n<p>PowerShell, Doctor Scripto, Certificates, Sean Kearney<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Using the Get-AuthenticodeSignature cmdlet to show if a file is Digitally Signed Q: Hey, Doctor Scripto! I was curious, since many new files are Digitally signed with a certificate if there was an easy way to see the status of the Digital Signatures of many files easily? \u2014SH A: Hello SH your good friend [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1739,1738,685],"tags":[646,1740,377,154],"class_list":["post-86114","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-doctor-scripto","category-powershell","category-scripting-techniques","tag-certificate","tag-doctor-scripto","tag-powershell","tag-sean-kearney"],"acf":[],"blog_post_summary":"<p>Summary: Using the Get-AuthenticodeSignature cmdlet to show if a file is Digitally Signed Q: Hey, Doctor Scripto! I was curious, since many new files are Digitally signed with a certificate if there was an easy way to see the status of the Digital Signatures of many files easily? \u2014SH A: Hello SH your good friend [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86114","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=86114"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86114\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=86114"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=86114"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=86114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}