I need help to create a script that can save my life.
My backup software got it wrong because I misdesigned my backup plan and I have lots of named files; filename or folder name (2) (encoding conflict).
I would like to recursively search my network share to find folders and files with "(encode conflict)" in their name and first export them for verification.
Then, if all goes well, I would like to move them to another place while keeping the folder's hierarchy and that's where I stuck.
Get-ChildItem -LiteralPath '\\?\E:\Network Shares\Commun' -Recurse -Filter "*(encode*" #| move-item -Destination 'C:\Users\Desktop\Conflits\'
For the export I found the script here :
https://stackoverflow.com/a/15261816/19493679
Thanks to OP
The files from my test are moving without folder's and file's hierarchy ...
Can you help me please ? :)
CodePudding user response:
Move-Item
doesn't know about the directory structure, it just gets paths fed one by one from Get-ChildItem
. For preserving directory structure, Move-Item
would have to know a common base path, but there is currently no way to specify one.
So I've created a helper function New-DestinationPath
that can be chained in between Get-ChildItem
and Move-Item
(or Copy-Item
). The function creates the destination directory structure and outputs the source path and the fully resolved destination path.
Function New-DestinationPath {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[Alias('Fullname', 'PSPath')]
[String] $Path,
[Parameter(Mandatory, Position=0)]
[String] $CommonPath,
[Parameter(Mandatory, Position=1)]
[String] $Destination
)
process {
# Temporarily change current directory -> base directory for Resolve-Path -Relative
Push-Location $CommonPath
try {
# Resolve input path relative to $CommonPath (current directory)
$relativePath = Resolve-Path $Path -Relative
}
finally {
Pop-Location # Restore current directory
}
# Resolve full target file path and directory
$targetPath = Join-Path $Destination $relativePath
$targetDir = Split-Path $targetPath -Parent
# Create target dir if not already exists (-Force).
$null = New-Item $targetDir -ItemType Directory -Force
# Output the full source and destination paths (for use with Copy-Item or Move-Item)
[PSCustomObject]@{
Path = $Path
Destination = $targetPath
}
}
}
Usage:
$searchPath = '\\?\E:\Network Shares\Commun'
Get-ChildItem -LiteralPath $searchPath -Recurse -File |
Where-Object Fullname -like '*(encode*' |
New-DestinationPath -CommonPath $searchPath -Destination 'C:\Users\Desktop\Conflits' -WhatIf |
Move-Item -LiteralPath { $_.Path } -Destination { $_.Destination } -WhatIf
- By using the common parameter
-WhatIf
the functions only output what they would do. Remove both-WhatIf
arguments when you have confirmed that the right paths are used. - In the
Move-Item
call we are using delay-bind scriptblocks to avoid aForEach-Object
command. Using the automatic variable$_
we can directly refer to the output of the previous command in the pipeline (New-DestinationPath
).