{"id":11501,"date":"2012-01-12T00:01:00","date_gmt":"2012-01-12T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/01\/12\/use-powershell-to-troubleshoot-exchange-server-public-folders\/"},"modified":"2012-01-12T00:01:00","modified_gmt":"2012-01-12T00:01:00","slug":"use-powershell-to-troubleshoot-exchange-server-public-folders","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-troubleshoot-exchange-server-public-folders\/","title":{"rendered":"Use PowerShell to Troubleshoot Exchange Server Public Folders"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft PFE, Seth Brandes, discusses using Windows PowerShell to troubleshoot a customer problem with Exchange Server public folders.\nMicrosoft Scripting Guy, Ed Wilson, is here. Today we are happy to have Seth Brandes as our guest blogger.<\/p>\n<p style=\"padding-left: 30px\">Seth Brandes is a premier field engineer who works in Microsoft Services. He began his foray into programming as a young lad punching the keys in BASIC on a Tandy TRS-80 back in the late 80s, and he gradually progressed through Pascal, VisualBasic, and C\/C++\/C#. He has most recently latched on to Windows PowerShell v2. He currently specializes in the Microsoft Exchange Server platform, providing Microsoft premier customers in the midwest guidance and support. He is currently gearing up his blog site and hopes to have it online in the near future.\nTake it away Seth&hellip;\nI was attending an internal Microsoft event a couple months ago, and one of my peers introduced me to Ed Wilson, THE Scripting Guy. Yes, I did get an autograph! He extended an invitation to me to write a guest blog illustrating an Windows PowerShell example related to Exchange Server, and needless to say, I could not refuse.\nRecently I had an interesting inquiry posed by one of my customers regarding an apparent inconsistency with the <b>Get-PublicFolderStatistics<\/b> cmdlet in their Exchange Servedr&nbsp;2010 environment. They had users calling their Help Desk complaining that certain public folders appeared empty of all content. Running the <b>Get-PublicFolderStatistics<\/b> cmdlet against the folders in the Exchange Management Shell returned non-zero metrics as if there was content present! I directed them to run the cmdlet with the <b>-server<\/b> switch against each server that contained replicas of the affected folder. They found discrepancies between the replicas because some were lacking content. We tied it back to a 2003 to 2010 routing group connector outage when they were migrating public folders. They updated the replicas and were placated. Great. Problem solved. Or so I thought&hellip;&nbsp;\nShortly after we wrapped that up, they had recurrences of the issue in several other folders. Therefore, they wanted a repeatable method that they could easily invoke to determine which folders had &ldquo;mismatched&rdquo; replica content in their hierarchy. I promptly informed them they already had a great monitoring system, the best ever designed in fact: the end user.&nbsp;\nThat didn&rsquo;t go over so well; so, I thought this would be a great opportunity to create a simple little script sample in Windows PowerShell that can display replica metrics for any folder (or folder tree) to determine if any replicas have mismatched metrics. Note that any high-volume folder will likely have slightly off numbers when comparing replicas because source data needs a little time to get to replica copies&mdash;even under the best of circumstances. This script should be a piece of cake.&nbsp;\nI didn&rsquo;t realize at the onset just how big the cake was going to be and what flavor. But I managed to cobble together a working script sample. Is it the best approach ever? Don&rsquo;t know, probably not. Did I learn some things I didn&rsquo;t know before? Sure. Is it a decent enough script to point out and review some cool Windows PowerShell concepts? I would say, &ldquo;Yes.&rdquo; Therefore, I decided to write this blog.\nBecause I had a preconceived picture about how I wanted the output to look, I started by sketching a visual output of the content on the whiteboard, thinking to myself that this should be doable. I envisioned a table with each row containing the folder and the item count of each replica, where the server names of the replicas would be the columns. Easy right? Let us get a mockup of how this <i>should<\/i> look according to my imagination. This mockup is shown in the following table.<\/p>\n<p style=\"padding-left: 30px\">Folder Path&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Replica1&nbsp; Replica2&nbsp; &nbsp;ReplicaX<\/p>\n<p style=\"padding-left: 30px\">&#8212;&#8212;&#8212;&#8211;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&#8212;&#8212;&#8211;&nbsp; &#8212;&#8212;&#8211;&nbsp; &nbsp;&#8212;&#8212;&#8211;<\/p>\n<p style=\"padding-left: 30px\">Level1Sub1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<\/p>\n<p style=\"padding-left: 30px\">Level1Sub1SubSub1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<\/p>\n<p style=\"padding-left: 30px\">Level2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;68\nNot too shabby. It&rsquo;s pretty much a formatted table output. Let us get that filed away&mdash;check.\nNext, I wrote a brief outline of the overall flow:<\/p>\n<ol>\n<li>Obtain folder as input so I know what to look for. <br \/>Wait&hellip;do I want to get all fancy and do recursion to look at a portion of the tree hierarchy too? &nbsp;Umm&#8230;sure, but let&rsquo;s leave it up to user to decide.<\/li>\n<li>Obtain input as whether or not to recurse. I mean, really, who doesn&rsquo;t curse, recurse, and recurse again public folders? Seriously.<\/li>\n<li>Grab the properties of the folder(s) in the folder list.<\/li>\n<li>Because we are interested in only a couple of folder properties, we&rsquo;ll specifically target the folder path, a unique identifier of the folder, and the list of replicas.<\/li>\n<li>For each replica, call the <b>Get-PublicFolderStatistics<\/b> cmdlet to obtain the item count metric&hellip;<\/li>\n<\/ol>\n<p>DOH! This won&rsquo;t work for replicas that are homed on Exchange Server 2003. What to do, what to do? The usual suspects for getting at 2003 are DAV, CDO, or WMI. I don&rsquo;t really know DAV or CDO programming, and I know there are built in WMI-based cmdlets in Windows PowerShell, so I&rsquo;ll give WMI a whirl. Let&rsquo;s rewrite the logic for step 5:<\/p>\n<p style=\"padding-left: 30px\">5. For each replica, determine if is being hosted on a server running Exchange Server&nbsp;2003 or on a server running Exchange Server&nbsp;2007 or Exchange Server&nbsp;2010. If it is 2003, make a WMI query via the <b>Get-WMIObject<\/b> cmdlet to the server to obtain the item count, else use the <b>Get-PublicFolderStatistics<\/b> cmdlet to obtain the item count. Store the results somewhere. Where? How? Why? Patience my young Padawan, patience. We&rsquo;ll get to it.<br \/>6. Rinse and repeat for each folder (ala steps 4-5).<br \/>7. When all the information has been gathered and stored in a meaningful place, spit out the output as described earlier.<br \/>8. Exit chair, open fridge, grab a cold drink.\n&nbsp;Eight steps ain&rsquo;t so bad&mdash;especially step 8! Let&rsquo;s get coding!!! Here is the opening to the script:<\/p>\n<p style=\"padding-left: 30px\">#get our input variables from the command line<\/p>\n<p style=\"padding-left: 30px\">Param(<\/p>\n<p style=\"padding-left: 30px\">&nbsp; #full PF path<\/p>\n<p style=\"padding-left: 30px\">&nbsp; [Parameter(Mandatory=$true)]<\/p>\n<p style=\"padding-left: 30px\">&nbsp; [ValidateNOtNullOrEmpty()]<\/p>\n<p style=\"padding-left: 30px\">&nbsp; [string] $Path,<\/p>\n<p style=\"padding-left: 30px\">&nbsp; #do we recurse?<\/p>\n<p style=\"padding-left: 30px\">&nbsp; [switch] $Recurse<\/p>\n<p style=\"padding-left: 30px\">&nbsp; )\nWe start by defining the input parameters of the script. The first is the folder path that will be stored as a string, and because we can&rsquo;t do anything without it, we throw in a parameter on the parameter (er, pun intended?) to make it mandatory, along with a function to ensure it is not a null value. The second is the <b>recurse<\/b> switch, which when defined with the type [switch], does not include a value; rather its presence alone is enough to use in a Boolean manner. So far, so good. Now add a bit of logic&hellip;<\/p>\n<p style=\"padding-left: 30px\">if($recurse) #recurse was requested, get the folder and all of its descendants<\/p>\n<p style=\"padding-left: 30px\">&nbsp; {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $pfCollection = Get-PublicFolder $Path -ErrorAction silentlycontinue -recurse | Select identity,replicas,@{Name=&#8221;LegPFDN&#8221;; Expression = {$_.identity.legacyDistinguishedName}}<\/p>\n<p style=\"padding-left: 30px\">&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">else #recurse was not requested, get only the folder defined<\/p>\n<p style=\"padding-left: 30px\">&nbsp; {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $pfCollection = Get-PublicFolder $Path -ErrorAction silentlycontinue | Select identity,replicas,@{Name=&#8221;LegPFDN&#8221;; Expression = {$_.identity.legacyDistinguishedName}}<\/p>\n<p style=\"padding-left: 30px\">&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">if(!$pfcollection) #validate a folder path was actually found, if not exit the script<\/p>\n<p style=\"padding-left: 30px\">&nbsp; {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Write-Host &#8220;ERROR! Could not find folder path: $path&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Write-Host &#8220;Please use a valid folder path.&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; exit<\/p>\n<p style=\"padding-left: 30px\">&nbsp; }&nbsp;\nIn the previous code, we are doing three things:<\/p>\n<ol>\n<li>Validating whether or not the user specified to use recursion.<\/li>\n<li>Grabbing the properties that interest us about the folder(s) in question via the <b>Get-PublicFolder<\/b> cmdlet.<\/li>\n<li>Validating that we actually found at least the root folder specified&mdash;else, what&rsquo;s the point right? Note that we are suppressing error output because we don&rsquo;t care if the command fails to find a folder. We do our own validation after the fact, and keep the output nice and clean.<\/li>\n<\/ol>\n<p>Note that we are grabbing three properties specifically:<\/p>\n<ol>\n<li><b>Identity<\/b>. This is the full name of the folder including the folder path. This is useful for our final output later. Stay tuned.<\/li>\n<li><b>Replicas<\/b>. This is a collection of one or more replicas, which we will use shortly to figure out which server they are on to use in querying for its replica&rsquo;s item count stats\/metrics. Again, stay tuned.<\/li>\n<li><b>LegPFDN<\/b>. Wha??? Huh?<\/li>\n<\/ol>\n<p>That&rsquo;s not a property of <b>Get-PublicFolder<\/b>! Here we are actually grabbing the <b>LegacyDistinguishedName<\/b> of the public folder, but because that&rsquo;s a lot to type (and more importantly, I&rsquo;m lazy), I elected to &ldquo;rename&rdquo; it to <b>LegPFDN<\/b> by using a simple hash table definition to assign a custom &ldquo;name&rdquo; for our purposes. I love this technique because it can be used in so many places and the expression can include calculated values. So cool!\nAnywho&hellip;it&rsquo;s important to note that the results will include the property name of <b>LegPFDN<\/b> and not <b>LegacyDistinguishedName<\/b>. Got it? Good. I know your burning to know why this specific property&mdash;read on and find out my friend, read on&hellip;\nBefore we continue with the code, let&rsquo;s take a quick timeout to explain my chosen data storage methodology. I burned many a brain cell trying to figure out a cool, but useful, way to store the results in a manner that would be easy to manipulate the output that I envisioned and described up above. I decided to store all the replica item counts of a given folder into a custom object, aka record. Each &ldquo;folder&rdquo; record would contain the following properties:<\/p>\n<ul>\n<li><b>Folder Path<\/b>, which contains the identity of the folder, including its full path.<\/li>\n<li>A separate property for each replica of the folder with the name of the replica&rsquo;s server as the property name and its value, which contains the item count.<\/li>\n<\/ul>\n<p>Each of these records are appended as they are completed to a master array called <b>$pfResults<\/b>. This manner of storing the data provides a very simple method to display the data the way I want to. However, output of the content completely falls apart when records in the set contain dissimilar property names. &nbsp;\nThis little nugget drove me crazy until I came up with a way around it. My ego tells me it&rsquo;s good enough, but my common sense is still telling me that &nbsp;it&rsquo;s a hatchet job at best. &nbsp;Oh well. It works. For now. To illustrate what the heck I&rsquo;m alluding to here, let&rsquo;s paint a picture. Here&rsquo;s what the script actually stores as output by <b>Format-List<\/b> &nbsp;against the <b>$pfResults<\/b> array:<\/p>\n<p style=\"padding-left: 30px\">Folder Path&nbsp;&nbsp; : Level1Sub1<\/p>\n<p style=\"padding-left: 30px\">Replica2 : 2<\/p>\n<p style=\"padding-left: 30px\">ReplicaX : 2<\/p>\n<p style=\"padding-left: 30px\">Folder Path&nbsp;&nbsp; : Level1Sub1SubSub1<\/p>\n<p style=\"padding-left: 30px\">Replica2 : 3<\/p>\n<p style=\"padding-left: 30px\">ReplicaX : 3<\/p>\n<p style=\"padding-left: 30px\">Folder Path&nbsp;&nbsp; : Level1Sub2<\/p>\n<p style=\"padding-left: 30px\">Replica1 : 68\nWhen you attempt to view this output with <b>Format-Table<\/b>, the third item&rsquo;s Replica information will not be written out, and it will look like this instead:<\/p>\n<p style=\"padding-left: 30px\">Folder Path&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Replica2&nbsp; &nbsp;ReplicaX<\/p>\n<p style=\"padding-left: 30px\">&#8212;&#8212;&#8212;&#8211;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&#8212;&#8212;&#8211;&nbsp; &nbsp;&#8212;&#8212;&#8211;<\/p>\n<p style=\"padding-left: 30px\">Level1Sub1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<\/p>\n<p style=\"padding-left: 30px\">Level1Sub1SubSub1&nbsp;&nbsp;&nbsp; &nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<\/p>\n<p style=\"padding-left: 30px\">Level2\nThe reason is when the first element in the array is used for its defining features. In this case, the first record in the array does not contain any properties named <b>Replica1<\/b>, so that never makes it to the table formatting &ldquo;definition.&rdquo;\nFor my purposes, this is the absolute worst. Instead of just throwing it away, I was determined (my better half would use the word &ldquo;stubborn&rdquo; here) to find a way around this. So, in came the hatchet job. I created a one-off custom object, and as I parse through all the replicas of each folder (or just the single folder if not using recursion), I simply add the server name to the object&mdash;but not any duplicates.\nWhy am I doing this? Because if I inject this custom record into the very first position in the array, it will be used for the <b>Format-Table<\/b> output definition! This will force all the columns to be present. Sweet! Is it a hatchet job? Certainly. So Whut?!\nBack to the code&hellip;<\/p>\n<p style=\"padding-left: 30px\">#define the array containing our overall folder(s) and metrics results<\/p>\n<p style=\"padding-left: 30px\">$pfResults = @()<\/p>\n<p style=\"padding-left: 30px\">#Define a custom object which will store the names of all servers<\/p>\n<p style=\"padding-left: 30px\">#containing replicas from (all) the folder(s).<\/p>\n<p style=\"padding-left: 30px\">$ReplicasObj = new-object system.object<\/p>\n<p style=\"padding-left: 30px\">Add-Member -InputObject $ReplicasObj -MemberType NoteProperty &#8220;Folder Path&#8221; &#8220;&#8221;\nDefine my master array that will hold the records. Also defined that one-off object I have named $ReplicasObj. Because this object will eventually be the first record in the array, I also throw in a property called &ldquo;Folder Path&rdquo; since it is critical to be defined for use as a column header.<\/p>\n<p style=\"padding-left: 30px\">#loop through each in folder in the hirarchy collection.<\/p>\n<p style=\"padding-left: 30px\">foreach ($pf in $pfCollection)<\/p>\n<p style=\"padding-left: 30px\">&nbsp; {\nThere is an overall loop occurring for all the folders in the original collection. If recursion was not used, it will simply exit after processing the single folder. Neato.<\/p>\n<p style=\"padding-left: 30px\">#create temp object to store information about replica<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $tmpObj = New-Object system.object<\/p>\n<p style=\"padding-left: 30px\">&nbsp; #add the name of the folder including the full path<\/p>\n<p style=\"padding-left: 30px\">&nbsp; Add-Member -InputObject $tmpObj -MemberType NoteProperty &#8220;Folder Path&#8221; $pf.Identity\nWe create a new custom temporary object that will hold this iteration&rsquo;s folder replicas info. Again, we are storing at least two or more properties: the folder identity and each replica&rsquo;s information. First, we add the &ldquo;Folder Path&rdquo; in the form of the folder identity.<\/p>\n<p style=\"padding-left: 30px\">foreach ($replica in $pf.replicas) #step through each replica of the folder<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; {\nWe then start a new loop inside the current loop to cycle through all the replicas of the folder and start processing the replica information.<\/p>\n<p style=\"padding-left: 30px\">#store replica&#8217;s server name into variable for use below.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $replicaServer = (Get-PublicFolderDatabase $replica.distinguishedname).server.name<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #add server to Replicas object to be used as the column headers for the $pfresults array<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Add-Member -InputObject $ReplicasObj -MemberType NoteProperty $replicaServer &#8220;&#8221; -ErrorAction SilentlyContinue\nGet the replica&rsquo;s server name and store it into the one-off object that will be used for the column headers in the first array element.\n<b>Note<\/b>: To prevent getting duplicate server names into the record, I simply suppress the error handling because by default, you cannot have two properties with the same name in an object using the <b>Add-Member<\/b> cmdlet (it normally throws an error if a duplicate property is added to the record). If I wanted to allow duplicates (which I don&rsquo;t, so this is just informational), I would use the <b>-force<\/b> switch as an override to create a duplicate property.<\/p>\n<p style=\"padding-left: 30px\">#determine which version of exchange the replica is homed on (as defined in KB158530)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; if ( (get-exchangeserver $replicaServer).admindisplayversion.major -lt 8)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { #Exchange 2003 server<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #grab item count via WMI since get-publicfolderstatistics will not work against a 2003 server. Store result in the temp object.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add-member -inputObject $tmpObj -membertype NoteProperty $replicaserver (Get-WmiObject -ComputerName $replicaServer -Namespace &#8220;rootMicrosoftExchangeV2&#8221; -Class &#8220;Exchange_PublicFolder&#8221; -Filter &#8220;targetaddress = &#8220;&#8221;$($pf.legPFDN)&#8221;&#8221;&#8221;).messagecount<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\nWe are finally ready to gather the metrics for the current replica, but we need to invoke the proper command, so we query the Exchange Server properties that the replica is homed on to figure out what its major version is. Per KB158530, if the administrative version is less than 8, it is not going to be Exchange Server 2007 or Exchange Server&nbsp;2010, so the <b>Get-PublicFolderStatistics<\/b> cmdlet goes out the window. I am making an assumption that Exchange Server&nbsp;5.5 and Exchange Server&nbsp;2000 are not in play, and I am therefore finding Exchange Server&nbsp;2003.\nAs I mentioned earlier, because there are precanned cmdlets for WMI&mdash;and I happen to know a WMI call to query public folder information&mdash;I&rsquo;m going with it! Here is where that pesky long named property of <b>LegacyDistinguishedName<\/b> (which we are calling <b>LegPFDN<\/b>) comes in. I use it as the filter criteria for the WMI call (and I&rsquo;ll use it also for the 2007\/2010 search below&hellip;stay tuned).\nWhy this property specifically? Er, we&rsquo;re gonna go on a slight tangent here to explain&hellip;\n&lt;TANGENT&gt;Basically, I ran into some logistical issues in the past when calling public folders via WMI where I wanted to perform built-in recursion, for example, with a filter using the <b>Path<\/b> attribute. Such a filter would be structured like &ldquo;path&gt;=&rsquo;\/level1\/Sub1\/&rsquo;&rdquo;. The problem is that if the name of another folder at the same level of &ldquo;Sub1&rdquo; is literally greater than from a comparison perspective (such as &ldquo;Sub2&rdquo;), Sub2&rsquo;s folder (and all of its descendant folders) would get caught up and returned in the results. Not good.\nSo, at the time, I elected to use the <b>LegacyDistinguishedName<\/b>. Plus using the <b>Path<\/b> attribute requires further monkeying around because with WMI, the path is returned with forward slashes instead of backslashes, and so on, I&rsquo;ve just found it kinda messy.&lt;\/TANGENT&gt;\nIs there a better attribute to use for the folder identity that is searchable via WMI and <b>Get-PublicFolderStatistics<\/b>? I don&rsquo;t know. Please tell me so I can repent and learn the error of my ways.\nIn any case, we store the results of the WMI call that contains the item count into a new property of the temporary object, and we name the property the server name that is hosting the replica.<\/p>\n<p style=\"padding-left: 30px\">else<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { #Exchange 2007 or 2010 server<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #grab item count via get-publicfolderstatistics since replica is on 2007 or 2010. Store result in the temp object.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add-member -inputObject $tmpObj -membertype NoteProperty $replicaserver (Get-PublicFolderStatistics $pf.legPFDN -Server $replicaserver).itemcount<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } #end of the else<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; } #end of the replica loop&nbsp;\nIf the version dictates Exchange Server 2007 or Exchange Server&nbsp;2010, we simply apply the exact same logic as previously, only this time we get the item count by using the very versatile <b>Get-PublicFolderStatistics<\/b> cmdlet. Rinse-and-repeat for any remaining replicas.\nThe end result is a record that contains the folder identity and all the replicas with their item counts all stored as properties. Yay!<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;#dump the content of the temp object into the results array<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $pfResults += $tmpObj<\/p>\n<p style=\"padding-left: 30px\">&nbsp; } #end of the folder loop&nbsp;\nBack in the main folder loop, we take the newly completed temporary object and append it to the master array that is holding our collection of objects. Double yay!<\/p>\n<p style=\"padding-left: 30px\">#prepend the ReplicasObject to the beginning of the array to allow a format-table to display all columns<\/p>\n<p style=\"padding-left: 30px\">$pfResults = @($replicasObj,$pfResults)<\/p>\n<p style=\"padding-left: 30px\">#output the results of the<\/p>\n<p style=\"padding-left: 30px\">$pfResults\nWe finally arrive at the tail end of the script. All of the objects have been loaded into the array, but if we attempt to display a table with the array elements, we&rsquo;d start potentially missing entire chunks due to that pesky &ldquo;first element properties defines the output definition&rdquo; business we explained earlier. So, we simply inject that one-off object that contains all the properties we need containing all the server names. We also add the &ldquo;Folder Path&rdquo; entry, which will be used for all of our column headers. Nice. Then, we simply call the array, and it paints itself to the console in all its glory in a table format.&nbsp;\n<b>Note<\/b>: There may be a need to pipe it to <b>Format-Table<\/b> if there are enough columns in play or if you want to punch it through to an <b>Export-CSV<\/b> cmdlet (for example). But because this is only a sample script, I&rsquo;m taking the easy way out. Customize it to your heart&rsquo;s content&hellip;\nTo summarize&hellip;\nIn my opinion, we covered some pretty cool Windows PowerShell concepts:<\/p>\n<ul>\n<li>Using hash tables to customize output<\/li>\n<li>Using custom objects to store data<\/li>\n<li>Using an array as a record set to store other data types<\/li>\n<li>Manipulating output of an array that contains dissimilar objects<\/li>\n<li>Determining the version of Exchange Server that is running<\/li>\n<li>Illustrating different ways to access public folder statistics information, depending on the version of Exchange Server that is hosting the folder replica<\/li>\n<li>Using different types of parameters for script input<\/li>\n<\/ul>\n<p>&nbsp;The complete script can be found in the <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/get-PublicFolderReplicaItem-692c7076\" target=\"_blank\">Script Center Repository<\/a>.\nSeth~\nThanks, Seth, for sharing your knowledge and time. Join us tomorrow as Bhargav Shukla shares another blog about Exchange Server.\nI 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=\"http:\/\/blogs.technet.commailto: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 PFE, Seth Brandes, discusses using Windows PowerShell to troubleshoot a customer problem with Exchange Server public folders. Microsoft Scripting Guy, Ed Wilson, is here. Today we are happy to have Seth Brandes as our guest blogger. Seth Brandes is a premier field engineer who works in Microsoft Services. He began his foray into [&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":[56,28,180,3,320,45],"class_list":["post-11501","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-guest-blogger","tag-messaging-and-communication","tag-microsoft-exchange-2010","tag-scripting-guy","tag-seth-brandes","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PFE, Seth Brandes, discusses using Windows PowerShell to troubleshoot a customer problem with Exchange Server public folders. Microsoft Scripting Guy, Ed Wilson, is here. Today we are happy to have Seth Brandes as our guest blogger. Seth Brandes is a premier field engineer who works in Microsoft Services. He began his foray into [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/11501","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=11501"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/11501\/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=11501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=11501"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=11501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}