Archive for the ‘Exchange 2003’ Category
PoshBoard – Powershell and Silverlight Web Portal
I have started to look at performance and charge back visualization options for my environment. The final result would be a web portal/dashboard providing visual data for my peers and management. I have been following a project on “CodePlex” called “PoshBoard” by Antoine Habert.
The author Antoine Habert describes it as a,
“PowerShell Dashboard is a modular IT web portal based onPowerShell and Silverlight controls”
I will be starting to look at “PoshBoard” and will be posting my progress, I am really impressed with this project.
Links:
Site: http://www.poshboard.com/
Author “Antoine Habert” Blog: http://www.devinfra.blogspot.com/
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
AD and Kerberos Token Bloat – Analyzing Group Nesting
How To: Analyze Nested AD Groups.
I am working on a Kerberos Token size issue (Token Bloat) and need to accurately depict a groups nested members for token size analysis and remediation.
Brief Token Bloat Explanation:
Token Bloat is where due to several factors including deep group nesting the Kerberos token utilized in AD for resource authentication bloats towards the set limit or even beyond. This can cause larger logon times to resources and even issues in applications like Exchange 2003 that can only exist on a 32Bit OS.
I came across this article on the “Microsoft Active Directory Group PowerShell” blog, it has a great script for analysing nested group memberships. Unfortunately to use the PowerShell script you need to be running Windows 2008 servers for the Active Directory cmdlets to be available. The environment that I required the script for was not W2008 so I converted the script to use the Quest cmdlets available with the Quest Active Roles Management PSSnapIn.
You will need to have these installed before using this script.
The script originally written by the MS AD PowerShell team, provides a visual tree view of the groups and their nested levels, a ‘MaxNestingLevel’ value and a ‘NestedGroupMembershipCount’.
Example:
PS C:\> Get-QADGroupNesting.ps1 group-name
Or
PS C:\> Get-QADGroupNesting.ps1 group-name -ShowTree
The above example not only displays group statistics it also plots the structure of the group in a tree format.
Download Script at PoshCode.org
Code:
##########Copy the below script into a new file called Get-ADGroupNesting.ps1 Param ( [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, HelpMessage="DN or ObjectGUID of the AD Group." )] [string]$groupIdentity, [switch]$showTree ) #Validate Quest PSSnapin is loaded Add-PSSnapin -Name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue $global:numberOfRecursiveGroupMemberships = 0 $lastGroupAtALevelFlags = @() function Get-GroupNesting ([string] $identity, [int] $level, [hashtable] $groupsVisitedBeforeThisOne, [bool] $lastGroupOfTheLevel) { $group = $null $group = Get-QADGroup -Identity $identity -SizeLimit 0 if($lastGroupAtALevelFlags.Count -le $level) { $lastGroupAtALevelFlags = $lastGroupAtALevelFlags + 0 } if($group -ne $null) { if($showTree) { for($i = 0; $i -lt $level - 1; $i++) { if($lastGroupAtALevelFlags[$i] -ne 0) { Write-Host -ForegroundColor Blue -NoNewline " " } else { Write-Host -ForegroundColor Blue -NoNewline "│ " } } if($level -ne 0) { if($lastGroupOfTheLevel) { Write-Host -ForegroundColor Blue -NoNewline "└─" } else { Write-Host -ForegroundColor Blue -NoNewline "├─" } } Write-Host -ForegroundColor Blue $group.Name } $groupsVisitedBeforeThisOne.Add($group.DN,$null) $global:numberOfRecursiveGroupMemberships ++ $groupMemberShipCount = $group.memberOf.Count if ($groupMemberShipCount -gt 0) { $maxMemberGroupLevel = 0 $count = 0 foreach($groupDN in $group.memberOf) { $count++ $lastGroupOfThisLevel = $false if($count -eq $groupMemberShipCount){$lastGroupOfThisLevel = $true; $lastGroupAtALevelFlags[$level] = 1} if(-not $groupsVisitedBeforeThisOne.Contains($groupDN)) #prevent cyclic dependancies { $memberGroupLevel = Get-GroupNesting -Identity $groupDN -Level $($level+1) -GroupsVisitedBeforeThisOne $groupsVisitedBeforeThisOne -lastGroupOfTheLevel $lastGroupOfThisLevel if ($memberGroupLevel -gt $maxMemberGroupLevel){$maxMemberGroupLevel = $memberGroupLevel} } } $level = $maxMemberGroupLevel } else #we've reached the top level group, return it's height { return $level } return $level } } $global:numberOfRecursiveGroupMemberships = 0 $groupObj = Get-QADGroup -Identity $groupIdentity -SizeLimit 0 if($groupObj) { [int]$maxNestingLevel = Get-GroupNesting -Identity $groupIdentity -Level 0 -GroupsVisitedBeforeThisOne @{} -lastGroupOfTheLevel $false Add-Member -InputObject $groupObj -MemberType NoteProperty -Name MaxNestingLevel -Value $maxNestingLevel -Force Add-Member -InputObject $groupObj -MemberType NoteProperty -Name NestedGroupMembershipCount -Value $($global:numberOfRecursiveGroupMemberships - 1) -Force $groupObj | Select-Object Name,DN,MaxNestingLevel,NestedGroupMembershipCount | Format-List }
Hope this helps
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Scanning Active Directory for SMTP Addresses
How To: Scanning Active Directory for SMTP Addresses.
When an object in AD is mail enabled it is assigned an SMTP address. Sometimes these addresses are assigned incorrectly to objects or a requested address is already in use on a object and you need to find the object that it is assigned to. I come across this situation sometimes and the simplest way is to query AD for the SMTP address. The SMTP addresses are stored in an AD attribute called “proxyAddresses” this holds all addresses including SMTP. Using the QUEST PowerShell PSSnapIn, you can query AD for this attribute using an LDAP filter.
Querying AD using Quest cmdlets and LDAP query.
Get-QADObject -LdapFilter "(proxyAddresses=*$Address*)" -IncludedProperties "proxyAddresses"
Using the above command with perform the filter, however you will only pull back the default cached set of attributes for the object so I add the ‘-includeallproperties’ switch to pull all attributes available for the object back into the cache.
I also set the ‘-SizeLimit 0′ so the result set isn’t limited to the standard 1000 returned objects.
The below code turns the basic shell command into a ‘Function’ called ‘Get-ProxyAddress.ps1′.
Instructions:
- Copy the below code into a file called ‘Get-ProxyAddress.ps1′
- Open the PowerShell shell and traverse to the directory that hosts the above file
- Run the script using this syntax, “./Get-ProxyAddress.ps1 address@domain.com”
- address@domain.com being the SMTP address you are searching for.
The output details either that the SMTP address is not found in AD or the below attributes are listed for the object that own the SMTP address.
- Name
- DisplayName
- ObjectClass
- AccountisDisabled
- AccountisLockedOut
- MailNickName
- LegacyExchangeDN
Download Script from PoshCode.org
Code:
Param ( [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, HelpMessage="Enter SMTP address to search for in Active-Directory." )] [string]$objSMTP ) Function Get-ProxyAddresses ([string]$Address){ $objAD = $null $objAD = Get-QADObject -LdapFilter "(proxyAddresses=*$Address*)" -IncludeAllProperties -SizeLimit 0 -ErrorAction SilentlyContinue Write-Output $objAD }#Close Function #Validate Quest PSSnapin is loaded Add-PSSnapin -Name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue #Run Function to search AD for SMTP address $Results = $null $Results = Get-ProxyAddresses -Address $objSMTP | Select-Object Name,DisplayName,ObjectClass,Email,AccountisDisabled,AccountisLockedOut,MailNickName,LegacyExchangeDN -ErrorAction SilentlyContinue IF($Results -eq $null){ Write-Host "" Write-Host "No Object Found with .attribute[proxyAddress] containing $objSMTP."} Else{$Results | Format-List *} #End
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Disconnected Mailboxes in Exchange 2003
I was looking into finding all disconnected/orphaned mailboxes in an Exchange2003 org. Normally I would use either an old VBScript I have or the Exchange 2003 ESM. I thought it would be good to experiment with PowerShell and try to simplify the VBScript that I have.
Below is a PowerShell script that utilizes ADSI to gather all Exchange 2003 servers in your configuration container. Then for each server it utilizes WMI to connect to the Root/MicrosoftExchangeV2 ‘NameSpace’ and the Exchange_Mailbox provider. From there we filter on only mailboxes that the “DateDiscoveredAbscentInDS” property is NOT NULL. That data is then passed through the pipeline to a Select-Object where a custom Hash table is built to display the Server Name of the filtered mailboxes. The filtered mailboxes and the selected data is then passed through the pipeline and exported to a .csv file on the root of C:\ named with the format C:\DisconnectedMailboxes_%Servername%.csv.
Code:
[String]$StrFilter = "(objectCategory=msExchExchangeServer)" $objRootDSE = [ADSI]"LDAP://RootDSE" [String]$strContainer = $objRootDSE.configurationNamingContext $objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = New-object System.DirectoryServices.DirectoryEntry("LDAP://$strContainer") $objSearcher.PageSize = 1000 $objSearcher.Filter = $strFilter $objSearcher.SearchScope = "Subtree" $colResults = $objSearcher.FindAll() ForEach ($objResult in $colResults) { [String]$ServerDN = $objResult.Properties.distinguishedname $objServer = [ADSI]"LDAP://$ServerDN" [String]$Server = $objServer.cn Get-WmiObject -NameSpace Root\MicrosoftExchangeV2 -Class Exchange_Mailbox -Computer $Server | ` Where { $_.DateDiscoveredAbsentInDS -ne $null } | ` Select-Object @{N="Server";E={$_.__Server}},` StorageGroupName,StoreName,MailboxDisplayName,Size,DateDiscoveredAbsentInDS | ` Export-Csv "C:\DisconnectedMailboxes_$Server.csv" -NoTypeInformation }#End ForEach
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Scheduling PowerShell Scripts
Just a quick Post…
Yesterday I had to schedule PowerShell scripts on a Windows 2003 Server, this following technique worked for me but I have not tested it on other OS platform.
Similar to a VBScript in the AT scheduled job you point to a .bat or .cmd file for the Program to run. In this file you have the below code to initialize the script in its shell.
In the .bat or .cmd file you will need the following code.
Powershell -NoLogo -Command "&{C:\Scripts\Posh\Script1.ps1}"
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Exporting 2003 Mailbox Data to CSV
I have been using this code for a while and thought I would post it.
I manage several Exchange 2003 servers, this PowerShell code will allow you to pull Mailbox data from each server into their own .CSV file.
It uses a built Array for the server list and parses the Array to get Mailbox data from each server.
$Mailboxes = $Null $Computers = "Server1","Server2","Server3","Server4" ForEach($Computer in $Computers) { $Mailboxes = Get-WmiObject -NameSpace Root\MicrosoftExchangeV2 -Class Exchange_Mailbox -Computer $Computer $Mailboxes | Export-Csv "C:\Mailboxes_$Computer.csv" -NoTypeInformation }
You can combine this with ADSI code to discover all your Exchange 2003 servers in your Directory.
This would give you Mailbox data on all of your Exchange 2003 servers without the need for a manual Array.
[Array]$ExchSrvs = @("") [String]$StrFilter = “(objectCategory=msExchExchangeServer)” $objRootDSE = [ADSI]“LDAP://RootDSE” [String]$strContainer = $objRootDSE.configurationNamingContext $objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = New-object System.DirectoryServices.DirectoryEntry(”LDAP://$strContainer”) $objSearcher.PageSize = 1000 $objSearcher.Filter = $strFilter $objSearcher.SearchScope = “Subtree” $colServers = $objSearcher.FindAll() ForEach($objServer in $colServers) { [String]$Server = $objResult.Properties.name $ExchSrvs += $Server } $ExchSrvs.Count
Your final script would look something like this.
[Array]$ExchSrvs = @("") [String]$StrFilter = “(objectCategory=msExchExchangeServer)” $objRootDSE = [ADSI]“LDAP://RootDSE” [String]$strContainer = $objRootDSE.configurationNamingContext $objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = New-object System.DirectoryServices.DirectoryEntry(”LDAP://$strContainer”) $objSearcher.PageSize = 1000 $objSearcher.Filter = $strFilter $objSearcher.SearchScope = “Subtree” $colServers = $objSearcher.FindAll() ForEach($objServer in $colServers) { [String]$Server = $objResult.Properties.name $Mailboxes = $Null $Mailboxes = Get-WmiObject -NameSpace Root\MicrosoftExchangeV2 -Class Exchange_Mailbox -Computer $Server $Mailboxes | Export-Csv "C:\Mailboxes_$Server.csv" -NoTypeInformation }
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Searching for DL's with Exchange Expansion Servers
Question:
Do we have any Email enabled groups in Active Directory that have an Exchange 2003 expansion server explicitly specified in its properties and who manages them?
Expansion Server:
“Exchange server dedicated to expanding the members of a specific mail enabled group (distribution list)”
Answer:
So I would need to look at Active Directory for all email enabled distribution lists that have the attribute ‘msExchExpansionServerName’ (which only exists when a group is mail enabled), and that it’s value is not blank. If the attribute is blank the distribution list is set to default which is ‘Any server in the organization’. The value can be viewed on the ‘Exchange Advanced’ TAB on the groups properties in ADUC.
Here is the PowerShell one line command that I used. I am utilizing the Quest Active Roles Management cmdlets.
You will need the following:
- DN, GUID or Canonical Name of the Domain or Container where you wish to search for groups. (The example quotes a DN for the group container)
- Quest Active Roles Management Shell snapin.
Get-QADGroup -SearchRoot 'OU=GrouOU,DC=company,DC=com' -SizeLimit 0 -LdapFilter '(msExchExpansionServerName=*)' -IncludeAllProperties | Select-Object name,msexchexpansionservername,managedby
If you need any assistance in using the Quest Active Roles Management cmdlets see this article.
Note:
I use the ‘-IncludeAllProperties’property of the ‘Get-QADGroup’ cmdlet to ensure the ‘msExchExpansionServerName’ attribute is returned into the local cached object result set, by default this would not be returned, for more information see this article..
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Populating Outlook forms with AD User Attributes
Did you ever want an Custom Outlook Form to automatically populate a Custom Outlook Field with the Active Directory .displayName of the logged on user?
The code below populates the custom Outlook Fields “LOUDisplay”,”LOUGivenName”,”LOUSN” upon the creation of the Form.
This action does not repeat if the item is re-opened. This is restricted because the code is initiated only when the Item_Open() event occurs and Item.size = “0″ or newly generated. You will have to add this code in the Visual Basic part of the Custom Form.
Function Item_Open() If Item.Size = "0" Then 'Item is New Set objSysInfo = CreateObject("ADSystemInfo") objUser = objSysInfo.UserName Set ADOUser = GetObject("LDAP://"&objUser) StrDisplayName = ADOUser.displayName StrGivenName = ADOUser.givenName StrSN = ADOUser.SN Item.UserProperties("LOUDisplay") = StrDisplayName Item.UserProperties("LOUGivenName") = StrGivenName Item.UserProperties("LOUSN") = StrSN Else 'Item Exists End If End Function
If you want any other properties for the logged on user accessing the Form just add to the fields pulled from ADUser and link to the required custom field.
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Scheduling ExMON Traces in Exchange 2003
When monitoring Mapi Client statistics, having to manually run the traces can be a troublesome.
After some investigation I found a way to schedule the EXMON traces using a tool called “Tracelog.exe” which is part of the W2000 Resource Kit.
Windows 2000 Resource Kit: Tracelog
Exchange User Monitor: ExMON
For this posting I will assume you have EXMON installed and have also run the installation for the Windows 2000 Resource Kit tool “TraceLog” found above.There are obviously several ways you can both schedule and manipulate the Exchange traces. For me the simplest is to create a folder, preferably on another local disk not your “system” drive. In the folder place both the “tracelog.exe” from the tracelog installation folder and a copy of the “.guid” file from the EXMON application folder.
Once created you can then proceed to create the Schedule jobs in the AT Scheduler.
You will need to create two scheduled jobs, one to start the trace and one to stop the trace.
Start Trace Command:
Tracelog.exe -start [sessionid] -guid [GUID file location] -f [Trace file location]
E.g.
TRACELOG.EXE -start "Exchange Trace" -guid guid.txt -f Trace.etl
Stop Trace Command:
Tracelog.exe -stop [sessionid]
E.g.
TRACELOG.EXE -stop "Exchange Trace"
Utilizing the above command in scheduled jobs, will enable you to schedule captures of Exchange User/Client Mapi session information. I normally embed the commands in batch files and add commands to rename and move the capture files off the DAS on the physical system. This will eliminate the need to keep track of the files and move them to prevent disks usage issues.
E.g.
In a command file you could have the following commands to stop a trace, rename and move a file.
TRACELOG.EXE -stop "Exchange Trace"Rename D:\trace.etl \\Remote\Server_EXMON-%date:~4,2%-%date:~7,2%-%date:~10,4%.etl
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
Getting Exchange 2003 Database Statistics
I routinely analyze Exchange 2003 stores. To do this I previously had written a VB script that dumps all the mailboxes on an Exchange 2003 server using the Exchange_Mailbox WMI class, but as this is a PowerShell article i hear you say “How does this help me?”.
I use PowerShell more and more I really enjoy the simplicity and power of the PowerShell cmdline. So I started to look into producing some clean one liners or small scripts to produce something similar to my large VB script solution.
Note: In all examples below just replace “Server” with an Exchange 2003 server name.
Getting all Exchange 2003 Mailboxes on a single server using WMI,
GWMI -NameSpace Root\MicrosoftExchangeV2 -Class Exchange_Mailbox -ComputerName $Server | Export-CSV "C:\Scripts\Mailboxes.csv" -NoTypeInformation
The next step is to start filtering the output to get detailed information on trouble spots, for example to look for any mailboxes that contain more than ’5000′ items.
To find these we use the ‘.totalItems’ property of the ‘Exchange_Mailbox’ class.
Getting all Exchange 2003 Mailboxes on a single server that have more than 5000 ‘Items’,
GWMI -NameSpace Root\MicrosoftExchangeV2 -Class Exchange_Mailbox -ComputerName $Server | Where{$_.totalitems -gt '5000'} | Export-CSV "C:\Scripts\Mailboxes.csv" -NoTypeInformation
Another WMI ‘Exchange_Mailbox’ class property I use is the ‘.DateDiscoveredAbsentInDS’ this tells me the date the mailbox was disconnected/deleted from the User Object in AD. If for any reason you do not want the store to clean up these automatically you can script the purge of the mailboxes using VBScript or PowerShell. The below code will enable you to see the mailboxes that are ready to be purged but will take no action.
Getting all Exchange 2003 Mailboxes that have been deleted (disconnected from their AD User object) and are ready to be ‘Purged’ on a single server,
GWMI -NameSpace Root\MicrosoftExchangeV2 -Class Exchange_Mailbox -ComputerName $Server | Where{$_.DateDiscoveredAbsentInDS -ne $NULL} | Export-CSV "C:\Scripts\Mailboxes.csv" -NoTypeInformation
Another part to the Exchange Mailbox is the counterpart attributes held in the User object. Some of these attributes are the status of the Mailbox, for example “Is the user over his/her set limits?” or “Is the account disabled in AD?”. To find out the answers here we need to interrogate the user object attribute values. To do this there are many methods depending upon the version of PowerShell you are using and if you have the Quest Management tools loaded. In the example below i am utilizing the Quest Management Tools.
Hope this helps.
All information is provided on an AS-IS basis, with no warranties and confers no rights.
