Disabling P2P File Transfers in Lync – and other settings not found in ClientPolicy

We’re rolling out Lync Server 2010, and among other limits on end-user behavior, management wanted a way to prevent most, but not all, users from transfering files from their Lync or Microsoft Office Communicator clients.

Most client-related settings are controlled with Set-CsClientPolicy -Identity "MyAwesomeClientPolicy" -TheSettingName thesettingvalue, then granted to specific users with Grant-CsClientPolicy -PolicyName "MyAwesomeClientPolicy" -Identity SomeHaplessUser

Oddly enough, the right to transfer files or use audio/video in their peer-to-peer chats is not controlled with ClientPolicy, but by ConferencingPolicy. Our Global (that is, default) ConferencingPolicy have, among many other attributes, AllowIPAudio and AllowIPVideo set to False and EnableAppDesktopSharing set to None in order to keep most of the users on the less-expensive Standard Lync Server CALs during our testing period.

To test if “Keith’s” answer to this question in the MS TechNet forums about blocking file transfers for specific users or groups was correct, my colleague first sent a file from a test user with no explicitly-assigned ConferencingPolicy to her Lync user (which does have a more permissive ConferencingPolicy). Success.

I then ran:

Set-CsConferencingPolicy -Identity Global -EnableP2PFileTransfer $false

She signed the test user off and back on, and the test user’s Office Communicator did not display the option to transfer a file to her real account.

She then tried sending that test user a file. Denied!

My colleague was still able to send me a file, and vice versa, because we have the same (generous) conferencing policy, which since it was assigned to us, overrides the settings in the Global policy.

So, if the user has a ConferencingPolicy that has EnableP2PFileTransfer set to False, the user can neither send nor receive files in chat. However, they can still send and receive files in a conference. Set EnableFileTransfer to False to prevent the user from sending or receiving files in a conference he organizes. From cmdlet help for Set-CsConferencePolicy, it appears that he would still be able to send and receive files in a conference someone with EnableFileTransfer=True organized, but we have not tested that yet.

Other things set in CsConferencingPolicy affecting peer-to-peer chats that I thought would be in ClientPolicy:


AudioBitRateKB
EnableP2PRecording
EnableP2PVideo
VideoBitRate

Advertisement

Self-Service User Can’t Add Member to Group, or Error (0x800403fb) Unknown to Anyone

The first thing you should do when you get a weird error code is plug it into your favorite search engine or, with ARS, the ActiveRoles Knowledge Base. This time, there was nothing even vaguely related to ActiveRoles Server when I tried searching for 0x800403fb, so here’s something for the next person who runs into this: the group in question has a member that ActiveRoles Server cannot directly access, and that is likely what is causing your user to have problems maintaining that group.

A Secondary Owner was getting a weird error when he tried adding a new user to one of his groups via the ActiveRoles Server Self-Service web interface. A tech at the Help Desk was getting it, too, so it got referred to me. I took a look at the group in the MMC, and it stopped listing users when it got to 1150 of them. We have some groups with over 5,000 users (I do NOT recommend this), so too many users could not have been the problem. I tried

Get-QADGroupMember ProblemGroupName -SizeLimit 0

and got after about the 1150th result:

Get-QADGroupMember : Unknown error (0x800403fb)
At line:1 char:19
+ Get-QADGroupMember <<<< ProblemGroupName -SizeLimit 0
+ CategoryInfo : NotSpecified: (:) [Get-QADGroupMember], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Quest.ActiveRoles.ArsPowerShellSnapIn.Powershel
l.Cmdlets.GetGroupMemberCmdlet

So, time to look at the members list as plain strings:

$group = Get-QADGroup ProblemGroupName

$group.members
(listed a whole bunch of distinguished names without complaint)

$group.members.count

1165

Ok, so a few more than were being displayed in the GUI.

I skimmed the list until this jumped out:

CN={17656956-4661-41ad-b4dd-0a1d4ff4fccf},CN=Application Contacts,CN=RTC Service,CN=Services,CN=Configuration,DC=root,DC=hld

root.hld is our infrastructure domain, and regular users should not have anything to do with it.

