SOLVED

Exchange Online PowerShell - Invoke-Command with Select-Object inside scriptblock

Steel Contributor

Update: I'm all good now:).  Had to up-to-snuff-ize my PowerShell remoting understanding.

 

Hello,

 

I'm trying to get help with something.  I've read this:Running PowerShell cmdlets for large numbers of users in Office 365 ...

Some things to note:

  • the comments are closed there...
  • (I believe <--: no longer:)) the article demonstrates impossible actions.

Very simply: The Select-Object cmdlet is not allowed to be used inside your Invoke-Command script block when you're connected to Exchange Online.  Only exported commands from the temporary module are allowed.  So that entire article and the StartRobustCloudCommand script completely miss the "Data Return" issue that that post is supposedly addressing. (...or:)

 

Am I missing something? (<--; Yup, I typed 'select', not 'Select-Object'.)  Here's a simple example:

 

>Invoke-Command -Session (Get-PSSession) -ScriptBlock {Get-MailboxPermission gray |select Identity}
The term 'select' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is
correct and try again.
+ CategoryInfo : ObjectNotFound: (select:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName : outlook.office365.com

 

8 Replies

Removed / no longer relevant.

Last point.  I'm not sure why but objects returned from Get-MailboxFolderPermission are different.  The User property is more than just a string

( I think I can guess why on this one now: it might be because there are usually very many folder permissions, so exposing .ADRecipient is a smart move to avert further lookups.) 

 

Get-MailboxFolderPermission <User>:\<Folder> | select @{n='TrusteeExchangeGuid';e={$_.User.ADRecipient.ExchangeGuid}}

Removed comment - no longer relevant.

best response confirmed by Jeremy Bradshaw (Steel Contributor)
Solution

Few points. First, Select-Object and select are two different things, because of the NoLanguage mode, as in - no aliases are allowed either. So you need to write it "properly":

 

# Invoke-Command -Session (Get-PSSession -id 19) { Get-Mailbox vasil | select PrimarySmtpAddress }
The term 'select' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
and try again.
    + CategoryInfo          : ObjectNotFound: (select:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : outlook.office365.com

# Invoke-Command -Session (Get-PSSession -id 19) { Get-Mailbox vasil | Select-Object PrimarySmtpAddress }

PrimarySmtpAddress PSComputerName        RunspaceId
------------------ --------------        ----------
vasil@michev.info  outlook.office365.com 58472f81-7f34-4e40-8ea7-486a0be474e7

Next, Get-MailboxPermission in ExO returns the UPN of the user, which is "unique enough" and you can get the GUID by querying based on the UPN if needed. I'd agree the full object would be better. It does return the SID though:

# Invoke-Command -Session (Get-PSSession -id 19) { Get-MailboxPermission sharednew -User vasil | Select-Object -ExpandProperty User } -HideComputerName


RunspaceId                  : 58472f81-7f34-4e40-8ea7-486a0be474e7
SecurityIdentifier          : S-1-5-21-3675944716-2045640655-299186705-3762784
ReturnUrlTokenEncodedString : False
RawIdentity                 : vasil@michev.info

You can apply the same method to get the ObjectGUID for the Identity value.

 

The mailbox folder permission entries returning a full ADRecipient object is something I probed the PG few years back, never got a reply whether it's intentional of bug. Most of the time you can get enough properties via Invoke-Command though.

Thanks very much - I was stuck in my own way with that one!

To confirm about the user being returned as UPN. What happens when the trustee is a group?

I was / am hoping to avoid needing to do any further lookups by using those nested properties that would be included otherwise (e.g. with the snapin).

But I can do select-object and work with that! Im happy to have a solution on day 1 of my post.

Well now, I'm back with a follow-on question.  Having now used the proper cmdlet name Select-Object I notice I can't create custom properties.

 

Works in Exchange on-premises PS remoting:

>Invoke-Command -Session $exPSSession -ScriptBlock {Get-MailboxPermission Gray | Select-Object @{n='t';e={$_.User.SecurityIdentifier}}}

But doesn't work in Exchange Online PS remoting:

>Invoke-Command -Session $exops -ScriptBlock {Get-MailboxPermission -Identity Ross | Select-Object -Property @{Name='MbxObjectGuid';Expression={$_.Identity.ObjectGuid}}}
The syntax is not supported by this runspace. This can occur if the runspace is in no-language
mode.
+ CategoryInfo : ParserError: (Get-MailboxPerm...ty.ObjectGuid}}:String) [], ParseExc
eption
+ FullyQualifiedErrorId : ScriptsNotAllowed
+ PSComputerName : outlook.office365.com 

