In this post:
What in the World Is Wrong with This Windows PowerShell Script I Wrote?
Hey, Scripting Guy! On trying to parse a datetime string in Windows PowerShell, I get a parse error, like the culture is set to en-US. But when I try it using the Get-Date method, it works. Please see the script output below. Now I can do this using the [datetime]::ParseExact method, but I do not understand why this is happening because the CurrentCulture is en-GB and the short date pattern clearly says dd/mm/yyyy. My question is why is the .NET Framework DateTime class using en-US culture or CurrentUICulture, and can I change this for my shell permanently? 39 > [datetime] "21/05/2010" NotSpecified: (:) [], RuntimeException 41 > $error| fl * -force PSMessageDetails : Exception : System.Management.Automation.RuntimeException: Cannot convert value "21/05/2010" to type "System.DateTime". Error: "String was not recognized as a valid DateT ime." ---> System.Management.Automation.PSInvalidCastException: Cannot convert value "21/05/2010" to type "System.DateTime". Error: "String was not recognized as a valid DateTime." ---> System.FormatException: String was not recognized as a valid DateTime. at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles) at System.DateTime.Parse(String s, IFormatProvider provider) --- End of inner exception stack trace --- at System.Management.Automation.LanguagePrimitives.IsParseTypeConversion(Object valueToConvert, Type resultType, IFormatProvider formatProvider, Object& re sult) at System.Management.Automation.LanguagePrimitives.ConvertTo(Object valueToConvert, Type resultType, Boolean recursion, IFormatProvider formatProvider, Typ eTable backupTypeTable) at System.Management.Automation.Parser.ConvertTo(Object obj, Type type, Token token) --- End of inner exception stack trace --- at System.Management.Automation.Parser.ConvertTo(Object obj, Type type, Token token) at System.Management.Automation.UnaryPrefixPostFixNode.ExecuteConversion(Object operand, Token op) at System.Management.Automation.UnaryPrefixPostFixNode.ExecuteUnary(Object operand, Token op, ExecutionContext context) at System.Management.Automation.UnaryPrefixPostFixNode.Execute(Array input, Pipe outputPipe, ExecutionContext context) at System.Management.Automation.AssignmentStatementNode.Execute(Array input, Pipe outputPipe, ExecutionContext context) at System.Management.Automation.StatementListNode.ExecuteStatement(ParseTreeNode statement, Array input, Pipe outputPipe, ArrayList& resultList, ExecutionC ontext context) TargetObject : CategoryInfo : NotSpecified: (:) [], RuntimeException FullyQualifiedErrorId : RuntimeException ErrorDetails : InvocationInfo : System.Management.Automation.InvocationInfo PipelineIterationInfo : {} 38 > get-date "21/05/2010" 21 May 2010 00:00:00 33 > $host Name : Windows PowerShell ISE Host Version : 2.0 InstanceId : 22476f38-943e-4255-a7a9-a2281730325a UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : en-GB CurrentUICulture : en-US PrivateData : IsRunspacePushed : False Runspace : System.Management.Automation.Runspaces.LocalRunspace 35 > (get-culture).get_datetimeformat().ShortDatePattern dd/MM/yyyy 37 > [System.Threading.Thread]::CurrentThread.CurrentCulture.datetimeformat.shortdatepattern dd/MM/yyyy !--[endif]-->!--[if>
-- JT
Hello JT,
I am going to make a guess here. The first is that if you try your cast in the Windows PowerShell console (the blue one), it will work. If this is so, it is because of the difference between the Windows PowerShell console and the Windows PowerShell ISE. Note that here are your settings: CurrentCulture: en-GB CurrentUICulture: en-US These variables contain similar information to what you can get via the Get-Culture cmdlet and the Get-UICulture. The reason there are two variables and two cmdlets is that Windows has two language settings. The first one—in Control Panel\Clock, Language, and Region on the Location tab—is the same as the Get-UICulture. Note that the tab description says that some software, including Windows, may provide you with additional information. The Windows PowerShell ISE uses Unicode and is therefore controlled by this setting.
On the Administrative tab, there is the Language for non-Unicode programs. The Windows PowerShell console is non-Unicode and therefore is controlled by this setting.
Please do three things for me:
JT follows up:
Your first guess is correct and I tried it in the blue console, but I am getting the same behavior. Now you refer to two setting locations which I understand as being the Regional Options tab and the Languages tab in the Region and Language Options on the Control Panel. But both appear as shown in the following images. Maybe there is another location where Windows sets the language? My computer is part of a corporate network, and I am trying to understand Windows PowerShell .
Hello again, JT.
Okay, I did some research, and have found out that this behavior is actually a special case and it is by design. If this sort of type conversion used the current locale by default, scripts written in one locale could break on another with the very same input. The problem occurs with data that is not represented in the appropriate data type yet.
In your example, you are using raw input to convert a string into a system.DateTime object. The System.DateTime structure casts it into a culture-independent format.
If you need to use a different date format, such as the UK uses of dd/mm/yyyy, you can use Parse(). By default, the parse method will use your current culture settings. Therefore, on a system that had UK English (en-GB), the following command would work:
[datetime]::Parse(“21/05/2010”)
You can also supply a cultureinfo object to parse in the second position. This is shown here:
$culture = Get-Culture [datetime]::Parse(“21/05/2010”, $culture)
On your system with en-GB cultural settings, this command would work. On my system with en-US cultural settings, the command fails. However, if you use the static GetCulturalInfo method from the system.globalization.cultureinfo class to create the required cultural settings, it does not matter what type of settings your computer uses. This is shown here, where on my en-US computer I parse your command:
PS C:\> $ukCulture = [Globalization.cultureinfo]::GetCultureInfo("en-GB") PS C:\> [datetime]::Parse("21/05/2010", $ukculture) Friday, May 21, 2010 12:00:00 AM
By the way, you can avoid all this by using the Get-Date cmdlet to create your datetime strings. This is shown here:
PS C:\> Get-Date -Month 5 -Day 21 -Year 2010 Friday, May 21, 2010 9:39:15 AM
Or by using the Get-Date cmdlet and passing a string:
PS C:\> Get-Date "5/21/2010"
Friday, May 21, 2010 12:00:00 AM
The Get-Date cmdlet will use your culture settings automatically, in the same way as the parse method from the datetime class.
How Can I Make a Script Run When a User Logs On?
Hey, Scripting Guy! Is it possible to make a script that starts when a certain user logs on? This script then needs to start a certain program, wait a minute, start another program, wait a few minutes, and then log off. Just curious if it is possible and how to do it or at least find information about how to do it in this wilderness of help sites. !--[endif]-->!--[if>
-- MK
Hello MK,
Yes, it is possible. Using Group Policy, you can specify a startup script on a per-user basis. You can also simply add the script to the user’s startup folder or the run key in their registry.
Then you need to decide if you want to write the script using VBScript or Windows PowerShell. There are examples of starting programs in the Script Repository as well as the Hey, Scripting Guy! Blog. As a matter of fact, one of the events in the 2010 Scripting Games involved logging off a user when a specific program launched. The expert commentators wrote solutions in both VBScript and Windows PowerShell .
Well, this concludes another edition of Quick-Hits Friday. Join us tomorrow for the Weekend Scripter as we delve into the mysteries of…well, we will let that remain a mystery for now.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
As for the date conversion: Reasons why I always use ISO 8601 date format in strings representing dates in my scripts. Those are parsed by PowerShell even if the locale tells a different story.
"Okay, I did some research, and have found out that this behavior is actually a special case and it is by design. If this sort of type conversion used the current locale by default, scripts written in one locale could break on another with the very same input. "
That's fair enough, but why would/should the "by design" use en-US as the culture. If it needs to be locale independant, should it use ISO 8601 instead?