I have the following PowerShell script, which I am using to move all files in a directory containing a specific string within:
gci -Path 'C:\Users\LG\Desktop\3039u\*.txt' -r|sls -Pattern '(?-i)^Engine:'|Move-Item -Destination "C:\Users\LG\Desktop"
However, when attempting to execute it, I get the error message:
Move-Item : The process cannot access the file because it is being used by another process.
At line:1 char:77
+ ... -Pattern '(?-i)^Engine:'|Move-Item -Destination "C:\Users\LG\Desktop"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (C:\Users\LG\Des...Zeus ZEU-6T.txt:FileInfo) [Move-Item], IOException
+ FullyQualifiedErrorId : MoveFileInfoItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand
Repeated for each file that sls selects and Move-Item attempts to move. I have verified that no other process is holding the files open using Process Explorer (Sysinternals). Could this be an issue of incorrectly written command, i.e. sls is holding the file open while collecting a list of all matching files which keeps Move-Item unable to access them? If so, how should I reformat the command?
To be clear - I want it to find each matching file using sls, and then move each match to a different folder.
Regards
Select-String
(the target of the sls
alias) might output a match before it's finished reading a given file - explaining why you can't move the file, because Select-String
still has an open handle to it.
You can split the operation into 2 pipelines, allowing Select-String
to complete it's search before you start moving files:
$FilesToMove = Get-ChildItem -Path 'C:\Users\LG\Desktop\3039u\*.txt' -Recurse |Select-String -Pattern '(?-i)^Engine:'
$FilesToMove |Move-Item -Destination "C:\Users\LG\Desktop"
A more efficient approach however, is to only invoke Select-String
against 1 file at a time - it might sound counter-intuitive, but is allows you to stop Select-String
as soon as you get the first match:
Get-ChildItem -Path 'C:\Users\LG\Desktop\3039u\*.txt' -Recurse |ForEach-Object {
if ($_ |Select-String -Pattern '(?-i)^Engine:' |Select-Object -First 1) {
$_ |Move-Item -Destination "C:\Users\LG\Desktop"
}
}