RTC Service is put in the Configuration container when you first install Lync Server, and the creation date of this object aligned pretty well with when we started our Lync deployment.

So, I removed the offending object from the group:

Remove-QADGroupMember -Member 'CN={17656956-4661-41ad-b4dd-0a1d4ff4fccf},CN=Application Contacts,CN=RTC Service,CN=Services,CN=Configuration,DC=root,DC=hld' -Identity ProblemGroupName

And when I redid Get-QADGroupMember ProblemGroupName … no problem 🙂

To make sure the problem object was no longer a group member:

(Get-QADGroup ProblemGroupName).members.count

1164

The help desk tech who referred the problem to me was able to add and remove users without issues, and will be calling the user to close the ticket.

How to Change the Attributes Get-QADUser Returns

Get-QADUser | where {$_.edsaAccountIsDisabled -eq $false} will usually result in disappointment. Why? edsaAccountIsDisabled is a calculated ActiveRoles Server attribute derived from userAccountControl and is not part of the default return set, along with most of the other AD and ARS attributes.

FatBeard wrote a great explanation of this a few years ago in his article, “Where’s my attribute?” He then shows you how to add a single attribute to the default return set. FatBeard’s blog is full of all sorts of PowerShell goodness; unfortunately, he’s not updated it in quite awhile. Go there and tell him to write more posts 🙂

If you want to add more than one attribute, here’s how:


# please note that employeeNumber and homeMDB
# might not be present in your environment.
# edsaAccountIsDisabled is ARS-only.

$attributes = Get-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject
$attributes += @("edsaAccountIsDisabled","employeeNumber","homeMDB","homeDirectory","homeDrive","msRTCSIP-PrimaryUserAddress")
Set-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject $attributes

As FatBeard mentions, this change will only be in effect for the rest of your current session, and if this is an attribute set you want to usually have around, you need to add those limes to your PowerShell profile, after Get-PSSnapIn quest.activeroles.admanagement.

So why not add a whole ton of attributes to the default return set, just so they’re handy? Each attribute you want to pull increases the amount of time it takes AD or ARS to return your results and increases the size of the result set.

Another caveat: once you change the default return set within a session, you cannot go back to the original default return set without opening up a new PowerShell session – unless you saved the “default” default return set before changing it.

Idea: have several return sets available in your profile, oriented around various tasks. For mail, pull more of the Exchange attributes, both msExch-* and edsva-MsExch*. For Lync, the msrtcsip-* attributes. For tracking down a Deprovision/Undeprovision issue, the edsvadepro* and edsvaundepro* sets.

Because I don’t like having to restart PowerGUI in the middle of things, here are the Set-QADPSSnapInSettings related lines from my PowerShell profile:


# Making sure the PSSnapIn for QADMS is loaded

if ( (Get-PSSnapin -Name quest.activeroles.admanagement -ErrorAction SilentlyContinue) -eq $null )
{
    Add-PsSnapin quest.activeroles.admanagement
}

# Connect to ARS; if connecting to native AD domain,
# Connect-QADService -Service my.domain.com

Connect-QADService -Proxy

$defaultQADuserattributes = Get-QADPSSnapInSettings -DefaultOutputPropertiesForUserObject

#Extra attributes I ALWAYS want to load -
#please note that employeeNumber and homeMDB
# might not be present in your environment.
# edsaAccountIsDisabled is ARS-only.
$defaultQADuserattributes += @("edsaAccountIsDisabled","employeeNumber","homeMDB","homeDirectory","homeDrive")
Set-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject $defaultQADuserattributes

# edsva = ARS-only
function Use-QADExchangeUserAttributes {
$attributes = Get-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject
$attributes += @("edsva-msexch-mailboxtypedescription","edsva-msexch-mailboxtypedescription","edsva-msexch-protocolsettings-activesync-enable")
Set-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject $attributes
}

function Use-QADLyncUserAttributes {
$attributes = Get-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject
$attributes += @("msrtcsip-line","msrtcsip-internetaccessenabled","msrtcsip-federationenabled","msRTCSIP-UserPolicy")
Set-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject $attributes
}

