Reputation: 858
I'm trying to move all files from a NAS to a cloud provider, which does not allow the char ?<>|/\\*:"
in its filenames, unfortunately some of the files do have these char in their filenames.
So I would like to fix these filenames before doing the migration, and thus I had the idea to list the forbiden filenames, but the forbiden char crash the Get-childItem command and I'm a bit stuck
Here's the command I use
Get-ChildItem $myPath -Recurse -Force -File | Where-Object {$_.name -match '[?<>|/\\*:"]+'} | select fullname, name
And here's the output I get :
Get-ChildItem : The given path's format is not supported
Char, Line:1 : 1
+ Get-ChildItem path -Recurse -Force ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ChildItem], NotSupportedException
+ FullyQualifiedErrorId : System.NotSupportedException,Microsoft.PowerShell.Commands.GetChildItemCommand
Is there a way to make the command fail but still tell me where was the file which crashed it ? Or is there another command or parameter to use to do what I want ?
Edit : For now I found a workaround, rather than mounting the distant nas with New-PSDrive, I sshed into the NAS and used the linux bash which was installed on it and supports these filenames but I am still interested by the answer to how to do it with powershell
Upvotes: 1
Views: 495
Reputation: 439767
Use the the common -ErrorVariable
(-ev
) parameter parameter in combination with the common -ErrorAction
(-ea
) parameter:
Get-ChildItem $myPath -Recurse -Force -File -ea SilentlyContinue -ev errs |
Where-Object {$_.name -match '[?<>|/\\*:"]+'} | select fullname, name
Write-Verbose -vb 'The following paths caused errors:'
$errs.TargetObject
-ea SilentlyContinue
silences error display (and continues execution as long as the errors are non-terminating, which they typically are).
-ev errs
captures the non-terminating errors in self-chosen variable $errs
, which can be inspected later.
The .TargetObject
property of the System.Management.Automation.ErrorRecord
instances collected in $errs
contains the source object that triggered the error, which in the case at hand is the full path of the file-system object; $errs.TargetObject
lists them all, across all error objects in the collection, courtesy of member-access enumeration.
Update:
The above doesn't seem to help in the specific case at hand, as seemingly only a single error record is returned that doesn't have .TargetObject
filled in and mentions only the starting directory of the recursive enumeration.
The Include *
approach shown below helped to at least narrow the problem down to individual directories containing offending files.
Adding -Include *
to force explicit processing of individual files in each directory may help:
# Tries to find offending file names only, via `$errs`
$null = Get-ChildItem $myPath -Recurse -Force -File -Include * -ea SilentlyContinue -ev errs
Another option, given that you say that passing -Directory
doesn't report errors, is to apply Get-Item * -Force
to each directory and see if the offending file names can at least be narrowed down to specific directories:
# Tries to find offending file names only, via `$errs`
$null = & { Get-Item $myPath; Get-ChildItem $myPath -Recurse -Force -Directory } |
Get-Item -Path { Join-Path $_.FullName * } -Force -ea SilentlyContinue -ev errs
Upvotes: 2