1

I'm trying to get the following command into a program I am developing in PowerShell studio, I'm having some issues figuring out the escaping sequence here, and testing takes forever since I have to import the PST just to view the data :(

Consider the following command which works correctly from the shell...

New-MailboxExportRequest -Mailbox user@domain.com -Name JobName -IncludeFolders "#Inbox#/*","#SentItems#" -ContentFilter {(Received -gt "06/10/2022") -and (Sent -gt "06/10/2022")} -FilePath "\\Server\Folder\MyPST.pst"

I am using variables inside program designer, so my actual code looks like this...

New-MailboxExportRequest -Mailbox $mailbox -Name $jobname -IncludeFolders $IncludeFolders -ContentFilter {(Received -gt "$RecDate") -and (Sent -gt "$SentDate")} -FilePath "$FilePath"

Basically I need to get the first code sample working using variables, however the -IncludeFolders and -ContentFilter parameters require some escaping I can't seem to figure out. Any and all help is much appreciated.

  • 1
    Please show us how you instantiate these variables so we can see what they contain – Theo Jun 20 '22 at 13:53
  • Sure, and thanks for the reply @theo. The form looks like this, all I do is pass the user input in variables to the command. [link](https://1drv.ms/u/s!AgBAbImA7NSlgZpgzrqkhfzRmzLcfw?e=2RrmV6) – SeeShellRun Jun 20 '22 at 14:46

1 Answers1

1

tl;dr:

  • You need to enclose your -ContentFilter argument in "..." overall in order to support embedding variable values, which you can themselves enclose in embedded '...' quoting:

    -ContentFilter "(Received -gt '$RecDate') -and (Sent -gt '$SentDate')"
    
  • No special syntax considerations apply with respect to using a variable with
    -IncludeFolders: Just make sure that variable $IncludeFolders contains an array of strings identifying the target folders; applied to your example:

    $IncludeFolders = '#Inbox#/*', '#SentItems#'
    
    • If the list of folders must be parsed from user input provided as a single string ($textbox5.text in this example) do the following to convert this single string to an array of names:

       # If $textbox5.text contains string '#Inbox#/*, #SentItems#', 
       # the result is the same as above.
       $IncludeFolders = ($textbox5.text -split ',').Trim()
      

Read on for background information and caveats re -ContentFilter.

Note:

  • The -ContentFilter information below also applies to other Exchange cmdlets that accept filters, such as Get-Recipient with its -Filter parameter.

  • It also applies analogously to the -Filter parameter used with AD (Active Directory) cmdlets such as Get-ADUser, although the situation there is complicated by the fact that the AD provider does support evaluation of PowerShell variables, but only in simple cases - see this answer.


  • New-MailboxExportRequest's -ContentFilter expects a string argument, not a script block ({ ... }), which you've used in your question.

    • While you can situationally get away with a script block, it is best avoided for two reasons:
      • When a script block is used as a string (converted to one), string interpolation (embedding the values of variables in the string) is not supported - a script block stringifies to its verbatim content (sans { and }).

      • Conceptually, use of a script block can give the mistaken impression that an arbitrary piece of PowerShell code may be passed, which is not the case: -ContentFilter supports a domain-specific syntax only that only emulates a limited set of PowerShell features, called OPath filter syntax.

        • Notably, evaluation of PowerShell variables is not supported - their values must be embedded in the string up front, by PowerShell, using string interpolation.
  • Therefore:

    • It's best to use a string argument with -ContentFilter to begin with.

    • Since you do need to embed variable values, you need string interpolation, via an expandable (double-quoted) string ("..."), inside of which you may quote values with '...' for syntactical convenience.

    • In case there is no need to embed variable values, use a verbatim (single-quoted) string ('...'), inside of which you may quote values with "...", as in your question. (In effect, this is the equivalent of the (ill-advised) use of { ... }).

Applied to your example: The following embeds the (stringified) values of variables $RecDate and $SentDate in your -ContentFilter argument:

# Note the use of "..." for the outer quoting, and 
# '...' for the embedded quoting.
-ContentFilter "(Received -gt '$RecDate') -and (Sent -gt '$SentDate')"

Caveats:

  • If the values of the variables to embed themselves contain ', use escaped embedded "..." quoting instead; e.g., `"$var`"

    • If a value could contain ' and/or " and you don't know which, you'd have to use an extra layer of up-front string interpolation on the PowerShell side to escape one of them, depending on the embedded quoting character chosen, using $(...), the subexpression operator, using a -replace operation:

    • In this escaping you must technically satisfy the OPath filter syntax requirements; the linked help OPath topic suggests that, like in PowerShell, '' can be used to escape ' inside a '...' string; e.g.:
      -ContentFilter "Body -like '$($var -replace "'", "''")*'"

  • While, as stated, OPath filters do not support evaluating PowerShell variable references in general, the following automatic variables - which are conceptually constants - are recognized (the linked help topic calls them system values):

    • $true, $false

    • $null

    • Therefore, if you use "..." for the outer quoting (for string interpolation), the $ in these variables must be escaped with ` (the so-called backtick, PowerShell's escape character), to prevent PowerShell from replacing these variable references with their values up front:

      • `$true, `$false
      • `$null
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thanks for this response @mklement0. I've modified my code to test this example. Question though that is tripping me up, would I have to use the double quotes in the textbox that is accepting the user input? Or would you leave the double quotes out in this part? [Link to screenshot](https://1drv.ms/u/s!AgBAbImA7NSlgZpgzrqkhfzRmzLcfw) – SeeShellRun Jun 21 '22 at 16:24
  • @SeeShellRun, no, what the user types should _not_ include double quotes, and neither should you add them programmatically. However, I suggest trimming leading and trailing whitespace first, and checking if the input is recognized as a date (e.g., `[datetime] '06/10/2022'`); PowerShell assumes that `06` is the _month_ in this example, irrespective of what culture is in effect. Not sure what OPath expects. – mklement0 Jun 21 '22 at 17:01
  • Thanks, I have been testing the code, seems like the Export job runs, but it never exports the folders I specify. Text fields looks like this [ScreenShot](https://1drv.ms/u/s!AgBAbImA7NSlgZphMlc3GoUaPu3HZw) Once I import the PST and expand it, the folders I specify in the text field are not there. Seems like its not taking my -ContentFilter switch. – SeeShellRun Jun 21 '22 at 20:11
  • Here is the most recent code I am using based on your last helpful recommendation. `New-MailboxExportRequest -Mailbox $ExportMailbox -Name "$JobName" -IncludeFolders "'$SourceRootFolder'" -ContentFilter "(Received -gt '$ReceivedDate') -and (Sent -gt '$SentDate')" -FilePath $FilePath` – SeeShellRun Jun 21 '22 at 20:13
  • Sorry, I meant to say "Seems like its not taking my -IncludeFolders switch".. Not -ContentFilter – SeeShellRun Jun 21 '22 at 20:22
  • This is what it looks like when I debug... [Debug Screenshot](https://1drv.ms/u/s!AgBAbImA7NSlgZpiqHRNaeaVaJ5N6g) – SeeShellRun Jun 21 '22 at 21:17
  • @SeeShellRun, please see my update (top section) re `-IncludeFolders` – mklement0 Jun 21 '22 at 22:09
  • Ah, ok missed that, thanks. Here is the code I have below, this doesn't appear to be working, think it is expecting the commas. User input could either but with the comma or without the comma, so I cant just use `$IncludeFolders = '#Inbox#/*', '#SentItems#'` Here is my code `$Folders = $textbox5.text $Folders2 = $Folders.split(",") $IncludeFoldersArray = @() foreach ($item in $Folders2) { $IncludeFoldersArray += $item }` Then I use $IncludeFoldersArray for the -IncludeFolders switch in my code. – SeeShellRun Jun 22 '22 at 18:04
  • @SeeShellRun, see my update about how to efficiently parse a _single string_ such as `'#Inbox#/*, #SentItems#'` into an array of tokens. Generally, please note that we're getting pretty far away from the original question, and that you should generally either (a) state all requirements _up front_, as much as possible or (b) create _new_ question posts for _follow-up_ questions. – mklement0 Jun 22 '22 at 18:31