@Vasil Michev do you know if this means I'd have to run Get-MailboxPermission multiple times in order to then do Select-Object -ExpandProperty against each property I'm trying to expand?

..Actually - nevermind, I get it now.  Only the commands that are available in the temporarily module are available, which includes Select-Object, but not Where-Object, and NoLanguage mode means no custom properties, etc.

 

This means, Get-MailboxPermission using Invoke-Command is not a good plan since I'd have to pull back all permissions this way, then sort through them and filter just the FullAccess ones on my side.  (<--: I'm completely wrong here.  Worst-case, we can make two passes with Get-MailboxPermission/Get-ADPermission/Get-RecipientPermission.  Once to get the index of all ACE's in the ACL with matching AccessRights/Inheritance/Allow|Deny criteria, then a second time to expand just the users for those ACE's.

 

Not bad at all!:ok_hand:  And no reason Invoke-Command would not be a good plan after all.:thumbs_up:)

 

Remaining comments removed: no longer relevant.

You can always filter the output client side. Or for the case of Get-MailboxPermission, use the -User parameter. The $using PowerShell modifier is a great way to pass variables inside remote sessions, I have few examples here: https://www.michev.info/Blog/Post/1687/using-variables-with-invoke-command-in-remote-powershell-sess...

Just wanted to touch back @Vasil Michev to say thanks for your help.  I've been busy since the day I opened this post, figuring our how to use Invoke-Command both with $args and $Using (cosmetically, I found use cases for using both).

 

I have updated my mailbox delegations script so that it's almost exclusively using Invoke-Command, in case it's of any value for you or anyone else who stumbles onto this thread:

Get-MailboxTrustee.ps1

 

If you have a lot of mailboxes to query, you may find the script's Write-Progress bars entertaining if nothing else.

1 best response

Accepted Solutions
best response confirmed by Jeremy Bradshaw (Steel Contributor)
Solution

Few points. First, Select-Object and select are two different things, because of the NoLanguage mode, as in - no aliases are allowed either. So you need to write it "properly":

 

# Invoke-Command -Session (Get-PSSession -id 19) { Get-Mailbox vasil | select PrimarySmtpAddress }
The term 'select' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
and try again.
    + CategoryInfo          : ObjectNotFound: (select:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : outlook.office365.com

# Invoke-Command -Session (Get-PSSession -id 19) { Get-Mailbox vasil | Select-Object PrimarySmtpAddress }

PrimarySmtpAddress PSComputerName        RunspaceId
------------------ --------------        ----------
vasil@michev.info  outlook.office365.com 58472f81-7f34-4e40-8ea7-486a0be474e7

Next, Get-MailboxPermission in ExO returns the UPN of the user, which is "unique enough" and you can get the GUID by querying based on the UPN if needed. I'd agree the full object would be better. It does return the SID though:

# Invoke-Command -Session (Get-PSSession -id 19) { Get-MailboxPermission sharednew -User vasil | Select-Object -ExpandProperty User } -HideComputerName


RunspaceId                  : 58472f81-7f34-4e40-8ea7-486a0be474e7
SecurityIdentifier          : S-1-5-21-3675944716-2045640655-299186705-3762784
ReturnUrlTokenEncodedString : False
RawIdentity                 : vasil@michev.info

You can apply the same method to get the ObjectGUID for the Identity value.

 

The mailbox folder permission entries returning a full ADRecipient object is something I probed the PG few years back, never got a reply whether it's intentional of bug. Most of the time you can get enough properties via Invoke-Command though.

View solution in original post