# ARS-only
function Use-QADDeprovisionUserAttributes {
$attributes = Get-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject
$attributes += @("edsvaDeprovisionCommands","edsvaDeprovisionDeletionDate","edsvaDeprovisionReportXML","edsvaDeprovisionStatus","edsvaUnDeprovisionCommand","edsvaUnDeprovisionReportXML","edsvaUnDeprovisionStatus")
Set-QADPSSnapinSettings -DefaultOutputPropertiesForUserObject $attributes
}

function Use-QADDefaultUserAttributes {
Set-QADPSSnapInSettings -DefaultOutputPropertiesForUserObject $defaultQADuserattributes
}

Note that if I do Use-QADExchangeUserAttributes and then Use-QADLyncUserAttributes without a Use-QADDefaultUserAttributes in between, I’ll get both extra sets of attributes added to the return set.

Have a nice attribute set you’d like to share? Done something clever for working with groups? Post it, or a link to your blog, in the comments!

Set-CalendarProcessing -ResourceDelegates (and Friends) Without Tears

(Get-CalendarProcessing -Identity “MyAwesomeRoom”).ResourceDelegates is equal to (Get-Mailbox -Identity “MyAwesomeRoom”).GrantSendOnBehalfTo. This is good to know, because while you can do Set-Mailbox -GrantSendOnBehalfTo @{add=”user3@awesome.com”} and not kick out user1 and user2, Set-CalendarProcessing does not do this. If you try it, you get back this mess:

Cannot process argument transformation on parameter ‘ResourceDelegates’. Cannot convert the “System.Collections.Hashtable”
value of type “System.Collections.Hashtable” to type “Microsoft.Exchange.Configuration.Tasks.RecipientIdParameter[]”.

Unfortunately, I have yet to find a similar, more friendly route for adding BookInPolicy, RequestInPolicy or RequestOutOfPolicy.

All of these parameters will take an array, so you need to read in what’s there, append your new delegate(s), then write the new list to Set-CalendarProcessing:

function Add-CalendarResourceDelegate {
Param(
$roomName
, $newDelegate
)
$resourceDelegates = (Get-CalendarProcessing -Identity $roomName).ResourceDelegates
$resourceDelegates += $newDelegate
Set-CalendarProcessing -Identity $roomName -ResourceDelegates $resourceDelegates
}
function Add-CalendarBookInPolicy {
Param(
$roomName
, $newDelegate
)
$bookInPolicy = (Get-CalendarProcessing -Identity $roomName).BookInPolicy
$bookInPolicy += $newDelegate
Set-CalendarProcessing -Identity $roomName -BookInPolicy $bookInPolicy
}

Add-CalendarResourceDelegate -roomName “MyAwesomeRoom” -newDelegate user3

Removing delegates is a bit trickier; they are stored in the array as canonical names (awesome.com/Site1/Users/user1), not email or UserPrincipalName (User.One@awesome.com or user1@awesome.com). However, you just need to do (Get-Mailbox user1).Identity to get this.

function Remove-CalendarResourceDelegate {
Param(
$roomName
, $delegateToRemove
)
$resourceDelegates = (Get-CalendarProcessing -Identity $roomName).ResourceDelegates
$delegateToRemoveIdentity = (Get-Mailbox $delegateToRemove).Identity
$resourceDelegates.Remove($delegateToRemoveIdentity)
Set-CalendarProcessing -Identity $roomName -ResourceDelegates $resourceDelegates
}

And so on for BookInPolicy, RequestInPolicy and RequestOutOfPolicy.

A step closer to extending ActiveRoles Server to handle all the Set-CalendarProcessing attributes…

The publicDelegates AD Attribute: Change GrantSendOnBehalfTo the ARS Way

While the Active Directory object’s publicDelegates attribute matched the contents of (Get-Mailbox “aliasGoesHere”).GrantSendOnBehalfTo for all the resource mailboxes and distribution groups I checked, I hesitated to give the way of modifying publicDelegates directly with ARS instead of using Set-Mailbox -GrantSendOnBehalfTo with Exchange Management Shell in my previous post on this topic. A little more research (and trial and error) shows that indeed, publicDelegates really is what Exchange uses to decide who gets to send stuff on behalf of another mailbox.

