{"id":9271,"date":"2012-05-30T00:01:00","date_gmt":"2012-05-30T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/05\/30\/learn-the-easy-way-to-use-powershell-to-get-file-hashes\/"},"modified":"2012-05-30T00:01:00","modified_gmt":"2012-05-30T00:01:00","slug":"learn-the-easy-way-to-use-powershell-to-get-file-hashes","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/learn-the-easy-way-to-use-powershell-to-get-file-hashes\/","title":{"rendered":"Learn the Easy Way to Use PowerShell to Get File Hashes"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell PSCX Get-Hash cmdlet to get hash files in a directory.<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\" \/><\/p>\n<p>Hey, Scripting Guy! I have a question that I hope will not require a lot of work on your part. I need to find the MD5 hash of files and folders. I use this information to determine if something has changed on a system. The problem is that everything I have seen appears to make this really complicated. Is there anything you can do that will make this easier?<\/p>\n<p>&mdash;MO<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\" \/><\/p>\n<p>&nbsp;Hello MO,<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. It is official. I am going to be doing a book signing at Microsoft TechEd 2012. I will be autographing copies of my Windows PowerShell&nbsp;2.0 Best Practices book that was published by Microsoft Press. Incidentally, the autograph session will take place at the O&rsquo;Reilly booth on Tuesday at 10:30 (refer to the following blog for a complete schedule: <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/05\/20\/weekend-scripter-scripting-guy-reveal-their-teched-2012-schedule.aspx\" target=\"_blank\">The Scripting Guys Reveal Their TechEd 2012 Schedule<\/a>. You will want to get to the booth early because we will be giving away autographed copies to the first 25 people in line. If you have a copy that you want to ensure gets signed, bring it to the book signing. Or just bring it along to the Scripting Guys booth, where I will also be glad to sign books, T-shirts, hats&hellip;whatever you happen to have (not blank checks, however).<\/p>\n<p style=\"padding-left: 30px\"><b>Note<\/b>&nbsp;&nbsp;&nbsp;This is the third in a series of four Hey, Scripting Guy! blogs about using Windows PowerShell to facilitate security forensic analysis of a compromised computer system. The intent of the series is not to teach security forensics, but rather to illustrate how Windows PowerShell could be utilized to assist in such an inquiry. The first blog discussed <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/05\/28\/use-powershell-to-aid-in-security-forensics.aspx\" target=\"_blank\">using Windows PowerShell to capture and to analyze process and service information<\/a>. &nbsp;The second blog talked about <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/05\/29\/use-powershell-to-perform-offline-analysis-of-security-logs.aspx\" target=\"_blank\">using Windows PowerShell to save event logs in XML format and perform offline analysis<\/a>.<\/p>\n<h2>MD5 hashing of files<\/h2>\n<p>MO, actually I do not think that doing a MD5 hash is all that complicated&mdash;a bit tedious, but not overly complicated. The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.security.cryptography.md5.aspx\" target=\"_blank\">MD5Class<\/a> is documented on MSDN, and it is not too bad. However, there is no real reason for IT Pros to have to mess with the .NET Framework classes if they do not want to do so. The reason? Well, the reason is that the Windows PowerShell Community Extensions includes a function that will get the MD5 hash for you. It works just like any other Windows PowerShell function or cmdlet, and it is extremely easy to use.<\/p>\n<p style=\"padding-left: 30px\"><b>Note&nbsp;&nbsp;&nbsp;<\/b>I have written several blogs about the <a href=\"http:\/\/blogs.technet.com\/search\/searchresults.aspx?q=pscx&amp;sections=7618\" target=\"_blank\">PowerShell Community Extensions (PSCX).<\/a> One especially well received blog, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2010\/07\/09\/hey-scripting-guy-tell-me-about-powershell-community-extensions.aspx\" target=\"_blank\">Tell Me About PowerShell Community Extensions<\/a><i>, <\/i>was written by one of the developers of the project, Windows PowerShell MVP, Keith Hill. To obtain the PSCX, download them from <a href=\"http:\/\/pscx.codeplex.com\/\" target=\"_blank\">CodePlex<\/a>, and follow the installation instructions in Keith&rsquo;s blog.<\/p>\n<p>After you install the PSCX, import the module by using the following command:<\/p>\n<p style=\"padding-left: 30px\">Import-Module pscx<\/p>\n<p>The cmdlet you want to use is the <b>Get-Hash<\/b> cmdlet. It accepts piped input for the path to the file to hash, and it returns an object with the path to the file and the hash value. You can specify the type of hash to use (MD5, SHA1, SHA256, SHA384, SHA512, or RIPEMD160), but this is not a requirement because it selects an MD5 hash by default. The <b>Get-Hash<\/b> cmdlet does not hash directories, only files. Therefore, an error returns (Access is denied) when the <b>Get-Hash<\/b> cmdlet runs across directories. There are several approaches to dealing with this issue:<\/p>\n<ol>\n<li>Ignore the error.<\/li>\n<li>Tell the cmdlet to ignore the error by specifying an error action.<\/li>\n<li>Develop a filter (by using the <b>Where-Object<\/b>) that returns only files.<\/li>\n<\/ol>\n<h2>Ignore the error<\/h2>\n<p>The following command generates an MD5 hash for every file in the c:\\fso directory:<\/p>\n<p><span class=\"Apple-tab-span\"> <\/span>dir c:\\fso -Recurse | Get-Hash<\/p>\n<p>The command and its associated output are shown here (errors appear in the output due to the presence of child directories).<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0844.hsg-5-30-12-01.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0844.hsg-5-30-12-01.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<h2>Tell the cmdlet to ignore the error<\/h2>\n<p>One way to deal with expected errors is to tell the cmdlet to ignore the error for you. Windows PowerShell cmdlets implement a common parameter named <i>ErrorAction. <\/i>Use of the <i>ErrorAction <\/i>ubiquitous parameter permits you to control the error action preference on a command-by-command basis. You can achieve the behavior of the VBScript script <i>On Error Resume Next <\/i>functionality if you so desire, but the real power is that it is doable on a cmdlet-by-cmdlet basis. There is also a global variable named <b>$ErrorActionPreference<\/b> that enables you to set the behavior on a global basis. There are four allowable values for the <b>ActionPreference<\/b>. These values are shown here (retrieved by using the <b>GetValues<\/b><i> <\/i>static method from the System.Enum .NET Framework class).<\/p>\n<p style=\"padding-left: 30px\">PS C:\\&gt; [enum]::GetValues(&#8220;System.Management.Automation.ActionPreference&#8221;)<\/p>\n<p style=\"padding-left: 30px\">SilentlyContinue<\/p>\n<p style=\"padding-left: 30px\">Stop<\/p>\n<p style=\"padding-left: 30px\">Continue<\/p>\n<p style=\"padding-left: 30px\">Inquire<\/p>\n<p>The <i>SilentlyContinue<\/i> value tells Windows PowerShell to not report any errors, but to continue to attempt to process the next command. This is the <i>On Error Resume Next <\/i>type of setting. <i>Stop<\/i> means that Windows PowerShell will halt execution when reaching an error. <i>Continue<\/i> means that Windows PowerShell will inform you of the error, and will then continue processing if possible (this is the default behavior). <i>Inquire<\/i> means that Windows PowerShell will let you know an error occurred, and ask you if you want to continue execution or halt the command. There are numerical equivalents to the values, and therefore, <i>SilentlyContinue<\/i> is equal to 0. The <i>ErrorAction<\/i> common parameter also has a parameter alias of <i>EA<\/i>. Therefore, by using the previous information, the following command appears.<\/p>\n<p style=\"padding-left: 30px\">dir c:\\fso -Recurse | Get-Hash -ea 0<\/p>\n<p>The command to retrieve an MD5 hash value for each file in the c:\\fso directory and to suppress any errors that may arise is shown here, along with the output associated with the command.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6825.hsg-5-30-12-02.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6825.hsg-5-30-12-02.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<h2>Develop a filter<\/h2>\n<p>To create a filter that only returns files, use the <b>psiscontainer<\/b><i> <\/i>property with <b>Where-Object<\/b>. Because I do not want to retrieve any <b>ps<\/b> container type of objects, I use the not operator (<b>!<\/b>) to tell Windows PowerShell that I want no containers. This approach is shown here.<\/p>\n<p style=\"padding-left: 30px\">dir c:\\fso -Recurse | Where-Object {!$_.psiscontainer } | get-hash<\/p>\n<p>The command and the output from the command are shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7652.hsg-5-30-12-03.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7652.hsg-5-30-12-03.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>From a performance standpoint, filtering out only files was a bit faster&mdash;not much, but a little: 3.06 total seconds as opposed to 3.28 total seconds. Due to file system caching, I rebooted my computer, ran the <b>Measure-Command<\/b> cmdlet, rebooted the computer, and ran the <b>Measure-Command<\/b> cmdlet. This eliminated caching from the equation. The commands and the associated output from the commands are shown here.<\/p>\n<p style=\"padding-left: 30px\">PS C:\\&gt; Measure-Command { dir c:\\fso -Recurse | Where-Object {!$_.psiscontainer } | g<\/p>\n<p style=\"padding-left: 30px\">et-hash }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Days&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0<\/p>\n<p style=\"padding-left: 30px\">Hours&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0<\/p>\n<p style=\"padding-left: 30px\">Minutes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0<\/p>\n<p style=\"padding-left: 30px\">Seconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 3<\/p>\n<p style=\"padding-left: 30px\">Milliseconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 61<\/p>\n<p style=\"padding-left: 30px\">Ticks&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 30610419<\/p>\n<p style=\"padding-left: 30px\">TotalDays&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 3.54287256944444E-05<\/p>\n<p style=\"padding-left: 30px\">TotalHours&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0.000850289416666667<\/p>\n<p style=\"padding-left: 30px\">TotalMinutes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0.051017365<\/p>\n<p style=\"padding-left: 30px\">TotalSeconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 3.0610419<\/p>\n<p style=\"padding-left: 30px\">TotalMilliseconds : 3061.0419<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">PS C:\\&gt; Measure-Command { dir c:\\fso -Recurse | Get-Hash -ea 0 }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Days&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0<\/p>\n<p style=\"padding-left: 30px\">Hours&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0<\/p>\n<p style=\"padding-left: 30px\">Minutes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0<\/p>\n<p style=\"padding-left: 30px\">Seconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 3<\/p>\n<p style=\"padding-left: 30px\">Milliseconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 280<\/p>\n<p style=\"padding-left: 30px\">Ticks&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 32803013<\/p>\n<p style=\"padding-left: 30px\">TotalDays&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 3.79664502314815E-05<\/p>\n<p style=\"padding-left: 30px\">TotalHours&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0.000911194805555555<\/p>\n<p style=\"padding-left: 30px\">TotalMinutes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0.0546716883333333<\/p>\n<p style=\"padding-left: 30px\">TotalSeconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 3.2803013<\/p>\n<p style=\"padding-left: 30px\">TotalMilliseconds : 3280.3013<\/p>\n<\/p>\n<p>MO, that is all there is to using the <b>Get-Hash<\/b> cmdlet from the PSCX to obtain hash values from files in a folder. Security Week will continue tomorrow when I will talk about storing and comparing hash values to detect changes to files.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell PSCX Get-Hash cmdlet to get hash files in a directory. Hey, Scripting Guy! I have a question that I hope will not require a lot of work on your part. I need to find the MD5 hash of files and folders. I use [&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":[3,63,45],"class_list":["post-9271","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-scripting-guy","tag-security","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell PSCX Get-Hash cmdlet to get hash files in a directory. Hey, Scripting Guy! I have a question that I hope will not require a lot of work on your part. I need to find the MD5 hash of files and folders. I use [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/9271","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=9271"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/9271\/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=9271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=9271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=9271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}