Monitor-MailboxDatabaseCopyStatus.ps1

#Exchange2010 #MsExchange #Powershell

Hello every Happy New Year and all that .. long time to talk.

Wanted to share this.  Basically had a Cisco UCS Blade failure today, where it took 2 nodes of a 3 node Exchange 2010 dag out.

Its been a fun day! NOT!

Anyway, I knocked this script up to monitor the database copy status when we put everything back.

PARAM([String]$Server = (HOSTNAME),
[int]$time            = 30)

Write-Host "Server:.."$Server
Write-Host "Timer:..."$time
$position = $host.ui.rawui.cursorposition
$position.y = $position.y+4
while($True){
  Get-MailboxDatabaseCopyStatus -Server $Server
  $endpos = $host.ui.rawui.cursorposition
  for($i=1;$i-le $time;$i++){write-host "." -nonewline -f Yellow;sleep 1}
  $host.ui.rawui.cursorposition=$endpos;
  Write-Host (" "*$time)
  $host.ui.rawui.cursorposition=$position;
}

Find Exchange Databases using Powershell

A small change in $strFilter=”(objectClass=msExchPrivateMDB)” and you get all the mailbox databases ;-)

$forest    = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$Dom  = "LDAP://CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=" + $Forest.Name.Replace(".",",DC=")
$strFilter="(objectClass=msExchPrivateMDB)"
$Root       = New-Object DirectoryServices.DirectoryEntry $Dom 
$selector   = New-Object DirectoryServices.DirectorySearcher 
$selector.PageSize    = 1000 
$selector.Filter      = $strFilter 
$selector.SearchRoot  = $root 
$selector.SearchScope = "Subtree" 
$Objs = $selector.findall() 
$Objs.count 
$Objs 

Find Exchange Servers using Powershell

#Powershell #MsExchange

I have a suite of discovery scripts that I use every now and then.  I adapted this to look in the AD and get a list of the exchange servers!

$forest    = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$Dom = "LDAP://CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=" + $Forest.Name.Replace(".",",DC=")
$strFilter="(objectClass=msExchExchangeServer)"
$Root       = New-Object DirectoryServices.DirectoryEntry $Dom
$selector   = New-Object DirectoryServices.DirectorySearcher
$selector.PageSize   = 1000
$selector.Filter     = $strFilter
$selector.SearchRoot = $root
$selector.SearchScope = "Subtree"
$Objs = $selector.findall()
$Objs.count
$Objs

Backing up Exchange Server 2010 with Windows Server Backup and Powershell

#powershell #msexchange

This was fun, or not as the case may be.So I have a temporary Exchange 2010 server that I am using to migrate users on to, and then off at a later date.

I slapped a 2TB external usb disk in the back of the server and wanted to back it up.  Using the GUI is easy, but I wanted to use Powershell do it!

Now you can use wbadmin to run a backup, but this for some reason doesn’t work if you run it in powershell.  After some digging I found the powershell snapin windows.serverbackup

So you can start powershell and run Add-PsSnapin windows.serverbackup

You then find a whole load of cmdlets you can use.  Check it them here: http://technet.microsoft.com/en-us/library/ee706683.aspx<

I’m not going to go in to real detail, but this is basics:

$policy = New-WBPolicy
$fileSpec = New-WBFileSpec -FileSpec D:\exchange.databases\database.swing01 
Add-WBFileSpec -Policy $policy -FileSpec $filespec
$fileSpec = New-WBFileSpec -FileSpec D:\exchange.databases\database.swing02 
Add-WBFileSpec -Policy $policy -FileSpec $filespec
$fileSpec = New-WBFileSpec -FileSpec D:\exchange.databases\database.swing03 
Add-WBFileSpec -Policy $policy -FileSpec $filespec

Set-WBVssBackupOptions -Policy $policy -VssFullBackup   
$backupLocation = New-WBBackupTarget -NetworkPath $BackupTarget 
Add-WBBackupTarget -Policy $policy -Target $backupLocation   
Start-WBBackup -Policy $policy

#Powershell Export-Clixml and Import-Clixml

I had a need to store some user data.  Using the Exchange 2010 Management Shell I could use Get-User and Get-Mailbox to get what I needed, but when you export it to CSV, some of the fields don’t export very well at all.I was looking at all kinds of funky ways to export the data, but then stumbled upon Export-Clixml.

I was amazed.  I could run say Get-Mailbox bob | Export-Cixml bob.xml

Then I could run $x = Import-Clixml bob.xml anywhere and I would have a variable ($x) with bob’s mailbox information in!

How cool is that!

#NetApp DataOnTap and Invoke-NaSysstat

So I have been play with the NetApp DataOnTap add in for a while now want to share this.  Essentially all it does is run Invoke-NaSysstat at timed intervals and saves it to an hourly csv file