Here is a thread from the [ActiveDir] listserv archive in which Joe Richards, an author of the classic O’Reilly Active Directory reference, states that “[t]he stuff in AD is strictly how Send On Behalf is controlled” and goes on to explain how an update bug in Exchange 2003 might prevent a recent change from being propogated to a user in a different domain from the delegated object. Since the conversation took place before Exchange 2007 was on the scene, I was a bit skeptical about its applicability to Exchange 2010.

To see which one of several dozen edsva-MsExch-blahblahblah attributes does this for the ARS connector to Exchange 2010, I used the ARS web interface to add and remove delegates from the “Send on Behalf” list of one of the test room mailboxes (Exchange Properties -> Delivery Options -> (Send on behalf) “Add”), then looked at the Change History for that room mailbox. The publicDelegates attribute was the only item changed. Still, I was concerned: the publicDelegatesBL for the delegates outside the domain of the room mailbox weren’t getting updated.

For comparison, I added some delegates the Exchange way:

Set-Mailbox “Room Name” -GrandSendOnBehalfTo @{add=”username”}

Then the Quest AD Management Shell way:

Set-QADUser -ObjectAttributes @{publicDelegates=@{append=(Get-QADUser username).DN}}

(trying to append the username directly didn’t work; it wants the distinguishedName)

After some more experimentation, I discovered that when a user in an different domain is added to the publicDelegates attribute, the delegated object will not show up in the user’s publicDelegatesBL, whether you use Exchange, Quest AD Management Shell or the ARS web interface, while the change to publicDelegatesBL occurs immediately for delegates within the domain of the delegated object. Cross-domain delegated objects will only show up in a user’s publicDelegatesBL once that user has connected to the object for the first time.

If anyone knows why this is, what trouble it might cause, or better yet, how to fix it, please post a comment. More importantly, if anyone knows of a reason NOT to use publicDelegates instead of GrandSendOnBehalfTo, please let me know. And let the ActiveRoles Server dev team know 🙂

Fun fact about the CalendarProcessing ResourceDelegates attribute: it is equal to a resource mailbox’s GrantSendOnBehalfTo, which is controlled by the AD attribute publicDelegates.

Next step: figuring out how to control the other CalendarProcessing attributes via ARS.

Goal: Complete management of resource mailboxes via ARS.

Post-Migration Deprovision and UnDeprovision Inconsistencies – Solved!

After a few rounds of email with Quest (Dell) support about our somewhat-successful management history migration, I found out that edsvaDeprovisionStatus and its sister edsvaUnDeprovisionStatus are stored in Change History, not Management History, and therefore are not moved by the Management History Migration Wizard. The helpful support engineer, Jose, suggested I try writing edsvaDeprovisionStatus directly. Since I couldn’t write to edsvaDeprovisionReportXml, I assumed that edsvaDeprovisionStatus and edsvaUnDeprovisionStatus were also unwritable. I was wrong.

If we had done this Management History migration in a more timely manner, I could have used Steps 6 and 9 of Matt Hitchcock’s migration process. If I’d paid a bit more attention to those steps, I might have given fiddling with those attributes manually a try earlier.

Since we ran split for over a year, I would do the following to avoid crushing subsequent changes that were made in 6.7 by simply copying over deprovision status from 6.5:

1) Find objects with dubious deprovisioning status in 6.7 and store them in lists.


Get-QADUser -Disabled -SearchAttributes @{DisplayName="Deprovisioned*";edsvaDeprovisionStatus=''} -IncludedProperties edsvaDeprovisionStatus, edsvaUnDeprovisionStatus, edsvaDeprovisionReportXml -SizeLimit 0 | Where { $_.edsvaDeprovisionReportXml -ne $null } | select name, edsvaDeprovisionStatus, edsvaUnDeprovisionStatus | export-csv C:\Temp\Deprovision-Problems.csv -notypeinformation

