Move a files that have the same name but different extension. Powershell - powershell

I am a junior tech and have been tasked to write a short powershell script. The problem is that I have started to learn the PS 5 hours ago - once my boss told that I'm assigned to this task. I'm a bit worried it won't be completed for tomorrow so hope you guys can help me a bit. The task is:
I need to move the files to different folders depending on certain conditions, let me start from the he folder structure:
c:\LostFiles: This folder includes a long list of .mov, .jpg and .png files
c:\Media: This folder includes many subfolders withe media files and projects.
The job is to move files from c:\LostFiles to appropiate folders in c:\Media folder tree if
The name of the file from c:\LostFiles corresponds to a file name in one of the subfolders of the C:\media We must ignore the extension, for example:
C:\LostFiles has these files which we need to move (if possible) : imageFlower.png, videoMarch.mov, danceRock.bmp
C:\Media\Flowers\ has already this files: imageFlower.bmp, imageFlower.mov
imageFlower.png should be moved to this folder (C:\media\Flowers) because there is or there are files with exactly the same base name (extension must be ignored)
Only the files that have corresponding files (the same name) should be moved.
So far I have written this piece of code (I know it is not much but will be updating this code as I am working on it now (2145 GMT time). I know I missing some loops, hey yeah, I am missing a lot!
#This gets all the files from the folder
$orphans = gci -path C:\lostfiles\ -File | Select Basename
#This gets the list of files from all the folders
$Files = gci C:\media\ -Recurse -File | select Fullname
#So we can all the files and we check them 1 by 1
$orphans | ForEach-Object {
#variable that stores the name of the current file
$file = ($_.BaseName)
#path to copy the file, and then search for files with the same name but only take into the accont the base name
$path = $Files | where-object{$_ -eq $file}
#move the current file to the destination
move-item -path $_.fullname -destination $path -whatif
}

You could build a hashtable from the media files, then iterate through the lost files, looking to see if the lost file's name was in the hash. Something like:
# Create a hashtable with key = file basename and value = containing directory
$mediaFiles = #{}
Get-ChildItem -Recurse .\Media | ?{!$_.PsIsContainer} | Select-Object BaseName, DirectoryName |
ForEach-Object { $mediaFiles[$_.BaseName] = $_.DirectoryName }
# Look through lost files and if the lost file exists in the hash, then move it
Get-ChildItem -Recurse .\LostFiles | ?{!$_.PsIsContainer} |
ForEach-Object { if ($mediaFiles.ContainsKey($_.BaseName)) { Move-Item -whatif $_.FullName $mediaFiles[$_.BaseName] } }

Related

Powershell List Excel Files and Copy

I apologize for the naivety of this post, please forgive my newness.
I have approximately 20,000 network files to filter through and copy certain ones to a local drive.
File List Requirements:
Excel files of various type (.xls, .xlsx, .xlsm)
Only files modified after 4/1/2022
Only files that contain "2022" in the filename
If the file meets those requirements then:
Copy the file to a local folder (original folder path structure doesn't matter, all files can go in one folder)
Output the original path and filename to a txt file, along with the lastwritedate
I have created the following code, which successfully obtains all excel files and creates the filename list
Get-ChildItem "D:\network_folder\" -Filter *.xls -Recurse | Select-Object -Property FullName, LastWriteTime |
Export-Csv -Path "C:\local_folder\file_list.csv" -Force -NoTypeInformation
However I cannot figure out the following issues:
how and where to filter for the lastwritetime
how and where to filter for the "2022" in the name
how and where to copy the files to the local folder
right now I'm just putting this all in the command line, do I need to make some file to run this process?
Thank you for any assistance you can provide!
I guess you want something like this.
It searches for files in the source folder with 2022 in the name and having .xls (or anything following xls) as extension.
It then loops over these items, creates the subfolder structure where they were found in the destination folder, copies the files and finally writes out a CSV file with information of the original file.
$sourcePath = 'D:\network_folder'
$destination = 'D:\dest_folder'
$refDate = [datetime]::new(2022,4,2) # --> next day date as of midnight
Get-ChildItem -Path $sourcePath -Filter '*2022*.xls*' -File -Recurse |
Where-Object {$_.LastWriteTime -ge $refDate} | ForEach-Object {
# create the destination folder if it does not already exist
$target = Join-Path -Path $destination -ChildPath $_.DirectoryName.Substring($sourcePath.Length)
$null = New-Item -Path $target -ItemType Directory -Force
# copy the file
$_ | Copy-Item -Destination $target
# output the wanted properties from the original file
$_ | Select-Object Name, FullName, LastWriteTime
} | Export-Csv -Path "C:\local_folder\file_list.csv" -Force -NoTypeInformation

List files details from folders and subfolders are duplicading

I'm trying to get the names of the files within the directory and the sub directories within the "parent" directory.
I managed to solve my problem in parts, but in the last directory it is multiplying the files (as if I was checking this folder twice).
If I have 2 items, he is exporting me 4 to that last directory.
I managed to get the files from the directories, but if I have any files in the root directory (parent directory), it won't list.
Parent dir "\XML"
File1.xlsx
File2.txt
Folder2
Dir "Folder2"
File1.xml
File2.xml
So, in the CSV file exported will be 4 rows, which is duplicate files from "Folder2" folder. And it won't bring me the files in the "XML" folder, which is the parent folder.
Powershell script:
# To execute the script without agreeing with the execution policy
Set-ExecutionPolicy Bypass -Scope Process
# Defines the parent directory, where all files and folders inside it will be
$DirPai = 'D:\Users\F02579\Desktop\XML'
# Variable to store all directories within the parent directory
$DirPastas = (Get-ChildItem -Directory -Recurse $DirPai).FullName
# Variable that will keep the final result
$results = #()
foreach ($Dir in $DirPastas)
{
# Write the directory name
Write-Host $Dir
# Get the file details
$Arquivos = Get-ChildItem -Path $Dir -Recurse | Select-Object Directory, Name, Lenght, LastWriteTime, #{Name="Extension";Expression={$_.Extension}} #| Where-Object "Extension"-ne ''
# Store the result for each path
$results += $Arquivos
}
# Defines the directory to which the final file will be exported
$DiretorioExportacao = 'D:\Users\F02579\Desktop\XML\I_PI_LISTFILES.csv'
# Export the result to CSV in the previously informed directory
$results | Export-Csv -Path $DiretorioExportacao -NoTypeInformation -Encoding UTF8
You could reduce your code to the following.
Keep only the first Get_ChildItem. Remove the -Dir switch (ie. get files and folders)
Pipe directly to Select-Object. Don't bother with an explicit loop.
This will give a result with five items: four files and one folder.
You also had a typo with 'length'.
Cheers.
# To execute the script without agreeing with the execution policy
Set-ExecutionPolicy Bypass -Scope Process
# Defines the parent directory, where all files and folders inside it will be
$DirPai = 'D:\Users\F02579\Desktop\XML'
$results = (Get-ChildItem -Recurse $DirPai) | Select-Object Directory, Name, Length, LastWriteTime, #{Name="Extension";Expression={$_.Extension}} #| Where-Object "Extension"-ne ''
# Defines the directory to which the final file will be exported
$DiretorioExportacao = 'D:\Users\F02579\Desktop\XML\I_PI_LISTFILES.csv'
# Export the result to CSV in the previously informed directory
$results | Export-Csv -Path $DiretorioExportacao -NoTypeInformation -Encoding UTF8
You already have all the directories captured so in your loop you need to specify the -File parameter and there is no need for the -Recurse parmaeter.
$Arquivos = Get-ChildItem -Path $Dir -File |
Select-Object #{Name="Directory",Expression($Dir),
Name, Lenght, LastWriteTime,
#{Name="Extension";Expression={$_.Extension}}
HTH

How to prevent PowerShell -Recurse from renaming first file twice?

When using powershell to rename files with their directory name and file name, my code works, except in the first file in a directory, it gives it two copies of the directory name. So the file book1.xlsx in folder folder1 should become folder1book1.xlsx but it becomes folder1folder1book1.xlsx. The remaining files in folder1 are correctly named folder1book2.xlsx, folder1book3.xlsx, etc.
I have a directory, with many sub-directories. In each sub-dir are files that need their sub-dir name added in.
I've been following this code. For me it looks like:
dir -Filter *.xlsx -Recurse | Rename-Item -NewName {$_.Directory.Name + "_" + $_.Name}
I've also tried
--setting the Recurse -Depth 1 so that it doesn't keep looking for folders in the sub-folders.
--using ForEach-Object {$_ | ... after the pipe, similar to this.
--running it in Visual Studio Code rather than directly in PowerShell, which turns it into:
Get-ChildItem "C:\my\dir\here" -Filter *.xls -Recurse | Rename-Item -NewName {$_.DirectoryName + '_' + $_.Name}
--putting an empty folder inside the sub-directory, setting -Depth 2 to see if that will "catch" the recurse loop
I would expect the files to be named folder1_book1.xlsx, folder1_book2.xlsx, folder1_book3.xlsx.
But all of the attempted changes above give the same result. The first file is named folder1_folder1_book1.xlsx [INCORRECT], folder1_book2.xlsx[CORRECT], folder1_book3.xlsx[CORRECT].
A workaround might be writing an if statement for "not files that contain the sub-directory name" as suggested here. But the link searches for a text string not an object (probably not the correct term) like #_.Directory.Name. This post shows how to concatenate objects but not something like #_.Directory.Name. Having to put in an if statement seems like an unnecessary step if -Recurse worked the way it should, so I'm not sure this workaround gets at the heart of the issue.
I'm running windows 10 with bootcamp on a 2018 iMac (I'm in Windows a lot because I use ArcMap). Powershell 5.1.17134.858. Visual Studio Code 1.38.0. This is a task I would like to learn how to use more in the future, so explanations will help. I'm new to using PowerShell. Thanks in advance!
This was a script I created for one of my customers that may help
<##################################################################################################################################
This script can be used to search through folders to rename files from their
original name to "filename_foldername.extension". To use this script
please configure the items listed below.
Items to Congfigure
-$Original
-$Source
-$Destination
-$Files
Also please change the Out-File date on line 29 to today's date ****Example: 2019-10-02****
We've also added a change log file that is named "FileChange.txt" and can be found in the location identified on line 30
>
$Original="C:\temp\test" #Location of ".cab" files copied
$Source="C:\temp\Test" #Location were ".cab" files are stored
$Destination="C:\temp\Test\2019-10-02" #Location were you want to copy ".cab" files after the file name change. Be sure to change the date to the date you run this script. The script creates a folder with todays date
$Files=#("*.cab") #Choose the file type you want to search for
$ErrorActionPreference = "SilentlyContinue" #Suppress Errors
Get-ChildItem $Original -Include "*.cab" -File -Recurse | Rename-Item -NewName {$_.BaseName+"_"+$_.Directory.Name +'.cab'}
New-Item -ItemType Directory -Path ".\$((Get-Date).ToString('yyyy-MM-dd'))"; Get-ChildItem -recurse ($Source) -include ($Files) | Copy-Item -Destination ($Destination) -EA SilentlyContinue
Get-ChildItem $Original | Where {$_.LastWriteTime -ge [datetime]::Now.AddMinutes(-10)} | Out-File C:\temp\test\2019-10-02\FileChange.txt

Moving files/folders based on creation date and keeping folder structure

Windows 7 Pro environment.
I'm looking to create a batch or PowerShell script to move folders based on creation or last modified date.
The source folder is "D:\Video". The destination is "F:\DVRBackups\".
The requirement is that the folder structure be maintained, and that only folders older than a certain creation date are moved, whilst the others are left untouched.
The folder structure for the source folder looks like this:
D:\Video\Cam01\XXXX
D:\Video\Cam02\XXXX
D:\Video\Cam03\XXXX
..etc..
(XXX = hundreds of folders within the Cam01/02/03 folders spanning months)
The number of camera folders changes based on the computer DVR box i'm working on. Some locations have 5 cameras, some have as many as 35 (i.e., Cam01, Cam02, .., Cam35).
Folders from within the Cam01/02/03 folders need to be moved over to F:\DVRBackups, whilst maintaining the original folder structure.
i.e.
D:\Video\Cam01\0318 --> F:\DVRBackups\Video\Cam01\0318
D:\Video\Cam01\0319 --> F:\DVRBackups\Video\Cam01\0319
D:\Video\Cam02\0501 --> F:\DVRBackups\Video\Cam02\0501
..etc..
Can someone assist?
If it's just the folders within each CamXX folder that you need to check the Last modified time and them move. You can use the following in PowerShell.
$source = "D:\Video\"
$destination = "F:\DVRBackups\"
$date = Get-Date "25/03/2015 12:00"
dir $source | %{ dir $_.FullName | ?{ $_.LastWriteTime -gt $date } | Copy-Item -Destination $destination -Recurse -Force }
If you want to test what folders will be moved before hand use this command first.
dir $destination | %{ dir $_.FullName | ?{ $_.LastWriteTime -gt $date } | select LastWriteTime, FullName }
This will provide a list of the all folders that will have all there content moved.

Finding folders and files with same name using PowerShell

I need to extract the fileversion of certain DLL files of which I do not know the name. All I know is where the file that holds the fileversion is located and that its name is the same as the folder it is hiding beneath.
In truth it's something like this:
C:\inetpub\wwwroot\APPFolder\bin\files
(where the name of the Subfolder matches the name of the file in the bin folder)
After many tries (and a lot of failures), I've gone a bit back and forth, and I'm now leaning comfortably at this bit of code .... close, but no cigar:
Get-ChildItem -Path c:\temp\Documents -recurse -Filter *.dll | where-object{ (Get-ChildItem -Path c:\temp\Documents -recurse -Filter *.dll) -match $_.Directory.Name }
This code searches for all the files recursively under \temp\documents and then matches the files in the folders, which is nice ... but not quite what I wanted. Also the code above gives the folders where the files that match the folders they are in and not only the matched file.
So ... any suggestions? There are more than one DLL file in the bin folder mentioned above which is part of why I need to select the one with the same name as the APPFolder.
Here is a code sample which will give you the full file path to the files you're looking for.
dir . -Recurse -Filter *.dll | ? { -not $_.PSIsContainer } | ? { $_.FullName.ToLower().Contains( [IO.Path]::DirectorySeparatorChar + [IO.Path]::GetFileNameWithoutExtension( $_.Name.ToLower() ) + [IO.Path]::DirectorySeparatorChar ) } | Select -ExpandProperty FullName
Breaking it down, we have:
dir . -Recurse -Filter *.dll
This will search the current directory and its children recursively for all files that have a .dll file extension:
? { -not $_.PSIsContainer }
This will eliminate directories that end in .dll. Unlikely, but possible
? { $_.FullName.ToLower().Contains( [IO.Path]::DirectorySeparatorChar + [IO.Path]::GetFileNameWithoutExtension( $_.Name.ToLower() ) + [IO.Path]::DirectorySeparatorChar }
This will filter it down to the DLL files that have a file name the same as the name of a directory above it in the path.
Select -ExpandProperty FullName
This will give you the full file path.
You can then follow the answer to this question here to get the FileVersion.