[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$filer   = [Microsoft.VisualBasic.Interaction]::InputBox("Enter the comma seperated filer name", "Enter Filer Name", "")

#Change to match you path
Import-Module E:\PsMON\netapp\DataONTAP.psd1
Connect-NaController $Filer -Credential root

$matrix = @()
$doit = $True

$timer = 10

$LastHour = (Get-Date -format "HH")

while($doit){
  $ThisHour = (Get-Date -format "HH")
  $tSysStat = Invoke-NaSysstat -Count 1 | Select
  $tSysStat
  $matrix += $tSysStat
  If($ThisHour -ne $LastHour){
    $outFile = $filer + "_" + (Get-Date -format "yyyy-MM-dd_HHmm") + ".csv";
    $Matrix | Export-Csv $outFile -NoTypeInformation;$matrix = @();
    "-$outFile-"
  }
  $LastHour = $ThisHour

  For($i=0;$i-le $timer;$i++){Sleep 1 }
}

$outFile = $filer + "_" + (Get-Date -format "yyyy-MM-dd_HHmm") + ".csv";$Matrix | Export-Csv $outFile -NoTypeInformation

Exchange Server 2010 Group Usage with Windows Powershell

#MsExchange #IAMMEC

So I have been running some discovery scripts on an M&A and wanted to check DL’s and when they were last used.  Came up with this ..

$days = 90
Set-ADServerSettings -ViewEntireForest:$true
$results = Get-TransportServer | get-messagetrackinglog -eventid expand -resultsize unlimited -start (get-date).addDays(-$days) | sort timestamp -desc
$results.count

IF(![string]::IsNullOrEmpty($results)) {
  $report = @()
  $lists = @()
  $data = $results | group relatedrecipientaddress | sort name
  $lists = get-distributiongroup -resultsize unlimited | Select Alias, primarysmtpaddress, Name, RecipientType, OrganizationalUnit, @{Expression={""};Label="Count"}, @{Expression={""};Label="LastUsed"}
  $lists += Get-DynamicDistributionGroup -ResultSize unlimited | Select Alias, primarysmtpaddress, Name, RecipientType, OrganizationalUnit, @{Expression={""};Label="Count"}, @{Expression={""};Label="LastUsed"}
  $lists = $lists | sort alias
  foreach ($list in $lists) {
    $check = $null
    $check = $data | ?{$_.name -like "$($list.primarySMTPaddress.tostring())"}
    if ($check) {
      $List.Count = $Check.Count
      $List.LastUsed = ($check | select -expand group | select -first 1).TimeStamp
    }
  }
}

$lists | Export-csv GroupsWithUsage.csv -NoTypeInformation -Encoding  Unicode

Enjoy

#MsExchange 2010 Get-MailboxDatabaseCopyStatus

So Tony Redmond gave me a blank look when I spoke to him for like 30 seconds at MEC, but this little code snippet is featured on PG 491 of Microsoft Exchange 2010 Inside Out.

I use this a lot, and have it wrapped in to a .ps1. Just discovered that like Get-ExchangeServer you can pipe an array of objects to Get-MailboxDatabase. So you could say run:

"db01","db02" | Get-MailboxDatabase
Now that is cool. I have an issue at the moment where some Donkey thought it would be a good idea to reseed two 600GB databases (We use NetApp storage so there is a better way to do it!). I wanted a way to keep an eye on them so I updated the original script.

Do you can use the -database switch like this to get the database copy status for db01 and db04
 .\Check-DatabaseCopyStatus.ps1 -Database @("db01","db04")

-and you could you the server switch to get the database copy status for db01 and db04 just on ex1
 .\Check-DatabaseCopyStatus.ps1 -Database @("db01","db04") -Server ex1

Enjoy
PARAM([String]$Server="", [String[]]$Database = "*")
If($server -ne ""){$srvtxt=$server;$Server="\" + $server.ToUpper()}ELSE{$srvTxt="All"}
Write-Host "Server:" $srvtxt "`nDatabase:"$Database "`n"

##########################################################################################
#Load the Exchange 2010 bits & bobs
#########################################################################################
$xPsCheck = Get-PSSnapin | Select Name | Where {$_.Name -Like "*Exchange*"}
If ($xPsCheck -eq $Null) {Write-Host "Loading Exchange Snapin"; Add-PsSnapin Microsoft.Exchange.Management.PowerShell.e2010}

$Database | Get-MailboxDatabase | Sort Name | FOREACH {$db=$_.Name; $xNow=$_.Server.Name ;$dbown=$_.ActivationPreference| Where {$_.Value -eq 1}; Write-Host $db "on" $xNow "Should be on" $dbOwn.Key -NoNewLine; If ( $xNow -ne $dbOwn.Key){Write-host " WRONG" -ForegroundColor Red; }ELSE{Write-Host " OK" -Foregroundcolor Green};Get-MailboxDatabaseCopyStatus $db$Server;"`n"}

Download it from here

#Powershell and #NetApp SnapDrive

I blogged this script earlier, but discovered an undocumented feature where the last entry in the output was not added to the array object.  Here is the updated version

Write-Host "Running sdcli disk list"
$diskInfo = Invoke-Expression "sdcli disk list"
$sdclidisks  = @()

$fields  = "UNCPath","LUNPath","StorageSystem","StorageSystemPath","Type","Diskserialnumber","BackedbySnapshotCopy"
$fields += "Shared","BootOrSystemDisk","SCSIport","Bus","Target","LUN","Readonly","Size","SnapmirrorSource","SnapvaultPrimary"
$fields += "DiskPartitionStyle","CloneSplitRestorestatus","DiskID","VolumeName","Mountpoints","IPAddresses","FCinitiatorWWPN"
ForEach($Item in $DiskInfo){
  $tmpItem = $Item.Trim()
  $tmpItemSplit = $tmpItem.Split(":")
  Switch -Wildcard ($tmpItem){
    "The operation completed successfully.*" {$sdclidisks  += $sdcliDiskList}
    "UNC Path:*"  {$sdclidisks  += $sdcliDiskList
                   $sdcliDiskList = "" | Select $fields
                   $sdcliDiskList.UNCPath = $tmpItemSplit[-1]}

    "LUN Path:*"                   {$sdcliDiskList.LUNPath                 = $tmpItemSplit[-1]}
    "Storage System:*"             {$sdcliDiskList.StorageSystem           = $tmpItemSplit[-1].trim()}
    "Storage System Path:*"        {$sdcliDiskList.StorageSystemPath       = $tmpItemSplit[-1].trim()}
    "Type:*"                       {$sdcliDiskList.Type                    = $tmpItemSplit[-1].trim()}
    "Disk serial number:*"         {$sdcliDiskList.Diskserialnumber        = $tmpItemSplit[-1].trim()}
    "Backed by Snapshot Copy:*"    {$sdcliDiskList.BackedbySnapshotCopy    = $tmpItemSplit[-1].trim()}
    "Shared:*"                     {$sdcliDiskList.Shared                  = $tmpItemSplit[-1].trim()}
    "BootOrSystem Disk:*"          {$sdcliDiskList.BootOrSystemDisk        = $tmpItemSplit[-1].trim()}
    "SCSI port:*"                  {$sdcliDiskList.SCSIport                = $tmpItemSplit[-1].trim()}
    "Bus:*"                        {$sdcliDiskList.Bus                     = $tmpItemSplit[-1].trim()}
    "Target:*"                     {$sdcliDiskList.Target                  = $tmpItemSplit[-1].trim()}
    "LUN:*"                        {$sdcliDiskList.Lun                     = $tmpItemSplit[-1].trim()}
    "Readonly:*"                   {$sdcliDiskList.Readonly                = $tmpItemSplit[-1].trim()}
    "Size:*"                       {$sdcliDiskList.Size                    = $tmpItemSplit[-1].trim()}
    "Snapmirror Source:*"          {$sdcliDiskList.SnapmirrorSource        = $tmpItemSplit[-1].trim()}
    "Snapvault Primary:*"          {$sdcliDiskList.SnapvaultPrimary        = $tmpItemSplit[-1].trim()}
    "Disk Partition Style:*"       {$sdcliDiskList.DiskPartitionStyle      = $tmpItemSplit[-1].trim()}
    "Clone Split Restore status:*" {$sdcliDiskList.CloneSplitRestorestatus = $tmpItemSplit[-1].trim()}
    "DiskID:*"                     {$sdcliDiskList.DiskID                  = $tmpItemSplit[-1].trim()}
    "Volume Name:*"                {$sdcliDiskList.VolumeName              = $tmpItemSplit[-1].trim()}
    "*Mount points:*"              {$sdcliDiskList.Mountpoints             = $tmpItem.Split("`t")[-1].trim()}
    "IP Addresses:*"               {$sdcliDiskList.IPAddresses             = $tmpItemSplit[-1].trim()}
   "FC initiator WWPN:*"           {$sdcliDiskList.FCinitiatorWWPN         = $tmpItem.Split("`t")[-1].trim()}
  }
 }

$sdclidisks = $sdclidisks | where {$_.DiskID -ne $Null}

Now you have $sdclidisks you can say export to csv.

Download

Enjoy

#Powershell and Get-ExchangeServer

#IAMMEC

Now that is cool.  Been playing with the cmdlet Get-ExchangeServer.  I wanted to get a group of different server names in one go, without having the run the cmdlet multiple times.

So I thought I would try and chuck an array at Get-ExchangeServer and see what it does?  It only bloody works ;-)

$s=@()
$s +="MyServers*"
$s += "Exch*"
$s | Get-ExchangeServer

Neat trick, and you can also pass arrays in as a script parameter too.  Found this: http://santoshbenjamin.wordpress.com/2008/09/30/powershell-and-arrays-as-named-parameters/

The key for a script or function parameter is [String[]]$Server=”*”

I Like it ALOT!