Powershell: Using Write-Information

This started out as a short entry for my Powershell Snippets page, but it quickly turned out that this cmdlet needs a longer text for explaining proper handling…

Background

The cmdlet Write-Information is interesting, but also a bit tricky.

It’s for using the ‘Information Stream’, which was added by Powershell 5.0 (released around 2016), and is the sixth stream, added to prevent further stream pollution:

  1. Output/Success
  2. Error
  3. Warning
  4. Verbose
  5. Debug
  6. Information

More on the topic:

Pitfall #1: InformationAction is set to SilentlyContinue by default

By default, one will see/get nothing from it in the shell; sometimes, this may be the right thing (for example if one is just collecting data for a logfile), but often, it is not:

> Write-Information -MessageData "Text"
>

You then need to either change the global preference variable $InformationPreference from “SilentlyContinue” to “Continue”, or instruct the particular call of the cmdlet by setting its parameter -InformationAction to “Continue”:

> Write-Information -MessageData "Text" -InformationAction Continue
Text

Pitfall #2: Inquire doesn’t tell you what you should confirm

A nice feature is -InformationAction Inquire, which shows a confirmation inquiry to the user:

> Write-Information -MessageData "Text" -InformationAction Inquire

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"): 

But as you may have noticed: The MessageData (“Text”) doesn’t appear anywhere!

When using -InformationAction Inquire, you only get the confirmation inquiry; the actual -MessageData will not be shown (unlike when using -InformationAction Continue).

This seems to be a bug (opened 2019-12, still unresolved 2022-07), that one needs to work around for now (e.g. by explicitly printing text before the inquiry).

After those stumbling blocks, let’s finish this section with a few nice features…

MessageData

The value of parameter MessageData doesn’t have to be a text string; it can be any kind ob object:

> Write-Information -MessageData (gci)  -InformationAction Continue -InformationVariable iv
System.Object[]

> $iv
System.Object[]

> $iv | select -expand MessageData

    Directory: C:\Test

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2021-01-01     11:00                Folder 1
d-----        2022-02-02     12:00                Folder 2
d-----        2023-03-03     13:00                Folder 3

Collecting InformationRecords in an InformationVariable

One can also collect so-called “information records” in a variable:

Notes:

> Write-Information -MessageData "Text" -Tags "Foo", "Bar" -InformationAction Continue -InformationVariable iv
Text

> $iv | gm
TypeName: System.Management.Automation.InformationRecord
# ...

> $iv
Text

But there’s more to it:

> $iv | select *

MessageData     : Text
Source          : Write-Information
TimeGenerated   : 2023-07-16 00:00:00
Tags            : {Foo, Bar}
User            : COMPUTER\Sascha
Computer        : Computer
ProcessId       : 4321
NativeThreadId  : 1234
ManagedThreadId : 10

If you want to collect multiple records, which you can then later filter for its tags, for example, try this:

Invoke a script or function with the common parameter -InformationVariable, like before (Common parameters are available to any Powershell cmdlet and your own advanced(!) scripts or functions).

The InformationVariable will automatically and implicitly be handed down; one doesn’t even have to mention the parameter in the call of Write-Information:

function Test-Me
{
    [CmdletBinding()] Param() # This makes it an 'advanced function'.
    0..3 | % { write-information -MessageData "Text $_" -Tag "FixedTag", "Tag $_" -InformationAction Continue }
}

Test-Me -InformationVariable iv

Now you can further examine the variable $iv in detail:

> $iv | ? { $_.Tags -eq 'FixedTag'} | select MessageData, Tags

MessageData Tags
----------- ----
Text 0      {FixedTag, Tag 0}
Text 1      {FixedTag, Tag 1}
Text 2      {FixedTag, Tag 2}
Text 3      {FixedTag, Tag 3}

or

> $iv | ? { $_.Tags -eq 'Tag 0'} | select MessageData, Tags

MessageData Tags
----------- ----
Text 0      {FixedTag, Tag 0}