I'm having the weirdest and most annoying problem with dealing with a string here that I need to convert to DateTime.
I'm doing the exact same thing from 2 different CSV files - it works perfectly on the first one, keeps returning an error on the second one.
$userDateOut = Get-Date $sourceLine.Date_OUT -Format "dd/MM/yyyy"
$userDateOut = ($userDateOut -as [datetime]).AddDays(+1)
$userDateOut = Get-Date $userDateOut -Format "dd/MM/yyyy"
In the first CSV, Date_OUT is just 31/12/2021 for example, and in the second one it's 31/12/2021 0:00:00.
So before the 3 lines to create $userDateOut, I do
$userDateOut = $sourceLine.Date_OUT.SubString(0,10)
Which makes me end up with the same type of variable as with the first CSV
PS C:\Windows\system32> $userDateOut = $sourceLine.Date_Out.Substring(0,10)
PS C:\Windows\system32> $userDateOut
31/12/2021
PS C:\Windows\system32> $userDateOut.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
However, with this variable, I'm getting
PS C:\Windows\system32> $userDateOut = Get-Date $userDateOut -Format "dd/MM/yyyy"
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "31/12/2021" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At line:1 char:25
+ $userDateOut = Get-Date $userDateOut -Format "dd/MM/yyyy"
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Date], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand
And I don't know why... Can someone help ?
-Format just converts [datetime] to a [string] - it doesn't influence parsing of input strings in any way.
For that, you need [datetime]::ParseExact():
$dateString = '31/12/2021'
# You can pass multiple accepted formats to ParseExact, this should cover both CSV files
$inputFormats = #(
'dd/MM/yyyy H:mm:ss'
'dd/MM/yyyy'
)
$parsedDatetime = [datetime]::ParseExact($dateString, $inputFormat, $null)
You can then use Get-Date -Format to convert it back to an intended output format if needed:
Related
I was trying to get the count of days between two dates, but getting the below error
Any suggestions would be greatly appreciated
$Days = $expiration - $currentDate
Cannot convert value "12/28/2020" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:1
+ $Days = $expiration - $currentDate
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
below is a snippet of code for reference
$expiration = $QueryResults.Results.ExpiryDate_s
$expiration
12/28/2020
$currentDate = Get-Date -Format 'MM/dd/yyyy'
$currentDate
09/30/2020
$expiration.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
$currentDate.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
PowerShell directly supports subtracting [datetime] (System.DateTime) instances, the result of which is reported as a span of time, expressed as a [timespan] (System.TimeSpan) instance.
For this to work, both operands passed to the - (subtraction) operator must be of type [datetime], which in your case you can simply be achieved by casting[1] your string operands to that type (instead of calling Get-Date -Format 'MM/dd/yyyy' you should just call (Get-Date).Date in order to return a [datetime] instance directly):
PS> [datetime] '12/28/2020' - [datetime] '09/30/2020'
Days : 89
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 76896000000000
TotalDays : 89
TotalHours : 2136
TotalMinutes : 128160
TotalSeconds : 7689600
TotalMilliseconds : 7689600000
To get just the count of days between the two dates, using the current date (without a time-of-day component) as the RHS:
$days = ([datetime] '12/28/2020' - (Get-Date).Date).Days
As for what you tried:
If you pass a string-typed LHS to the - operator, PowerShell tries to interpret it as a number.
Since a string such as '12/28/2020' cannot be parsed as a numeric type, the operation fails. To provide a more obvious example:
PS> 'I am not a number' - 1
Cannot convert value "I am not a number" to type "System.Int32"
...
[int] (System.Int32) just happens to be the one numeric type chosen for the error message.
[1] Note that PowerShell casts are always based on the invariant culture, which is based on the US English culture, irrespective of what culture is currently in effect. This means that a [datetime] cast accepts whatever string [datetime]::Parse($string, $null) accepts, which includes month-first date strings such as '1/13/2020' as well as less ambiguous formats such as '2020-1-13'
You are trying to do math against datetime data type values which is not correct.
I belive you could use New-TimeSpan cmdlet to achieve your needs. Like so:
PS C:\WINDOWS\system32> New-TimeSpan -Start '01.01.2020' -End $(Get-Date)
Days : 274
Hours : 3
Minutes : 38
Seconds : 17
Milliseconds : 295
Ticks : 236866972950824
TotalDays : 274,151589063454
TotalHours : 6579,63813752289
TotalMinutes : 394778,288251373
TotalSeconds : 23686697,2950824
TotalMilliseconds : 23686697295,0824
You could also invoke datetime data type variable's methods such as AddDays(). Like so:
PS C:\WINDOWS\system32> $CurrentDate = Get-Date
PS C:\WINDOWS\system32> $CurrentDate.AddDays(-274)
1 января 2020 г. 3:40:59
I have a requirement to increment to read and increment the pom.xml version by 1 using powershell script.
I was able to fetch the version value as for example: 1.0.123, but the type given here is string, when I try to convert it into Decimal or Double I am getting below error:
Code:
PS C:\Users\XXXX\Downloads> $finale
1.0.153
PS C:\Users\XXXX\Downloads> $finale.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
Error:
PS C:\Users\XXXX\Downloads> $finale1 = [Double]::Parse($finale)
Exception calling "Parse" with "1" argument(s): "Input string was not in a correct format."
At line:1 char:1
+ $finale1 = [Double]::Parse($finale)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
The reason is 1.0.123 is not math. It is nether an integer, nor a double. It is simply a string that contains numbers and symbols. This is why you are getting the error.
See the following Help files:
About_Arithmetic_Operators
.NET Math Class
Using a [version] type is nice, but it is immutable. This code splits it into an array, increments the third (Build) number, and produces a string in $newfinale.
Note that this does not check to see if there is a third (Build) value. It will produce an exception if the $finale is '1.2'.
PS C:\> $finale = '2.3.4.5'
PS C:\> $a = $finale.split('.')
PS C:\> $a[2] = [int]$a[2] + 1
PS C:\> $newfinale = $a -join '.'
PS C:\> $newfinale
2.3.5.5
Per this Code-Golf tip, in PowerShell you can use scientific notation to easily generate numbers which are powers of 10: https://codegolf.stackexchange.com/a/193/6776
i.e. 1e7 produces the number 10,000,000.
If I pass this value to get-date (or alias date, for the purposes of code golf) I get a single second: i.e. date 10000000 => 01 January 0001 00:00:01.
Yet if I use the scientific notation, even with brackets (i.e. date (1e7)) I get an error:
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "10000000" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At line:1 char:6
+ date (1e7)
+ ~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Date], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand
Question
Is there a way to use scientific notation with the Get-Date's default (date) parameter?
This is because 1e7 gets outputed as a double, so you just have to cast it to an integer:
date ([int]1e7)
You can check that if you call the GetType method on the output:
(1e7).GetType() | Format-Table -AutoSize
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Double System.ValueType
Edit:
Shortest script probably is:
1e7l|date
This is taken from PetSerAls comment - just removed another character by using pipe instead of brackets.
I have some date variables, with which to perform queries against files in a specific directory. I can GCI each file no problem, as shown in the example below:
File1.xml 14/07/2016 17:09
File2.xml 15/07/2016 09:32
So I am searching for all files between a specific age range and my criteria is:
Older than:
$Today4am = Get-Date -Hour 4 -Minute 0 -Second 0
But later than
$Yesterday4am = $Today4am.AddDays(-1)
The variables output
$Today4am = 15 July 2016 04:00:00
$Yesterday4am = 14 July 2016 04:00:00
So the variable pipes out the date in a different format to the file themselves, so I need to ensure both formats are the same in order to do the comparison. Here is the original script:
$Filter = gci c:\temp\*.xml |
Where {$_.LastWriteTime -gt $Yesterday4am -and {$_.LastWriteTime-lt $Today4am}}
Bad argument to operator '-gt': Could not compare "14/07/2016 17:09:52" to "14/07/2016 0
4:00". Error: "Cannot convert value "14/07/2016 04:00" to type "System.DateTime". Error:
"String was not recognized as a valid DateTime."".
So I try to convert the variables to add -Format "dd/MM/yyyy HH:mm" and this outputs the correct format. But converting $Yesterday4am = $Today4am.AddDays(-1) -Format "dd/MM/yyyy HH:mm" produces the error:
Cannot convert value "15/07/2016 04:00" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
How can I get both date formats to agree?
Try using Get-date again to convert $Yesterday4am to DateTime:
| Where {$_.LastWriteTime -gt (Get-Date $Yesterday4am) -and {$_.LastWriteTime-lt $Today4am}}
And if you're worried about performance you can do the Get-Date conversion outside of the Where operator:
$Yesterday4am = Get-Date $Yesterday4am
$Filter = gci c:\temp\*.xml `
| Where {$_.LastWriteTime -gt $Yesterday4am -and {$_.LastWriteTime-lt $Today4am}}
I believe this was just an issue with your comparisons. If you run my script below you will see that they are both types "DateTime". If you format them they become strings which will not easily compare. When I ran my Where-Object command below I had no errors. Note: I am using PowerShell version 5.
PS> Write-Host "PowerShell Version: $($PSVersionTable.PSVersion.ToString())"
PowerShell Version: 5.0.10586.122
PS> $Today4am = Get-Date -Hour 4 -Minute 0 -Second 0
PS> Write-Host "`$Today4am is type `"$($Today4am.GetType().FullName)`""
$Today4am is type "System.DateTime"
PS> $Yesterday4am = $Today4am.AddDays(-1)
PS> Write-Host "`$Yesterday4am is type `"$($Yesterday4am.GetType().FullName)`""
$Yesterday4am is type "System.DateTime"
PS> $Filter = Get-ChildItem c:\temp\* | Where-Object -FilterScript { ( $_.LastWriteTime -gt $Yesterday4am ) -and ( $_.LastWriteTime-lt $Today4am ) }
PS> $Filter
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/14/2016 1:13 PM 0 asdfasd
I am very confused of this error message:
Get-Date : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Object reference not set to an instance of an object."
The problem line is:
$logondate = $(Get-Date $([datetime]::Parse( $user.LastLogonDate)) -Format 'yyyy-MM-dd HH:mm:ss')
# User is vartype: System.Management.Automation.PSMethod
#$user.LastLogonDate in debug with this value: 10.06.2014 14:26:13 (dd.MM.yyyy)
What does this error mean?
From 30 AD accounts there are only three with this ParameterBindingException.
Full error message:
Get-Date : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Object reference not set to an instance of an object."
At C:\scripts\AD.ps1:309 char:28
+ $logondate = $(get-date <<<< $([datetime]::Parse( $user.LastLogonDate)) -Format 'yyyy-MM-dd HH:mm:ss')
+ CategoryInfo : WriteError: (:) [Get-Date], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.PowerShell.Commands.GetDateCommand
You get that error, because for some reason Parse() cannot parse $user.LastLogonDate into a date. Perhaps because the user never logged on (so the value is $null), or because Parse() doesn't recognize the default date format.
However, the LastLogonDate property (as created by Get-ADUser) already holds a DateTime value. What you're trying to do here is: implicitly convert the date to a string, parse that string back into a date, then create a formatted string from it again.
Don't.
Simply format the DateTime value you already have:
PS C:\> $user = Get-ADUser $env:USERNAME -Property *
PS C:\> $user.LastLogonDate.GetType().FullName
System.DateTime
PS C:\> $user.LastLogonDate
Monday, July 11, 2014 8:50:38 AM
PS C:\> $user.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss')
2014-07-07 08:50:38
Add a check for $null values to prevent errors for users that never logged on:
if ($u.LastLogonDate -ne $null) {
$user.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss')
}