I'm trying to write a script that will copy a file to a second location, when the file changes.
For that I'm using an if statement like this:
if (
(Get-ChildItem C:\folder2\file).LastWriteTimeUtc -ge (Get-ChildItem C:\folder1\file).LastWriteTimeUtc
)
{exit}
else
{#execute}
Right now the files are exactly the same and if I run
(Get-ChildItem C:\folder2\file).LastWriteTimeUtc
the result for both is
Friday, 15. April 2022 23:32:09
My issue is that both LastWriteTimes appear to be the same and the script shouldn't do anything, but it does. And the reason for that is, that even though both values seem to be the same they are not and comparing them with "-eq" returns "False".
I'm using PowerShell 5.1
Thanks for all the replies. I'm sorry if I wasn't as specific as I should have been. But because of them I found an answer that should work for me.
First I get both dates as ticks and convert them to strings
$datef2 = (Get-ChildItem C:\folder2\file).LastWriteTimeUtc.Ticks.ToString()
$datef1 = (Get-ChildItem C:\folder1\file).LastWriteTimeUtc.Ticks.ToString()
then I replace the last 7 digits with 0 (which is everything small than a second) and compare them
($datef2.Substring(0,$datecb.Length-7) + "0000000") -ge ($datef1.Substring(0,$datenx.Length-7) + "0000000")
Might not be the most elegant solution but it gives the if statement the correct values.
Related
I've written a pretty nifty PowerShell script that works with VMware PowerCLI to clone a couple of VMs off to a second storage device and then automatically delete them when they reach a certain age. It seems to work great until it gets to the end/beginning of the month, then the approach I used for date time seems to fail and all clones are deleted unexpectedly. Rather than include the entire script, here are the pieces that matter.
First, when the clones are created I am using the following code..
$vmdatestamp = (Get-Date).tostring('yyyyMMdd-HHmmss')
new-vm -Name $VM-$vmdatestamp -VM $VM -Datastore $CPFlag -vmhost host.domain.local -Location 'Regular Clone'
This variable ends up creating a VM clone that is named something like "VMName-20200214-040022" in the case that the date is Feb 14th, 2020 and the variable captured 4 AM and 00 Min and 22 seconds.
Then later on in the script there is a cleanup section that lists these cloned VMs and checks the date. The objective is to run a delete command if the clone is older than 3 days. So there is a foreach loop that runs off of all VMs found within a particular folder, "Regular Clone". $vmls is the var within the loop for each VM found. Here is the code I am using to check the dates and delete older than 3 days.
#Grab matched string and doctor it to only look at 8 digit date.
$var1 = $vmls.name
$var2 = $var1 -split '-' | Select-String '\d{8}'
$var3 = $var2 -replace '(?S)'
#Grab todays date in the same 8 digit format then subtract to compare variance. How old is the clone?
$CompareDate = (Get-Date).tostring('yyyyMMdd')
$var4 = $CompareDate - $var3
#If clone is older than 3 days, delete it. Turn this knob based on your requirements.
if($var4 -gt '3') {
So this last "if" statement that checks $var4 is greater than 3 is where the source of my problem is. I don't think the script is smart enough to figure out if for example today is the 1st, how minus '-' works. Anyone have a suggestion on how to better deal with this?
Regards,
Adam Tyler
Powershell has a great deal of flexibility in dealing with dates and times using the [datetime] type. There is probably another answer to this somewhere out there, and I'll search for it later, but here are some basics.
When you read in your filenames, which I am assuming are in 'VMName-yyyyMMdd-HHmmss' format, you can turn that into a PowerShell [datetime] object like so (Thanks to this post for the info on [datetime]::parseexact):
[string]$VMFileName = #load $VMFileName variable with the name of your VM file somehow
$VMFNSplit = $VMFileName -split '-'
$FileDateStamp = [datetime]::ParseExact("$($VMFNSplit[-2])-$($VMFNSplit[-1])",'yyyyMMdd-HHmmss',$null)
EDIT:
Tested the above, and got this:
PS> $VMFileName = 'VMName-20200222-043322'
PS> $VMFNSplit = $VMFileName -split '-'
PS> $VMFNSplit[-2]
20200222
PS> $VMFNSplit[-1]
043322
PS> "$($VMFNSplit[-2])-$($VMFNSplit[-1])"
20200222-043322
PS> $FileDateStamp = [datetime]::ParseExact("$($VMFNSplit[-2])-$($VMFNSplit[-1])",'yyyyMMdd-HHmmss',$null)
PS> $FileDateStamp
Saturday, February 22, 2020 4:33:22 AM
Once you have your file date/time stamp in a [datetime], you can use the built in methods to add/subtract your intervals, like this:
#If clone is older than 3 days, delete it. Turn this knob based on your requirements.
$TooOld = (Get-Date).AddDays(-3)
If ($FileDateStamp -lt $TooOld) {#Delete it}
Hope this helps!
I have a script that takes the creation date of a file and injects it into an xml tag. Everything works but the formatting of the date shows 2019-4-3 and I need the format to be 2019-04-03.
I have tried the 'tostring(MM)' and that has not worked for me. Anyone have any ideas? Here is a snippet of the code where I think the issue is. I can post the whole script if anyone wants to see it.
$filename="C:\Users\Public\file.xml"
$filename2="C:\Users\Public\file2.xml"
$month = (Get-ChildItem $filename).CreationTime.Month
$day = (Get-ChildItem $filename).CreationTime.Day
$year = (Get-ChildItem $filename).CreationTime.Year
$hour = (Get-ChildItem $filename).CreationTime.Hour
$min = (Get-ChildItem $filename).CreationTime.Minute
$sec= (Get-ChildItem $filename).CreationTime.Second
$output=[string]$year+"-"+[string]$month+"-"+[string]$day+"T"+[string]$hour+":"+[string]$min+":"+[string]$sec+":00z"
Write-Host $output
The output of the dates are single digit and I need them double digits. Any ideas?
The following should work assuming you don't actually need each part of the datetime as a separate variable:
$filename="C:\Users\Public\file.xml"
(Get-ChildItem $filename).creationtime.toString('yyyy-MM-ddTHH:mm:ss')+':00z'
I don't know why the toString() method did not work for you previously unless you didn't quote contents inside the parentheses. The method doesn't always require an input argument, but with what you are trying it requires a string to be passed to it.
You are constructing this the hard way. Formatting dates and times as strings is fully explained here: https://ss64.com/ps/syntax-dateformats.html
A simpler way to do this, and faster since right now you are getting the file info 6 times right now, would be to use the built-in [datetime] method ToString().
(Get-Item $filename).CreationTimeUtc.ToString("yyyy-MM-ddTHH:mm:ss.00Z")
Notice that I used the CreationTimeUtc property instead of CreationTime, since the "Z" at the end of your string that you are creating indicates that this is the time in UTC (the "Z" stands for Zulu time, as explained in Wikipedia).
To complement TheMadTechnician's helpful answer:
Except for the T separating the date and time parts and a sub-second component, your format is the same as the standard u date/time format:
PS> (Get-Item /).CreationTimeUtc.ToString('u') -replace ' ', 'T'
2018-11-30T10:47:40Z
If you need an explicit zero-valued sub-second component, append -replace 'Z$', '.00Z' - note the use of ., not :, as the separator, because . is normally used.
So I am trying to get the date 3 months back using the Powershell command Get-Date. However, when I try to add multiple get-dates in one line it errors out or doesn't give me the results I'm looking for.
The End result I'm trying to get is $checkDate = 6-7-2016
I've tried this, but it doesn't really work:
$checkDate = (Get-Date).month -3 "-" (Get-Date).day "-" (Get-Date).year
Any ideas on how to accomplish this? I'm newer to Powershell and not exactly sure how to concatenate properly.
I'm using PS 4.0
What you are trying to do is format a calculated date. So let's start with calculating the date:
(Get-Date).AddMonths(-3)
That gets you today's date minus 3 months. Next you want to format it in a specific manner. That being Month-Day-Year. That can be done as such:
(Get-Date).AddMonths(-3).ToString("M-d-yyyy")
That results in:
6-7-2016
I'm trying to find files from the previous day to copy, but my simple get-childitem isn't working. It works with every other switch except -eq. Any suggestions to list files only from the previous day ?
get-childitem c:\users| where-object {$_.LastWriteTime -eq (get-date).adddays(-2)}
You are looking for files that are written at exact time ( hours mins, secs, year, month and 2 days before). Unless the files were written to the second, two (or one) days ago, you will not find them. In other words, you were comparing full DateTime objects and not just a date and hence there is very less chance that they were exactly equal, which seemed to suggest that -eq doesn't work, but other comparisons do.
You probably wanted to just compare the dates, without the times:
$yesterday = (get-date).AddDays(-1).Date
gci c:\users | ?{ $_.LastWriteTime.Date -eq $yesterday}
( also moved the get-date outside, as you probably don't want to do it again and again.)
They are not equal because they differ in time. If you want an exact date match, use the Date property:
get-childitem c:\users| where-object {$_.LastWriteTime.Date -eq (get-date).adddays(-2).Date}
I tried my best to find the answer on my own for almost 2 days before posting. I apologize in advance if this question is already answered somewhere on this site.
In short, I need to pull VersionInfo from a .dll which I am currently doing using:
[System.Diagnostics.FileVersionInfo]::GetVersionInfo('C:\PathHere.dll').FileVersion | New-Item –ItemType file c:\test.txt
This works for me, though if someone has what they feel is a cleaner method, I'm all ears...or more accurately...all eyes. The script will take the full version value and write to to a text file just as I want, but I the problem is that I only want the first 3 decimal places and in this case, I'm getting the full version info which is always 4 decimal places long.
So, if the VersionInfo is 1.3.102310.0345, I want that .txt file to only contain 1.3.102310
It is very important that the number remaining NOT be rounded.
As long as the end result is the full values for those first 3 decimal places, I don't really care if the version output is somehow limited to only display the first 3 decimal places, or if the full versioninfo is recorded to the .txt and then reliably removed from the file.
Try this:
$value = [System.Diagnostics.FileVersionInfo]::GetVersionInfo(...)
$version = [version]$value.ProductVersion
$output = $version.tostring(3) # show x.y.z
$output | out-file c:\test.txt
This is another way:
$a = [System.Diagnostics.FileVersionInfo]::GetVersionInfo('C:\my.dll').fileversion; $a.Substring(0, $a.LastIndexOf('.')) | New-Item –ItemType file c:\test.txt
This should do it:
[string]::Join('.', (Get-Item C:\PathHere.dll).versionInfo.FileVersion.Split('.')[0..2]) | New-Item –ItemType file c:\test.txt
Or a regex way in case you want two problems:
(Get-Item C:\PathHere.dll).versionInfo.FileVersion -replace '^(\d+\.\d+\.\d+)\.\d+$', "`$1" | New-Item –ItemType file c:\test.txt
These answers are excellent and all did the trick. After having posted this question, I slowed down, took a step back and while talking to a friend, another possible answer hit me.
$VersionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo('C:\Builds\Agent1\QACodeLine\Sources\WebPublicBuild\Binaries\PowerWallet.Common.CommonTypes.dll').FileVersion
$VersionInfo.split('.') | select -first 3 | out-File "C:\testies.txt"
This method first splits the output into 4 parts using the .split('.') and then takes only the first 3 via the select -first 3 (select only the first 3 outputs. The output can then be rejoined or if more useful, saved to a file line by line but I think I will go with one of the methods provided here as in the end, I will be better off writing to a text file with the first 3 octets in their proper version info format.
Thanks again for the speedy responses - the help is very much appreciated! PowerShell is incredible and it's supportive community even more so!