{"id":245,"date":"2015-05-01T10:01:03","date_gmt":"2015-05-01T10:01:03","guid":{"rendered":"https:\/\/www.lieben.nu\/liebensraum\/?p=245"},"modified":"2015-05-01T10:01:03","modified_gmt":"2015-05-01T10:01:03","slug":"multi-threading-powershell-script-to-check-and-repair-numerous-exchange-databases","status":"publish","type":"post","link":"https:\/\/lieben.nu\/liebensraum\/2015\/05\/multi-threading-powershell-script-to-check-and-repair-numerous-exchange-databases\/","title":{"rendered":"Multi-Threading Powershell script to Check and Repair numerous Exchange databases"},"content":{"rendered":"<p>For a global customer with terrabytes of Exchange 2013 data, I recently wrote a multi-threading powershell script I&#8217;d like to share with everyone.<\/p>\n<p>The use case was an integrity check of the database backups prior to Exchange maintenance. First we have to commit all log files to a large number of databases, then run a\u00a0surface or deep\u00a0check on these databases before\u00a0we can be relatively sure a restore won&#8217;t fail.<!--more--><\/p>\n<p>All database backups were mounted to mountpoints in a root folder on a windows server. Each database had it&#8217;s own subfolder in the root folder, the logfiles were in the same folder as the .edb file.<\/p>\n<p><a href=\"https:\/\/technet.microsoft.com\/en-us\/library\/aa996953%28v=exchg.65%29.aspx\" target=\"_blank\">ESEUtil<\/a>\u00a0is our tool of choice when running integrity checks on Exchange databases. The tool has to be installed on the same server, the executable path is then referenced in the script.<\/p>\n<p><strong>Summarization<\/strong><\/p>\n<ul>\n<li>Backed up databases are mounted to mount points<\/li>\n<li>The root folder contains a seperate folder for each database<\/li>\n<li>The .chk file and transaction logs are in the same folder as the database\u00a0(.edb)\u00a0they belong to<\/li>\n<li>ESEUtil is installed on the server<\/li>\n<\/ul>\n<p>Once completed, we&#8217;re ready to configure\u00a0the script. The script is multi-threading, which means it can check several databases at once. \u00a0I recommend using CPU&#8217;s-1 threads. Note that ESEUtil can use up a LOT of memory.<\/p>\n<p><strong>Script configuration<\/strong><\/p>\n<p>$DBPath \u00a0 \u00a0 \u00a0= &#8220;D:\\DATABASES&#8221; \u00a0#This is the path to the folder on your machine where you mounted each database to subfolder (example: D:\\DATASES\\DB01)<\/p>\n<p>$LogFile \u00a0 \u00a0 = &#8220;D:\\DATABASES\\Log.txt&#8221; #Results will be written here, including errors ESEUtil spills out<\/p>\n<p>$ESEUtil \u00a0 \u00a0 = &#8216;D:\\ESEutil\\eseutil.exe&#8217; #Path to ESEUtil.exe<\/p>\n<p>$maxThreads \u00a0= 4 #Number of concurrent checks to run<\/p>\n<p>$deepscan = $true #Set to $False if you only want to run a \/mh instead of \/g after commit<\/p>\n<p><strong>Running the script<\/strong><\/p>\n<p>The script is now ready to run, right click EDBChecker_V0.3.ps1 and choose Run with Powershell. You&#8217;ll see a window, it&#8217;ll take some time to load and you&#8217;ll see a progress bar come up. Checking databases with \/g can take a very long time (hours) per database, you can monitor eseutil with your task manager. Once databases have been checked, a line will be written to the log file. \u00a0Once repaired, another line will be written and the job engine will move on to the next database.<\/p>\n<p><b>The script<\/b><\/p>\n<p><a href=\"https:\/\/www.lieben.nu\/liebensraum\/wp-content\/uploads\/2015\/05\/EdbChecker_V0.3.zip\">EdbChecker_V0.3<\/a><\/p>\n<p>Note: EdbChecker_V0.3Thread.ps1 is a required file and should be in the same folder as EdbChecker_V0.3.ps1, but should not be run.<\/p>\n<p><strong>Edit<\/strong><\/p>\n<p>And for advanced users, if you want to be really cool and let your Offline drives in drive manager automatically get mapped to a mountpoint, so you don&#8217;t have to manually assign a mountpoint to each disk, you may modify this snippet:<\/p>\n<p><code>$root = \"D:\\mountpoint\\\"<\/code><\/p>\n<p>foreach($disk in Get-Disk | where-object {$_.AllocatedSize \/1GB -gt 2450}){<br \/>\nif($disk.IsOffline){<br \/>\nSet-Disk -Number $disk.Number -IsOffline $False<br \/>\n}<\/p>\n<p>if($disk.IsReadOnly){<br \/>\nSet-Disk -Number $disk.Number -IsReadonly $False<br \/>\n}<\/p>\n<p>Get-Partition -DiskNumber $disk.Number | where-object {$_.DriveLetter} | % {<br \/>\n$drive = &#8220;$($_.DriveLetter):&#8221;<br \/>\nremove-partitionaccesspath -disknumber $disk.Number -partitionnumber $_.PartitionNumber -accesspath $drive<br \/>\n}<\/p>\n<p>Get-Partition -DiskNumber $disk.Number | where-object {$_.Size \/1GB -gt 2450} | % {<br \/>\n$foldername = &#8220;$($disk.Number)$($_.PartitionNumber)&#8221;<br \/>\n$foldername = &#8220;$($root)$($foldername)&#8221;<br \/>\nNew-Item $foldername -type directory<br \/>\nadd-partitionaccesspath -disknumber $disk.Number -partitionnumber $_.PartitionNumber -accesspath $foldername<br \/>\n}<br \/>\n}<\/p>\n<p>You&#8217;ll have to modify the where-object clauses to select the correct disk\/partition in your situation. In my situation they were over 2450GB in size, and all other disks weren&#8217;t.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For a global customer with terrabytes of Exchange 2013 data, I recently wrote a multi-threading powershell script I&#8217;d like to share with everyone. The use case was an integrity check of the database backups prior to Exchange maintenance. First we have to commit all log files to a large number of databases, then run a\u00a0surface &hellip; <a href=\"https:\/\/lieben.nu\/liebensraum\/2015\/05\/multi-threading-powershell-script-to-check-and-repair-numerous-exchange-databases\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Multi-Threading Powershell script to Check and Repair numerous Exchange databases<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[4,16,39],"tags":[],"class_list":["post-245","post","type-post","status-publish","format-standard","hentry","category-automation","category-exchange-2013","category-powershell"],"_links":{"self":[{"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/posts\/245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/comments?post=245"}],"version-history":[{"count":0,"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/posts\/245\/revisions"}],"wp:attachment":[{"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/media?parent=245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/categories?post=245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lieben.nu\/liebensraum\/wp-json\/wp\/v2\/tags?post=245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}