Friday, April 17, 2009

Using PowerShell, LogParser and PowerGadgets to get Exchange 2003 storage information – Part 1

Was asked this week to write up a script that would graphically show how much free space was available in our Exchange Databases. My twitter colleague Alan Renouf made me aware of Jonathan Medds's post about Exchange free space. This gave me a good starting point. I now knew to look for EventID 1221 in the Exchange server(s) application event log. Being a big fan of LogParser, I decided to query the event logs using it instead of Get-WMIObject Win32_NTLogEvent.  My reasoning for this is two-fold, I have a lot of LogParser scripts that I am able to reuse in PowerShell.  Additionally, for many log parsing tasks, LogParser still is faster then using Select-String or other parsing methods. 

I highly suggest that if you are entertaining the idea of using call LogParser within PowerShell, you should copy David Muegge’s LogParser library into your code base.  Check out his posting for an explanation on how his library works (it is slick).

function Get-ExchangeEventLogRecords {

# Include our LogParser library
# Check out David Muegge's Blog
# for more info on his library

# This is the query we will be passing
# to LogParser
# Let's hear it for Here-Strings!
$query = @"
SELECT ComputerName, timewritten, Message
FROM \\Exchange01\application
WHERE eventID = 1221 and
SourceName = 'MSExchangeIS Mailbox Store' and
to_date(timewritten) = System_Date()
$inputformat = Get-LPInputFormat "evt"
$records = Get-LPRecordSet $query $inputformat
return $records

The function Get-ExchangeEventLogRecords returns all the records that I care about (in this example I have included only one Exchange Server). In order to get the exact fields I want, I need to parse the Message field from the event log.  The field looks something like this:

The database "MSXC01SG4\MSXC01SG4DB4" has 4626 megabytes of free space after online defragmentation has terminated…

The next function takes care of the parsing and creates a custom object for me.

function Format-ExchangeEventLogObject {
Begin {
$regex = [regex] '(?:MSXC\w+\\MSXC\w+)'
$regex1 = [regex] '(?:\s\d+)' }
Process {
$Store = $regex.Match($_.message) | select Value
$Mem = $regex1.Match($_.message) | select Value
$Mem = $Mem.value.ToString().Trim()
$obj = New-Object psObject
$obj | Add-Member NoteProperty TimeWritten $_.TimeWritten
$obj | Add-Member NoteProperty ExchangeServer $_.ComputerName
$obj | Add-Member NoteProperty Store $Store.Value
$obj | Add-Member NoteProperty AvailableMem $Mem
Write-Output $obj }

One thing to note, so far, we have only looked at the available space within the *.EDB file.  In the next post, I will take this information and gather a few more relevant fields (total size of the EDB file, size of STM file, estimated availability in the STM file) and show a graphical representation of the data.


Thursday, April 9, 2009

Quest Management Shell 1.2 – Updated AD cmdlets!

I just installed Quest’s latest version of their free AD cmdlets. After installing, I wanted to see what new cmdlets have been provided. The first thing I noticed in looking for the updated cmdlets was that you can no longer use Get-QADCommand to see the Quest Commands, that has been replaced with Get-QCommand. Looks like there are 9 new cmdlets:

  • Add-QADMemberOf – I see this one getting some use! Allows you to add a single object to one or many groups.
  • Approve-QARSApprovalTask – An ActiveRoles Server cmdlet. Looks like a workflow approval cmdlet
  • Get-QADMemberOf – This will be handy for auditing purposes! This cmdlet allows you to retrieve the groups that an object belongs to.
  • Get-QADPasswordSettingsObjectAppliesTo – This new cmdlet is specific to Windows Server 2008 Active Directory. Allows you to retrieve groups affected by a particular password settings object.
  • Get-QARSApprovalTask – Another ActiveRoles Server cmdlet. You can use this one to grab approval task records.
  • Get-QARSOperation - Another ActiveRoles Server cmdlet. Used to retrieve the operations records.
  • Reject-QARSApprovalTask – Like the Approve-QARSApprovalTask accept this one is used to reject the workflow task.
  • Remove-QADMemberOf – The opposite of Add-QADMemberOf. Use the cmdlet to remove an object from one or more groups. This one will get some use in our environment!
  • Restore-QADDeletedObject – Wish we had this one a few months ago! This cmdlet will allow you to undelete objects in AD by restoring tombstones into normal objects. An example from the help file demonstrates the power of this cmdlet:
    Get-QADUser -Tombstone -LastKnownParent '<DN of container>' -Name 'John Smith*' Restore-QADDeletedObject

Nice collection of new functionality!

When looking at the example in the help on Restore-QADDeletedObject, I saw the parameter –Tombstone used with Get-QADUser. Further investigation yields that Quest has added quite a few parameters to various QAD cmdlets.

This is a list of new parameters from the documentation supplied with the new version:

ParametersCmdlet added to

Can’t wait to dive in a bit more and use the newest version.


HIMSS - MSHUG Presentation

I had the opportunity to evangelize about PowerShell at the Healthcare Information and Management Systems Society (HIMSS) - Microsoft Health Users Group (MSHUG) last Saturday (4/4/2009). Other then my laptop freezing in the first ten minutes of the presentation, all went well. Given that I only had about 50 minutes, I decided to focus on "what" PowerShell can do versus "how". So I demonstrated the following:

There were not nearly as many questions as I had anticipate (perhaps following lunch had a little to do with that).  Of the questions asked, a couple stood out.

  • Why not continue to use VBScript and/or Perl
  • Can scripts be compiled

Was able to reiterate the point that if you are moving forward with Microsoft, you really have no choice.  Throughout the session I tried to emphasize the power of objects and how utilizing them makes a systems admin job so much easier. As far as compiling is concerned, my response was “if compiling them is a requirement, then you should look at writing it in C# instead”.  Would be interested in seeing how others would have responded.

I want to thank the following people for sending PowerShell related materials for distribution at the session:

  • Susan Roper (Quest Software)
  • SoftwareFX sales staff
  • Jeffery Hicks (Sapien Technologies)