I have a requirement to exclude files based on year, country name and last modified date from that particular year and rest files from that particular year and the country moved to an archive folder
for an example
SS_MM_Master_finland_2018.xlsx last modified date 27/06/2018 19:00.
SS_MM_Master_finland_2017.xlsx last modified date 27/06/2017 19:00.
in this case, same country and year is different in the file name so that particular year- last modified date would be excluded so both the files will be excluded
wants to know if someone can give a small example based on their experience...not necessary to be from above example or any multiple exclude rule or anything contribution would be appreciated
funny thing is that i have only single file excluder statement and do not know the multiple file excluder rule based on file name, Any example appericiated
I have only single file exclude statement
$sourcedir = 'C:\Test\Country'
$destdir = 'C:\Test\Country\Archive'
Get-ChildItem -File -Path $sourcedir |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Destination $destdir -force
thanks
I post this as an answer as I don't have the characters to do it as comment.
Let me see if I understand this.
$Files = Get-ChildItem -File C:\Setup | select Name, LastWriteTime
You then have an export of the files like:
Name LastWriteTime
---- -------------
SS_MM_Master_Finland_2017.txt 6/27/2018 4:30:09 PM
SS_MM_Master_Finland_2018.txt 6/27/2018 4:30:09 PM
SS_MM_Master_Germany_2017.txt 6/27/2018 4:30:09 PM
SS_MM_Master_Germany_2018y.txt 6/27/2018 4:30:09 PM
SS_MM_Master_Italy_2017.txt 6/27/2018 4:30:09 PM
SS_MM_Master_Italy_2018.txt 6/27/2018 4:30:09 PM
And then you can go with an foreach with if like:
foreach ($File in $Files) {
If ($File.Name -like "*Italy*" -and $File.Name -like "*2017*") {
Write-Host $File.Name
}
Else{
Write-Host "This is not the file you are looking for" $file.Name
}
}
I believe you can understand the concept behind this code. You can replace the Italy with a variable that you can do with Read-Host that goes for all your conditions on the if statement and then if those are true move the file to the other folder.
Hope this answer will help you.
Related
I am creating a backup and restore tool with powershell script and I am trying to make it so that when restoring, the script picks the last folder created and restores from that directory structure. Basically I am having the script start with making a backup directory with a date/time stamp like so:
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$CurrentDomainName = $CurrentUser.split("\")[0]
$CurrentUserName = $CurrentUser.split("\")[1]
$folderdate = Get-Date -f MMddyyyy_Hm
$homedir = Get-Aduser $CurrentUserName -prop HomeDirectory | select -ExpandProperty
HomeDirectory
New-Item $homedir -Name "TXBackup\$folderdate" -ItemType Directory
$cbookmarks = "$env:userprofile\Appdata\Local\Google\Chrome\User Data\Default\Bookmarks"
md $homedir\TXBackup\$folderdate\Chrome
Copy-Item $cbookmarks "$homedir\TXBackup\$folderdate\Chrome" -Recurse
Backup Folder Structure
Basically everytime someone runs the backup tool it will create a subfolder under the Backup directory with the date/time name to track the latest one. The problem comes when I want to restore from the last one create I can no longer use a $folderdate variable since it will pull the whatever the time is while the tool is being run. Here is the code without taking into account what the last folder is. I tried using sort but that doesn't appear to give me a clear path to select the last one created or I just am such a noob I didn't use it right :(
##Restoring Files from Backup
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$CurrentDomainName = $CurrentUser.split("\")[0]
$CurrentUserName = $CurrentUser.split("\")[1]
$homedir = get-aduser $CurrentUserName -prop HomeDirectory | select -ExpandProperty HomeDirectory
##Restoring Chrome Bookmarks
Sort-Object -Property LastWriteTime |
Select-Object -Last 1
$rbookmarks = "$homedir\TXBackup\$folderdate\Chrome\Bookmarks"
Copy-Item $rbookmarks "C:\Test\"
I know I didn't use that correctly but any direction would be awesome for this newbie :)
You can use Sort-Object with a script block and use [DateTime] methods to parse the date from the folder name, using the same format string you used to create them.
# Sort directory names descending
Get-ChildItem -Directory | Sort-Object -Desc {
# Try to parse the long format first
$dt = [DateTime]::new( 0 )
if( [DateTime]::TryParseExact( $_.Name, 'MMddyyyy_HHmm', [CultureInfo]::InvariantCulture, [Globalization.DateTimeStyles]::none, [ref] $dt ) ) {
return $dt
}
# Fallback to short format
[DateTime]::ParseExact( $_.Name, 'MMddyyyy', [CultureInfo]::InvariantCulture )
} | Select-Object -First 1 | ForEach-Object Name
Note: I've changed the time format from Hm to HHmm, because Hm would cause a parsing ambiguity, e. g. 01:46 would be formatted as 146, but parsed as 14:06.
Also I would move the year to the beginning, e. g. 20220821_1406, so you could simply sort by name, without having to use a script block. But that is not a problem, just an (in)convenience and you might have a reason to put the year after the day.
Given these folders:
08212022
08222022
08222022_1406
08222022_1322
08222022_1324
08222022_1325
08222022_1343
The code above produces the following output:
08222022_1406
To confirm the ordering is correct, I've removed the Select-Object call:
08222022_1406
08222022_1343
08222022_1325
08222022_1324
08222022_1322
08222022
08212022
Note that the ordering is descending (-Desc), so Select-Object -First 1 can be used to more effectively select the latest folder.
In PowerShell, I can get a nice list of files in descending sorted order using a filter:
$tt = gci -Path \\Munis2\musys_read\export_test\* -Include "ARLMA_*.csv" | sort LastWriteTime -Descending
PS H:\WindowsPowerShell\Scripts\ProductionScripts\Munis> $tt
Directory: \\Munis2\musys_read\export_test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 03/04/2022 3:09 AM 25545520 ARLMA_20220304030027.csv
.
.
.
Then, I can get just the name of the file for the purposes of transferring that file to an FTP site.
PS H:\WindowsPowerShell\Scripts\ProductionScripts\Munis> $tt[0].Name
ARLMA_20220304030027.csv
How can I parse $tt[0].LastWriteTime
PS H:\WindowsPowerShell\Scripts\ProductionScripts\Munis> $tt[0].LastWriteTime
Friday, March 4, 2022 3:09:14 AM
into something that looks like yymmddhhmmss, or is there a way to get the binary time of the file the last time it was accessed?
The ToString() method can be used to format the date into a string. Are you sure that a two digit year is appropriate?
$DateResult = (Get-ChildItem -Path \\Munis2\musys_read\export_test\* -Include "ARLMA_*.csv" |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -First 1).LastWriteTime.ToString('yyMMddHHmmss')
I am trying to use powershell to get all child elements in a folder the code I am using is
Get-ChildItem -Recurse -path C:\clntfiles
this code gives output like
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 4/29/2015 9:11 AM 6919044 HD 100616 Dec2014.pdf
-a--- 5/1/2015 11:42 AM 7091019 HD 101642 Jan2015.pdf
I don't want Mode lastWriteTime Length and name of file without .pdf extension
the output should be like
Dec2014
Jan2015
I am not sure how to filter that. please advise
I'll start by posting something similar to Leptonator's answer, but simplified by using the Select-Object command (alias Select used in code because it's habit, and I'm lazy).
$files = Get-ChildItem -Recurse -path C:\clntfiles | Select -ExpandProperty BaseName
Now that gets you the file names without extension. But, you actually asked for only part of the file names, as the first file name is "HD 100616 Dec2014.pdf" and you specified that you actually only want "Dec2014" to be returned. We can do that a couple different ways, but my favorite of them would be a RegEx match (because RegEx is awesome, and I think the LastIndexOf/SubString combo is overly complicated imho).
So, a RegEx match of "\w+$" will get what you want. That is broken down like this:
\w means any letter or number
+ means 1 or more of them
$ means the end of the string/line
So that's 1 or more alpha-numeric characters at the end of the string. We pipe our array of file names into a ForEach-Object loop (alias ForEach used out of habit), and then we have:
$Files | ForEach{ [RegEx]::Matches($_,"\w+$")}
Now, this outputs a [System.Text.RegularExpressions.Match] object, which is more than you want, but it does have a property Value which is exactly what you asked for! So we use Select -Expand again for that property and the output is precisely what you asked for:
$files = Get-ChildItem -Recurse -path C:\clntfiles | Select -ExpandProperty BaseName
$files | ForEach{[regex]::Matches($_,"\w+$")} | Select -Expand Value
RegEx matches are really handy, and if you learn about them you can simplify that quite a bit more like this:
gci C:\clntfiles -Rec | ?{$_.BaseName -match "(\w+)$"} | %{$Matches[1]}
That one line, as well as the two line code above it both should output:
Dec2014
Jan2015
Something like this should do it for you..
$files = Get-ChildItem -Recurse -path C:\clntfiles
if ($files -ne $null)
{
foreach ($file in $files)
{
$file.BaseName
}
}
In my folder, it shows:
> 2014-03-28_exeresult_file
> 2014-03-30_exeresult_file
> 2014-03-31_exeresult_file
> 2014-04-02_exeresult_file
> 2014-04-03_exeresult_file
> 2014-04-04_exeresult_file
> 2014-04-06_exeresult_file
> 2014-04-08_exeresult_file
and are indeed .txt files
Hope this helps!
Use the following Get-ChildItem -Recurse -name -path C:\clntfiles. This will get you only the file names.
Working solution:
$names = Get-ChildItem -name
foreach($n in $names) {$n.Substring(0,$n.IndexOf("."))}
You can also use LastIndexOf if part of the file name is .
I have a file that is generated daily. It is generated with the filename dailyfile.dat.
The file needs to be copied into a destination folder and numerated with a single digit that is one higher than the file already in the destination folder so that all files coexist and have no gap in numeration.
In other words, I need each day's copy to add +1 to whatever is already in the destination folder. If 0,1 & 2 exist in the destination folder, then the new copy placed in the destination should be named 3 and so on. If no files exist, it gets named 0.
i.e.
Exists
c:\source\dailyfile.dat
c:\destination\dailyfile0.dat
process
copy c:\source\dailyfile.dat -> c:\destination\dailyfile1.dat
results
c:\destination\dailyfile0.dat
c:\destination\dailyfile1.dat
Alternatively you could parse the name of the file, get the number off the end, select the highest number, and add one to create the new path. This has the advantage of being able to "pick up where you left off" if you ever archive some of your daily files.
$src = 'c:\source\dailyfile.dat'
$dstFolder = 'c:\destination'
[int32]$LastFile = Get-ChildItem $dstFolder |
Where {$_.BaseName -match "^dailyfile(\d+)"} |
ForEach {$Matches[1]} |
Sort -Descending |
Select -First 1
If ($LastFile) {$LastFile++} else {$LastFile = 0}
$Dest = "C:\Destination\DailyFile$LastFile.dat"
Copy-Item $src -Dest $Dest
This way if you archive them annually or something in a couple years you would end up with (assuming you always leave at least 1 file in the folder):
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 5/21/2015 7:47 PM 2015
d---- 5/21/2016 7:47 PM 2016
-a--- 5/21/2017 2:00 PM 580984 DailyFile730.dat
-a--- 5/22/2017 2:00 PM 392610 DailyFile731.dat
Something like this should work:
$src = 'c:\source\dailyfile.dat'
$dstFolder = 'c:\destination'
$f = Get-Item $src
$n = 0
do {
$dst = Join-Path $dstFolder ($f.BaseName + $n + $f.Extension)
$n++
} while (Test-Path -LiteralPath $dst)
Copy-Item $src $dst
Adding to Ansgar's post, if you can include a separator character like _ then you could use:
$src = 'c:\source\dailyfile.dat'
$dstFolder = 'c:\destination'
#Get the number from the last file in the destination directory
[int]$NextNum = [int](gci $dstFolder | Sort-Object -Property Basename | Select -Last 1).basename.split("_")[1] + 1
#Get source file
$f = Get-Item $src
# Add more zeros in the ToString for more padding
$dst = Join-Path $dstFolder ($f.BaseName + "_" + $NextNum.ToString("000") + $f.Extension)
Copy-Item $src $dst
This script compare FILE objects by Name, Length, and LastWriteTime.
cls
$Source= "C:\Source"
$Destination = "C:\Destination"
Compare-Object (ls $Source) (ls $Destination) -Property Name, Length, LastWriteTime | Sort-Object {$_.LastWriteTime} -Descending
Output:
Name Length LastWriteTime SideIndicator
---- ------ ------------- -------------
11.0.3127.0.txt 6 8/31/2013 10:01:19 PM <=
11031270.txt 0 8/31/2013 9:43:41 PM <=
11.0.3128.0.txt 13 8/31/20131:20:15PM =>
11.0.3129.0.txt 0 8/28/2013 11:34:38 AM <=
I need to create a script that retrive the current DB version and checks if single or multiple patches are available.
The way it works is the following:
Run a SQL Query against a DB
Store the SQL Info onto a fileName (eg.11.0.3128.0.txt) on C:\Destination
Compare the information in the .txt file against the files/patches present in the Source folder
List item
If Source folder contains older files/patches -- do nothing
If Source folder contain newer files, then copy those files to C:\NewPatchFolder
Then run a script to apply all the new patches
I already took care of #1, #2. I was planning to modify/add on to above script to simplify the steps in #3, #4 and #5.
Is it possible to modify above script to achive my goals as follow:
compare LastWriteTime from the files in C:\Source folder with the file in C:\Destination
copies the files in C:\Source folder to C:\NewPatchFolder if LastWriteTime is equal or greater then the LastWriteTime of the file on the C:\Destination folder
I wouldn't use Compare-Object for this. Try the following:
Get-ChildItem $Source | % {
$f = Join-Path $Destination $_.Name
if (Test-Path -LiteralPath $f) {
if ($_.LastWriteTime -ge (Get-Item $f).LastWriteTime) {
Move-Item $_.FullName 'C:\NewPatchFolder'
}
}
}