powershell compress files within subfolder and over certain age - powershell

I have been looking around for several hours on this issue. I am looking for some help to fix this script. The Script is to search the shared folder for files in sub-folders and zip the folder up in that sub folder. What I need to also do is add the last access time of the files or folder so I can set an age to it such as 1 year or 365 days. Then 7z would remove the file after compression saving space on the server for other things.
So c:\share
c:\share\folder1
c:\share\folder2
c:\share\folder3
etc...
the script in my testing is like this
<#
.SYNOPSIS
<A brief description of the script>
.DESCRIPTION
<A detailed description of the script>
.PARAMETER <paramName>
<Description of script parameter>
.EXAMPLE
<An example of using the script>
#>
#Compress all the files based on your folder structure
Set-Location -Path 'c:\shared'
Get-ChildItem -Path 'c:\shared' -Recurse | Where-Object {$_.PSIsContainer } | ForEach-Object {
$directoryFullName = $_.FullName
$directoryName = $_.Name
Invoke-Expression -Command 'C:\7-Zip\7z.exe a "-x!*.zip" -sdel $directoryFullName\$directoryName.zip $directoryFullName\*'
}
I am trying this below but getting an error I do not understand yet as to formatting property.
<#
.SYNOPSIS
<A brief description of the script>
.DESCRIPTION
<A detailed description of the script>
.PARAMETER <paramName>
<Description of script parameter>
.EXAMPLE
<An example of using the script>
#>
#Compress all the files based on your folder structure
Set-Location -Path 'c:\shared'
Get-ChildItem -Path 'c:\shared' -Recurse | Where-Object {$_.PSIsContainer $_.LastWriteTime -gt "01-01-1900" -and $_.LastWriteTime -lt (get-date).AddDays(-365) } | ForEach-Object {
$directoryFullName = $_.FullName
$directoryName = $_.Name
Invoke-Expression -Command 'C:\7-Zip\7z.exe a "-x!*.zip" -sdel $directoryFullName\$directoryName.zip $directoryFullName\*'
}
here is the error
At C:\Users\HarrelsonNetworks\Documents\windowspowershell\Scripts\testbackup3.ps1:14 char:75
+ ... Path 'c:\shared' -Recurse | Where-Object {$_.PSIsContainer $_.LastWri ...
+ ~~
Unexpected token '$_' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
FullyQualifiedErrorId : UnexpectedToken
thanks
for your help
jharl

I would suggest the following: 1. Create a temp folder 2. MOVE (not copy) everything you want over to the temp folder 3. Zip the temp forder and save to desired location 3. delete the temp folder.
Breaking it out into steps like this will let you work through the problem better.
Here is something similar I wrote recently, it doesn't solve your problem but it should point you in the right direction:
function archiveLogs ( [string]$OriginalLocation, [string]$NewLocation ){
## Age of files to be archived
$DeleteOlderThan = 30
# Create temp folder to store files to be archived
New-Item c:\Temp\_tempfolder -type directory
# Get all children of specific directory older than 'X' days and of ".log" file type and move to temp folder
get-childitem -Path $OriginalLocation\*.log |
where-object {$_.LastWriteTime -lt (get-date).AddDays(-$DeleteOlderThan)} |
move-item -destination "C:\Temp\_tempfolder"
## Zip all .log files in temp folder and save to '$NewLocation\(DATE)_Archive'
& "C:\temp\7za.exe" a -tzip $NewLocation\$((Get-Date).ToString('yyyy-MM-dd HH-mm'))_Archive -r c:\Temp\_tempfolder\*.log
## Delete temp folder
Remove-Item c:\temp\_tempfolder -recurse -ErrorAction SilentlyContinue
Goodluck and let me know if you have any questions.

You're missing the logical operator -and. To resolve the error, change:
{$_.PSIsContainer $_.LastWriteTime -gt "01-01-1900" -and $_.LastWriteTime -lt (get-date).AddDays(-365) }
To:
{$_.PSIsContainer -and ($_.LastWriteTime -gt "01-01-1900") -and ($_.LastWriteTime -lt (get-date).AddDays(-365)) }

Related

Include folder name in file name as part of a loop

I try to get the directory name as part of a filename. The problem is that I want to do this for each file in a different separate folder, which does not seem to work.
What I have come to thus far is that I am able to get a list of subfolders ($GetAllActionTargetSubFolders) that each contain one or more files. In each of the subfolders, the files are combined into one file with the name 'temp'. Now, what does not work is, I want to rename this combined 'temp' file that is in each of the subfolders and want to include the subfolder name as such: FoldernameA_Consolidated202209161304.rpt (instead of temp.rpt)
I thought that the '$_.Directory.Name' would give me the directory name, but then I get this error message:
Rename-Item : Could not find a part of the path.
At line:5 char:125
+ ... de *temp* | Rename-Item -NewName {$_.Directory.Name + "_Consolidated ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (\\networkdrive\R...ctions\temp.rpt:String) [Rename-Item], DirectoryNotFoundException
+ FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
This is the script that I have thus far:
#get a list of all sub directories:
$ActionTargetFolder = "\\networkdrive\2_ActionData_Prep\"
$GetAllActionTargetSubFolders = Get-ChildItem -Path $ActionTargetFolder -Recurse | Where-Object { $_.PSIsContainer -eq $true}
#for each sub directory, make 1 file that contains all lines from the files that are in that specific sub directory:
ForEach ($foldername in $GetAllActionTargetSubFolders.FullName) {Get-ChildItem $foldername -Recurse -File -Include *.rpt | get-content | sort | get-unique | Out-File -FilePath "$($foldername)\temp.rpt"-Force }
#rename the 'temp' file that is created and include the sub-directory name, text and date/time:
ForEach ($foldername in $GetAllActionTargetSubFolders.FullName) {Get-ChildItem $foldername -Recurse -File -Include *temp* | Rename-Item -NewName {$_.Directory.Name + "_Consolidated" + $((Get-Date).ToString('yyyyMMddhhmm')) + ".rpt"}}
I hope someone could help me with this
As Cid already commented, there is no need to create a file with name temp.rpt first and rename it afterwards.
By naming the file as you want it straight away, you don't need that second loop.
Also, when using Get-ChildItem and want it to filter for just one extension, you should use -Filter instead of -Include because this works a lot faster.
Try:
# get a list of all sub directories:
$ActionTargetFolder = "\\networkdrive\2_ActionData_Prep\"
$GetAllActionTargetSubFolders = Get-ChildItem -Path $ActionTargetFolder -Directory -Recurse
# for each sub directory, make 1 file that contains all lines from the files that are in that specific sub directory:
foreach ($folder in $GetAllActionTargetSubFolders) {
# create the full path and filename for the output
$outFile = Join-Path -Path $folder.FullName -ChildPath ('{0}_Consolidated_{1:yyyyMMddHHmm}.rpt' -f $folder.Name, (Get-Date))
$content = $folder | Get-ChildItem -File -Filter '*.rpt' | Get-Content
$content | Sort-Object -Unique | Set-Content -Path $outFile
}

Powershell command doesnt find files/folder

Hello I am facing an issue with a script given here by #zett42
PowerShell search recursively for files and folder which the name contains "..."
$DesktopPath = [Environment]::GetFolderPath("Desktop")
$searchPath = '\\?\E:\Network Shares\Commun'
Get-ChildItem -LiteralPath $searchPath -Recurse -File |
Where-Object Fullname -like '*(case*' |
New-DestinationPath -CommonPath $searchPath -Destination "$home\desktop\conflits" -WhatIf | Move-Item -LiteralPath { $_.Path } -Destination { $_.Destination } -WhatIf
For example there is a complete path ;
E:\Network Shares\Commun\DOSSIER COMMUN\OFFRES EN COMMUN\ENGRAM 5000\5520 - Ecole Communale drièle**(case conflict)** - 2022-09-03T011223.317039Z\(subfolders ...)
But the command doesn't find files / folders, my network share contains a lot of long paths.
And it contains also some special characters like éèà etc.
Can you help me to adapt the command to find the unfound files/folders please ?
Thanks by advance :)

Trying to iterate through folders and take recursive actions on each file

I'm trying to build a script that I can use to delete old files based on Last Accessed date. As part of the script I want to interrogate each sub folder, find files not accessed in the last X days, create a log in the same folder of the files found and record file details in the log then delete the files.
What I think I need is a nested loop, loop 1 will get each subfolder (Get-ChildItem -Directory -Recurse) then for each folder found a second loop checks all files for last accessed date and if outside the limit will append the file details to a logfile in the folder (for user reference) and also to a master logfile (for IT Admin)
loop 1 is working as expected and getting the subfolders, but I cannot get the inner loop to recurse through the objects in the folder, I'm trying to use Get-ChildItem inside the first loop, is this the correct approach?
Code sample below, I have added pseudo to demo the logic, its really the loops I need help with:
# Set variables
$FolderPath = "E:TEST_G"
$ArchiveLimit = 7
$ArchiveDate = (Get-Date).AddDays(-$ArchiveLimit)
$MasterLogFile = "C:\Temp\ArchiveLog $(Get-Date -f yyyy-MM-dd).csv"
# Loop 1 - Iterate through each subfolder of $FolderPath
Get-ChildItem -Path $FolderPath -Directory -Recurse | ForEach-Object {
# Loop 2 - Check each file in the Subfolder and if Last Access is past
# $ArchiveDate take Action
Get-ChildItem -Path $_.DirectoryName | where {
$_.LastAccessTime -le $ArchiveDate
} | ForEach-Object {
# Check if FolderLogFile Exists, if not create it
# Append file details to folder Log
# Append File & Folder Details to Master Log
}
}
I think you're overcomplicating a bit:
#Set Variables
$FolderPath = "E:\TEST_G"
$ArchiveLimit = 7
$ArchiveDate = (Get-Date).AddDays(-$ArchiveLimit)
$MasterLogFile = "C:\Temp\ArchiveLog $(get-date -f yyyy-MM-dd).csv"
If (!(Test-Path $MasterLogFile)) {New-Item $MasterLogFile -Force}
Get-ChildItem -Path $FolderPath -File -Recurse |
Where-Object { $_.LastAccessTime -lt $ArchiveDate -and
$_.Extension -ne '.log' } |
ForEach-Object {
$FolderLogFile = Join-Path $_.DirectoryName 'name.log'
Add-Content -Value "details" -Path $FolderLogFile,$MasterLogFile
Try {
Remove-Item $_ -Force -EA Stop
} Catch {
Add-Content -Value "Unable to delete item! [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"`
-Path $FolderLogFile,$MasterLogFile
}
}
Edit:
Multiple recursive loops are unnecessary since you're already taking a recursive action in the pipeline. It's powerful enough to do the processing without having to take extra action. Add-Content from the other answer is an excellent solution over Out-File as well, so I replaced mine.
One note, though, Add-Content's -Force flag does not create the folder structure like New-Item's will. That is the reason for the line under the $MasterLogFile declaration.
Your nested loop doesn't need recursion (the outer loop already takes care of that). Just process the files in each folder (make sure you exclude the folder log):
Get-ChildItem -Path $FolderPath -Directory -Recurse | ForEach-Object {
$FolderLogFile = Join-Path $_.DirectoryName 'FolderLog.log'
Get-ChildItem -Path $_.DirectoryName -File | Where-Object {
$_.LastAccessTime -le $ArchiveDate -and
$_.FullName -ne $FolderLogFile
} | ForEach-Object {
'file details' | Add-Content $FolderLogFile
'file and folder details' | Add-Content $MasterLogFile
Remove-Item $_.FullName -Force
}
}
You don't need to test for the existence of the folder log file, because Add-Content will automatically create it if it's missing.

Deleting Files Older than 30 Days with Powershell

I am trying to delete all files in a directory and all files in its sub-directories older than 30 days, leaving all folders intact. This question seems to have been asked to death online and I have this solution which i got from Stackoverflow:
$limit = (Get-Date).AddDays(-30)
$path = "path-to"
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
Now this works and it doesn't.
When I try this on certain directories it works fine and exits normally. But when I try it on others I get this error:
Get-ChildItem : The given path's format is not supported.
At C:path-to-whatever\ClearFiles.ps1:5 char:1
+ Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsCo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ChildItem], NotSupportedException
+ FullyQualifiedErrorId : System.NotSupportedException,Microsoft.PowerShell.Commands.GetChildItemCommand
I assume this is because of the time format in $._CreationTime, I have tried to remove this but when I do it continually asks me if i really want to delete the following files because I have not specified the recursive parameter, which I have at the beginning.
Could anyone clear this up? And perhaps explain why it works on some directories and not others.
Cheers
I couldn't reproduce your issue with the following code, but I will explain how I did it with some error handling ideas.
Lets first compare the two variables.
$_.LastWriteTime = Last time the file was written to.
$_.CreationTime = Time the file was created or Copy and pasted.
Adding the Out-GridView with the Select statement will provide us with a list of files on that path. I have added the Name, Attributes, CreationTime, LastWriteTime, and Fullname.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { $_.CreationTime -lt $Date } | Select Name, Attributes, CreationTime, LastWriteTime, Fullname | Out-GridView
If you Run As Administrator you could see more files. Certain hidden directories requires Run As Administrator.
Remove-Item has a really nice option of -WhatIf. What if we decide to delete the folders and files. WhatIf option doesn't delete, but it will show you what would have been deleted. Great for testing.
Get-ChildItem -Path $path -Recurse | Where-Object { $_.CreationTime -lt $Date } | Remove-Item -Recurse -whatif
Lets put this into a working Function with some error handling:
Function Remove_FilesCreatedBeforeDate{
$Path="F:\ISO\"
$Date=(Get-Date).AddDays(-30)
$ValidPath = Test-Path $Path -IsValid
If ($ValidPath -eq $True) {
Write-Host "Path is OK and Cleanup is now running"
#Get-ChildItem -Path $path -Recurse | Where-Object { $_.CreationTime -lt $Date } | Select Name, Attributes, CreationTime, LastWriteTime, Fullname | Out-GridView
#Get-ChildItem -Path $path -Recurse | Where-Object { $_.CreationTime -lt $Date } | Remove-Item -Recurse -whatif
Get-ChildItem -Path $path -Recurse | Where-Object { $_.CreationTime -lt $Date } #| Remove-Item -Recurse -Verbose
}
Else {Write-Host "Path is not a ValidPath"}
}
Remove_FilesCreatedBeforeDate
You only see the Warning\Confirm menu when you are about to delete a folder structure. What a lot of people fail to understand is the -Force option only removes hidden files and read-only files. We will want to use the -Recurse option to avoid this prompt, but note that it will delete everything.
I have commented out the Remove-Item for safety reasons.
#| Remove-Item -Recurse -Verbose
This works with $Path options like \\SERVER\$C\Directory\ or C:\Directory\. Let me know if you have any issues with this function.

PowerShell copying folders from a backup Folder with date to destination folder

I have a folder on a net share - call it \Server\Backup\November.25.2013.backup.
This folder has the sub folders \test1, \test2, \test3.
Example:
\\Server\Backup\November.25.2013.backup\
.\Test1
.\Test2
.\Test3
I need to copy the sub folders of November.25.2013.backup to c:\Test.
This function is only to copy the backup folder contents of a specified day (in this case yesterday's backup). I am using this script to restore the last day's backup minus the name (November.25.2013.backup). Here is what I have been trying to utilize:
Get-ChildItem -Path \\Server\Backup -r | Where-Object {$_.LastWriteTime -gt (Get-Date).Date}
% { Copy-Item -Path $_.FullName -Destination C:\Test -WhatIf }
However I get the error
Copy-Item : Cannot bind argument to parameter 'Path' because it is null.
At line:3 char:20
+ % { Copy-Item -Path <<<< $_.fullname -destination C:\Test -whatif }
+ CategoryInfo : InvalidData: (:) [Copy-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand
Please understand that I am still a greenhorn with Powershell scripting and I am not sure how to troubleshoot this. I appreciate any advice.
My goal is to restore folders from a backup folder. Thanks.
You are missing a pipe at the end of the first line.
Also, If you are trying to get a folder with a last write time of yesterday, it would be less than -lt the current date
Get-ChildItem -Path \\Server\Backup -r | Where-object {$_.lastwritetime -lt (get-date).date} |
% { Copy-Item -Path $_.fullname -destination C:\Test -whatif }
But that might grab more history than you want if there is a folder for every day. If you only wanted what was written yesterday use this:
Get-ChildItem -Path \\Server\Backup -r | Where-object {($_.lastwritetime.date -eq ((get-date).adddays(-1)).date)} |
% { Copy-Item -Path $_.fullname -destination C:\Test -whatif }
Example from comment:
Get-ChildItem -Path c:\test -r | Where-object {$_.PSIscontainer -and (($_.lastwritetime.date -eq ((get-date).adddays(-1)).date))} |
% { Copy-Item $_.fullName -destination C:\Testoutput\ -recurse}
(Adding as an answer as well.)
In your pasted code, there is no pipe between the Where-Object and %.
Simple solution: add a | to the end of the first line:
Get-ChildItem -Path \\Server\Backup -r | ? {$_.lastwritetime -gt (get-date).date} |
% { Copy-Item -Path $_.fullname -destination C:\Test -whatif }