Using powershell to move/make folders/subfolders based on filename - powershell

I don't really have much experience in powershell but I have files that I need to organize. The files are all pdf and will have a format similar to "Dept123_Name_year.pdf".
I want to move the documents into a folder based on "Dept123" and a sub folder "Name". If the folder is yet to exist I would like it to create the folder/subfolder.
To make it easier I was thinking of using creating an "Organize" folder on the desktop and running the program on that. If you think it'd be easier some other way, let me know.
Thanks in advance.

You can use a regular expression to match the different components of the filenames, then generate a directory structure based on that. The -Force parameter of mkdir lets you ignore whether or not the directory already exists:
$list = ls
for ($i=0; $i -le $list.Length; $i++) {
if ($list[$i].Name -match '([A-Za-z0-9]+)_([A-Za-z]+)_.*\.pdf') {
$path = Join-Path $matches[1] $matches[2]
mkdir -Force -Path $path
cp $list[$i] "$path\."
}
}
The regular expression part is in the quotes; you might need to modify it to suit your specific needs. Note that the sections in round brackets correspond to the different parts of the name being extracted; these parts are loaded, in order, into the $matches variable, which is generated automatically. E.g. '([A-Za-z0-9]+)\.txt' will match any text file with only letters or numbers in the name, and will stick the actual name - minus the extension - into $matches[1].

Using regex and full-form Powershell:
# using ?<name> within a () block in regex causes powershell to 'name' the property
# with the given name within the automatic variable, $matches, object.
$Pattern = "(?<Dept>.*)_(?<Name>.*)_(?<Year>.*)\.pdf"
# Get a list of all items in the current location. The location should be set using
# set-location, or specified to the command by adding -Path $location
$list = Get-ChildItem
# Foreach-Object loop based on the list of files
foreach ($file in $list) {
# send $true/$false results from -matches operation to $null
$File.Name -matches $Pattern 2> $Null
# build destination path from the results of the regex match operation above
$Destination = Join-Path $matches.Dept $matches.Name
# Create the destination if it does not exist
if (!(Test-Path $Destination) ) {
New-Item -ItemType Directory -Path $destination
}
# Copy the file, keeping only the year part of the name
Copy-Item $file "$destination\$($matches.year)"+".pdf"
}

Related

PowerShell - Unable to Search for [LIKE] File Names recursively through sub-directories

