0

I have 1 disk, on my home server, which has all my media in, and where my films download to. I wonder if you could suggest a quick way to move files, to different hard drives, on the letter they start with. E.g my H drive has all my media, I would like files beginning with A-F to drive D, files G-L to drive F and files M-Z to drive E. So far I have ‘Move-Item H:\done\C* D:\ -Force’ line for every letter of the alphabet. Just wondered if there was a quicker was of moving the files.

A work colleague provided me with a script, but it doesn't work, and not sure if its me doing something wrong or the script:

#get a list of files at the source
$files = gci H:\done


#loop through each item in the variable "$files" which will then on be referenced to using the variable "$file"
foreach($file in $files){

#assign the drive letter using a switch statement. Switch statements are a quick way to return a new value based on if a condition is met... in this case if the first letter of the input matches the regex statement.
  $drive =  switch -regex ($file.basename[0]) {

       '[A-F]' {'D:\'}
       '[G-L]' {'F:\'}
       '[M-Z]' {'E:\'}

   }

#quick way to show progress
   write-host "Moving $($file.Name) to $drive" -f Cyan

#perform the move
   Move-Item $file.FullName $drive -Force -Verbose


}
Theo
  • 49,970
  • 8
  • 20
  • 38
  • Take advantage of poweshell's helpful `[char]` type. – Nico Nekoru May 22 '20 at 18:53
  • `$var = @(65..90); for($i=0;$i -lt $test.length;$i++){ [char]$test[$i] = $test[$i]; }` – Nico Nekoru May 22 '20 at 18:56
  • Can you elaborate about _"but it doesn't work"_ ? Do you get error messages? Do you have permission to move files to the root of these drives? BTW if you do not use switch `-File` on the Get-ChildItem cmdlet, it will return both FileInfo and DirectoryInfo objects. – Theo May 25 '20 at 12:05

1 Answers1

1

This should do the trick:

$files = dir C:\Users\Neko\Desktop #Whatever directory
$var1 = @(65..70); 
$var2 = @(71..76);
$var3 = @(77..90);
echo work3
for($i=0;$i -lt $var1.length;$i++){ [char]$var1[$i] = $var1[$i]; }
for($i=0;$i -lt $var2.length;$i++){ [char]$var2[$i] = $var2[$i]; }
for($i=0;$i -lt $var3.length;$i++){ [char]$var3[$i] = $var3[$i]; }
foreach($file in $files){
    if($file.name[0] -in $var1){$drive = 'D:\'}
    if($file.name[0] -in $var2){$drive = 'F:\'}
    if($file.name[0] -in $var3){$drive = 'E:\'}
    write-host "Moving $($file.Name) to $drive" -f Cyan
    MI -path "$file.fullname" -destination $drive -Force
}

This is very basic powershell coding. I was able to sort the files into $var1, $var2, and $var3 categories since they listed ascii characters for the letters you wanted and then converted them to letters using the for loops, a bit convoluted but this is the easiest way to do this in my opinion. You then loop through the $files variable where it takes everything from the directory you in the variable, in my case C:Users\Neko\Desktop\* and for you it would be H:\done\* and seperates them into categories from the $var1 $var2 $var3 we mentioned earlier and sets the $drive variable. It then moves the files.

ERRORS WITH YOUR COLLEAGUE'S CODE

  • [A-F] does is not the same as a number group like (1..100) and would not do anything except produce errors.
  • $file.basename isn't necessary compared to just the normal $file.name if you are only going to take the first character. Its just typing extra letters.

Overall, it was good, but not enough to accomplish your task. Full code for your case:

$files = dir H:\done
$var1 = @(65..70); 
$var2 = @(71..76);
$var3 = @(77..90);
echo work3
for($i=0;$i -lt $var1.length;$i++){ [char]$var1[$i] = $var1[$i]; }
for($i=0;$i -lt $var2.length;$i++){ [char]$var2[$i] = $var2[$i]; }
for($i=0;$i -lt $var3.length;$i++){ [char]$var3[$i] = $var3[$i]; }
foreach($file in $files){
    if($file.name[0] -in $var1){$drive = 'D:\'}
    if($file.name[0] -in $var2){$drive = 'F:\'}
    if($file.name[0] -in $var3){$drive = 'E:\'}
    write-host "Moving $($file.Name) to $drive" -f Cyan
    MI -path "$file.fullname" -destination $drive -Force
}
Nico Nekoru
  • 2,402
  • 1
  • 15
  • 32
  • Hey Neko, Thank you for this. One question, do i leave the var value as (65..70) etc or put the letters i require? – Jordon Blackstock May 23 '20 at 19:11
  • The numbers are the ascii equivalent of the letters, you would have to leave the var vaues as is – Nico Nekoru May 23 '20 at 19:12
  • Ascii codes `65-70` are `a-f` and `71-76` is `g-l` and `77-90` is `m-z` – Nico Nekoru May 23 '20 at 19:14
  • UPDATE: As of PS 6 I found out you can use the rang operator with letters using `('a'..'f')` but I have powershell ver 5.1.18362.752 so I did not realize this. https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Operators?view=powershell-7#range-operator- If you have any success with that method or my previous method, mark it as answered and if it doesn't work, let me know. – Nico Nekoru May 31 '20 at 23:33