How to do time "HH:mm" comparison in Powershell? - powershell

Apparently my code is like this and it is now working. I think the logic is already there. the $openTime and $closeTime is read from csv using import-csv in "HH:mm" form.
$openTime = $ip.openTime
$closeTime = $ip.closeTime
$time = Get-Date -UFormat "%R"
if (($time -ge $openTime) -and ($time -le $closeTime)) {
Write-Host "Store is Open!" -ForegroundColor Green
}else{
Write-Host "Store is outside open hours!" -ForegroundColor Red
}

powershell 7
$csv = #"
store, openTime, closeTime
Wallmart, 08:00, 18:00
Ikea, 10:00, 20:30
"# | ConvertFrom-Csv
Get-Date
$csv | ForEach-Object{
[int]([datetime]::Now - [datetime]::Today).TotalMinutes -in (.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.openTime.split(":"))..(.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.closeTime.split(":")) ? "Store {0} is Open! " -f $_.store : "Store {0} is outside open hours!" -f $_.store
}
16 февраля 2021 г. 8:52:42
Store Wallmart is Open!
Store Ikea is outside open hours!
powershell 5
$csv = #"
store, openTime, closeTime
Wallmart, 08:00, 18:00
Ikea, 10:00, 20:30
"# | ConvertFrom-Csv
Get-Date
$csv | ForEach-Object{
("Store {0} is outside open hours!", "Store {0} is Open! ")[[int]([datetime]::Now - [datetime]::Today).TotalMinutes -in (.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.openTime.split(":"))..(.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.closeTime.split(":"))] -f $_.store
}
Try it online!

I find it's much easier to work with date and times if I convert them to [DateTime] objects. We can use the DateTime class method ParseExact to convert the time into [DateTime] objects for us. This object will actually contain today's date as well as the time we supply, but for our purposes this is fine since the $time object also will be today's date. For the current time ($time) just let Get-Date return to us a [DateTime] object that will represent the current date and time (now). After that the rest of your code works as expected. Hurray!
# this $ip hashtable object just represents data similar to your csv import
$ip = #{
openTime = "09:00"
closeTime = "21:00"
}
$openTime = [datetime]::ParseExact($ip.openTime, 'HH:mm', $null)
$closeTime = [datetime]::ParseExact($ip.closeTime, 'HH:mm', $null)
$time = Get-Date
if (($time -ge $openTime) -and ($time -le $closeTime)) {
Write-Host "Store is Open!" -ForegroundColor Green
}
else {
Write-Host "Store is outside open hours!" -ForegroundColor Red
}

If you are working with the time are imported from csv, make sure the time format in the csv file is in "HH:mm"

Related

Powershell script to check if given hours is between working hours

What I've done is to get the current hour and then compare it to a string that I get as an output from a system that I split to get the starting hour and ending hour.
The check keeps showing up as True no matter what the time is
$current_day = Get-Date -Format "dddd"
$current_hour = Get-Date -Format "HH:mm"
$string = "Sat 16:00 to 00:00".Split(" ")
$day = $string[0]
$from_hour = Get-Date $string[1] -Format "HH:mm"
$to_hour = Get-Date $string[3] -Format "HH:mm"
Write-Output("CURRENT TIME: {0} {1}" -f $current_day, $current_hour)
Write-Output("GIVEN TIME: {0} from {1} to {2}" -f $string_day, $string_from_hour, $string_to_hour)
if($current_hour -le $from_hour -and $current_hour -ge $to_hour)
{
return $true
}
else
{
return $false
}
Your code does work with just a few small changes.
The most critical is just swapping the operators around for your if statement
Write-Output("GIVEN TIME: {0} from {1} to {2}" -f $string_day, $from_hour, $to_hour)
if($current_hour -ge $from_hour -and $current_hour -le $to_hour)
Finally, instead of comparing to 00:00 midnight, change the end time to 23:59 which is close enough for government work. With these two things done, it works.
CURRENT TIME: Thursday 19:13
GIVEN TIME: from 16:00 to 23:59
True
You can try something like this:
$StartTime = "16:00";
$EndTime = "00:00"
$EndTime_ = (Get-Date $EndTime).AddDays(1);
if (((Get-Date) -gt (Get-Date $StartTime)) -and ((Get-Date) -lt ($EndTime_))) {
Get-Date -Format "hh:mm";
}
else {
$false
}
Thanks everyone for their suggestions.
I couldn't miss a minute as the script is intended to run per hour.
So what I've done is to convert 00:00 into 99:99 (both current time and working hours) and it works flawlessly.