A lot of objects were “manually” undeprovisioned – enabled, attributes changed, but edsvaDeprovisionStatus was not changed. For reasons unknown to me, the -Enabled flag does not play nice with -SearchAttributes @{edsvaDeprovisionStatus=1}, and the calculated attribute edsaAccountIsDisabled is not searchable server-side. Icky.


Get-QADUser -SearchAttributes @{edsvaDeprovisionStatus=1} -SizeLimit 0 -IncludedProperties edsvaDeprovisionStatus, edsvaUnDeprovisionStatus, edsaAccountIsDisabled | where {$_.edsaAccountIsDisabled -eq $false} | select name, displayName, edsvaDeprovisionStatus, edsvaUnDeprovisionStatus | Export-Csv -NoTypeInformation -Path U:\Temp\UndeprovisionProblems.csv

2) Using those lists, get their edsvaDeprovisionStatus and edsvaUnDeprovisionStatus from 6.5.
3) Write the edsvaDeprovisionStatus and edsvaUnDeprovisionStatus from 6.5 into 6.7, then try deprovisioning/undeprovisioning my test objects.

Continue reading

Deprovision and UnDeprovision Users and Groups with PowerShell

Since I’ve got deprovisioning problems on the brain for some reason, here are a few little things that do work as expected.

Using Quest’s Active Directory Management Shell, connected to ARS (Connect-QADService -Proxy) as a user allowed to deprovision objects, Deprovision-QADUser works like a champ on any user who could be deprovisioned via the ARS MMC or the web interface. However, there is no UnDeprovision-QADUser or UndoDeprovision-QADUser or even Deprovision-QADUser -Undo.

There are also no cmdlets that parallel the Deprovision/Undo Deprovision functions available for groups in the ARS MMC and web interface.

The edsvaDeprovisionType and edsvaUnDeprovision attributes are accessible via the -ObjectSettings parameter of the Set-QADUser and Set-QADGroup cmdlets. So, here’s what I’ve added to my profile to remedy these slight shortcomings of the otherwise amazing QADMS:


# Makes deprovisioning groups by script similar to deprovisioning users.

function Deprovision-QADGroup {
Param($Group)

Get-QADGroup -Identity $Group | Set-QADGroup -ObjectAttributes @{edsvaDeprovisionType=1}

}

# For undeprovisioning groups. Would work the same for undeprovisioning users.

function Undeprovision-QADGroup {
Param($Group)

Get-QADGroup -Identity $Group | Set-QADGroup -ObjectAttributes @{edsvaUnDeprovision=1}

}

# Undeprovision user.

function Undeprovision-QADUser {
Param($User)

Get-QADUser -Identity $User | Set-QADUser -ObjectAttributes @{edsvaUnDeprovision=1}

}

Before you get carried away, remember that what Deprovision-QADGroup actually does is as much up to you or your ARS developer/consultant as the effects of Deprovision-QADUser are; likewise, you have to do a bit of work for what Undo Deprovision does.

ActiveRoles Server Management History Migration Wizard – A Personal Experience

We’re off to see the wizard – the Management History Migration Wizard, that is. As discussed in this previous post, we did not migrate our management history from ARS 6.5 at the same time we started having our admins start managing user accounts with ARS 6.7, and that caused no small amount of annoyance.

Today (Friday) is the day. The test accounts have been created, deprovisioned and in some cases, undeprovisioned. The SQL Server DBA has handed me scripts to back up the ARS databases. I have created Access Template Links so that the admins whose normal write privileges I am suspending this weekend can still unlock accounts and reset passwords. Access Template Links for normal privileges have been disabled. Admins have gotten spammed. Self Service users have seen the bulletin. IIS (w3svc) has been stopped on all the ARS servers.

It is time to do the Management History migration that did not happen earlier, as discussed in a previous post, ……

Quest’s own Knowledge Base gives the vague statement that this could take “in excess of 25 hours”, and I have not found anything more concrete. Therefore, I have allocated 60 hours for ARS to be unavailable.

Our stats:

