{"id":1779,"date":"2014-03-23T00:01:00","date_gmt":"2014-03-23T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2014\/03\/23\/weekend-scripter-use-powershell-to-investigate-file-signaturespart-2\/"},"modified":"2022-06-10T12:14:29","modified_gmt":"2022-06-10T19:14:29","slug":"weekend-scripter-use-powershell-to-investigate-file-signaturespart-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-to-investigate-file-signaturespart-2\/","title":{"rendered":"Weekend Scripter: Use PowerShell to Investigate File Signatures\u2014Part 2"},"content":{"rendered":"<p><strong>Summary<\/strong>: Windows PowerShell MVP, Boe Prox, concludes this two-part series about investigating file signatures with Windows PowerShell and the .NET Framework.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Welcome back guest blogger, <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/tag\/boe-prox\/\" target=\"_blank\" rel=\"noopener\">Boe Prox<\/a>, for the conclusion of the two-part series he started yesterday. Also read <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-to-investigate-file-signaturespart-1\/\" target=\"_blank\" rel=\"noopener\">Use PowerShell to Investigate File Signatures\u2014Part\u00a01<\/a>.<\/p>\n<p>Today I am going to demo a function that I wrote and discuss a couple of items that I came across while investigating the file signatures. But first, I am going to talk about a couple of things that helped shape the direction of my function, which is called <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Get-FileSignature-f5ae19f5\" target=\"_blank\" rel=\"noopener\">Get-FileSignature<\/a> (the download is available on the Script Center Repository).<\/p>\n<p>I wanted to know if there was a way to easily determine if an extension had been altered by looking at the <strong>LastWriteTime<\/strong> time stamp. The reason is that if a drive or folder was being blocked from hosting files of a certain type, files that are already there could have their extension altered to avoid being detected by using a casual scan such as the following:<\/p>\n<p style=\"margin-left:30px\">\n  Get-ChildItem -Filter *.iso\n<\/p>\n<p>You could use &#42;.iso&#42;, or &#42;.iso.&#42;, or any other means, but there is a potential to miss files in the scan. The point is that there is always the possibility of an extension being changed because a user knows of the file\u2019s impending removal.<\/p>\n<p>When I tested the <strong>LastWriteTime<\/strong> of a file after I changed the extension, I found that nothing changed and the time stamp remained the same.<\/p>\n<p style=\"margin-left:30px\">\n  $file = Convert-Path en_windows_8_enterprise_x64_dvd_917522.iso\n<\/p>\n<p style=\"margin-left:30px\">\n  Get-Item $File | Select Name,LastWriteTime\n<\/p>\n<p style=\"margin-left:30px\">\n  Rename-Item -Path $File -NewName &#8220;$File.txt&#8221; -Verbose\n<\/p>\n<p style=\"margin-left:30px\">\n  Get-Item &#8220;$File.name.txt&#8221; | Select Name,LastWriteTime\n<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-1.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>As you can see, there is no change to <strong>LastWriteTime<\/strong> when the extension is changed. Fortunately, I am able to use a function that I wrote called <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Get-MFT-Timestamp-of-a-file-9227f399\" target=\"_blank\" rel=\"noopener\">Get-FileTimeStamp<\/a>. This function uses P\/Invoke to display the <strong>ChangeTime<\/strong> (also known as MFT TimeStamp), which updates with any change, including metadata changes such as the extension. (I also wrote a blog post about this topic: <a href=\"http:\/\/learn-powershell.net\/2013\/03\/03\/finding-a-files-mft-timestamp-using-powershell\/\" target=\"_blank\" rel=\"noopener\">Finding a File\u2019s MFT Timestamp using PowerShell<\/a>.)<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-2.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Now I have a more useful way to determine if a file extension had been changed. I will reiterate that this is not a foolproof way of determining that the extension has changed because any change to the file (such as an attribute) will trigger the <strong>ChangeTime<\/strong> to update. The <strong>Get-FileSignature<\/strong> function uses a portion of the code from <strong>Get-FileTimeStamp<\/strong> to provide the <strong>ChangeTime<\/strong>.<\/p>\n<p style=\"margin-left:30px\">\n  Get-Content vs. [io.file]::ReadAllBytes() vs. FileStream\n<\/p>\n<p>Next on my agenda was to find the most efficient way of getting the file signature. I needed a method that would take into account not only small files, but also larger files, such as the 3\u00a0GB ISO file that I am using in my examples today. I looked at three possible ways of getting the file signature:<\/p>\n<ul>\n<li>Use\u00a0<strong>Get-Content<\/strong> with the <strong>\u2013Encoding Byte<\/strong> parameter<\/li>\n<li>Use [io.file]::ReadAllBytes()<\/li>\n<li>Use\u00a0[io.filestream] \u00a0(the examples that I presented in Part\u00a01)<\/li>\n<\/ul>\n<p>Any of these methods would work fairly quickly on smaller files, so I will not waste any time looking at that performance. Instead, we will tackle the ISO file\u2014not only because it is large, but because it uses a byte offset that others (such as .exe files) do not:<\/p>\n<p style=\"margin-left:30px\">\n  $ByteLimit = 5\n<\/p>\n<p style=\"margin-left:30px\">\n  $ByteOffset = 0x8001\n<\/p>\n<p style=\"margin-left:30px\">\n  $total = $ByteLimit + $ByteOffset\n<\/p>\n<p style=\"margin-left:30px\">\n  #Takes some time to run on larger files as long as they are less than 2GB; fine against smaller files\n<\/p>\n<p style=\"margin-left:30px\">\n  $sum = (Measure-Command {\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 Get-Content -Path $File -Encoding Byte -TotalCount $total | Select -First $ByteLimit -Skip $ByteOffset\n<\/p>\n<p style=\"margin-left:30px\">\n  }).TotalMilliseconds\n<\/p>\n<p style=\"margin-left:30px\">\n  [pscustomobject]@{\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 Type = &#8216;GetContent&#8217;\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 TotalMilliseconds = $sum\n<\/p>\n<p style=\"margin-left:30px\">\n  }\n<\/p>\n<p style=\"margin-left:30px\">\n  #Still slower on larger files; fine against smaller files\n<\/p>\n<p style=\"margin-left:30px\">\n  $sum = (Measure-Command {\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 [io.file]::ReadAllBytes($File) | Select -First $ByteLimit -Skip $ByteOffset\n<\/p>\n<p style=\"margin-left:30px\">\n  }).TotalMilliseconds\u00a0\n<\/p>\n<p style=\"margin-left:30px\">\n  [pscustomobject]@{\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 Type = &#8216;ReadAllBytes&#8217;\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 TotalMilliseconds = $sum\n<\/p>\n<p style=\"margin-left:30px\">\n  }\n<\/p>\n<p style=\"margin-left:30px\">\n  #Most work setting up, but faster with larger files\n<\/p>\n<p style=\"margin-left:30px\">\n  $Sum = (Measure-Command {\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 #Open a FileStream to the file; this will prevent other actions against file until it closes\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 $filestream = New-Object IO.FileStream($File, [IO.FileMode]::Open, [IO.FileAccess]::Read)\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 #Determine starting point\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 $filestream.Position = $ByteOffset\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 $bytebuffer = New-Object &#8220;Byte[]&#8221; -ArgumentList $ByteLimit\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 [void]$filestream.Read($bytebuffer, 0, $bytebuffer.Length)\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 $bytebuffer\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 $filestream.Close()\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 $filestream.Dispose()\n<\/p>\n<p style=\"margin-left:30px\">\n  }).TotalMilliseconds\n<\/p>\n<p style=\"margin-left:30px\">\n  [pscustomobject]@{\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 Type = &#8216;FileStream&#8217;\n<\/p>\n<p style=\"margin-left:30px\">\n  \u00a0\u00a0\u00a0 TotalMilliseconds = $sum\n<\/p>\n<p style=\"margin-left:30px\">\n  }\n<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-3.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>We can see a limitation with <strong>Get-Content<\/strong> in files that exceed 2\u00a0GB in size. Even then, it was still in the upwards of 2000 milliseconds to get to that point. The <strong>ReadAllBytes<\/strong> method was much faster, but it forces us to read the entire file before grabbing the specified bytes needed for the signature. The approach that I discussed yesterday (even with some of the setup) was the fastest method available, and it became the approach that I chose for my function.<\/p>\n<p style=\"margin-left:30px\">\n  Get-FileSignature\n<\/p>\n<p>Speaking of the function, let\u2019s take a look at it in action. It supports pipeline input, and it allows you to specify a byte offset and the number of bytes to return. It is perfect for looking for a specific file signature. I also added a <strong>\u2013HexFilter<\/strong>, which can be used to filter for a specific file signature by its hex signature.<\/p>\n<p>In this case, I want to find only ISO files:<\/p>\n<p style=\"margin-left:30px\">\n  Get-ChildItem -Path G: -Recurse -File |\n<\/p>\n<p style=\"margin-left:30px\">\n  Get-FileSignature -ByteLimit 5 -ByteOffset 0x8001 -HexFilter &#8220;4344 3030 31&#8221; |\n<\/p>\n<p style=\"margin-left:30px\">\n  Format-Table\n<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-4.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-3-23-14-4.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Looks like I had more than one ISO file residing on this drive.<\/p>\n<p>Depending on the type of file that you are looking for, you can adjust the parameters to suit your needs, and then use this function to locate files that may not quite be what they appear.<\/p>\n<p>Here is one last demo that uses the signature for an .exe file:<\/p>\n<p style=\"margin-left:30px\">\n  Get-ChildItem -Path G: -Recurse -File |\n<\/p>\n<p style=\"margin-left:30px\">\n  Get-FileSignature -ByteLimit 2 -ByteOffset 0 -HexFilter &#8220;4D5A&#8221; |\n<\/p>\n<p style=\"margin-left:30px\">\n  Format-Table\n<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/prod.evol.blogs.technet.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/00\/76\/18\/8507.5.PNG\"><img decoding=\"async\" src=\"https:\/\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/prod.evol.blogs.technet.com\/CommunityServer.Blogs.Components.WeblogFiles\/00\/00\/00\/76\/18\/8507.5.PNG\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Looks like .exe files are not the only files that carry the 4D5A hex filter\u2014.dlls are just one of many other files that hold the same file signature.<\/p>\n<p>That is it for my two-part series about finding file signatures by using Windows PowerShell. Thank-you to Ed for giving me a couple of days to talk about this. Hope everyone found it interesting! You can download the function from this series from the Script Center Repository: <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Get-FileSignature-f5ae19f5\" target=\"_blank\" rel=\"noopener\">Get-FileSignature<\/a>.<\/p>\n<p>~Boe<\/p>\n<p>Thank you, Boe, for writing these two posts and sharing.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\" rel=\"noopener\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\" rel=\"noopener\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\" rel=\"noopener\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\" rel=\"noopener\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong>\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Windows PowerShell MVP, Boe Prox, concludes this two-part series about investigating file signatures with Windows PowerShell and the .NET Framework. Microsoft Scripting Guy, Ed Wilson, is here. Welcome back guest blogger, Boe Prox, for the conclusion of the two-part series he started yesterday. Also read Use PowerShell to Investigate File Signatures\u2014Part\u00a01. Today I am [&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":[1],"tags":[400,162,38,56,3,4,63,12,61,45],"class_list":["post-1779","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-net","tag-boe-prox","tag-files","tag-guest-blogger","tag-scripting-guy","tag-scripting-techniques","tag-security","tag-storage","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Windows PowerShell MVP, Boe Prox, concludes this two-part series about investigating file signatures with Windows PowerShell and the .NET Framework. Microsoft Scripting Guy, Ed Wilson, is here. Welcome back guest blogger, Boe Prox, for the conclusion of the two-part series he started yesterday. Also read Use PowerShell to Investigate File Signatures\u2014Part\u00a01. Today I am [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/1779","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=1779"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/1779\/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=1779"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=1779"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=1779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}