PowerShell script efficiency advice

I have a telephony .csv with compiled data from January 2020 and some days of February, each row has the date and time spent on each status, since someone uses different status over the day the file has one row for each status, my script is supposed to go through the file, find the minimum date and then start saving on new files all the data for the same day, so I'll end with one file for 01-01-2020, 02-01-2020 and so on, but it has 15 hours running and it's still at 1/22.
The column I'm using for the dates is called "DateFull" and this is the script
write-host "opening file"
$AT= import-csv “C:\Users\xxxxxx\Desktop\SignOnOff_20200101_20200204.csv”
write-host "parsing and sorting file"
$go= $AT| ForEach-Object {
$_.DateFull= (Get-Date $_.DateFull).ToString("M/d/yyyy")
$_
}
Write-Host "prep day"
$min = $AT | Measure-Object -Property Datefull -Minimum
Write-Host $min
$dateString = [datetime] $min.Minimum
Write-host $datestring
write-host "Setup dates"
$start = $DateString - $today
$start = $start.Days
For ($i=$start; $i -lt 0; $i++) {
$date = get-date
$loaddate = $date.AddDays($i)
$DateStr = $loadDate.ToString("M/d/yyyy")
$now = Get-Date -Format HH:mm:ss
write-host $datestr " " $now
#Install-Module ImportExcel #optional import if you dont have the module already
$Check = $at | where {$_.'DateFull' -eq $datestr}
write-host $check.count
if ($check.count -eq 0 ){}
else {$AT | where {$_.'DateFull' -eq $datestr} | Export-Csv "C:\Users\xxxxx\Desktop\signonoff\SignOnOff_$(get-date (get-date).addDays($i) -f yyyyMMdd).csv" -NoTypeInformation}
}
$at = ''
The first loop doesn't make much sense. It loops through CSV contents and converts each row's date into different a format. Afterwards, $go is never used.
$go= $AT| ForEach-Object {
$_.DateFull= (Get-Date $_.DateFull).ToString("M/d/yyyy")
$_
}
Later, there is an attempt to calculate a value from uninitialized a variable. $today is never defined.
$start = $DateString - $today
It looks, however, like you'd like to calculate, in days, how old eldest record is.
Then there's a loop that counts from negative days to zero. During each iteration, the whole CSV is searched:
$Check = $at | where {$_.'DateFull' -eq $datestr}
If there are 30 days and 15 000 rows, there are 30*15000 = 450 000 iterations. This has complexity of O(n^2), which means runtime will go sky high for even relative small number of days and rows.
The next part is that the same array is processed again:
else {$AT | where {$_.'DateFull' -eq $datestr
Well, the search condition is exactly the same, but now results are sent to a file. This has a side effect of doubling your work. Still, O(2n^2) => O(n^2), so at least the runtime isn't growing in cubic or worse.
As for how to fix this, there are a few things. If you sort the CSV based on date, it can be processed afterwards in just a single run.
$at = $at | sort -Property datefull
Then, iterate each row. Since the rows are in ascending order, the first is the oldest. For each row, check if date has changed. If not, add it to buffer. If it has, save the old buffer and create a new one.
The sample doesn't convert file names in yyyyMMdd format, and it assumes there are only two columns foo and datefull like so,
$sb = new-object text.stringbuilder
# What's the first date?
$current = $at[0]
# Loop through sorted data
for($i = 0; $i -lt $at.Count; ++$i) {
# Are we on next date?
if ($at[$i].DateFull -gt $current.datefull) {
# Save the buffer
$file = $("c:\temp\OnOff_{0}.csv" -f ($current.datefull -replace '/', '.') )
set-content $file $sb.tostring()
# Pick the current date
$current = $at[$i]
# Create new buffer and save data there
$sb = new-object text.stringbuilder
[void]$sb.AppendLine(("{0},{1}" -f $at[$i].foo, $at[$i].datefull))
} else {
[void]$sb.AppendLine(("{0},{1}" -f $at[$i].foo, $at[$i].datefull))
}
}
# Save the final buffer
$file = $("c:\temp\OnOff_{0}.csv" -f ($current.datefull -replace '/', '.') )
set-content $file $sb.tostring()

Compare current date to date string in a file using powershell

I am writing some PS scripts to log times into a text file, login.txt, using the following code:
$logdir = "C:\FOLDER"
$logfile = "$logdir\LastLogin.txt"
$user = $env:USERNAME
$date = Get-Date -Format "dd-MM-yyyy"
if (!(Test-Path $logdir)){New-Item -ItemType Directory $logdir}else{}
if (!(Test-Path $logfile)){New-Item $logfile}else{}
if (Get-Content $logfile | Select-String $user -Quiet){write-host "exists"}else{"$user - $date" | Add-Content -path $logfile}
(Get-Content $logfile) | Foreach-Object {$_ -replace "$user.+$", "$user - $date"; } | Set-Content $logfile
This creates an entry in the text file like:
UserName - 01-01-1999
Using Powershell, I want to read the text file, compare the date, 01-01-1999, in the text file to the current date and if more than 30 days difference, extract the UserName to a variable to be used later in the script.
I would really appreciate any hints as to how I could do the following:
Compare the date in the text file to the current date.
If difference is more than 30 days, pick up UserName as a variable.
I would really appreciate any advice.
Checking all dates in the file with the help of a RegEx with named capture groups.
$logdir = "C:\FOLDER"
$logfile = Join-Path $logdir "LastLogin.txt"
$Days = -30
$Expires = (Get-Date).AddDays($Days)
Get-Content $logfile | ForEach-Object {
if ($_ -match "(?<User>[^ ]+) - (?<LastLogin>[0-9\-]+)") {
$LastLogin = [datetime]::ParseExact($Matches.LastLogin,"dd-MM-yyyy",$Null)
if ( $Expires -gt $LastLogin ) {
"{0} last login {1} is {2:0} days ago" -F $Matches.User, $Matches.LastLogin,
(New-TimeSpan -Start $LastLogin -End (Get-Date) ).TotalDays
}
}
}
Sample output
username last login 31-12-1999 is 6690 days ago
There is a way of doing that using regex (Regular Expressions). I will assume that the username which you get in your text file is .(dot) separated. For example, username looks like john.doe or jason.smith etc. And the entry in your text file looks like john.doe - 01-01-1999 or jason.smith - 02-02-1999. Keeping these things in mind our approach would be -
Using a regex we would get the username and date entry into a single variable.
Next up, we will split the pattern we have got in step 1 into two parts i.e. the username part and the date part.
Next we take the date part and if the difference is more than 30 days, we would take the other part (username) and store it in a variable.
So the code would look something like this -
$arr = #() #defining an array to store the username with date
$pattern = "[a-z]*[.][a-z]*\s[-]\s[\d]{2}[-][\d]{2}[-][\d]{4}" #Regex pattern to match entires like "john.doe - 01-01-1999"
Get-Content $logfile | Foreach {if ([Regex]::IsMatch($_, $pattern)) {
$arr += [Regex]::Match($_, $pattern)
}
}
$arr | Foreach {$_.Value} #Storing the matched pattern in $arr
$UserNamewithDate = $arr.value -split ('\s[-]\s') #step 2 - Storing the username and date into a variable.
$array = #() #Defining the array that would store the final usernames based on the time difference.
for($i = 1; $i -lt $UserNamewithDate.Length;)
{
$datepart = [Datetime]$UserNamewithDate[$i] #Casting the date part to [datetime] format
$CurrentDate = Get-Date
$diff = $CurrentDate - $datepart
if ($diff.Days -gt 30)
{
$array += $UserNamewithDate[$i -1] #If the difference between current date and the date received from the log is greater than 30 days, then store the corresponding username in $array
}
$i = $i + 2
}
Now you can access the usernames like $array[0], $array[1] and so on. Hope that helps!
NOTE - The regex pattern will change as per the format your usernames are defined. Here is a regex library which might turn out to be helpful.

convert date time to Epoch format in CSV in powershell

I want to convert datetime to Epoch format in csv file using PowerShell. In the csv file I have only time data, and I want to use current date and time specified in csv to convert it to Epoch format .
in.csv
"192.168.1.2","01-any1TEST ","Ping","Down at least 3 min","17:25:14",":Windows 2012 Server"
"192.168.1.2","02-any2TEST ","Ping","Down at least 4 min","17:25:40",":Unix Server"
"192.168.1.2","03-any3TEST ","Ping","Down at least 3 min","17:26:21",":windows host "
My findings
This should be doable using a combination of the below two. The main issue I am facing is that I am unable to combine the current date with the time in csv file.
Import-Csv ".\out.csv" |
ForEach-Object {
$_.Date = [datetime]::Parse($_.Date).ToString('MM/dd/yyyy HH:mm')
}
Get-Date -Date "12/31/2015 23:59:59" -UFormat %s
When using Get-Date, you have the option to override values manually or using another datetime
For example:
Import-Csv ".\out.csv" |
ForEach-Object {
$tempDate = [datetime]::Parse($_.Date).ToString('MM/dd/yyyy HH:mm')
Get-Date -Hour $tempDate.Hour -Minute $tempDate.Minute -UFormat %s
}
I'd do it like this:
Import-Csv ".\out.csv" |
ForEach-Object {
$_.Date = Get-Date -Date $_.Date -UFormat %s
}
If you want to be a bit more explicit about what it's doing, you can convert the time to a timespan, which can be added to a date. Then you can pipe it to Get-Date to format it:
Import-Csv ".\out.csv" |
ForEach-Object {
$_.Date = [DateTime]::Today + [Timespan]::Parse($_.Date) | Get-Date -UFormat %s
}
[DateTime]::Today is today's date at midnight (time 00:00:00).
Ok, try the code below. It will write a warning message to the console when it finds a date that it can't parse. It won't fix the problem, but it will tell you where the problem is.
Import-Csv ".\out.csv" |
ForEach-Object {
$t = [timespan]::Zero
if ([Timespan]::TryParse($_.Date,[ref]$t)) {
$_.Date = [DateTime]::Today + $t | Get-Date -UFormat %s
}
else {
Write-Warning "Unable to parse timespan '$($_.Date)' for record $($_)"
}
}
This is working perfectly for me in 2.0 and not on 4.0 version . If possible please let me know why is is not working on powershell 4.0 .
$EventTime = $($s.EventTime)
$value = get-date -format d
$Imported = Import-Csv 'C:\PathToFIle\out.csv'
$Output = foreach ($i in $Imported) {
foreach ($c in $EventTime) {
$time=$i.eventtime
$fulltime =$value+' '+$time
$i.EventTime = Get-Date -Date $fulltime -UFormat %s
}
$i
}
$Output
$Output | Export-Csv 'C:\PathToFIle\TestComputers.csv' -NoTypeInformation

Script to check files at a server for a certain time

I'd created below script to check files remaining at a particular path in server.
I've below question please help me out.
How to change file.CreationTime to 12 hours format.
How to export the entire contents to file or email.
Kindly help me in fine tuning the below script
$fullPath = "\\server\D$\fn_1"
$numdays = 0
$numhours = 0
$nummins = 1
function ShowOldFiles($path, $days, $hours, $mins)
{
$files = #(get-childitem $path -include *.* -recurse | where {($_.LastWriteTime -lt (Get-Date).AddDays(-$days).AddHours(-$hours).AddMinutes(-$mins)) -and ($_.psIsContainer -eq $false)})
if ($files -ne $NULL)
{
for ($idx = 0; $idx -lt $files.Length; $idx++)
{
$file = $files[$idx]
write-host ("File Name: " + $file.Name, ", Pending Since : " + $file.CreationTime) -Fore Red
}
}
}
ShowOldFiles $fullPath $numdays $numhours $nummins
To dump to a file, replace your whole for loop with this:
$files | select-object Name,#{name="Pending Since";Expression={$_.CreationTime}}|export-csv -notypeinfo -path c:\output.csv;
This will produce a CSV file with all of your files listed, along with their creation time. Save the formatting for your final delivery/presentation to the user (in this case, you could format the columns in Excel & then save as XLSX).
To send via email, you'll probably want to convert it to HTML.
$filesForEmail = $files | select-object Name,#{name="Pending Since";Expression={$_.CreationTime}} | convertto-HTML;
send-mailmessage -to RECIPIENT -from FROM -subject "Your file listing" -body $filesForEmail -BodyAsHTML -smtpserver smtp.yourcompany.com
You can format the CreationTime value by running it through get-date and using the -format command and the standard DateTime formatting options (http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo(VS.85).aspx). Try this line:
write-host ("File Name: " + $file.Name, ", Pending Since : " + $(get-date $file.CreationTime -format "dddd, MMMM d, yyy h:mm tt")) -Fore Red
The main bit here is replacing $file.CreationTime with $(get-date $file.CreationTime -format "dddd, MMMM d, yyy h:mm tt"). That is a fairly standard date/time format with 12 hour formatting. You could get more detailed if you wanted and define the format earlier and only put out relevant info (such as, if days = 0 exclude that from the date format).