Reputation: 79
Editor's note:
The original form of this question had a well-defined problem that stemmed from accidentally -le
-comparing a [string]
LHS with a [double]
RHS (annotations added):
$c = Get-Date (Get-Date).ToUniversalTime() -UFormat %s
$epochseconds=[math]::Round($c) # $epochseconds is now a [double]
$d = get-childitem C:\scripts\PALO\* -recurse | Select-String -pattern "expiry-epoch"
$e = $d -split "epoch" # -split always returns *strings*
$certtime = $e[1] # $certtime is now a [string]
$epochtime = $epochseconds - 2505600 # $epochtime is a [double]
ForEach ($i in $d){
If ($certtime -le $epochtime) { # LHS is [string], RHS is [double]
Write-Output $i
}
}
The OP's later revision (see below), by replacing the original code, accidentally eliminated this problem by first applying a subtraction to the [string]
LHS (during which an implicit conversion to a number happens), rendering the existing answer inapplicable.
[The OP's later revision, which should be a *new* question.]
I am writing a script that is supposed to notify me if the expiry-epoch time of a certificate is within 30 days of expiration. However, if one file does not match the IF statement then I get no output, if all files match the IF statement then I get the appropriate output.
PS C:\scripts> $certtime
1560350005
PS C:\scripts> $epochtime
1520858749
I just updated the code:
$c = Get-Date (Get-Date).ToUniversalTime() -UFormat %s
$epochtimes=[math]::Round($c)
$d = get-childitem C:\scripts\PALO\* -recurse | Select-String -pattern "expiry-epoch"
$e=$d -split "epoch"
$certtime=$e[1]
$certexp = $certtime - 2592000
ForEach ($i in $d){
If ($certexp -le $epochtime) {
Write-Output $i
}
}
Upvotes: 1
Views: 332
Reputation: 439812
Note:
* This answer is based on the original code in the question.
* There's an additional problem with the original code not addressed below: $d
is expected to contain multiple items, yet only the 1st item's epoch time is extracted with $certtime=$e[1]
; this must be moved into the foreach
loop: $certtime = [double] ($i -split "epoch")[1]
-split
operator always returns strings.-le
being a [string]
means that the RHS is quietly converted to a string, whatever its original type.Thus, given that $certtime
is a string, $certtime -le $epochtime
performs lexical comparison, which is not your intent.
The solution is to cast to the desired numerical data type:
# Use [double], because $epochtime is of type [double] in your code.
$certtime = [double] $e[1]
Or, directly in the context of your conditional:
if ([double] $certtime -le $epochtime) ...
[1] There are exceptions: -
and /
convert both operands from strings to numbers on demand; e.g., ' 10' - '2'
yields [int] 8
; by contrast, this does not happen with +
and *
, which have string-specific semantics (concatenation and replication).
For other LHS types, +
, -
, *
and /
only succeed if the given type custom-defines these operators via operator overloading.
Without overloading, the behavior of non-string-coercing operands such as -eq
, -lt
, -gt
, ... depends on whether the LHS type implements interfaces such as IEquatable
and IComparable
.
Finally, with the collection-based -in
and -contains
operators, it is the individual elements of the collection-valued operand that drive the coercion - see this answer.
Upvotes: 2