My Samsung S8 always saves photos in the format: 20180101_001741 so the year, month and day is at the start. I was grabbing all files off the phone and sticking them in one folder on another drive as back up. Been doing this for several years so now its a mass of over 30k files from several years. Was causing Explorer to take ages to sort. So wanted to move the files to specific folders based on the year. Was taking ages doing manually so, with the help of ChatGPT and Reddit (mainly Reddit & surfingoldelephant) put this together:

<# Get files in the specified folder, ONLY files. #>

$sourceFiles = Get-ChildItem -Path 'F:\PhoneBackup\19 08 2023\SD card\DCIM\Camera' -File

<# Set the backup path. Same as sourcefiles because we get the first 4 characters of the file name and move to that folder. #>

$backupPath  = 'F:\PhoneBackup\19 08 2023\SD card\DCIM\Camera'

<# For each $file (variable declared here as its thrown away after) in sourceFiles, set $year to be the first 4 characters of the file name. #>

foreach ($file in $sourceFiles) {
    $year = $file.Name.Substring(0, 4)

    <# From reading the IO.PATH is a class (so you don't have to write all the code out. This handles folder paths)
    The combine takes the two arguements $backupPath and $year and using the IO.Path class, combines them to give a valid
    path (IO.Path sorts that) and stores that in $destDirPath #>

    $destDirPath = [IO.Path]::Combine($backupPath, $year)

    <# Void supress' the output for the following command so you don't see anything
    The command creates a new item in the $destDirPath, itemtype is a directory. The -Force just does it without confirmation. #>

    [void] (New-Item -Path $destDirPath -ItemType 'Directory' -Force)

    <# Move the item from its current path to the destination path.#>

    Move-Item -Path $file.FullName -Destination $destDirPath
}

<# Output that script has finished. #>

Write-Host "Finished moving."