Moving files based on file name with powershell - powershell

I need to parse a file name and move the file to a folder based on part of the file name.
Lets say I have several files in a folder C:\SYSLOG\Servers and Firewall\Logs. They are log files from several different servers or devices.. I need to move them to our NAS for archival. Sample file names:
Boston.North.Application.S01.120613.log
Boston.South.Application.S12.122513.log
Lexington.System.S02.073013.log
Lexington.System.S22.073013.log
Madison.IPS.S01.050414.txt
I need to move them to a corresponding folder on the NAS. My folder structure looks like this:
\\NAS\Logs\Boston North Application
\\NAS\Logs\Boston South Application
\\NAS\Logs\Lexington System
\\NAS\Logs\Madison IPS
So basically I am wanting to parse the file name for everything to the left of the server (Sxx), and replace the . with spaces to create the destination folder name.
The files are not always .log files. All files have a .Sxx in the name and xx will always be numbers. If destination folder does not exist, then skip the file. There are no subfolders in C:\SYSLOG\Servers and Firewall\Logs.
I think I am trying to do something similar to powershell to move files based on part of file name

Rely on the fact that everything in the file name up until the Sxx block is the destination if you just replace the . with a space:
# Retrieve the filenames
$Directory = "C:\SYSLOG\Server and Firewall\Logs"
$FileNames = (Get-Item $Directory).GetFiles()
foreach($FileName in $FileNames)
{
# Split the filename on "."
$Pieces = $FileName-split"\."
# Counting backwords, grab the pieces up until the Sxx part
$Start = $Pieces.Count*-1
$Folder = $Pieces[$Start..-4]-join" "
# Build the destination path
$Destination = "\\NAS\Logs\{0}\" -f $Folder
# Test if the destination folder exists and move it
if(Test-Path $Destination -PathType Container)
{
Move-Item -Path $FileName -Destination $Destination
}
}

Final Version.
# Retrive list of files
# $sDir = Source Directory
$sDir = "C:\Temp\Logs\"
# Generate a list of all files in source directory
$Files = (Get-ChildItem $sDir)
# $tDir = Root Target Directory
$tDir = "C:\Temp\Logs2\"
# Loop through our list of file names
foreach($File in $Files)
{
# $wFile will be our working file name
$wFile = $File.Name
# Find .Sx in the file name, where x is a number
if ($wFile -match ".S0")
{
# tFile = Trimmed File Name
# We now remove everything to the right of the . in the .Sx of the file name including the .
$tFile = $wFile.substring(0,$wFile.IndexOf('.S0'))
}
# If we do not find .S0 in string, we search for .S1
elseif ($wFile -match ".S1")
{
$tFile = $wFile.substring(0,$wFile.IndexOf('.S1'))
}
# If we do not find .S0, or S1 in string, then we search for .S2
elseif ($wFile -match ".S2")
{
$tFile = $wFile.substring(0,$wFile.IndexOf('.S2'))
}
# Now we exit our If tests and do some work
# $nfold = The name of the sub-folder that the files will go into
# We will replace the . in the file name with spaces
$nFold = $tFile.replace("."," ")
# dFold = the destination folder in the format of \\drive\folder\SubFolder\
$dFold = "$tDir$nFold"
# Test if the destination folder exists
if(Test-Path $dFold -PathType Container)
{
# If the folder exists then we move the file
Move-Item -Path $sDir$File -Destination $dFold
# Now we just write put what went where
Write-Host $File "Was Moved to:" $dFold
Write-Host
}
# If the folder does not exist then we leave it alone!
else
{
# We write our selves a note that it was not moved
Write-Host $File "Was not moved!"
}
# Now we have a drink!
}

Related

Powershell script to copy files to folders by matching file to folder names

I have a directory with empty folders, let's call it D1. And another directory (let's call it D2) with files which are named such that the file name contains the folder names from D1. I want to match the file names from D2 to folder names from D1 and copy (not move) the files to the corresponding folder in D1. Can this be done using Powershell? As an example,
D1 looks like:
FolderName1
FolderName2
FolderName3
And files in D2 look like:
abcd.FolderName1.txt
xyz.FolderName2.txt
qwerty.FolderName3.txt
EDIT: the folder names above are just an example. The actual folder/file names could vary e.g. to Folder#Name, My_Folder, abcd.1234.Folder_Name etc.
I pulled the folder names from the filename with regex.
There's a little bit of error handling in there, but you might want to instead create the folder if it doesn't exist.
$FromPath = 'C:\D2'
$ToPath = 'C:\D1'
$FilesToMove = Get-ChildItem -Path $FromPath -File
$RegexPattern = '^[^.]+\.(?<NewFolder>[^.]+)\..+$'
foreach ($File in $FilesToMove) {
If($File.Name -match $RegexPattern){
$OutFolder = Join-Path -Path $ToPath -ChildPath $Matches.NewFolder
if (Test-Path -Path $OutFolder) {
Copy-Item -Path $File -Destination $OutFolder
}
else {
Write-Error -Message "Invalid or Inaccesible path $OutFolder"
}
}
else {
Write-Error -Message "Filename $($File.Name) Is Incorrectly Formatted"
}
}

