Regex - Understanding what i did !

This topic contains 6 replies, has 4 voices, and was last updated by Profile photo of Graham Beer Graham Beer 1 year, 3 months ago.

  • Author
  • #27352
    Profile photo of Graham Beer
    Graham Beer

    So i'll briefly describe my issue and how i got it working, but not sure how !

    From the WMI command, Get-CimInstance -Namespace root\cimv2 -ClassName Win32_Product, when query the app and the install date i found the string that came back was written as 20150706.
    I want to see the date displayed as 06/07/2015

    I needed to create a "white Space" between the year, month and date.

    "20150706" -replace  ("([4-9]+)",'$1 ')

    Result now is 2015 07 06

    Now with the white space, i can split up the date separately
    .Split(' ')
    So added to the regex line to create white space

    ("([4-9]+)",'$1 ')).Split(' ')

    Finally i need to rejoin the date but in the reverse order and with '/'
    [2..0] -join "/"
    So i'm joining the split up date in reverse order (2 to 0, backwards), then joining with '/' where the white space is.

    So finally looks like this with the WMI query set as a variable:

    $Product = Get-CimInstance -Namespace root\cimv2 -ClassName Win32_Product
    $Product | select name,version, @{n='Date of Install';e={($_.installdate -replace ("([4-9]+)",'$1 ')).Split(' ')[2..0] -join "/"}}

    Now, if i play a bit more i find this '"([4-5])",'$1 " does the same as this, ([4-9]+)",'$1 ', but without 9 (replaced with a 5) and no '+' required.

    I was playing with this for a large amount of time and i'm not sure why what i did worked or fully understand. The [4-5], so this i don't fully get. the $1 i'm think is the variable is written too. Some basic Regex i get, ^start, $end. But pieces it together is very confusing !

    Any help would be great.

  • #27353
    Profile photo of Dave Wyatt
    Dave Wyatt

    In a regex, [4-9] will match any single character that's a 4,5,6,7,8 or 9.

    I would make two suggestions here: one, don't use Win32_Product. Seriously, trust me on this. See for explanation. 🙂

    Two, rather than parsing this string yourself, it's probably easier to just use the DateTime class, which allows you to do all sorts of conversions to and from string. In this case:

    $wmiDateString = '20150706'
    $dateTime = [datetime]::ParseExact($wmiDateString, 'yyyyMMdd', [cultureinfo]::CurrentCulture)
    $newString = $dateTime.ToString('dd/MM/yyyy')

    In this case, I'm using custom date/time formatting strings from the .NET framework, which you can find documented here:

  • #27354
    Profile photo of Graham Beer
    Graham Beer

    I did try looking into that, but didn't get far. Looking at your code i can see why ! its brilliant, would really like to have that level of understanding. Thanks.

  • #27394
    Profile photo of Tim Curwick
    Tim Curwick

    A minor tweak to Dave's great solution...

    The current culture is what you would want to use almost all the time with this method, and the developers anticipated that and made it the default value for that parameter. So we can shorten it a bit and take out a confusing obscure reference thus:

    $wmiDateString = '20150706'
    $dateTime = [datetime]::ParseExact($wmiDateString, 'yyyyMMdd', $Null)
    $newString = $dateTime.ToString('dd/MM/yyyy')

    And especially now that it's simpler, I would tend to combine the two lines.

    $wmiDateString = '20150706'
    $newString = [datetime]::ParseExact($wmiDateString, 'yyyyMMdd', $Null).ToString('dd/MM/yyyy')
  • #27418
    Profile photo of Graham Beer
    Graham Beer

    Thanks Tim. Can I ask, how did you find out about this and what part the $null is playing ?

    Just for my learning and understanding.

  • #27453
    Profile photo of Tim Curwick
    Tim Curwick


    The first place to go for understanding a particular .Net object is always MSDN, which is the official Microsoft repository of such information. (It's not a great place for learning .Net, because it tends to assumes a high level of .Net experience in the reader, but it's the place to go for the intricate details of an object.) So I Googled "MSDN datetime ParseExact" to find the MSDN article on the ParseExact method for datetime objects.

    I saw there that ParseExact has 3 "overloads", so called because the method is overloaded with three different definitions. Overloads are distinguished by the number and type of parameters they take. Dave is using three parameters, so the first overload in the article is the one being triggered.

    The three parameters are the string to be parsed, a string showing the format of the string to be parsed, and IFormatProvider. The third one is the complex one here of course. As the article explains, it can be any of several object types. The purpose of it is basically to tell .Net how you like to format your numbers, where you stick your commas and periods, whether you put your dates in US or European order, etc.

    Fortunately, we don't have to understand it too deeply, because we can just tell it to use the same settings that current Windows session is already using. That's what Dave did.

    Even better, at the end of the remarks, it says that it will also do that if we just use $Null instead, which is what I did. That makes it easier to remember and use, and easier for the person modifying your script in the future to understand what it does.

  • #27463
    Profile photo of Graham Beer
    Graham Beer

    Thank you Tim for taking the time to reply. Brilliant reply.

You must be logged in to reply to this topic.