Building on the helpful comments:
Because argument $today$saturday.allshift
is implicitly treated as if it were enclosed in "..."
, the interpolation rules of expandable strings apply.
Inside "..."
strings, only stand-alone variable references are expanded as-is by default, e.g., $saturday
, and not also expressions, which includes property access, e.g. $saturday.allshift
. In the latter case, $saturday
is expanded as a whole, and .allshift
is printed verbatim.
In order to embed expressions such as $saturday.allshift
inside "..."
, you need $(...)
, the subexpression operator:
# "..." isn't strictly necessary, but is conceptually clearer.
Write-Host "$today$($saturday.allshift)"
See this answer for more information, and this answer for a comprehensive overview of the string-interpolation rules.
What makes your example tricky are the subtleties around how PowerShell decides whether a given command argument is implicitly treated as if it were "..."
-enclosed:
A few examples (Write-Output
is used instead of Write-Host
, to make it more obvious when a compound token is actually passed as two arguments):
# Argument is treated as an *expression*
# -> 'All_Shifts_Checklist_Saturday.xlsx'
Write-Output $saturday.allshift
# The compound token treats $saturday.allshift as an *expression*,
# and $today therefore becomes a *separate argument*.
# -> 'All_Shifts_Checklist_Saturday.xlsx', '20220923'
Write-Output $saturday.allshift$today
# Your case:
# Because the compound token starts with a stand-alone variable reference
# *followed by additional characters* that do not constitute a property
# access or method call, the whole token is considered a single, expandable
# string:
# * $today expands as intended
# * $saturday expands *as a whole* - resulting in just the *type name* of
# the hashtable, 'System.Collections.Hashtable' (try `@{}.ToString()`)
# * and '.allshift' is treated as a literal.
# -> '20220923System.Collections.Hashtable.allshift'
Write-Output $today$saturday.allshift
That is, if a compound token starts with a variable-based expression that is a property access or method call, the expression is recognized as such, and whatever follows becomes a separate argument.
- The exact rules are complex; this answer discusses them.
Therefore, it is best to form a habit to enclose compound tokens that are meant to be a single string argument in "..."
, and use $(...)
to enclose any embedded expressions or commands.