Move Folders and files from folders/subfolders with same name (copies to be renamed)

(I have tried to rewrite this to be more clear)
I have a problem with having hundreds of folders and files (each start with ABC and then numbers 001-936) that need to be moved to a single folder with the same name. For example:
C:\folders\ABC001
C:\folders\random\ABC001\
C:\folders\files\ABC001.pdf
C:\folders\ABC002.pdf
C:\folders\ABC002\
C:\folders\needs sorting\ABC002\
That I would like to move all files and folders to a folder with the same name:
C:\folders\ABC\ABC001\
C:\folders\ABC\ABC002\
and so on...
However, sometimes the orginal folder and/or file will have a duplicate in the destination folder(or may already have since folders already exist), so I want it to add to the name (1), (2), etc.
C:\folders\ABC\ABC001\ABC001\
C:\folders\ABC\ABC001\ABC001 (1)\
C:\folders\ABC\ABC001\ABC001.pdf
C:\folders\ABC\ABC002\ABC002.pdf
C:\folders\ABC\ABC002\ABC002\
C:\folders\ABC\ABC002\ABC002 (1)\
Any help would be greatly appreciated, I have been trying to solve this for weeks (everytime I needed the files) but am new to scripting/code. I started with:
for /R "C:\folders" %x in (*abc123*.*) do move "%x" "D:\folders\abc\abc123"
Closest attempt (minor edits to another code):
function MoveFileToFolder ([string]$source,[string]$destination){
# get a list of source files
$files = Get-ChildItem -Path $source -Recurse | ?{($_.PSIsContainer)}
# verify if the list of source files is empty
if ($files -ne $null) {
foreach ($file in $files) {
$filename = $file.Name
$filebase = $file.BaseName
$fileext = $file.Extension
# verify if destination file exists
$filenameNU = $filename
if (Test-Path (Join-Path $destination $filename)) {
$n = 0
while ((Test-Path (Join-Path $destination $filenameNU)) -eq $true)
{
$filenameNU = $filebase + "(" + ++$n + ")" + $fileext
}
}
Move-Item $file.FullName (Join-Path $destination $filenameNU)
}
}
}
MoveFileToFolder C:\folders\ C:\folders\abc\abc123
(I would try and run this in Powershell for each subfolder, but it became very hard to keep up with)
Thank you for reading.

Powershell - Referencing part of file name string

I am trying to extract the first part of a file name, then move to a corresponding folder with powershell. The filename looks something like "X02348957 RANDOM WORDS HERE" - I'm trying to get powershell to only look at the X02348957. The X#'s are also different lengths, so I can't just do it based on a location variable (like read everything 8 spaces to the left - the number won't always be eight spaces).
Here is my code in progress so far;
# Retrieve list of files
# $sDir = Source Directory
$sDir = "U:\Test\"
# Generate a list of all files in source directory
$Files = (Get-ChildItem $sDir)
# $tDir = Root Target Directory
$tDir = "N:\USERS\Username\General\Test\"
# Loop through our list of file names
foreach($File in $Files)
{
# $wFile is the working file name
$wFile = $File.BaseName
# Here is where the code to make it only move based on the first part of file name would go (the X#)?
# dFold = the destination folder in the format of \\drive\folder\SubFolder\
$dFold = "$tDir$wFile"
# Test if the destination folder exists
if(Test-Path $dFold -PathType Container)
{
# If the folder exists then move the file
Copy-Item -Path $sDir$File -Destination $dFold
# Denote what file was moved to where
Write-Host $File "Was Moved to:" $dFold
Write-Host
}
# If the folder does not exist, leave file alone
else
{
# Denote if a file was not moved
Write-Host $File "Was not moved!"
}
}
If I understand the issue, then:
$firstPart = $wFile.Split(' ')[0]
If you feel the need to use a regex:
$wFile -match '^(?<FirstPart>x\d+)'
$firstPart = $matches.FirstPart

