Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Converting Lexical Timespans with PowerShell

Posted on December 18, 2019December 18, 2019

I've been working on a few scripting projects and the data I'm working with contains lexical timespans. Say what? You have probably seen these things. This is a string like P0DT0H0M47S to represents a timespan. They aren't difficult for humans to read. This one says "0 days 0 hours 0 minutes 47 seconds". The format is how timespans, or durations, are stored in XML files. You can read more about this at https://www.w3.org/TR/xmlschema-2/#duration. But I want to see these value as more PowerShell-friendly timespans. Turns out, this is actually very easy.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

One place you can see these values is with scheduled tasks in Windows.

A lexical duration

I know PT72H represents a 72 hour timespan. To convert this into a timespan object is simple. Once you know how and in a second you will. You can use a built-in XML method to convert the value.

[System.Xml.XmlConvert]::ToTimeSpan("PT72H")

image

And sure enough, this is 72 hours or 3 days. What about converting the other way?

$ts = New-TimeSpan -hours 72
[System.Xml.XmlConvert]::ToString($ts)

Converting a timespan

The string is admittedly different, but it still represents 72 hours.

The process is simple, but I still wrote a pair of PowerShell advanced functions to handle these tasks.

Function ConvertTo-LexicalTimespan {
    [cmdletbinding()]
    [OutputType("String")]
    Param(
        [Parameter(Position = 0, Mandatory,HelpMessage = "Enter a timespan object", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [timespan]$Timespan
    )
    Begin {
        Write-Verbose "[$((Get-Date).TimeofDay) BEGIN  ] Starting $($myinvocation.mycommand)"

    } #begin

    Process {
        Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Converting $Timespan"
        Try {
            [System.Xml.XmlConvert]::ToString($Timespan)
        }
        Catch {
            Throw $_
        }
    } #process

    End {
        Write-Verbose "[$((Get-Date).TimeofDay) END    ] Ending $($myinvocation.mycommand)"
    } #end

} #close ConvertTo-LexicalTimespan

Function ConvertFrom-LexicalTimespan {
    [cmdletbinding()]
    [OutputType("string", "timespan")]
    Param(
        [Parameter(Position = 0, Mandatory, HelpMessage = "Enter a lexical time string like P23DT3H43M. This is case-sensitive.", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$String,
        [Parameter(HelpMessage = "Format the timespan as a string")]
        [switch]$AsString
    )
    Begin {
        Write-Verbose "[$((Get-Date).TimeofDay) BEGIN  ] Starting $($myinvocation.mycommand)"
    } #begin

    Process {
        Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Converting $($String.toUpper()) to a timespan"
        Try {
            #convert string to upper case to help the user out
            $r = [System.Xml.XmlConvert]::ToTimeSpan($String.ToUpper())
            if ($AsString) {
                Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Displaying as a timespan string"
                $r.toString()
            }
            else {
                $r
            }
        }
        Catch {
            Throw $_
        }
    } #process

    End {
        Write-Verbose "[$((Get-Date).TimeofDay) END    ] Ending $($myinvocation.mycommand)"
    } #end

} #close ConvertFrom-LexicalTimespan

Let's see how these work.

Here's another raw example.

Lexical durations

Or I can use code like this:

(get-scheduledtask dailywatcher).settings.idlesettings | 
select-object @{Name="Idle";Expression={ConvertFrom-LexicalTimespan $_.idleDuration}},
@{Name="Wait";Expression={ConvertFrom-LexicalTimespan $_.WaitTimeout}}

Converted lexical durations

Now, I have more meaningful output.

Here's one final example using Get-WsManInstance to show connected pssessions.

Result with lexcial durations

But I think you'll agree that using this code produces a better result.

Get-WSManInstance -ComputerName DOM1 -ResourceURI Shell -Enumerate | 
 Select-Object -Property ResourceURI,Owner,ClientIP,
 @{Name="ShellRunTime";Expression = {ConvertFrom-LexicalTimespan $_.ShellRunTime}},
 @{Name="ShellInactivity";Expression = {ConvertFrom-LexicalTimespan $_.ShellInactivity}},
 @{Name="IdleTimeOut";Expression = {ConvertFrom-LexicalTimespan $_.IdleTimeOut}},
 @{Name="MaxIdleTimeOut";Expression = {ConvertFrom-LexicalTimespan $_.MaxIdleTimeOut}},
 @{Name="Computername";Expression={"DOM1"}}

Properly formatted timespans

This is code I would put into a function to create meaningful output to the PowerShell pipeline. Or if I wanted something more interactive, I could use my PSTypeExtensionTools module and create extensions.

$t = "System.Xml.XmlElement#http://schemas.microsoft.com/wbem/wsman/1/windows/shell#Shell"
$t | Add-PSTypeExtension -MemberType ScriptProperty -MemberName ShellRun -Value {[System.Xml.XmlConvert]::ToTimeSpan($this.ShellRunTime) }
$t | Add-PSTypeExtension -MemberType ScriptProperty -MemberName ShellInactive -Value {[System.Xml.XmlConvert]::ToTimeSpan($this.ShellInactivity) }
$t | Add-PSTypeExtension -MemberType ScriptProperty -MemberName Idle -Value {[System.Xml.XmlConvert]::ToTimeSpan($this.IdleTimeout) }
$t | Add-PSTypeExtension -MemberType ScriptProperty -MemberName MaxIdle -Value {[System.Xml.XmlConvert]::ToTimeSpan($this.MaxIdleTimeout) }

This makes it easier to run the command and select the new properties.

Using PowerShell type extensions

Or I could create a custom format view. But I'll leave that exercise for you.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

1 thought on “Converting Lexical Timespans with PowerShell”

  1. Matthew Gray says:
    December 18, 2019 at 12:10 pm

    Very, very cool! It is so simple. I killed 4 hours to test and parse scheduled task intervals with regex. Thanks a lot.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d