I'm looking to fetch the list of
based on which of the 3 pieces of information the end user wants. I'm looking to expanding this function of mine to accommodate more properties based on inputs provided. Given below is a snippet of my code and the failure following it.
$Path is a path, it's an input$CustomMetaList is an array of properties, it's an input. $BaseCmd = "Get-ChildItem $Path -Recurse"
$Hidden = ""
$FullName = ""
$LastWriteTime = ""
$Size = ""
$PropList = ""
$CustomMetaList = $CustomMetaList.split(",")
foreach ($Meta in $CustomMetaList) {
if ($Meta -eq "'Hidden'") {
$Hidden = "-Force"
}
if ($Meta -eq "'FullName'") {
$PropList = [String]::Join(",","@{e={`$_.FullName};width=250}")
}
if ($Meta -eq "'LastWriteTimeUtc'") {
$PropList = [String]::Join(",",$PropList,"@{e={`$_.LastWriteTimeUtc -UFormat %s}}")
}
if ($Meta -eq "'Size'") {
$PropList = [String]::Join(",",$PropList,"@{e={`$_.Length}}")
}
}
Invoke-Expression "$BaseCmd $Hidden | Format-Table -HideTableHeaders -Property $PropList -AutoSize | Out-String -Width 5000"
}
I receive the following error when I try to run my script, Do ou have any idea on what's wrong ?
Invoke-Expression :
At line:1 char:210
+ ... stWriteTimeUtc -UFormat %s}},@{e={$_.Length}} -AutoSize | Out-String -Width 5000
+ ~~~~~~~~
Unexpected token '-UFormat' in expression or statement.
At line:1 char:219
+ ... meUtc -UFormat %s}},@{e={$_.Length}} -AutoSize | Out-String -Width 5000
+ ~~
Unexpected token '%s' in expression or statement.
At E:\299955427760_GetData.ps1:114 char:5
+ Invoke-Expression "$BaseCmd $Hidden | Format-Table -HideTableHeaders -Proper ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Invoke-Expression], ParseException
+ FullyQualifiedErrorId : UnexpectedToken,Microsoft.PowerShell.Commands.InvokeExpressionCommand
As Ansgar Wiechers soundly advises, Invoke-Expression should be avoided, because there are almost always better solutionsand it comes with security risks.
Generally, for iteratively constructing commands with varying arguments, argument splatting is the best solution, though in your case that's not strictly necessary - see bottom section.
However, your problem is unrelated to the use of Invoke-Expression, because it is the following expression that causes your problem:
$_.LastWriteTimeUtc -UFormat %s # !! Syntax error
You can only pass -UFormat to the Get-Date cmdlet, not to a variable or expression:
Get-Date -Date $_.LastWriteTimeUtc -UFormat %s # OK
Additionally, due to a bug in Windows PowerShell v.5.1 (since corrected in PowerShell Core), Get-Date -UFormat %s outputs fractional seconds too, which is incorrect; you can fix this by simply casting to [int]:
[int] (Get-Date -Date $_.LastWriteTimeUtc -UFormat %s)
(Even without the bug present you may want to do this in order to receive a numeric result, given that Get-Date -UFormat always outputs strings).
As an aside: Another bug causes the result to be based on local times by default, whereas Unix time stamps are required to be UTC-based; since you're using property .LastWriteTimeUtc, your code is not affected.
Here's a solution that avoids Invoke-Expression and is much shorter too:
# Sample input values.
$Path = $env:TEMP
$CustomMetaList = 'FullName,Size,LastWriteTimeUtc'
# Construct the array of property definitions to pass to Select-Object
# based on the custom list, and record in $force whether hidden items
# should be included.
$props = switch ($CustomMetaList -split ',') {
'Hidden' { $force = $True; continue } # save in Boolean var.
'FullName' { $_; continue } # same name as property
'Size' { 'Length'; continue } # map 'Size' to 'Length'
'LastWriteTimeUtc' { # calculated property
@{ n=$_; e = { [int] (Get-Date -Date $_.LastWriteTimeUtc -UFormat %s) } }
}
}
Get-ChildItem $Path -Recurse -Force:$force |
Format-Table -Property $props -HideTableHeaders -AutoSize |
Out-String -Width 5000
Note how switch is used to implicitly iterate over the elements of the array that $CustomMetaList -split ',' returns.
The branch handlers of a switch statement are all tested for by default, so continue is used to short-circuit that, once a match has been found. Caveat: Do not use break, as it stops iterating over further array elements.
The output from the iterations of the switch statement is implicitly collected in an array stored in $props, which is later passed to Format-Table.
-Force:$force is a way to mimic the effects of passing / not passing switch parameter -Force: if $force is $true, it is the same as if just -Force had been passed; otherwise, it is treated as if -Force had not been passed.
This will yield something like:
FullName Length LastWriteTimeUtc
-------- ------ ----------------
C:\path\to\sample.txt 51 1543853694
# ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With