Powershell Move file to new destination based on trimmed file name

I have a folder where files get dropped, I wish to pull the files from that folder and move to a new folder based on part of the file name. If the new folder is missing then create it.
I have attempted to put together the below, however it throws an error about the path already existing and doesn't move the file.
File names can be any thing with out pattern except the last 16 characters of the file, I am removing these and using the remaining as the folder name.
I am really new to scripting so if i have made a silly mistake explanations are appreciated.
Edit
I have played with different orders of operations, added a "-Force" to the new item command, tried with using "Else" and not "If (!(".
I am now at the point where it proudly displays the new directory and then stops.
Could i add the move-item part to a new for each loop so it is processed after the dir is created and tested? If so how do you arrange the { } parts?
Edit 2
I finally have it working, updated script below, the movie-item command was having issues when running into special characters in file names, in my case it was square brackets. The -literalpath switch fixed that for me.
Thanks every one for your input.
Updated script 3.0
#Set source folder
$source = "D:\test\source\"
#Set destination folder (up one level of true destination)
$dest = "D:\test\dest\"
#Define filter Arguments
$filter = "*.txt"
<#
$sourcefile - finds all files that match the filter in the source folder
$trimpath - leaves $file as is, but gets just the file name.
$string - gets file name from $trimpath and converts to a string
$trimmedstring - Takes string from $trimfile and removes the last 16 char off the end of the string
Test for path, if it exists then move on, If not then create directory
Move file to new destination
#>
pushd $source
$sourcefile = Get-ChildItem $source -Filter $filter
foreach ($file in $sourcefile){
$trimpath = $file | split-path -leaf
$string = $trimpath.Substring(0)
$trimmedstring = $string.Substring(0,$string.Length-16)
If(!(Test-Path -path "$dest\$trimmedstring")){New-Item "$dest\$trimmedstring" -Type directory -Force}
move-Item -literalpath "$file" "$dest\$trimmedstring"
}
You may have to tweak the paths being used but the below should work.
$sourcefiles = ((Get-ChildItem $source -Filter $filter).BaseName).TrimEnd(16)
foreach ($file in $sourcefiles)
{
if(!(Test-Path "$dest\$file")){
New-item -ItemType directory -path "$dest\$file"
}
Move-Item "$source\$file" "$dest\file"
}
I finally have it working, updated script below, the movie-item command was having issues when running into special characters in file names, in my case it was square brackets. The -literalpath switch fixed that for me. Thanks every one for your input.
#Set source folder
$source = "D:\test\source\"
#Set destination folder (up one level of true destination)
$dest = "D:\test\dest\"
#Define filter Arguments
$filter = "*.txt"
<#
$sourcefile - finds all files that match the filter in the source folder
$trimpath - leaves $file as is, but gets just the file name.
$string - gets file name from $trimpath and converts to a string
$trimmedstring - Takes string from $trimfile and removes the last 16 char off the end of the string
Test for path, if it exists then move on, If not then create directory
Move file to new destination
#>
pushd $source
$sourcefile = Get-ChildItem $source -Filter $filter
foreach ($file in $sourcefile){
$trimpath = $file | split-path -leaf
$string = $trimpath.Substring(0)
$trimmedstring = $string.Substring(0,$string.Length-16)
If(!(Test-Path -path "$dest\$trimmedstring")){New-Item "$dest\$trimmedstring" -Type directory -Force}
move-Item -literalpath "$file" "$dest\$trimmedstring"
}

Creating a folder on a basis of filename and move the file to that folder

I have a folder with MANY files like this
Character 1 - object one.txt
Character 4 - Object two.txt
and so on.
I would like to create subfolders based on the part before " -" and move the files into that folder.
I haven't touched PS for quite a while and I am sorry to say that I am unsure where to start except for GCI..
Any help would be greatly appreciated!
#Change Current Directory to the Folder with txt files
cd C:\path\to\folder
#List all the file contents and pipe to a foreach loop
Get-ChildItem -file | % {
#Split the file name at the dash, take the first half, and trim the spaces
#($_ is the pipeline variable so in this case it represents each file)
$folder = ($_ -split "-")[0].trim()
#if the folder doesn't exist, create it
if(-not (Test-path $folder)) {
New-item $folder -ItemType Directory
}
#Move file to the folder
Move-item $_ $folder
}