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"
}