Home > front end >  What does this PowerShell syntax mean?
What does this PowerShell syntax mean?

Time:05-13

In powershell what does the syntax $x = . { ... } mean? How is it different from $x = @( ... ) From what I can tell they both create an array of the provided values but their output is slightly different.

I came across it in this script https://powershell.one/tricks/filesystem/filesystemwatcher when the author defines the handlers in the async example. Is there any significance to doing it that way? Other async examples for filewatcher use similar code.

$x = @(1,2,3)
$y = . {1,2,3}
@($x,$y) | foreach-object {
    $_
    $_.GetType()
}

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array
1,2,3
True     True     Object[]                                 System.Array
1
2
3

Non Trivial Example

$handlers = . {
  Register-ObjectEvent -InputObject $watcher -EventName Changed  -Action $Action 
  Register-ObjectEvent -InputObject $watcher -EventName Created  -Action $Action
  Register-ObjectEvent -InputObject $watcher -EventName Deleted  -Action $Action
  Register-ObjectEvent -InputObject $watcher -EventName Renamed  -Action $Action
}

CodePudding user response:

In PowerShell what does the syntax $x = . { ... } mean?

When put together, . { ... }, the script block is executed as soon as it's interpreted by PowerShell.

How is it different from $x = @( ... )?

For this particular case, I don't see a difference between both because your script block is storing a System.Array and the dot sourcing operator doesn't change the return type of your expression.

However, when wrapping a sub-expression in @( .. ) you can ensure that the return will always be an array even if the sub-expression returns $null:

@( $null ).GetType()    # is an array
(. { $null }).GetType() # is an error

If you were to use the .Invoke() method to execute the script block, the difference would've been the return type, from System.Array to Collection`1:

({1, 2, 3}.Invoke()).GetType()

IsPublic IsSerial Name              BaseType
-------- -------- ----              --------
True     True     Collection`1      System.Object

As for the linked code, the author is wrapping multiple calls to Register-ObjectEvent inside the script block and executing it, there is no difference either because there are multiple calls to the cmdlet and the return type of both expressions is an array. If however, we do the same with only one call to the cmdlet with the script block example we get the output type from Register-ObjectEvent:

$watcher1 = [System.IO.FileSystemWatcher]::new($pwd.Path)
$watcher2 = [System.IO.FileSystemWatcher]::new($pwd.Path)

$handler1 = . {
    Register-ObjectEvent $watcher1 -EventName Changed -Action { Write-Host 'hello '}
}
$handler2 = @(
    Register-ObjectEvent $watcher2 -EventName Changed -Action { Write-Host 'hello '}
)
$handler1.GetType() # => PSEventJob
$handler2.GetType() # => object[]
  • Related