I am trying to write a Powershell script for a small problem I am having.
I have various log files in various directories. These log files are related to various other computers, and a new batch of these files are added every so often. These files have timestamps within the filename.
For example:
index\1\computer1_system_01122022.evtx
index\2\computer1_system_01122021.evtx
index\3\computer2_system_01122022.evtx
index\4\computer2_system_01122021.evtx
Note: date is ddMMyyyy
I am trying to write a script that can go into the 'Index' directory, look for all files containing "system", then only selecting the latest file based on the datestamp in the filename.
So for the above example, only copy the following to another directory (i.e. index\latest)
index\latest\computer1_system_01122022.evtx
index\latest\computer2_system_01122022.evtx
I hope I have described the problem clearly enough. I have tried various things, but can't figure this one out.
Any help would be much appreciated.
What I have tried so far:
I have not come up with any script for this so far, I am fairly new to powershell. I have to used .indexof to separate the datestamp, and then sort and select the newer one. But this results in the script selecting only the newest file, and discarding the files for other computers. I can't think of a way to make powershell only compare the datestamp of the two 'computer1' files and selecting the newer ones, and then two 'computer2' find and selecting the newer one, and so on.
So to clarify, the script should compare 'computer1' with all other files that contain 'computer1' and select the newer one based on the datestamp in the filename. Then, compare 'computer2' and select the newer one, then 'computer3' and so on.
Each of these selected files should be copied to a new directory.
Note: the latest datestamp on computer1 may be different from the latest datestamp on computer2. I.e. newest computer1 file may be named computer1_01122022.evtx and computer2 may be computer2_02022022.evtx. comparison of computer1 should only be with other files that contain computer1, and computer2 files should only be compared with other computer2 files.
This is part is a larger script that is being used to extract log data from files. I have written a script to extract the data, but cannot figure out what to do to get the latest log files out from the folders as described above.
Combine Group-Object with Sort-Object, using calculated properties:
# Simulate Get-ChildItem output.
[System.IO.FileInfo[]] $files =
'index\1\computer1_system_01122022.evtx ',
'index\2\computer1_system_01122021.evtx',
'index\3\computer2_system_01122022.evtx',
'index\4\computer2_system_01122021.evtx'
$files |
Group-Object { ($_.BaseName -split '_')[0] } | # group by computer name
ForEach-Object { # for each group of computer-specific files
# sort by timestamp embedded in the file name and output the most recent
$_.Group |
Sort-Object -Descending {
$dateStr = ($_.BaseName -split '_')[-1]
[datetime]::ParseExact($dateStr, 'ddMMyyyy', [cultureinfo] '')
} |
Select-Object -First 1
}
Related
I need a PS script that can copy specific files from one directory to another.
Main Goal: I want to copy all files from Month folder (November) to DirectoryX. HOWEVER,I only want to move the files with specific names from an .xlsx file with the column named FileName. So say there are 3,000 filesnames in the .xlsx file with unique filenames. This is a monthly report that is generated from SSMS.
Process: .xlsx file is created with data. The column for the filenames is FileName. I want to cross reference those filenames with the November folder and copy those files to a new directory to upload to the client.
Folder Structure:
Year: 2022
Month: 11
Day: 09
File Naming Convention: CA09a37ce4c69f31997c8656df274749c4.mp3.
Not sure the best way to do this. I have looked around on here and nothing that really suits what I need.
I really hope this makes sense and someone can guide me in the right direction. Thank you so much in advance.
We use an in-house application. I can add a PS script to it. I am brand new to Powershell so this is more complex than what I can handle.
Install the ImportExcel module, then this should work if you update the paths:
# import the FileNames column from excel file
$FileNames = Import-Excel 'C:\folder\file.xlsx' | Select -ExpandProperty FileName | Sort
# specify folder(s) to search
$Month = '11'
$SearchFolder = "C:\SourceFiles\2022\$Month" # all days in month
# get the list of existing source files, filtered by the imported file names
$SourceFiles = Get-ChildItem -Path $SearchFolder -Recurse -File |
Where Name -In $FileNames
# optionally check for missing files
$MissingFiles = Compare-Object $SourceFiles.Name $FileNames
If ($MissingFiles) {
Write-Warning "Could not find $($MissingFiles.Count) source files in $SearchFolder"
$MissingFiles.InputObject
}
# copy files to separate folder
$SourceFiles | Copy-Item -Destination "C:\Uploads\"
It's not the most efficient thing, but it should be easy enough to modify as needed
Need help with command like, one-liner, powershell to remove folders
I'm trying to find an elegant way to remove folders by folder name which reflects the date but I cannot rely on the file/folder date meta-data attributes.
Here's the problem I'm trying to solve:
I have a folder in which there are archived call recordings for each day the recording system creates folders and fills them with call recordings, a folder for each day named like format MM_dd_yyyy.
I need to remove all but the last 7 folders. But, I cannot rely on the creation/modified date on the file. That would be much easier with just powershell. So I MUST, unfortunately, remove the folders by testing the file name against the dates of the folders that I need to retain with same format (MM_dd_yyyy).
I can get the list of folder names that are to be retained base on the previous 6 days with the following Windows command line:
c:\>powershell $d0=(Get-Date).ToString('MM-dd-yyyy'); $d1=(Get-Date).AddDays(-1).ToString('MM-dd-yyyy'); $d2=(Get-Date).AddDays(-2).ToString('MM-dd-yyyy'); $d3=(Get-Date).AddDays(-3).ToString('MM-dd-yyyy'); $d4=(Get-Date).AddDays(-4).ToString('MM-dd-yyyy'); $d5=(Get-Date).AddDays(-5).ToString('MM-dd-yyyy'); $d6=(Get-Date).AddDays(-6).ToString('MM-dd-yyyy'); $d0; $d1; $d2; $d3; $d4; $d5; $d6
NOTE: I need to keep this in a command one-liner and cannot use PS1 power shell script because of corporate and domain enforced security limitations
This produces the folder names to be retained as listed below (ran on 20 NOV 2021 to retain last 7 days).
11_20_2021
11_19_2021
11_18_2021
11_17_2021
11_16_2021
11_15_2021
11_14_2021
The intention would be to remove any folder names that were like 11_13_2021, 11_12_2021... etc.
I can get away with running nested FOR loops in a Windows bat file to try and hack this together but I'm trying to find a more simple, readable and elegant one-liner that will let me do something like the following:
powershell $d=(Get-Date).AddDays(-7).ToString('MM-dd-yyyy'); and then some magic powershell stuff to remove any folder that doesn't match any of those that are to be retained.
If I had a way to provide the folder name (MM_dd_yyyy) to the (get-date).AddDays(-6) powershell command and have it return a boolean yes or no, that would be something closer to what I'm looking for.
I've been reading and you tubing and pulling hairs out but so far I'm learning but mostly making a mess of it. Any ideas are most welcome.
I'm likely approaching this all wrong. The constraints are:
Given a list of folders with naming format MM_dd_yyyy, I need to remove/delete all that are not within the last week of days.
I cannot run powershell scripts .ps1
I can run windows bat or cmd files with for loops and such
I cannot rely on the folder of files date/time meta attributes, some data in the folders may have create/write/modified dates that are not in line with the folder name. I must rely on the folder name (MM_dd_yyyy) to remove the folders.
UPDATED with resolution:
powershell "($f=Get-ChildItem -Path 'D:\PosConvSav' -Filter '*_*_*' -Directory | Where-Object { $_.Name -match '\d{2}_\d{2}_\d{4}' } | sort-object -desc)[14..($_.count)] | remove-item -recurse"
The PowerShell code for this would be:
Get-ChildItem -Path 'RootPath\Where\The\Folders\To\Delete\Are\Found' -Filter '*_*_*' -Directory |
Where-Object { $_.Name -match '\d{2}_\d{2}_\d{4}' } | # filter some more using regex -match
Sort-Object { [datetime]::ParseExact($_.Name, 'MM_dd_yyyy', $null) } | # sort by date
Select-Object -SkipLast 7 | # skip the newest 7 folders
Remove-Item -Recurse -Force # remove the rest
To play it safe, add -WhatIf to the final Remove-Item command. By doing that, the code does not actually delete anything, but show in the console what would be deleted. If you are satisfied that is correct, then remove -WhatIf to actually remove those folders.
As Olaf already commented, don't think using one-line code would be best, because what you'll end up with is code that isn't readable anymore and where mistakes are extremely hard to find.
There is no penalty whatsoever for multiline code, in fact it is THE way to go!
i want to create a .csv list of some folders in a giant directory (1400+ folders and subfolders, more than 6TB). I need to list the Fullname, creation date, last access time and last write time. Yesterday i have managed to extract some folders, but then it stopped (PC went to sleep...). The .csv that the script created got almost 1GB big, which isn't the problem. The real problem is that i don't want to list those files again.
Here is my script, that i used:
Get-ChildItem -Path P:\ -Recurse -Force -ErrorAction SilentlyContinue | Sort-Object -Property FullName,Name,CreationTime,LastAccessTime,LastWriteTime | Select-Object FullName,Name,CreationTime,LastAccessTime,LastWriteTime | Export-Csv -Path C:\...\*.csv -NoTypeInformation
I've tried some -Exclude-Parameters but that didnt work. The output file always is 0KB.
Is there a way to exclude the folders, that already got listet? The remaining 1300+ folders would be too much to insert them manually. I've tried to create a .txt list, merged them side-by-side (with Ubuntu) but that also didn't work, because of the missing backslash in the path name, like P:\folder\ (the last backslash is always missing).
The last option is to insert every path manually, which also could be automated, but i don't know how.
I have the following situation:
I have a large number of files in a directory named as thus:
'######_dynamicname_timestamp.xml'
I want to group the files by ###### then zip the grouped files into an archive named after ###### of the group. In this situation the filename and timestamp are not important, only the first six digits.
I am new to PowerSHell and am not familiar with the commands (cmdlets?) just yet. Looking for the answer at ss64 I came across group-object however I still can't get it right. So far this is as all I got:
ls D:\directory\ | select name | group-object name
Due to the timestamp and dynamic filename each file is in its own individual group. I need a way to group only by the first six digits then pass those groups to a zip or archive command. Thank you in advance for your assistance.
This pipeline should give you the desired result / the idea how to do it
Get-ChildItem D:\directory |
Group-Object -Property { $_.Name.Substring(0, 6) } |
% { Compress-Archive -Path $_.Group -DestinationPath "$($_.Name).zip" }
I have directory where various daily files gets copied. I need to write a power shell script which will create 7z archive based on groups of file create date.The name of the archive includes those group dates.
Example Below
FileA 06/23/11
FileB 06/23/11
FileC 06/24/11
Script should create 2 archives
062311.7z contains FileA, FileB
062411.7z contains FileC
Thanks in advance
--------- Now I have to develop a compression routine which can take care of daily/Weekly/ Monthly durations
The first thing you need to do is group all the files via date using group-object:
$groups = dir | group-object -property {$_.LastWriteTime.Date}
then for each group, build a command string that does your zipping and execute it:
$groups | foreach{$cmd = "7z.exe a $((Get-Date $_.Name).ToString(`"MMddyy`")).7z $([string]::join(`" `", $_.Group))"; invoke-expression $cmd}
Warning, the above is not really tested (for ex. it won't work if you spaces in your filename). But hopefully, it will give you enough to proceed.