I have a very odd thing happening in Powershell.
Here is the code:
add-pssnapin windows.serverbackup
$wbs = Get-Wbsummary
$lastbackuptime = $wbs.lastBackupTime
$solution = "Windows Server Backup"
$surl = "https://REDACTED:1338/REDACTED.asp?querysolution=$solution&querylastbackuptime=$lastbackuptime"
write-host $surl
write-host $lastbackuptime
Here is what is output when I run this
https://REDACTED:1338/REDACTED.asp?querysolution=Windows Server Backup&querylastbackuptime=05/07/2013 05:04:12
07/05/2013 05:04:12
Why is powershell swapping the date around when made as part of another variable but not when I output the variable on its own?!
This is a special case with casting a datetime object. When you simply print the date as a string using write-host, that will be equal to running $lastbackuptime.toString(). This method uses the culture of you're computer. In my case, the culture in Region settings for Windows is Norway, so I get the "european" dateformat: dd/mm/yyyy.
However, when you include $lastbackuptime inside a string, it performs a cast to a string-object. In PowerShell(or .Net) it was decided that when casting a datetime-object, it should use a standard format to convert it to string so that the code would run the same no matter what culture the computer was configured with. That's why casting gives you the US format, while toString() and Write-Host gives the "european" format
Ex:
[16:07:43] PS-ADMIN C:\> $d.tostring()
07.05.2013 16:04:17
[16:13:05] PS-ADMIN C:\> write-host $d
07.05.2013 16:04:17
[16:13:12] PS-ADMIN C:\> [string]$d
05/07/2013 16:04:17
To specify the format your datetime should be displayed, you can do something like this:
[16:14:28] PS-ADMIN C:\> $d.tostring("dd/MM/yyyy")
07.05.2013
[16:14:34] PS-ADMIN C:\> "examplestring $($d.tostring("dd/MM/yyyy"))"
examplestring 07.05.2013
Read more here
Check your regional settings, specifically the Short Date & Long Date formats.
On my system, Short Date is MM/dd/yyyy and and Long Date is dddd, MMMM dd,yyyy. Then, running a simplified version of your example:
>$lastbackuptime = get-date;
>$lastbackuptime
Tuesday, May 07, 2013 10:07:42
>$url="http://whatever/redacted.asp?time=$lastbackuptime";
>$url
http://whatever/redacted.asp?time=05/07/2013 10:07:42
When used on its own, the Long Date format is used in returning the date, but when concatenated with (or expanded inside) another string the Short Date format is used.
Related
Currently having a really really hard time with something that looks very easy to fix but for some reason just doesnt work.
I have an Excel file with a column called "Date" with uh...dates in it with the following format; 21-3-2021. All I want is to use these dates to set an AD account Expiration date.
So this is what I did:
import-CSV ".\Example.csv" | % {
$User = $._username
$ExpirationDate = [datetime]::Parse($_.Date).ToString('dd/MM/yyyy')
if ($_.Date -ne '') {
Set-ADAccountExpiration $User $ExpirationDate
}
else {
Clear-ADAccountExpiration $user
}
Exception calling "Parse" with "1" argument(s): "String was not recognized as a valid DateTime."
Please, if someone can tell me what I am doing wrong I would be really happy.
This is driving me nuts!
The single-argument [datetime]::Parse() overload - e.g.,
[datetime]::Parse('21-3-2021') - implicitly uses the date/time formats of the current culture[1], as reflected in $PSCulture and Get-Culture, and it seems that that current culture in effect for you doesn't recognize a date string such as '21-3-2021'.
A simple solution is to explicitly specify a culture in which such a date format is valid and pass that culture as the second argument:
# The German culture supports such a format.
# Sample output is from my en-US (US English system).
PS> [datetime]::Parse('21-3-2021', [cultureinfo] 'de-DE')
Sunday, March 21, 2021 12:00:00 AM
If you had a truly exotic format not recognized by any of the predefined cultures (which isn't the case here), you could use the [datetime]::ParseExact() method:
PS> [datetime]::ParseExact('21-3-2021', 'd\-M\-yyyy', [cultureinfo]::InvariantCulture)
Sunday, March 21, 2021 12:00:00 AM
Note:
The - instances are \-escaped to ensure that they are matched verbatim in the input; by default, they are treated as abstract placeholders for any of the date-component separators supported by the target culture.
The specific culture context passed as the 3rd argument - the invariant culture here - would only matter if the input string contained abstract placeholders and/or culture-specific month names, such as "März" for March; you can pass $null to use the current culture.
[1] Note that if you cast a string to a type in PowerShell - e.g., [datetime] '1/13' - the invariant culture is always used for parsing; in other words: [datetime] '1/13' is equivalent to:
[datetime]::Parse('1/13', [cultureinfo]::InvariantCulture).
The invariant culture is derived from the US-English culture and is designed to be both independent of the current culture and to be stable over time, which makes it suitable for programmatic use - see this answer for more.
I'm passing a string that represents a date i.e. 20180625 to my Powershell script.
I'm then taking the string parameter, which is called $currentDate and formatting it as follows:
$date = [datetime]::ParseExact($currentDate,"yyyyMMdd",$null)
However, when I write the $date variable out it's displaying as 6/29/2018 12:00:00 AM.
I'm doing this because I need to get the day of the year for my script:
$dayofyear = ($date).dayofyear
Which works. I just expected the $date to be in the yyyyMMdd format. Just curious as to why this is happening.
The format parameter for ParseExact tells the parser what format the date you are giving it is in. The object you get back is a DateTime object not a string. To get the string in the format that you want, use the .ToString() method then give if the format that you want the string to be in.
As an example:
$currentDate = '20180629'
$date = [datetime]::ParseExact($currentDate,"yyyyMMdd",$null)
$dayOfYear = $date.DayOfYear
$date.ToString('yyyyMMdd')
$date is an object of type [datetime] which contains an exact measure of time in ticks. For instance, a timespan of 1 day would be 864000000000 ticks. Thus it is not possible to have $null values in a lesser field (864 ticks would only be a few milliseconds). $date prints to the console with a default formatting, which can be changed. However, since each field down to -Milliseconds is populated as 0, when that default format does contain fields such as -hours, they will be displayed as the minimum value (in this case, 12am exactly).
When I run Get-Date -DisplayHint Time, the output is 10:30:19.
When I run "$(Get-Date -DisplayHint Time)", the output is 02/15/2018 10:30:15.
Why the difference?
PSVersion = 5.1.16299.98
Because -DisplayHint is, well, a display hint. The result of the cmdlet is still a DateTime object. Inside a string the expression doesn't count as being "displayed", and you will get... something else. (Curiously, it's not the result of a simple .ToString()). Use "$(Get-Date -Format 'T')" if you want the locale-dependent long time format inside a string (which is apparently what -DisplayHint Time will do, although that's not explicitly documented as such).
I have a CSV file with the following data
"Date","Time","Name","SourceIP","DestinationIP"
"Sep 1","03:55:57","mmt-5","172.16.48.158","22.22.22.22"
"Sep 1","03:55:57","mmt-5","172.16.48.158","22.22.22.22"
"Sep 1","03:55:57","mmt-5","172.16.48.158","22.22.22.22"
"Sep 1","03:55:57","mmt-5","172.16.48.158","22.22.22.22"
I would like to convert the date into something more usable like 09-01-2016 (the year would be the current year).
How can I accomplish this?
That's easy using the [DateTime] class's ParseExact method. You supply the string that is a date, you tell it how the date is formatted, and you provide a culture or provider or something, but I always just use $null.
[datetime]::ParseExact("Sep 1","MMM d",$null)
That comes out to:
Thursday, September 1, 2016 12:00:00 AM
So you could just do something like:
$Array | ForEach{[datetime]::ParseExact($_.Date,"MMM d",$null)}
And that would convert each entry's Date property to a valid [datetime] object. Then you just format it however you want:
$Array | ForEach{[datetime]::ParseExact($_.Date,"MMM d",$null).ToString("M-d-yyyy")}
That would output:
9-1-2016
Or for the exact thing you asked for use "MM-dd-yyyy" to get 09-01-2016.
Edit: Thanks to wOxxOm for educating me about the third parameter's necessity when dealing with non-localized date formats! So, if this needs to be localized for other cultures, you will need to include that last parameter. That can be done as such:
$Culture = [cultureinfo]::GetCultureInfoByIetfLanguageTag('en-US')
$Array | ForEach{[datetime]::ParseExact($_.Date,"MMM d",$Culture).ToString("MM-dd-yyyy")}
Edit2: Ok, to replace your current Date field with this information you could pass the array to the Select command, and create a new Date property on the fly, and discard the original, then pass that to Export-CSV:
$Array | Select *,#{l='Date';e={[datetime]::ParseExact($_.Date,"MMM d",$null).ToString("M-d-yyyy")}} -Exclude Date | Export-CSV D-Sample-2.csv -NoType
If I have:
Write-Host "[$(Get-Date -displayhint time)] backup starting..."
I get:
[02/17/2010 1:26:12pm] backup starting...
i. e. the Get-Date parameters are being ignored and is just returning the output of Get-Date.
What's the best way to do inject the current time in the middle of a string?
thanks
Well, in this case you're converting to a string because you are using the output in a string. The result of the Get-Date command is still a DateTime object. The display hint would then be honored by the Out-Host cmdlet.
You can use the -Format parameter to force a certain format in which case the cmdlet returns a string:
Get-Date -Format T
("T" being the format string for the full time) which then looks like this:
PS Home:\> Write-Host "[$(Get-Date -Format T)] backup starting..."
[19:35:12] backup starting...
You can also use the ToString() method of the DateTime class. I usually do something like this:
[PS] C:\>write-host "$((get-date).tostring('yyyy.MM.dd-HH:mm:ss'))"
2010.02.19-09:54:51