ARS 6.5 DB: 94 GB, 3.75 million records to import
ARS 6.7 DB: 6 GB
SQL Server 2005, running on Windows Server 2003 (both DBs are in the same instance)

The local backup of the 6.7 DB took less than two minutes; the enormous 6.5 DB took about 20 minutes.

18:32 – And we’re off!

At 21:30, 55% of the first step was finished. At that pace, that part should be over about 00:30.

Saturday:

08:00 – it’s gotten through steps 1-3, and is now 23% through the actual data transfer.
08:05 – 887000
08:10 – 897500 – 10500 record per 5 minutes – 126000 per hour

estimated finish time for data transfer: Sunday, 6:00. Might as well go skiing at this lovely little place in the Bavarian Forest while the Wizard works its magic.

19:00 – Back from skiing; the snow was pretty good, and the Wizard is at 61%. A bit slower than hoped, but still on track for a Sunday morning finish.

Sunday:

10:20 – 81%. Oh, dear – this won’t be done by start of business Monday! My test accounts had their depro history available, but did not offer undo depro. What a disaster. Hmmm…. synthetic undepro using the xml history?
16:00 – 93% (whew), 250000 records to go – might be done around 19:00.
19:37 – DONE, 49 hours after I kicked off the Wizard, and 50 hours after I restricted everyone’s access to ARS and took SQL Server backups. This is exactly twice as long as the “sometimes in excess of 25 hours”, which is the only estimate I could find. So here is a real datapoint: it took 50 hours to import 2 years’ worth of management history for an ARS installation with about 50,000 enabled user accounts and 3.75 million changes.

New ARServer67 DB size: 80 GB. The ARServer65 DB was unchanged.
Just about everything looks to be in order – the deprovision information itself (edsvaDeprovisionReportXML) was brought over and looks right for my test objects, as does the surrounding Change History.

There is still that one fly in the ointment: the edsvaDeprovisionStatus attribute was not changed to 1, and Undo Deprovision is not available in the context menu; Deprovision is. This is disappointing, as this was the main goal of the import (aside from being able to dump the old database and 6.5 server). I’m seriously considering a sort of scripted Undeprovisioning, available for disabled objects with existing edsvaDeprovisionReportXML data.

But before I get into all that, I’ll restart the arssvc on both the 6.7 servers and hope for the best.

21:20 – Doh! No difference.

Monday:
6:00 – Enabled the Access Template Links I disabled Friday at 18:00, restarted w3svc so that the ARS web interface would be available to admins and data owners. Did NOT do the same on ARS 6.5 🙂

So far, no one has reported any funny business, so I’ll count the whole exercise as mostly harmless, even slightly helpful. At least I have the data from 6.5 in the same place as the current stuff.

So now what?

edsvaDeprovisionReportXML contains the changes to the following attributes:

description
displayname
edsaAccountIsDisabled
msExchHideFromAddressLists
altRecipient
showInAddressBook
edsaMailboxSecurityDescriptor

but not

authOrig
manager
homeDirectory
accountExpires

These last four are under the username of the ARS service account; the depro itself takes place under the username of the admin who initiated the depro request.

The four attributes not included in edsvaDeprovisionReportXML are changed a few seconds before the ones in the the Depro Report; they could be picked up by Get-QARSOperation -ChangedBefore [5 minutes after depro request] -changedAfter [5 minutes before depro request]

Could change depro policy to keep the attributes the same if “Deprovisioned” is in the homeDirectory or the DisplayName, then change undepro to truncate the depro+date info.

Any ideas would be GREATLY appreciated!

Link to my discussion on the Quest Communities ActiveRoles Server board: http://communities.quest.com/thread/21170

Modifying GrantSendOnBehalfTo Without Tears

If you run the cmdlet

Set-DistributionGroup "Sales Team" -GrantSendOnBehalfTo jonestom

you will overwrite the current contents of that distribution group’s GrantSendOnBehalfTo list. Oops.

