Folder X has a lot of subfolders A,B,C,D... each subfolder has a lot of files and I want to archive all files that are in those subfolders and that are older than 6 months. After that check if archive is created and delete the files that have been archived.
Here is what I tried:
#$SourceFolder = "C:\Users\sec\Desktop\X"
ForEach-Object
{
Get-ChildItem -Path "$($_.FullName)" -Exclude "*.zip"
Where-Object {($_.LastWriteTime -lt (Get-Date).AddMonths(-6))} |
Compress-Archive -DestinationPath "$($_.FullName)\06.2020andOlder.zip" -Update;
if (Test-Path 06.2020andOlder.zip) {
Remove-Item -Force
}
}
Assuming you want each subfolder to end up with a .zip archive where the older files are in, try this:
Use Group-Object to group all older files within the same subdirectory together and use that to the create the .zip file and also to remove the original files after zipping.
$SourceFolder = 'D:\Test'
$refDate = (Get-Date).AddMonths(-6).Date # take this from midnight
Get-ChildItem -Path $SourceFolder -File -Recurse -Exclude "*.zip" |
Where-Object { $_.LastWriteTime -lt $refDate } |
Group-Object DirectoryName | ForEach-Object {
# construct the target folder path for the zip file using the Name of each group
$zip = Join-Path -Path $_.Name -ChildPath '06.2020andOlder.zip'
# archive all files in the group
Compress-Archive -Path $_.Group.FullName -DestinationPath $zip -Update
# here is where you can delete the original files after zipping
$_.Group | Remove-Item -WhatIf
}
Note I have added switch -WhatIf to the Remove-Item cmdlet. This is a safety switch, so you are not actually deleting anything yet. The cmdlet now only displays what would be deleted. Once you are happy with this output, remove that -WhatIf switch so the files are deleted.
Related
I have this simple cmdlet that correctly copies files and folders to a second directory:
Copy-Item -Path 'G:\xyz\Test\A' -Recurse -Destination 'G:\xyz\Test\B\'
However I am unable to tweak it to only copy the latest file in each folder within its folder (i.e. also copying the folder structure). I have written the following, but this doesn't copy folder names and does not go down all the hierarchies of sub-folders.
Get-ChildItem -Path 'G:\xyz\Test\A' -Directory | ForEach-Object {
Get-ChildItem -Path 'G:\xyz\Test\A' -File -Recurse |
Sort-Object LastWriteTime | Select-Object -Last 1 |
Copy-Item -Destination 'G:\xyz\Test\B\'
}
Could someone please identify my errors!
A slightly different approach of collecting the directories first then iterating through them to retrieve the files.
If ( -not (Test-Path -Path "G:\Test\B")) {
$Null = New-Item -ItemType "Directory" "G:\Test\B"
}
Get-ChildItem -Path 'G:\Test\A' -Directory -Recurse |
#Sort to insure dirs are created shortest to longest
Sort-Object FullName |
ForEach-Object {
$DestPath = $($_.FullName).Replace("`\Test`\A","`\Test\`B")
If ( -not (Test-Path -Path "$DestPath")) {
$Null = New-Item -ItemType "Directory" "$DestPath"
}
Get-ChildItem -Path "$($_.FullName)" -File |
Sort-Object LastWriteTime |
Select-Object -Last 1 |
Copy-Item -Destination "$DestPath"
}
First error is that you don't pass the current directory from the outer Get-ChildItem to the inner one. The inner one currently always loops over the same sub directory.
Also, when you copy individual files in a Get-ChildItem pipeline, you have to build up the destination path on your own, in order to keep the relative source directory structure:
$source = 'G:\xyz\Test\A'
$destination = 'G:\xyz\Test\B\'
# Set base directory for outer Get-ChildItem and Resolve-Path -Relative
Push-Location $source
try {
Get-ChildItem -Directory | ForEach-Object {
Get-ChildItem -Path $_.Fullname -File -Recurse |
Sort-Object LastWriteTime | Select-Object -Last 1 |
ForEach-Object {
# Make the current file path relative to $source
$relativePath = Resolve-Path $_.Fullname -Relative
# Build up the full destination file path
$destinationFullPath = Join-Path $destination $relativePath
# Create destination directory if not already exists (-force)
$null = New-Item (Split-Path $destinationFullPath -Parent) -ItemType Directory -Force
# Copy the current file
Copy-Item -Path $_.Fullname -Destination $destinationFullPath
}
}
}
finally {
Pop-Location # Restore the current directory
}
Resolve-Path -Relative makes the given path relative to the current directory. In order to get paths relative to the source directory, we set the current directory to the source directory path using Push-Location.
The try and finally blocks make sure the current directory is restored even in case of a script-terminating error (exception).
The question is an oversimplification of the real issue.
I have a folder let's call it "ParentFolder". Within this folder are files and subfolders. I want all the files and subfolders moved from the "ParentFolder" except one specific subfolder, let's call it "SpecificChildFolder". For the "SpecificChildFolder" I don't want the folder to be moved but only the files in it.
I can do these two tasks separately. I can either move all the files and folders(including the "SpecificChildFolder) in the "ParentFolder" or I can move files from the "SpecificChildFolder" only (excluding the rest of the files and subfolders in the "ParentFolder").
I want these two tasks to happen simultaneously.
I thought I would accomplish this in two separate functions:
Move everything except "SpecificChildFolder"
Move files from within the "SpecificChildFolder"
The stage# 2 code works. It is Stage# 1 I have issues with.
I have also tried Get-ChildItem $src -ErrorAction SilentlyContinue | Where-Object {$_.Directory.Name -NotLike "*SpecificChildFolder*"} | ForEach-Object{} but this doesn't work either
Secondly, can this is not happen in one line of PowerShell?
I am using PowerShell Core 7.2
Code for Stage 1:
#Sources
$src = "C:\User\Desktop\TEST\ParentFolder\*"
$srcMcaNameChg = "C:\User\Desktop\TEST\ParentFolder"
#Destination
$dest = "C:\Users\harguls\Desktop\TEST\DestinationFolder"
Function MoveFiles{
Param(
[string]$src,
[string]$dest,
[string]$srcNameChange
)
Get-ChildItem $src -Recurse -Exclude 'SpecificChildFolder' -ErrorAction SilentlyContinue | ForEach-Object{
$fileName = $_.Name
# Check for duplicate files
$file = Test-Path -Path $dest\$fileName
Write-Output $file
if($file)
{
"$srcNameChange\$fileName" | Rename-Item -NewName ("Copy_"+$fileName)
}
}
Move-Item -Path $src -Destination $dest -Force
}
MoveFiles -src $src -dest $dest -srcNameChange $srcMcaNameChg
Here is a vague representation of what it seems you're looking to accomplish, hope the inline comments are explanatory.
$source = '\path\to\source\folder'
$destination = '\path\to\destination\folder'
# you can add multiple folders here if you want
$exceptWith = 'foldertoexclude1', 'foldertoexclude2'
# get only the subfolders of `$source` and iterate over them
Get-ChildItem $source -Directory | ForEach-Object {
# if this folder name is in the folders to exclude array
if($_.Name -in $exceptWith) {
# get only the files of this folder and move them to destination
Get-ChildItem $exclude -File | Move-Item -Destination $destination
# if we're here we can proceed with next subfolder
return
}
# if we're here means that the name of the folder was not in `$exceptWith`
# so we move this folder and all it's child folders / files
Move-Item -LiteralPath $_.FullName -Destination $destination -Recurse
}
Delete all Files in C:\temp older than Current day(s)
$Path = "E:\Testing\Order\123456"
$CurrentDate = Get-Date
Get-ChildItem $Path | Where-Object { $_.LastWriteTime -lt $CurrentDate } | Remove-Item
I am trying to run this script but it is deleting every thing. It is not maintain current date files. Is there any modification please suggesting me sir.
Make sure you get the file extensions right if they have any.
Get-ChildItem -Path C:\folder1\data -Include * -Exclude text.1, folder1 -Recurse | foreach { $_.Delete()}
Edit to answer the comment:
So you want to delete all files and folders in C:\folder1 except of files text.1 and folder.1 in data, other and alpha? It means you cannot remove these 3 folders too so they have to be excluded.
Get-ChildItem -Path C:\folder1\ -Include * -Exclude text.1, folder.1, alpha, data, other -Recurse | foreach { $_.FullName}
try this (and dont stay into your dir when you try) :
Get-ChildItem "C:\folder1\data\*" -Recurse | where Name -notin ('text.1', 'folder.1') | Remove-Item -Force -Recurse
So lets say there are a bunch of folders containing different sub folders. The example below has a root folder of user 1 and 3 sub-directories under that folder. How can I create a looping script to move items from only sub-directories that contain the string "upload" up one level to the user folder.
->user1
--->user1upload
--->randomfolder1
--->randomfolder2
->user2
--->user2upload
--->randomfolder1
--->randomfolder2
So far I have the following code which moves all files in the sub-directories to the root user folder.
$files = Get-ChildItem '*\*\*'
Get-ChildItem $files | Move-Item -Destination { $_.Directory.Parent.FullName }
$files | Remove-Item -Recurse
I want to eliminate the other folders from this so that only folders with 'upload' in its name have the file contents moved up to the root user folder. How can I do this?
EDIT:
also tried this with no luck
$files = Get-ChildItem '*\*\*' | Select-String -Pattern "upload"
Get-ChildItem $files | Move-Item -Destination { $_.Directory.Parent.FullName }
EDIT2 (3/21/2019)
To be clear, his is for an SFTP program. There is a list of user folders in C:/usrs and I want to move files from c:/usrs/user1/user1upload to C:/usrs/user1
This uses PowerShell 5 to specify -Directory. It can be done in a different way if you are not yet to PowerShell 5.
Search for the directories, then search for files within the directories.
When you are confident the the files will be moved correctly, remove the -WhatIf from the Move-Item cmdlet.
Get-ChildItem -Directory -Path $Env:USERPROFILE -Filter '*upload*' |
ForEach-Object {
Get-ChildItem -File -Path $_.FullName |
ForEach-Object {
Move-Item -Path $_.FullName -Destination $_.PSParentPath -WhatIf
}
}
I thought you were in "user's" directories where you typically would not have permission to access all. One more level of directory search.
Get-ChildItem -Directory -Path 'C:\Users\*\*upload*' |
ForEach-Object {
Get-ChildItem -File -Path $_.FullName |
ForEach-Object {
Move-Item -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath) -WhatIf
}
}
I have a powershell script that takes the list of folders in a directory and zips the latest .bak file and copies it into another directory.
There are two folders that I do not want it to look in for the .bak files. How do I exclude these folders? I have tried multiple ways of -Exclude statements and I haven't had any luck.
The folders I would like to ignore are "New folder" and "New folder1"
$source = "C:\DigiHDBlah"
$filetype = "bak"
$list=Get-ChildItem -Path $source -ErrorAction SilentlyContinue
foreach ($element in $list) {
$fn = Get-ChildItem "$source\$element\*" -Include "*.$filetype" | sort LastWriteTime | select -last 1
$bn=(Get-Item $fn).Basename
$CompressedFile=$bn + ".zip"
$fn| Compress-Archive -DestinationPath "$source\$element\$bn.zip"
Copy-Item -path "$source\$element\$CompressedFile" -Destination "C:\DigiHDBlah2"
}
Thank you!
What I would do is use the Directory property on the files that you find, and the -NotLike operator to do a simple match for the folders you don't want. I would also simplify the search by using a wildcard:
$Dest = "C:\DigiHDBlah2"
$files = Get-ChildItem "$source\*\*.$filetype" | Where{$_.Directory -NotLike '*\New Folder' -and $_.Directory -NotLike '*\New Folder1'} | Sort LastWriteTime | Group Directory | ForEach{$_.Group[0]}
ForEach($file in $Files){
$CompressedFilePath = $File.FullName + ".zip"
$file | Compress-Archive -DestinationPath $CompressedFilePath
Copy-Item $CompressedFilePath -Dest $Dest
}
Or, if you want to just supply a list of folders to exclude you could do a little string manipulation on the directoryName property to just get the last folder, and see if it is in a list of excludes like:
$Excludes = #('New Folder','New Folder1')
$Dest = "C:\DigiHDBlah2"
$files = Get-ChildItem "$source\*\*.$filetype" | Where{$_.DirectoryName.Split('\')[-1] -NotIn $Excludes} | Sort LastWriteTime | Group Directory | ForEach{$_.Group[0]}
ForEach($file in $Files){
$CompressedFilePath = $File.FullName + ".zip"
$file | Compress-Archive -DestinationPath $CompressedFilePath
Copy-Item $CompressedFilePath -Dest $Dest
}