Powershell file name check - powershell

I need verify a file copied to a destination exists, the file format is like:
SuperFile_yyyyMMdd_randomstring.txt
What I have tried to do is the below:
$FileDate = Get-Date -format yyyyMMdd
$FileExists = (Test-Path "\\UNC\TestShare\SuperFile_$FileDate_*")
However all files that match the first part SuperFile_ are copied and not just the ones matching the date. This file is created daily and I want to ignore any other file that do not contain the today's date. I had tried to do a Get-ChildItem query and pipe this into my check but it never returned any files.
So my problem is both copying and also verifying the file I just copied exists in the destination.
Thanks for any help.

_ is a valid character for variable names, so the expression evaluated $FileDate_, which is not defined. This can be prevented by using a subexpression:
$FileDate = Get-Date -format yyyyMMdd
$FileExists = (Test-Path "\\UNC\TestShare\SuperFile_$($FileDate)_*")
or by putting the variable name in curly braces:
$FileDate = Get-Date -format yyyyMMdd
$FileExists = (Test-Path "\\UNC\TestShare\SuperFile_${FileDate}_*")

Related

How to set Get-Date format as variable but get up to date time in function

I'm trying to store a get-date format as a variable so it's at the top of the file but be able to have it get an up to date get-date in functions using the variable name. Example:
$LogDir = "c:\somefolders"
$LogSubDir = $(Get-Date -f MM-yyyy)
function MakeLogSubDirs{
$Path = "$LogDir\$LogSubDir" # rather than "$LogDir\$(Get-Date -f MM-yyyy)"
If(!(test-path $path)) {
New-Item -ItemType Directory -Path $path
}
But I don't want it to set the time in the variable, I want the variable in the variable, to get gotten in the function. I tried single quotes $LogSubDir = '$(Get-Date -f MM-yyyy)', but that didn't work. "$LogDir\$(Get-Date -f MM-yyyy)" works to make the folder. Any suggestions?
here is a demo of the save the pattern into a $Var & use that later idea ... [grin]
$EU_Backwards = 'dd-MM-yyyy'
$US_InsideOut = 'MM-dd-yyyy'
$SaneSortable = 'yyyy-MM-dd'
Get-Date -Format $EU_Backwards
output = 15-05-2022
as an aside, try to use the sane, sortable largest 1st layout whenever you can. [grin]

PowerShell insert a string into a filename, just before the extension

A general thing that I need to do a lot with files is to create/reference a backup version of a file. e.g. I might want to have a date/time stamp version of a file so that I can reference both the original report and the backup version throughout a script:
$now = $(Get-Date -format "yyyy-MM-dd__HH-mm")
$ReportName = "MyReport-en.csv"
$Backups = "D:\Backups\Reports"
I found that using -join or + always inserted a space before the date/time stamp:
$ReportBackup = "$Backups\$($ReportName -split ".csv")" + "_$now.csv"
$ReportBackup = "$Backups\$($ReportName -split ".csv")" -join "_$now.csv"
I found a way to do this, but it looks feels inefficient with the triple $ and duplication of the .csv
$ReportBackup = "$Backups\$($($ReportName -split ".csv")[0])$_now.csv"
which results in:
$ReportBackup => D:\Backups\Reports\MyReport-en_2022-04-15__07-55.csv
Can you think of simpler/cleaner way to achieve the generic goal of inserting a piece of text before the extension, without the triple $ or duplication of the extension? ("Use a $name = "MyReport-en"" is not so useful because often I am reading a file object and get the name complete with extension.
$now = Get-Date -Format "yyyy-MM-dd__HH-mm"
$reportName = "MyReport-en.csv"
$backups = "D:\Backups\Reports"
$reportBackup = Join-Path $backups $reportName.Replace(".csv","_$now.csv")
$reportBackup
P.S.
There is no risk in using .Replace(), if you know how it works.
This method is case sensitive and replaces all occurrences. In this particular case, we know exactly the name in advance, so we can use this method safely.
The name "My.csvReport-en.csv" is an nonsense, but if the problem explicitly referred to the universal solution "any-name.ext":
$reportName = "My.aSd_Report-en.aSD"
$backups = "D:\Backups\Reports"
$reportBackup = Join-Path $backups ($reportName -replace "(?=\.[^.]+$)", (Get-Date -Format "_yyyy-MM-dd__HH-mm"))
$reportBackup
If you have obtained the report file as FileInfo object by perhaps using Get-Item or Get-ChildItem, you'll find that object has convenient properties you can use to create a new filename with the date included:
# assume $ReportName is a FileInfo object
$Backups = "D:\Backups\Reports"
# I'm creating a new filename using the '-f' Format operator
$NewName = '{0}_{1:yyyy-MM-dd__HH-mm}{2}' -f $ReportName.BaseName, (Get-Date), $ReportName.Extension
$ReportBackup = Join-Path -Path $Backups -ChildPath $NewName
If however $ReportName is just a string that only holds the filename, you can do:
$ReportName = "MyReport-en.csv"
$Backups = "D:\Backups\Reports"
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($ReportName)
$extension = [System.IO.Path]::GetExtension($ReportName)
$NewName = '{0}_{1:yyyy-MM-dd__HH-mm}{2}' -f $baseName, (Get-Date), $extension
$ReportBackup = Join-Path -Path $Backups -ChildPath $NewName
P.S. It is always risky to simply use .Replace() on a filename because that doesn't allow you to anchor the substring to replace, which is needed, because that substring may very well also be part of the name itself.
Also, the string .Replace() method works case-sensitive.
This means that
'My.csvReport-en.csv'.Replace(".csv", "_$(Get-Date -Format 'yyyy-MM-dd__HH-mm').csv")
would fail (returns My_2022-04-15__13-36.csvReport-en_2022-04-15__13-36.csv)
and
'MyReport-en.CSV'.Replace(".csv", "$(Get-Date -Format 'yyyy-MM-dd__HH-mm').csv")
would simply not replace anything because it cannot find the uppercase .CSV
..
If you really want to do this by replacing the extension into a date+extension, go for a more complex case-insensitive regex -replace like:
$ReportName -replace '^(.+)(\.[^.]+)$', "`$1_$(Get-Date -Format 'yyyy-MM-dd__HH-mm')`$2"
Regex details:
^ Assert position at the beginning of the string
( Match the regular expression below and capture its match into backreference number 1
. Match any single character that is not a line break character
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
( Match the regular expression below and capture its match into backreference number 2
\. Match the character “.” literally
[^.] Match any character that is NOT a “.”
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
$ Assert position at the end of the string (or before the line break at the end of the string, if any)

Copy and rename file following a pattern with Powershell

I have a file with name like this:
KE1_F00177_077_00_50
When I show the Property of the file, 2018.02.21.10.30 is the modified Date of the File which is copied like the picture below. I want to copy this file to another Location and rename it with Powershell. The new name should be:
_F00177_2018_02_2018.02.21.10.30_KE1_F00177_077_00_50
This will generate the format you mention including hour in 12 hour format (AM/PM).
$source = 'c:\temp\KE1_F00177_077_00_50'
$destinationFolder = 'c:\temp\new'
$file = Get-ChildItem $source
$date = '{0:yyyy_MM_yyyy.MM.dd.HH.mm}' -f $file.LastWriteTime
$head = $file.Name.Split('_')[1]
Copy-Item $source "$($destinationFolder)/_$($head)_$($date)_$($file.Name)"
However you should consider either using 24 hour format or including AM/PM in the name, otherwise it won't be easy to know when it is AM or PM.
For 24 hour format, replace hh for HH:
$date = '{0:yyyy_MM_yyyy.MM.dd.HH.mm}' -f $modified

Combine path, file strings and literals for path

Trying to combine a path, filename, and add some text along with a variable for Out-File log.
I've tried many alternatives unsuccessfully and need assistance;
FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$OldVersion = C:\Temp\TestFile.txt
$OldPath = (Get-Item $OldVersion).DirectoryName
$OldBaseName = (Get-Item $OldVersion).BaseName
ErrFile = Join-Path $OldPath OldBaseName
Out-File -FilePath "$ErrFile_$FormattedDate Error.txt"
Out-File -FilePath "$($OldPath)$($OldBaseName)_$($FormattedDate)_Error.txt"
...just two examples.
I've tried many other combinations and driving me crazy.
Basically I want it to be.
C:\Temp\TestFile_2017-08-24 16:51:36_Error.txt
Update:
I've tried both
$filename = '{0}_{1:s}_Error{2}' -f $basename, (Get-Date), $extension
I get _2017-08-25T13:02:17_Error.txt but no basename (TestFile).
$newpath = "${dirname}\${basename}_${date}_Error${extension}"
I get
A drive with the name '_2017-08-25 13' does not exists.
Can you also explain or provide a resource of what '{0}_{1:s}_Error{2}' and/or '{0}_{1:yyyy-MM-dd HH:mm:ss}_Error{2}' does?
Use the format operator (-f) for constructing the filename and Join-Path for building the path.
$oldpath = 'C:\Temp\TestFile.txt'
$basename = [IO.Path]::GetFileNameWithoutExtension($oldpath)
$extension = [IO.Path]::GetExtension($oldpath)
$filename = '{0}_{1:yyyy-MM-dd HH:mm:ss}_Error{2}' -f $basename, (Get-Date), $extension
$newpath = Join-Path ([IO.Path]::GetDirectoryName($oldpath)) $filename
Unless you must have the space in the date format you could simplify the format string by using the standard sortable format specifier (s) that will produce date strings like 2017-08-24T23:58:25 instead of 2017-08-24 23:58:25.
$filename = '{0}_{1:s}_Error{2}' -f $basename, (Get-Date), $extension
If you want to construct the path as a string with inline variables you need to make sure that the underscores in your file name are kept separate from the variable name. Because underscores are valid name components for variable names $var_ is the variable var_, not the variable var followed by a literal underscore. Use curly braces to ensure that variables and literal underscores don't get mixed up.
$oldpath = 'C:\Temp\TestFile.txt'
$date = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
$dirname = [IO.Path]::GetDirectoryName($oldpath)
$basename = [IO.Path]::GetFileNameWithoutExtension($oldpath)
$extension = [IO.Path]::GetExtension($oldpath)
$newpath = "${dirname}\${basename}_${date}_Error${extension}"
Addendum: Your file names should not contain colons. Colons in Windows paths either terminate a drive name or separate the file name from the name of an alternate data stream. Your date format string should rather be something like yyyy-MM-dd HH-mm-ss or yyyy-MM-dd_HH-mm-ss to avoid this pitfall.

Rename and copy select files in nested directory Powershell

I cannot seem to rename let alone copy any text files using this code, I am trying to go through a nested directory which should be taken care of with Get-ChildItem -Recurse.
It seems like I am only going through the selected source folder's files instead of fully recursing through all of the subfolders.
A sample text file in the directory would be 02-01-2016 Test.txt
$InputDate = Read-Host -Param 'Please select a starting date (In the following format: mmddyyyy)'
$Date = [datetime]::ParseExact($InputDate, "MMddyyyy", [Globalization.CultureInfo]::CreateSpecificCulture('en-US'), $null)
$Dst = Select-FolderDialog #This function is working for me, assume you can select a folder
$Src = 'C:\Users\Bart Zhang\Downloads\Test Folder (1)\Test Folder' # #source
$FileType = '*.txt'
Get-ChildItem -Path $Src -Recurse -Force | Where-Object {$_.Name -notcontains "Archive"} | ForEach-Object {
$DateStr = $_.BaseName.Substring(0, 2) + $_.BaseName.Substring(3, 2) + $_.BaseName.Substring(6, 4)
$FileDate = [datetime]::ParseExact($DateStr, "MMddyyyy", [Globalization.CultureInfo]::CreateSpecificCulture('en-US'), $null)
If ( $FileDate -ge $Date ) {
Rename-Item -NewName { $_.Directory.Name + ' ' + $_.Name} -Filter $FileType -Recurse -Force
Copy-Item -Path (Join-Path -Path $Src -ChildPath '\*' ) -Destination $Dst -Filter $FileType -Recurse -Force
}
}
I started with a sample folder with files with this naming standard, matching what you described.
Then I ran through your date conversion logic and found that it didn't seem to work as described (lots of errors trying to conver '04082011' to date, for instance) , so I made a change on line 10, changing the line to this:
$DateStr = $_.BaseName.Substring(0,2)+'/'+$_.BaseName.Substring(3,2)+'/'+$_.BaseName.Substring(6,4)
I simply added slashes to the date, so we would end up with '04/08/2011' which seemed to be all I needed for $DateStr to populate, which then allowed the line of file date comparison to work. I also changed the conversion on line 11 to this
$FileDate = get-date $DateStr
Adding some Write-Host lines for visibility and I get this.
03/02/2017 03-02-2017 Test has date of 03/02/2017 00:00:00
03-02-2017 Test has a file date of 03/02/2017 00:00:00 which is newer than 02/04/2014 10:13:14, time to move it
03/22/2010 03-22-2010 Test has date of 03/22/2010 00:00:00
03-22-2010 Test has a file date of 03/22/2010 00:00:00 which is older than 02/04/2014 10:13:14, ignoring...
04/08/2011 04-08-2011 Test has date of 04/08/2011 00:00:00
04-08-2011 Test has a file date of 04/08/2011 00:00:00 which is older than 02/04/2014 10:13:14, ignoring...
05/08/2016 05-08-2016 Test has date of 05/08/2016 00:00:00
05-08-2016 Test has a file date of 05/08/2016 00:00:00 which is newer than 02/04/2014 10:13:14, time to move it
I haven't checked the rest of your code, but this should get you back on track.
Conclusion
Good work for parsing out the file date from a file name like that, which is tricky. However the Conversion technique you were trying was making things harder than it needed to be, so by changing the way we parse the filename (adding slashes so that PowerShell would recognize the string with the much easier Get-Date cmdlet), we could use a different technique which is easier to understand.