I have a list of a few hundred files that I need to search for. Most do NOT have file extensions, some do. I can separate those and run the job multiple times if I have to.
I have a script that I have been trying to get right and it Does not seem to work.
I need to match on just the file names and NOT the extensions.
I'm using the "-Like" option but that is not getting me the results I need. If I include a file extension then it works. Unfortunately I have many file names with unknown extensions and I need to match on just the name.
Also, the script does not seem to be scanning the sub-directories for matches. Does -Recurse not work in my example?
And Finally, when testing and I FORCE a match, it does not display the subdirectory the match was found in.
Any assistance would be most welcome.
Regards,
-Ron
#Start in this DIR
$folder = 'C:\Workspace\'
#Get the file list here
$Dir2 = 'C:\Workspace\'
$files=Get-Content $Dir2\MISSING_BMS.txt
Write-Host "Starting Folder: $folder"
# Get only files and only their names
$folderFiles = Get-ChildItem -Recurse $folder -File -Name
#Read through Directory and sub-directories
foreach ($f in $files) {
if ($folderFiles -contains $f) {
Write-Host "File $f was found." -foregroundcolor green
} else {
Write-Host "File $f was not found!" -foregroundcolor red
}
}
Get-ChildItem's -Name switch doesn't just output names when combined with -Recurse, it outputs relative paths for items located inside subdirectories.
Therefore, it is better not to use this switch and compare against the .Name property of the [System.IO.FileInfo] instances that Get-ChildItem emits by default.
# Get only files and only their names - note the use of (...).Name
$folderFiles = (Get-ChildItem -Recurse $folder -File).Name
Note that if your $Dir2\MISSING_BMS.txt file contains verbatim file names rather than wildcard patterns, you should use the -contains operator rather than -like, the wildcard matching operator.
Also, if you need to access the full paths later:
# Get the files as [System.IO.FileInfo] instances
$folderFileInfos = Get-ChildItem -Recurse $folder -File
# ...
# Access the .Name property now, using member enumeration, and see
# if the array of names contains $f
if ($folderFileInfos.Name -contains $f) { ...

Powershell Script Check if folder doesnt contain random file other than specific file, It will Create New File

Im quite new to powershell script. Currently I wan to find the files in the path, if the path doesnt contain .txt file, it will create a new text file. Is there anyway i can do that?
I've tried with script below but it came out with the error parameter eq not found
if (Test-Path $path -Exclude *.bak -eq false)
We can use Get-ChilItem as our base here and pass the properties we are searching for such as the the .txt extension and do something with it. Using the if conditional statement, we can accomplish this like so:
#assign the objects returned from Get-ChildItem to $loc
$Loc = Get-ChildItem C:\users\Abraham
#Check to see if the extension is found using a -notcontains conditional operator
#(against the property of .extension of each returned object (paths))
#See here https://www.computerperformance.co.uk/powershell/contains/
if($Loc.extension -notcontains ".txt"){
#this is our "DO", where the condition was met above
#so we will create the text file named "MyText"
#(by passing the "fullname" property which contains the full path of the objects in $Loc.)
New-Item -Path $Loc.fullname -Name MyText.txt}
What we're doing here is referencing the properties of the returned objects from Get-ChildItem by using whats called, "Dot Notation": $loc.Name, $loc.fullname, $loc.LastWriteTime, etc
You can get a list of the properties and methods(stuff you can do to the object(s)) by piping any cmdlet to Get-Member. Get-ChildItem | GM #GM is an alias for Get-Member.
Do you mean you want to use Test-Path to check if a certain file is present and if not create it?
Something like this then perhaps?
$path = 'D:\Test'
if (!(Test-Path -Path "$path\*" -Filter '*.txt' -PathType Leaf)) {
$null = New-Item -Path $path -Name ('Test_{0:ddMMyyyy}.txt' -f (Get-Date))
}

How can we separate folders using powershell script with reference of filename

I am newbie to powershell scripting and I did go through lot of articles here and not able to get much help.Can someone help me out on how to put files in specific folders:
file name example:
2008_11_chan_3748_NB001052_031_SIGNED.pdf
put it in folders:
2008/11/NB001052-031/....
if it ends with "draft", e.g.
2008_11_chan_3748_NB001052_031_Draft.pdf
put it in a separate draft folder as below
2008/11/NB001052-031/Draft
Any help is really appreciated.
Thanks in advance.
Push-Location c:\2009
Get-ChildItem -File -Filter *_*_*_*_*_*.pdf |
Move-Item -Destination {
$tokens = $_.Name -split '_'
$subdirNames = $tokens[0,1,4]
if ($tokens[-1] -like 'Draft.*') { $subdirNames += 'Draft' }
(New-Item -Force -Type Directory ($subdirNames -join '\')).FullName
} -WhatIf
Pop-Location
Note: The -WhatIf common parameter in the command above previews the move operation, but the target subfolders are created right away in this case.
Remove -WhatIf once you're sure the operation will do what you want.
(Partial) explanation:
The Get-ChildItem call gets those files in the current directory whose name matches wildcard pattern *_*_*_*_*_*.pdf.
Move-Item -Destination uses a delay-bind script block ({ ... }) to dynamically determine the target path based on the current input object, $_, which is of type System.IO.FileInfo
The code inside the script block uses the -split operator to split the file name into tokens by _, extracts the tokens of interest and appends Draft as appropriate, then creates / returns a subdirectory path based on the \-joined tokens joined in order to output the target directory path; note that -Force creates the directory on demand and quietly returns an existing directory.

Sorting jpg/pdf files into folders that already exist by name but only using the the first 6 digits

I am having issues trying to sort a large amount of files into folders.Screen shot of files that i need sorted,new files are added daily
My main issue is coming from the naming format of the files relative to the folders. Is there a way to move them by the first 6 digits into the corresponding folders that include those digits and if the folder doesn't exist have one created? I couldn't get name-split to work since the beginning of the file name isn't broken up by a break. Does anybody have any code that could do this for me? I'm still learning powershell, not great at writing from scratch yet :)
Use the String.Substring() or String.Remove() to extract the first 6 digits:
$sourceItemFolder = 'C:\unsorted'
$targetRootFolder = 'C:\folder\with\directories'
Get-ChildItem $sourceItemFolder -File |ForEach-Object {
if($_.Name.Length -ge 6){
# Extract prefix from file name
$prefix = $_.Name.Remove(6)
# Use prefix to find appropriate folder, pick the first match
$targetFolder = Get-ChildItem $targetRootFolder -Filter "${prefix}*" -Directory |Select -First 1
if(-not $targetFolder){
# No matching folder found, create one
$targetFolder = New-Item -Path $targetRootFolder -Name $prefix -Type Directory
}
# Move the file
$_ |Move-Item -Destination $targetFolder.FullName
}
}

Add to Array of wildcards in Powershell

I am new to powershell and looking to test something for a POC.
There are multiple files stored on the cloud inbox (File_1.txt, File_2.txt and so on).
I want to add these files using a wildcard to an array and then run some commands (specific to the cloud) for each file.
I cannot specify the -Path in the code as the files are located on cloud and I do not have the path.
The below code works:
$files = #("File_1.txt","File_2.txt","File_3.txt")
foreach ($file in $files) {
Run commands on cloud like...delete inbox/$file
}
However I cannot hard code the file names. I am looking to add file names using wildcard.
$files=#("File*.txt")
foreach ($file in $files) {
Run commands on cloud like...inbox/$file
}
But this does not work as in the log it is taking File*.txt as the name of the file.
Thanks in advance
You should use dir equivalent of PowerShell, Get-ChildItem (In fact dir and ls are aliases for the Cmdlet) to search files using wildcards:
$files = Get-ChildItem file*.txt
foreach($file in $files) {
DoSomeStuffWithFile $file
}
Get-ChildItem returns FileInfo objects. If you want to use the filename String in the loop, you should refer to the Name property of the object:
DoSomeStuffWithFileName $file.Name
You can easily update the file number using string interpolation. Here is a basic example of how this might work:
1 .. 10 |
ForEach-Object {
"hello" | Out-File -Path "File_$_.txt"
}
Here we generate an array of the numbers from 1 to 10 (using the range operator ..), then this is piped to our command (and hence placed in the $_ variable). As each number comes through, the path is constructed with the current value of $_, so you get File_1.txt, File_2.txt, etc.
You can use other looping techniques, but the key is that you can build the filename/path on-the-fly by having PowerShell replace the variables for you.