Monday, May 13, 2013
Dump Exchange mailbox permissions
A complete script to first dump all exchange mailboxes to .csv and then enumerate all mailbox permissions.
It uses the Exchange 2010 management shell and Quest’s Active Directory Powershell modules.
Usage:
- Load the script in the ISE editor.
- Set the two global parameters
- Run the script
- first execute: dump_mailboxes (this wil generate a .csv with all mailboxes)
- then execuite: dump_all_mailbox_permission (this will generate a second .csv with all permissions. Open in Excel to filter)
echo "-" $global_ad_domain = "AD.CUSTOMER.LOCAL" $global_ad_short = "AD" ### Load Modules for Active Directory and Exchange 2010 if (!($QUEST_LOADED)) { Add-PSSnapin Quest.ActiveRoles.ADManagement Set-QADPSSnapinSettings -DefaultSizeLimit 0 $logged_on_to = $env:USERDNSDOMAIN if (!($logged_on_to -eq "$global_ad_domain")) { $user = read-host "Enter username in adusername format" $pw = read-host "Enter password" -AsSecureString connect-QADService -service '$global_ad_domain' -ConnectionAccount $user -ConnectionPassword $pw } else { connect-QADService } Set-QADProgressPolicy -ShowProgress $false $QUEST_LOADED=$TRUE echo "quest loaded" } if ($EMS_loaded -eq $NULL) { . 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1' echo "- Exchange Management Shell Loaded" Connect-ExchangeServer -auto $EMS_loaded = $true echo "- Exchange Management Shell Connected" } ### Functions function dump_mailboxes { $output_file = "d:\temp\mailboxes.csv" echo "Name`tAlias" >$output_file # $mailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox $mailboxes = Get-Mailbox -resultsize Unlimited foreach ($mailbox in $mailboxes) { $Name = $mailbox.Name $Alias = $mailbox.Alias echo "$Name`t$Alias" >>$output_file } } function dump_all_mailbox_permission { $output_file = "d:\temp\mailbox_permissions.csv" $lijst = import-csv -delimiter "`t" d:\temp\mailboxes.csv $aantal = $lijst.count $teller = 0 write-host "Aantal functionele mailboxen: $aantal" echo "Mailbox`tAuthType`tGroup`tSam`tType" >$output_file foreach ($regel in $lijst) { $teller++ $Alias = $regel.alias write-host "$teller / $aantal -> $Alias" mailbox_permissions $Alias >>$output_file } } function mailbox_permissions($mailbox) { if ($perms = get-mailboxpermission -identity "$mailbox" | where {($_.isinherited -eq $false) -and ($_.User -like "$global_ad_short\*")}) { foreach ($perm in $perms) { $usr = $perm.User.tostring() $typeusr = (get-qadobject -identity $usr -DontUseDefaultIncludedProperties).type $usr = $usr.replace("$global_ad_short","") $rights = $perm.AccessRights if ($typeusr -eq "group") { $members = get-qadgroupmember -identity "$usr" foreach ($member in $members) { $mbmrsam = $member.samaccountname echo "$mailbox`t$typeusr`t$usr`t$mbmrsam`t$rights" } } else { echo "$mailbox`t$typeusr`t`t$usr`t$rights" } } } } echo "-"
Wednesday, April 27, 2011
Exchange 2010 SP1 anonymous relay
A common usecase for the need of open relays are MFC’s (”Copiers”) because people need to scan documents and want to mail them directly to recipients on the internet.
Never apply the following to your normal connector for mailflow, as your mailserver will most certainly be used to send spam!
Create a new receive connector (Server configuration, Hub Transport) and make sure it’s bindings don’t conflict with other connectors. The name for the connector could be something like “Relay Connector MFC’s” and make sure you add the right ip-addresses or ranges.
To grant the relay access, the following line will do the trick:
Get-ReceiveConnector "Relay Connector MFC's" | Add-ADPermission -User "NT AUTHORITY\ANONYMOUS LOGON" -ExtendedRights "Ms-Exch-SMTP-Accept-Any-Recipient"
Thursday, March 3, 2011
exchange 2003 powershell - forwarding
Because i need to maintain lots of Exchange 2003 servers and there are no Exchange 2003 powershell modules, i’m writing my own.
Here’s a piece of code that handles the forwarding of mail for users.
As you know, forwarding mail for a mailbox/user involves creating a contact with an external smtp address in Active Directory. Next, that contact can be assigned to the mailbox and a forwarding mode can be selected.
This script will handle all of those functions for you.
The script uses two global variables (customize to match your own Active Directory and/or place where you want to create these forwarding contacts):
$FQDN=",DC=netherlands,DC=europe,DC=microsoft,DC=com" $base_security_groups_container="CN=Users"
Here’s the code:
function set_forward_mail($username, $forwarding_mode, $forwarding_address) { # forwarding_mode # 0 = forwarding disabled # 1 = forward without local delivery # 2 = forward with local delivery if ($forwarding_mode -eq "2") { if (!(get-qadobject -identity "$username (forwarded by PowershellApp)")) { # contact doesn't exist (yet). Create now New-QADObject -ParentContainer "$base_security_groups_container$FQDN" -type "contact" -name "$username (forwarded by PowershellApp)" -DisplayName "$username (forwarded by PowershellApp)" -ObjectAttributes @{Description="$username (forwarded by PowershellApp)";mail="$forward_address";targetAddress="SMTP:$forwarding_address";mailNickname="$username"+"_forwarded_by_PowershellApp";msExchHideFromAddressLists=$true} # Recipient Update Service will do the rest. # Set the forwarding mode, type 2 $forward_user_dn = (Get-QADObject -identity "$username (forwarded by PowershellApp)" | Select-Object dn).dn set-qaduser -identity $username -objectAttributes @{deliverAndRedirect=$true;altRecipient=$forward_user_dn} } else { # contact DOES exist. Update set-qadobject -identity "$username (forwarded by PowershellApp)" -ObjectAttributes @{Description="$username (forwarded by PowershellApp)";mail="$forward_address";targetAddress="SMTP:$forwarding_address";mailNickname="$username"+"_forwarded_by_PowershellApp";msExchHideFromAddressLists=$true} # clear any old addresses in the list of addresses and make the new one primary get-qadobject -identity "$username (forwarded by PowershellApp)" | Clear-QADProxyAddress | Add-QADProxyAddress -Address "SMTP:$forwarding_address" -Primary # make sure the forwarding mode is correct, type 2 $forward_user_dn = (Get-QADObject -identity "$username (forwarded by PowershellApp)" | Select-Object dn).dn set-qaduser -identity $username -objectAttributes @{deliverAndRedirect=$true;altRecipient=$forward_user_dn} } } if ($forwarding_mode -eq "1") { if (!(get-qadobject -identity "$username (forwarded by PowershellApp)")) { # contact doesn't exist (yet). Create now New-QADObject -ParentContainer "$base_security_groups_container$FQDN" -type "contact" -name "$username (forwarded by PowershellApp)" -DisplayName "$username (forwarded by PowershellApp)" -ObjectAttributes @{Description="$username (forwarded by PowershellApp)";mail="$forward_address";targetAddress="SMTP:$forwarding_address";mailNickname="$username"+"_forwarded_by_PowershellApp";msExchHideFromAddressLists=$true} # Recipient Update Service will do the rest. # Set the forwarding mode, type 2 $forward_user_dn = (Get-QADObject -identity "$username (forwarded by PowershellApp)" | Select-Object dn).dn set-qaduser -identity $username -objectAttributes @{deliverAndRedirect=$false;altRecipient=$forward_user_dn} } else { # contact DOES exist. Update set-qadobject -identity "$username (forwarded by PowershellApp)" -ObjectAttributes @{Description="$username (forwarded by PowershellApp)";mail="$forward_address";targetAddress="SMTP:$forwarding_address";mailNickname="$username"+"_forwarded_by_PowershellApp";msExchHideFromAddressLists=$true} # clear any old addresses in the list of addresses and make the new one primary get-qadobject -identity "$username (forwarded by PowershellApp)" | Clear-QADProxyAddress | Add-QADProxyAddress -Address "SMTP:$forwarding_address" -Primary # make sure the forwarding mode is correct, type 2 $forward_user_dn = (Get-QADObject -identity "$username (forwarded by PowershellApp)" | Select-Object dn).dn set-qaduser -identity $username -objectAttributes @{deliverAndRedirect=$false;altRecipient=$forward_user_dn} } } if ($forwarding_mode -eq "0") { if (!(get-qadobject -identity "$username (forwarded by PowershellApp)")) { # contact doesn't exist, just disable forwarding set-qaduser -identity $username -objectAttributes @{deliverAndRedirect=$false;altRecipient=""} } else { # contact DOES exist. disable forwarding and delete contact set-qaduser -identity $username -objectAttributes @{deliverAndRedirect=$false;altRecipient=""} Remove-QADObject -identity "$username (forwarded by PowershellApp)" -Force } } }
Wednesday, December 22, 2010
exchange 2003 powershell - create mailbox
As i told before, it’s not that easy to make changes with powershell to your Exchange 2003 environment as it is nowadays with Exchange 2010.
Since it was pretty hard to read certain values from Active Directory, i’m doing a pretty nasty trick: copy the values from an existing user.
Here’s how to create a mailbox for an existing user:
function add_exchange2003_mailbox_for_user($username) { # to keep it simple: let's copy the properties of a template user, e.g. Administrator, and create the mailboxes in the same database $template_user = "Administrator" $userproperties = get-qaduser -identity $template_user -IncludeAllProperties set-qaduser -identity $username -objectAttributes @{msExchHomeServerName=$userproperties.MsExchHomeServerName} set-qaduser -identity $username -objectAttributes @{mailnickname="$username"} set-qaduser -identity $username -objectAttributes @{mDBUseDefaults='TRUE'} set-qaduser -identity $username -objectAttributes @{homeMBD=$userproperties.homeMDB} # now the Recipient Update Service will do the rest ... }
exchange 2003 powershell - add primary address
When you’re making changes to your active directory or exchange environment with powershell, it’s a piece of cake with Windows 2008 R2 and/or Exchange 2010. All the cmdlets are there by default.
But when you’re dealing with Windows 2003 and/or Exchange 2003, it’s a whole different story.
I will be posting some of my scripts for Windows 2003 and Exchange 2003 from now on.
Because Windows 2003 has no active directory powershell module, i’m using the Quest AD Templates for that purpose (highly recommended!).
Here’s how to change the primary address for an exchange 2003 user:
function set_exchange2003_primary_address($username, $primary_smtp_address) { # lowercase the to-be-added address $primary_smtp_address = $primary_smtp_address.ToLower() # get current addresses $userinfo = get-qaduser -identity $username $new_proxyaddresses = $userinfo.ProxyAddresses # lowercase all the "SMTP:" entries foreach ($number in 0..($new_proxyaddresses.Count - 1) ) { $address = $new_proxyaddresses[$number] $new_proxyaddresses[$number]=$address.Replace("SMTP:", "smtp:") } # Next, check if the to-be-added address is allready in the list $allready_in_list = $FALSE foreach ($number in 0..($new_proxyaddresses.Count - 1) ) { $address = $new_proxyaddresses[$number].ToLower() $check = $address.CompareTo("smtp:$primary_smtp_address") if ($check -eq 0) { # address is found in the list. Make it PRIMARY $new_proxyaddresses[$number]=$address.Replace("smtp:", "SMTP:") $allready_in_list = $TRUE } } # But if it's not found, add the new adress to the list as primary if ($allready_in_list -eq $FALSE) { $new_proxyaddresses += 'SMTP:'+$primary_smtp_address } # now write the addresses to active directory set-qaduser -identity $username -objectAttributes @{ProxyAddresses=$new_proxyaddresses} }
Hmm..
Guess I should have payed more attention… Why not do this:
function set_exchange2003_primary_address($username, $primary_smtp_address) { get-qaduser -identity $username | Add-QADProxyAddress -Address $primary_smtp_address -Primary }
Thursday, November 11, 2010
renew a self-signed ssl certificate on exchange 2007
To renew a self-signed ssl certificate on an Exchange 2007 server:
Start the Exchange Management Shell, then:
Get-ExchangeCertificate -DomainName CAS01.contoso.com
Find the certificate that contains a “W” from the list of certificates For example, select IP.WS. The “W” indicates that the certificate is assigned to IIS.
Then to clone the certificate, run the following cmdlet (the thumbprint is unique):
Get-ExchangeCertificate -Thumbprint c4248cd7065c87cb942d60f7293feb7d533a4afc | New-ExchangeCertificate
The new cloned certificate will then be stamped with a new expiration date one year after the date you run the cmdlet.
And last but not least: assign the certificate to a service:
Enable-ExchangeCertificate -Thumbprint c4248cd7065c87cb942d60f7293feb7d533a4afc -Service IIS
Monday, November 1, 2010
Export .pst files in Exchange 2010 SP1
In addition to the import procedures, here’s how to export to .pst files:
Add an import to the queue:
New-MailboxExportRequest -Mailbox p.puk -FilePath "\\FS01\data\Backup Mailbox (PST)\p.puk.pst"
And status:
Get-MailboxExportRequest
Friday, October 29, 2010
Import .pst files in Exchange 2010 SP1
SP1 for Exchange 2010 has a new approach for importing .pst files.
First of all make sure the group “Exchange Trusted Subsystem” has NTFS permissions on the folder which contains all the .pst files.
Second, make sure this folder has been shared. Exchange only accepts unc paths.
Third, you have to make a new role assignment to a security group.
Create a universal group called “Mailbox Import Export Access” in active directory and add the user who’s going to do the export. Next, from the Exchange Management Shell:
New-ManagementRoleAssignment -Name "Mailbox Import Export Access" -SecurityGroup "Mailbox Import Export Access" -Role "Mailbox Import Export"
All the preparations have been made.
To queue (yes queue!) the import for a user:
New-MailboxImportRequest -Mailbox p.puk -FilePath "\\FS01\data\Backup Mailbox (PST)\p.puk.pst"
You can repeat the line for other users or pipe a list of users to build a bigger queue.
The following command shows the queue and the status of all imports:
Get-MailboxImportRequest
or
get-mailboximportrequest | fl filepath,status
One drawback so far:
I haven’t been able to find a way to set the locale by default (was possible with non-SP1 by typing
-locale "nl-NL"
for Dutch users) which is really annoying since users will end up with “Inbox” instead of “Postvak In”, “Sent Items” instead of “Verzonden Items”, etc.
This can be overcome by logging in to the webmail before starting the import and set the default language from there (first question asked when logging in). But that’s still annoying.
Update 2011/03/25
I haven’t been able to test it yet but running the following command prior to the import might do the trick ….
Set-MailboxRegionalConfiguration p.puk -Language "nl-NL" -DateFormat "dd-MM-yyyy" -LocalizeDefaultFolderName:$true
or for all mailboxes
get-mailbox | set-mailboxregionalconfiguration -Language nl-NL -DateFormat "dd-MM-yyyy" -LocalizeDefaultFolderName:$true
Wednesday, September 1, 2010
powershell - import .pst files in exchange 2010 (pt2)
In addition to the previous article, you might want to add your default locale to the import-mailbox command.
e.g.
import-mailbox -identity "hugo" -pstfolderpath "c:\pstfiles" -locale "nl-NL"
Otherwise annoying duplicate folders like Inbox/Postvak IN, Calendar/Agenda, Drafts/Concepten, etc will appear.
Wednesday, August 25, 2010
powershell - import .pst files in exchange 2010
I haven’t figured out how to get proper resultcodes or errorhandling from the “Import-Mailbox” command, but you can use your transcript file for that. See my other post for that.
You’ll need some global vars, e.g.:
$your_import_file="c:\import\import.csv" $folder_with_psts="C:\exmerge\primary database export files"
Then it’s as simple as this:
function import_mailboxes() { $UserDetails=Import-Csv -delimiter ";" $your_import_file $count=0 $found=0 $notfound=0 foreach($UD in $UserDetails) { $count++ $username=$UD.Code.ToLower() $full_path_to_pst=$folder_with_psts + $username + ".pst" $FileExists = Test-Path $full_path_to_pst if ($FileExists) { write-host "$count - $username - Ready to import ($full_path_to_pst)" -ForegroundColor Green $found++ Import-Mailbox -Identity $username -PSTFolderPath $folder_with_psts } else { write-host "$count - $username - No matching pst file found!" -ForegroundColor Red $notfound++ } } write-host "Summary: Found (and hopefully successfully imported): $found, Not Found: $notfound" }