One of my colleagues, a very old Exchange hand and a new PowerSheller, asked me if there was a simpler way to add one mailbox owner ($trustee) to the GrantSendOnBehalfTo attribute of another Exchange mailbox or distribution group ($target) than having to get both items, extract $trustee.distinguishedname and the current value of $target.GrantSendOnBehalfTo (and save it to another variable, $currentTrustees), append the trustee’s distinguished name to the current list of trustees ($currentTrustees += $trustee.DistinguishedName), then finally replace the old value of $target.GrantSendOnBehalfTo with $currentTrustees (Set-DistributionGroup $target -GrantSendOnBehalfTo $currentTrustees)

Yes, there is, at least as of Exchange 2010 SP1.

Set-DistributionGroup "Sales Team" -GrantSendOnBehalfTo @{add='domainA\jonestom','domainB\smithjane'}

Removing an unwanted trustee works the same way:

Set-DistributionGroup "Sales Team" -GrantSendOnBehalfTo @{remove='domainA\jonestom'}

Because combining these operations often does not end well, here is a cmdlet I made for the help desk to replace a departing colleague with his successor:

function Replace-DLGrantSendOnBehalfTo {
Param($oldTrustee,
	$newTrustee,
	$targetDistributionGroup
	)
Set-DistributionGroup $targetDistributionGroup -GrantSendOnBehalfTo @{add=$newTrustee}
Set-DistributionGroup $targetDistributionGroup -GrantSendOnBehalfTo @{remove=$oldTrustee}
}

For greater efficiency, it can be part of a pipeline, preceded by the names of the target distibution groups and surrounded by a foreach statement. A similar cmdlet can be made for mailboxes. There is probably a way to make it more generic; I might add that later.

The only article I’Ve seen that showed the @{add=$foo}, @{remove=$bar} way to modify this: http://blogs.technet.com/b/manjubn/archive/2012/10/02/grantsendonbehalfto-permissions-for-mailbox-overwrites-existing-permission.aspx

An article that shows the longer way around I described at the beginning, but gives a good explanation of the difference between GrantSendOnBehalfTo and SendAs permissions in Exchange: http://exchangeserverpro.com/exchange-2010-grant-send-behalf-permissions-distribution-group

Finding disconnected mailboxes the PowerShell and EMS way

Like most IT books, Microsoft Exchange Server 2010 Inside Out is a huge doorstop of a book. Since my boss was kind enough to purchase it, and I’m by far the department’s foremost reader of English and its least-experienced Exchange admin, I’ve decided to try to read the whole thing, a chapter a day.

It’s already paid off – I solved a problem using it just a day after reading the fantastic “Exchange Management Shell” chapter.

When a user gets transferred to a location in another domain in our Active Directory forest, he gets a new user account in that domain, but his old mailbox is moved to the Exchange server for that location in the new domain. Occasionally, something goes wrong and the mailbox ends up in a disconnected state – in this case, the old account was deleted before the mailbox was connected to the new one. The real problem was that the help desk staff member who did the move couldn’t remember which mailbox database (or even server) he moved the mailbox to…

Exchange Management Shell and Tony Redmond to the rescue!

The script below is adapted from “Exchange Server 2010 Inside Out”, page 132, mostly to overcome the pipelining problem Tony describes in the “Code changes required by remote PowerShell” section on page 120. I ran this, as I run everything I can, in an implicit Exchange remoting session in my trusty PowerGUI, rather than in Exchange Management Shell itself. Make sure you are either implicitly remoted to an Exchange server or in Exchange Management Shell before running it.

$mbxServers = (Get-MailboxServer | ForEach-Object { $_.name })
Foreach ($mbxserver in $mbxServers) {Get-MailboxStatistics -Server $mbxserver `
| where {$_.disconnectdate -ne $null } | select displayname,OriginatingServer, `
DisconnectDate,LastLoggedOnUserAccount,LastLogonTime,TotalItemSize,Database `
| Export-Csv c:\temp\$mbxserver-disconnectedmailboxes.csv -NoTypeInformation }

The main weakness is that it will only find disconnected mailboxes on 2007 or 2010 servers, but that’s because Get-MailboxStatistics only works on those newer mailboxes.

Tony Redmond’s blog: http://thoughtsofanidlemind.wordpress.com/