I have a main folder where other folders reside with .mkg files . These folders have a certain format.
Folder = NameSerie.SxEy.Randomstuf
Item in folder = NameSerie.SxEy.Randomstuf.mkv
Where x is the season number and y is the episode number.
What i want to do is automaticly create a folder if the nameSerie isnt already created and put the .mkv files in this folder.
So, if we have folders named NameSerie.SxEy.Randomstuf we check if folder NameSerie exists, if not we create one. Then we enter folder NameSerie.SxEy.Randomstuf and copy the NameSerie.SxEy.Randomstuf.mkv file in the NameSerie folder.
the file name needs to change from NameSerie.SxEy.Ra.n[dom}stuf.mkv to NameSerie.SxEy.mkv but I cant seem to figure out how to remove the random stuf after the NameSerie.SxEy.< >.mkv
This is the code that i have managed to create but im still stuck. I have managed to create a folder if one does not exists but this only works if the .mkv file is not in a folder.
$Location = "\\<ip>\Share\Media\Series"
#rename files
Get-ChildItem $Location | Rename-Item -NewName {$_.Name.Replace(" [480p]","") }
#make folder for serie if it does not exist
Get-ChildItem "$Location\*.mkv" |
Foreach-Object {
$FullName = $_.Name
$pos = $FullName.IndexOf(" - ")
$Name = $FullName.Substring(0, $pos)
Write-Host $_.FullName
$TARGETDIR = "$Location\$Name"
if( -Not (Test-Path -Path $TARGETDIR ) )
{
New-Item -ItemType directory -Path $TARGETDIR
}
Move-Item -Path $_.FullName -Destination $TARGETDIR
}
You could use the parameter -Recurse when you list files from the path like this:
Get-ChildItem "$Location\*.mkv" -Recurse
instead of:
Get-ChildItem "$Location\*.mkv"
With the -Recurse parameter, the script will list files in the current directory and for each directory in the current directory, it will do the same recursively. So the .mkv inside other folders won't hide any longer.
Related
I need to batch copy a sort of file extensions from subfolders to specific folders for each location.
All folders have a 6 digit number
let's say folder Rood folder: BATCH
Subfolder 1: 000000
Subfolder 2: 111111
despite their extensions, most files have the name as the subfolder but some of them may have extra alphanumeric characters, therefore the script should grab only the ones that are not larger than 6 digits.
Example Subfolder1: 000000.pdf 000000.eps the script would need to grab all pdf within subfolders and export them to a PDF exclusive new folder, and the same would apply for eps files.
I know nothing about powershell but I know that something like this would work for an specific subfolder but I'm still missing the parts where it distributes them to a new PDFONLY and EPSONLY folders and the fact the I want to apply this to all the folders whiting the root folder.
Get-ChildItem -Path "C:\BATCH\*" -Include *.pdf,*.eps -Recurse | Copy-Item -Destination D:\
You can use Group-Object to group all the files by their extension and then loop over each group of objects, create a new folder with the desired name and lastly copy all objects of each group to their folders.
$target = 'D:\' # Set destination here
Get-ChildItem -Path C:\BATCH\* -Include *.py, *.ps1 -Recurse |
Group-Object Extension | ForEach-Object {
# Example of `$folderName` would be `PDF ONLY`
$folderName = '{0} ONLY' -f $_.Name.TrimStart('.').ToUpper()
$destination = Join-Path $target -ChildPath $folderName
# If the `$destination` folder doesn't exist
if(-not (Test-Path $destination)) {
# Create it
$null = New-Item $destination -ItemType Directory
}
Copy-Item -LiteralPath $_.Group.FullName -Destination $destination
}
Similar to Santiago's answer but with an extra filter and without grouping you can do this:
$destination = 'X:\somewhere'
Get-ChildItem -Path "C:\BATCH" -Include '*.pdf','*.eps' -File -Recurse |
Where-Object {$_.BaseName -match '^\d{6}$' } | # filter files with a BaseName of just 6 digits
ForEach-Object {
$targetPath = Join-Path -Path $destination -ChildPath ('{0}ONLY' -f $_.Extension.TrimStart(".").ToUpper())
# make sure the target path exists
# for directories, using the -Force switch either creates a new folder
# or returns the DirectoryInfo object of an existing folder.
$null = New-Item -Path $targetPath -ItemType Directory -Force
$_ | Copy-Item -Destination $targetPath
}
I am trying to clean up and group files in a directory by creating subdirectories and then copying the files into the new directories.
Example:
test01.a.jpg
test01.a.txt
test01.b.bak
test01.b.txt
test02.a.txt
test02.a.jpg
test02.a.bak
test03.a.txt
test03.a.bak
test03.b.txt
I wish to create subdirectories like test01, test02, test03 and ideally copy the relevant files over. All groups will have a txt file but more or less of the others.
To create the directories I have got as far as
gci -file *.txt | New-Item -ItemType directory $_.name
which doesn't work as expected.
If your files have names like that, you can simply split the filename on the dot and take only the first part as new folder name.
Then test if a subfolder like that already exists (if not create it) and move the file.
Something like this
$sourcePath = 'D:\Test' # put the real path to the files here
# if you want only the files with extension .txt, use filter '*.*.txt'
(Get-ChildItem -Path $sourcePath -File -Filter '*.*.*') | ForEach-Object {
# use the first part of the file name for subdirectory name
$destinationPath = Join-Path -Path $sourcePath -ChildPath $_.Name.Split(".")[0]
if (!(Test-Path -Path $destinationPath -PathType Container)) {
# if a subdirectory with that name does not already exist, create it
$null = New-Item -Path $destinationPath -ItemType Directory
}
# now move the file to that (new) destination folder
$_ | Move-Item -Destination $destinationPath
}
Actually, algorithm is simple (we don't need to previously compare names of files. All we need is just use a $_.BaseName property)
<#Creating folders and moving files using BaseName property #>
gci *.txt | % { new-item -ItemType Directory -Path ($_.Directory.ToString() + "\" + $_.BaseName.ToString())}
gci -file | % { Move-item $_.Fullname ($_.Directory.ToString() + "\" + $_.BaseName.ToString())}
I have Several zip files that Contain multiple filetypes. The ONLY ones I am interested in are the .txt files. I need to extract the .txt files only and place them in a folder of their own, ignoring all other file types in the zips files.
All the zip files are in the same folder.
Example
-foo.zip
--1.aaa
--2.bbb
--3.ccc
--4.txt
-foo2.zip
--5.aaa
--6.bbb
--7.ccc
--8.txt
I want to have 4.txt and 8.txt extracted to another folder. I can't for the life of my figure it out and spent ages looking, googling and trying. Even managing to delete to zips once in a while :-)
Thanks in advance
Use the ZipArchive type to programmatically inspect the archive before extracting:
Add-Type -AssemblyName System.IO.Compression
$destination = "C:\destination\folder"
# Locate zip file
$zipFile = Get-Item C:\path\to\file.zip
# Open a read-only file stream
$zipFileStream = $zipFile.OpenRead()
# Instantiate ZipArchive
$zipArchive = [System.IO.Compression.ZipArchive]::new($zipFileStream)
# Iterate over all entries and pick the ones you like
foreach($entry in $zipArchive.Entries){
if($entry.Name -like '*.txt'){
# Create new file on disk, open writable stream
$targetFileStream = $(
New-Item -Path $destination -Name $entry.Name -ItemType File
).OpenWrite()
# Open stream to compressed file, copy to new file stream
$entryStream = $entry.Open()
$entryStream.BaseStream.CopyTo($targetFileStream)
# Clean up
$targetFileStream,$entryStream |ForEach-Object Dispose
}
}
# Clean up
$zipArchive,$zipFileStream |ForEach-Object Dispose
Repeat for each zip file.
Note that the code above has very minimal error-handling, and is to be read as an example
Try this:
Set-Location "Extraction path"
#("full path of foo.zip","full path of foo2.zip") | ForEach {
& "Full path of 7z.exe" x '-i!*.txt' $_.FullName
}
Sets location to the path where files will be extracted.
Passes a array of zip files to for loop.
Exexute 7z command to extract only zip files.
Here is one approach:
Go through each .zip file in a folder.
Extract archive into separate folder.
Extract .txt file from folder.
Copy files into destination folder containing all .txt files. This will overwrite files if they already exist in the destination folder.
Cleanup extracted folders once finished.
Demo:
function Copy-ZipArchiveFiles {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[ValidateScript({
if (-not(Test-Path $_ -PathType Container))
{
throw "The source path $_ does not exist. Please enter a valid source path."
}
else
{
$true
}
})]
[string]$Path,
[Parameter(Mandatory=$true)]
[ValidateScript({
if ([string]::IsNullOrEmpty($_.Trim()))
{
throw "The Destination path is null or empty. Please enter a valid destination path."
}
else
{
$true
}
})]
[string]$Destination,
[Parameter(Mandatory=$false)]
[AllowNull()]
[AllowEmptyString()]
[AllowEmptyCollection()]
[string[]]$Include
)
# Create destination folder if it doesn't already exist
if (-not(Test-Path -Path $Destination -PathType Container))
{
try
{
New-Item -Path $Destination -ItemType Directory -ErrorAction Stop
}
catch
{
throw "The destination path $Destination is invalid. Please enter a valid destination path."
}
}
# Go through each .zip file
foreach ($zipFile in Get-ChildItem -Path $Path -Filter *.zip)
{
# Get folder name from zip file w/o .zip at the end
$zipFolder = Split-Path $zipFile -LeafBase
# Get full folder path
$folderPath = Join-Path -Path $Path -ChildPath $zipFolder
# Expand .zip file into folder if it doesn't exist
if (-not(Test-Path -Path $folderPath -PathType Container))
{
Expand-Archive -Path $zipFile.FullName -DestinationPath $folderPath
}
# Copy files into destination folder
foreach ($file in Get-ChildItem $folderPath -Include $Include -Recurse)
{
Copy-Item -Path $file.FullName -Destination $Destination
}
# Delete extracted folders
Remove-Item -Path $folderPath -Recurse -Force
}
}
Usage:
Copy-ZipArchiveFiles `
-Path "C:\path\to\zip\files" `
-Destination "C:\path\to\text\files" `
-Include "*.txt"
Note: Could also use this for multiple extension types as well by passing -Include *.txt, *.pdf. I also went a bit overboard in the parameter error checking, but I believe in writing robust code. Good habit to get into when writing your own cmdlets anyways :)
I have a folder that contains many rar or zip files. I want put similar files (based on part word in filename if exist) to own folder.by default in parent folder there isn't any folder.maybe in future another part of file added to parent directory so this time it should move file to his own folder instead of create new folder.
For example assume the files are:
Visual_Studio_2015.part1.rar
Visual_Studio_2015.part2.rar
Visual_Studio_2015.part3.rar
SQL-Server-Enterprise-2016-SP1.part1.rar
SQL-Server-Enterprise-2016-SP1.part2.rar
VSCodeSetup x64 1.29.1.rar
Microsoft.Visual.Studio.Ultimate.2012.update.3.part1.rar
Microsoft.Visual.Studio.Ultimate.2012.update.3.part12.rar
after moving,become looks like this:
Parent Directory
├───Visual_Studio_2015
│ ├───Visual_Studio_2015.part1.rar
│ ├───Visual_Studio_2015.part2.rar
│ ├───Visual_Studio_2015.part3.rar
├───VSCodeSetup x64 1.29.1
│ ├───VSCodeSetup x64 1.29.1.rar
├───SQL-Server-Enterprise-2016-SP1
│ ├───SQL-Server-Enterprise-2016-SP1.part1.rar
│ ├───SQL-Server-Enterprise-2016-SP1.part2.rar
├───Microsoft.Visual.Studio.Ultimate.2012.update.3
│ ├───Microsoft.Visual.Studio.Ultimate.2012.update.3.part1.rar
│ ├───Microsoft.Visual.Studio.Ultimate.2012.update.3.part2.rar
i can't use any software or compiled programming language for this problem. sorry for weak English
update:
in powershell somthing like this:
Get-ChildItem -File |
Group-Object { $_.Name -replace '.part.*' } |
ForEach-Object {
$dir = New-Item -Type Directory -Name $_.Name
$_.Group | Move-Item -Destination $dir
}
can separating files that have part in filename but not work for without it, also i must mention that all filename end with .partX (X is a digit) if it is multi parted archives.
If all the files are in one root folder and have the naming convention you specify, then here is one way to move them into appropriate subfolders:
Get-Childitem -path "C:\Test" -File |
ForEach-Object {
if($_.Name -match "^(?<folder>.*)\.part\d+|(?<folder>.*)\.rar$") {
New-Item -Path "$($_.Directory)\$($matches.Folder)" -ItemType Directory -Force | Out-Null
Move-Item -Path $_.FullName -Destination "$($_.Directory)\$($matches.Folder)\$($_.Name)" -Force
}
}
Change the path in Get-Childitem as appropriate. Also, you can modify the paths for New-Item and Move-Item if you want them to be located somewhere else instead of as subfolders of the root directory.
Another way to do it would be this:
$parentFolder = '<THE PARENTFOLDER THAT HOLDS ALL .RAR AND .ZIP FILES>'
# Get all files inside the parent folder with extension '.rar' or '.zip'
# Because '-Filter' only accepts a single string, we need to use a 'Where-Object' clause.
# Another way would be to use the '-Include' parameter on Get-Childitem, but for that to work
# you must either also use '-Recurse' or append '\*' to the $parentfolder like this:
# Get-ChildItem -Path "$parentFolder\*" -File -Include *.rar, *.zip
Get-ChildItem -Path $parentFolder -File | Where-Object { $_.Extension -match '\.(rar|zip)$' } | ForEach-Object {
# create the name of the subfolder by removing the '.partX' from the basename if that exists
$subFolder = Join-Path -Path $parentFolder -ChildPath ($_.BaseName -replace '\.part\d+', '')
# create this subfolder if it does not already exist
if (!(Test-Path -Path $subFolder -PathType Container)) {
New-Item -Path $subFolder -ItemType Directory -Force | Out-Null
}
# move the file to the subfolder
$_ | Move-Item -Destination $subFolder
}
Requirements:
Iterate through all folders and files in each directory
Delete all files in each subdirectory except for the newest one (contains filename time stamp) and has a specific filename pattern or instead copy the one file in each subdirectory that is the newest and that is preceded with LIVE_DATA. (There are other files in each subdirectory I wish to ignore).
Directory: AISI-301.0000000001006165.2015-08-24_23-57-46-1
File: LIVE_DATA_2015-08-24_23-57-51.413+0000.MCA
How can I iterate through all of the files recursively while doing comparisons between files in each subdirectory only? I don't want to compare all of them together. Just the one's inside each subdirectory.
for $filename in Get-ChildItem -recurse {
for $filename in $directory {
if ($filename > $filename2) {
$temp = $filename
}
$filename2 = $filename1
}
}
This is what I ended up using to rename my file's after the directory names. It appends the file name to the end and the directory name comes first. I hope this helps somebody else that might be searching for this solution.
Get-ChildItem -include *LIVE_DATA_*.MCA -recurse | Rename-Item -NewName { $_.Directory.Name+'_'+$_.Name}
If you want to remove all files LIVE_DATA_* except the most recent one on a per-folder basis you could do something like this:
$root = 'C:\path\to\root\folder'
Get-ChildItem $root -Recurse | ? { $_.PSIsContainer } | ForEach-Object {
Get-ChildItem (Join-Path $_.FullName 'LIVE_DATA_*') |
Sort-Object Name -Desc |
Select-Object -Skip 1 |
Remove-Item -Force
}
Get-ChildItem $root -Recurse | ? { $_.PSIsContainer } lists all subfolders of $root. Then the ForEach-Object runs another Get-ChildItem statement (without recursion) for each subfolder separately. The Join-Path statement builds a wildcard path from the filename pattern and the full path to the folder (C:\path\to\root\folder\sub\folder\LIVE_DATA_*).
Basically the code lists all folders, then processes the files for each individual folder.