How to get Get-ChildItem to handle path with non-breaking space
It's still unclear why Sandra's code didn't work: PowerShell v2+ is capable of retrieving files with paths containing non-ASCII characters; perhaps a non-NTFS filesystem with different character encoding was involved?
However, the following workaround turned out to be effective:
$objFile = Get-ChildItem -Path ($inFile -replace ([char] 0xa0), '?')
The idea is to replace the non-breaking space char. (Unicode
U+00A0
; hex.0xa
) in the input file path with wildcard character?
, which represents any single char.For
Get-ChildItem
to perform wildcard matching,-Path
rather than-LiteralPath
must be used (note that-Path
is actually the default if you pass a path argument positionally, as the first argument).Hypothetically, the wildcard-based paths could match multiple files; if that were the case, the individual matches would have to be examined to identify the specific match that has a non-breaking space in the position of the
?
.
Get-ChildItem
is for listing children so you would be giving it a directory, but it seems you are giving it a file, so when it says it cannot find the path, it's because it can't find a directory with that name.
Instead, you would want to use Get-Item -LiteralPath
to get each individual item (this would be the same items you would get if you ran Get-ChildItem
on its parent.
I think swapping in Get-Item
would make your code work as is.
After testing, I think the above is in fact false, so sorry for that, but I will leave the below in case it's helpful, even though it may not solve your immediate problem.
But let's take a look at how it can be simplified with the pipeline.
First, you're starting with an empty array, then calling a command (Get-Content
) which likely already returns an array, wrapping that in an array, then concatenating it to the empty one.
You could just do:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv"
Yes, there is a chance that $inFiles
will contain only a single item and not an array at all.
But the nice thing is that foreach
won't mind one bit!
You can do something like this and it just works:
foreach ($string in "a literal single string") { Write-Host $string}
But Get-Item
(and Get-ChildItem
for that matter) accept pipeline input, so they accept multiple items.
That means you could do this:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Itemforeach ($inFile in $inFiles) { Write-Host("Processing: " + $inFile) New-Object PSObject -Prop @{ FullName = $inFile.FullName ModifyTime = $inFile.LastWriteTime }}
But even more than that, there is a pipeline-aware cmdlet for processing items, called ForEach-Object
, to which you pass a [ScriptBlock]
, in which $_
represents the current item, so we could do it like this:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Item | ForEach-Object -Process { Write-Host("Processing: " + $_) New-Object PSObject -Prop @{ FullName = $_.FullName ModifyTime = $_.LastWriteTime } }
All in one pipeline!
But further, you're creating a new object with the 2 properties you want.
PowerShell has a nifty cmdlet called Select-Object
which takes an input object and returns a new object containing only the properties you want; this would make for a cleaner syntax:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Item | Select-Object -Property FullName,LastWriteTime
This is the power of the the pipeline passing real objects from one command to another.
I realize this last example does not write the processing message to the screen, however you could re-add that in if you wanted:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Item | ForEach-Object -Process { Write-Host("Processing: " + $_) $_ | Select-Object -Property FullName,LastWriteTime }
But you might also consider that many cmdlets support verbose output and try to just add -Verbose
to some of your existing cmdlets. Sadly, it won't really help in this case.
One final note, when you pass items to the filesystem cmdlets via pipeline, the parameter they bind to is in fact -LiteralPath
, not -Path
, so your special characters are still safe.