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

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
}

Related

Extract name from folder and use it powershell

i have to build a script in powershell that does those tasks:
read the name of the the folder (example GRA - First Man on Mars)
extract the name of the folder before the "-" character and store into a variable named "shop"
copy a sample folder named "2021" with subfolders and files into the first folder "ex. GRA - First man on mars)
enter into the folder (GRA - first man on mars) and rename the excel file from "sample.xlsx" to "shop - sample.xlsx
move to the second folder
The script must repeat the same operations for all the first level folders.
i tried some script in batch, but i think that i have to move to powershell...
first step:
i tried to read the name of the folder with this:
Get-ChildItem -Recurse -Directory | Select Name,
#{ n = 'Foldername'; e = { ($_.PSPath -split "-")[1] } }
but i have to extract the left part of the name, not the right part.
Approach it like this:
Get a list of the folders
For each folder..
Parse the name
Copy the Content
Rename the file
$sampleDirectory = Get-Item -Path C:\PathTo\yourSample\Directory
$Folders = Get-ChildItem -Directory -Path C:\PathTo\YourFolders
ForEach ($folder in $folders){
$folderName = $_.Name.Split("-")[0]
Copy-Item $sampleDirectory -Destination $folder
#Play with the syntax here to get your ideal name
$desiredName = $folderName + "whatever.xls"
Get-Item $folder\sample.xls | Rename-Item -NewName $desiredName -WhatIf
}
This should get you going

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"
}

Moving files based on file name with 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!
}

Powershell script to copy and rename files in a loop

I have a number of files with extension .psa in my Prevalidation folder and I want to:
copy them one by one into my working folder
rename the .psa file to psaload.csv
run a set of commands against the file to load it to my db
and then delete the csv file from my working folder.
This will be repeated for all the .psa files I have on my source folder.
So, the question is how do I execute the set of commands in a loop over as many .psa files as present.
Here's my piece of code testing for only one file in my Prevalidation folder -
Copy-Item C:\Downloads\PreValidation\*.psa C:\Downloads\Validation\WIP
Rename-Item 'C:\Downloads\Validation\WIP\abc 1234.psa' 'psaload1.csv'
Get-Content C:\Downloads\Validation\WIP\psaload1.csv | ForEach-Object { $_.replace("\,"," ") } | Set-Content C:\Downloads\Validation\WIP\psaload.csv
Remove-Item C:\Downloads\Validation\WIP\psaload1.csv
<run the psaload.csv to load to my db>
This is what I intend to do -
Consider multiple .psa files in my C:\Downloads\Prevalidation folder.
For each C:\Downloads\PreValidation\*.psa
BEGIN LOOP
Copy-Item C:\Downloads\PreValidation\aaaa.psa C:\Downloads\Validation\WIP\aaaa.psa
Rename-Item 'C:\Downloads\Validation\WIP\aaaa.psa' 'psaload1.csv'
Get-Content C:\Downloads\Validation\WIP\psaload1.csv | ForEach-Object { $_.replace("\,"," ") } | Set-Content C:\Downloads\Validation\WIP\psaload.csv
Remove-Item C:\Downloads\Validation\WIP\psaload1.csv
END LOOP
I am looking for the syntax to run these set of commands for each files one by one as present in my /prevalidation folder.
Since all the other answers were quite horrible code and not very idiomatic PowerShell, here is my take (though untested):
# Get all .psa files
Get-ChildItem C:\Downloads\PreValidation\*.psa |
ForEach-Object {
# Load the file's contents, replace commas with spaces
(Get-Content $_) -replace ',', ' ' |
# and write it to the correct folder and file name
Out-File C:\Downloads\WIP\psaload.csv
# I guess you'd run whatever you're doing against the file here,
# not after the loop
Remove-Item C:\Downloads\WIP\psaload.csv
}
You can use foreach with Get-Item to do the loop. Get-Item will return a FileInfo
object that you can use to get the file name (and other info) from. So you could do something like:
foreach($file in (Get-Item .\*.psa))
{
Copy-Item $file.FullName "C:\Downloads\Validation\WIP\$($file.Name)";
}
etc.
Try this:
$a = Get-Item .\*.psa
foreach($file in $a)
{
Copy-Item $file.FullName "C:\Downloads\Validation\WIP\$($file.Name.replace(".psa",".psload.csv)";
remove-item $file
}