PowerShell snippet: Get-Choice

You know when you want the user to make a choice, and you want him to type it out and get it right?

class Choice {    
    [string] $Key;
    [string] $Option;
    Choice($Key, $Option) {
        $this.Key = $Key
        $this.Option = $Option
  Read userinput and validate against choices
  Read userinput and validate against choices. Must match one of the keys. Not case sensitive.
 .Parameter Prompt
  Text to show when waiting for input
 .Parameter Choices
  List of Choice elements
 .Parameter NoHints
  Don't show list of hints for Choices
  $MyChoices = @(
      [Choice]::new('yes', 'Let me continue'), 
      [Choice]::new('no', 'I want to stop')
  $key = Get-Choice -Prompt "Do you want to continue?" -Choices $MyChoices
function Get-Choice {
    #    [OutputType([string])]
    param (
    $Hints = ""
    $Comma = ""
    $Opts = ""
    $Sep = ""
    $Choices | ForEach-Object {
        $Hints = $Hints + $Comma + '[' + $_.Key + '] ' + $_.Option
        $Comma = ', '
        $Opts = $Opts + $Sep + $_.Key 
        $Sep = '|'
    if (-not $NoHints) {
        Write-Host $Hints
    $pattern = $Opts.ToLower()
    $pattern = "¤¤$pattern¤¤" -replace "\|", "¤¤|¤¤"
    $ok = $false
    while (-not $ok) {
        [string]$userinput = (Read-Host -Prompt "$Prompt ($Opts)").ToLower()
        $userinput = ("¤¤$userinput¤¤" | Select-String -Pattern $pattern) -replace "¤¤" , ""
        $ok = ("$userinput" -ne "")
    return $userinput
} # Get-Choice

PowerShell snippet: Show-TextFile

You know those times that you need to show a log file or some text file?

  Open NotePad with the specified filename
  Open NotePad with the specified filename
 .Parameter FileName
  Name of text file to open
 .Parameter ScrollToEnd
  Scroll to the bottom of the opened file
 .Parameter Wait
  Wait for Notepad to close before continuing script
 .Parameter Kill 
  Kill Notepad after Timeout -Requires Wait
 .Parameter TimeOut 
  Timeout period in seconds - default = 300 - Requires Wait
  Show-TextFile -FileName 'C:\Some path\folder\filename.txt' -ScrollToEnd -Wait -Kill -TimeOut 30 
function Show-TextFile {
    param (
        [int]$TimeOut = 300
    if (Test-Path -Path $FileName) {
        $proc = Start-Process -FilePath 'NotePad.exe' -ArgumentList "$FileName" -NoNewWindow -PassThru
        if ($ScrollToEnd) { 
            # Use VBScript to send Ctrl-End keystroke to Notepad
            $wshell = New-Object -ComObject wscript.shell
            $title = Split-Path -path $FileName -Leaf
            Start-Sleep -seconds 0.5
            $wshell.AppActivate($title) | Out-Null
            $wshell.SendKeys('^{END}') | Out-Null
        if ($Wait) {
            Write-Host "To continue, close Notepad for '$FileName'"
            if (-not (Wait-Process -InputObject $proc -Timeout $TimeOut -ErrorAction SilentlyContinue)) {
                if (-not $Proc.HasExited) {
                    if ($Kill) {
                        Write-Host "Closed Notepad for $FileName"
                        Stop-Process -InputObject $proc -Force
                    } }
    else {
        Write-Warning "Show-TextFile -FileName not found: $FileName"
} # Show-TextFile

Snippet: Convert Java time to TDateTime

I am currently working on an application that need to extract content from a Java Web Service using a SOAP interface. The interface delivers all timestamps as Java timestamps (64-bit integer – UTC time in milliseconds before or after the start of January 1, 1970), so I need to convert them to TDateTime for further processing in the Delphi code.

First, I convert it to a Windows filesystem time – which is similar to the Javatime, except from the start time offset and the time resolution. Next, I convert the filetime to Windows UTC time, and adjust for the timezone – simplified to just use the default – ie current local timezone. The final step is to convert the system time constant to a TDateTime.

The whole thing is done with blatant disregard of the tradition of checking return values from the two system calls. The less optimistic of you may choose to check for return values equaling zero to indicate an error.

Windows, SysUtils; // Time functions

function JavaTimeToDateTime(javatime:Int64):TDateTime;
// java time -> Win32 file time -> UTC time
// adjust to active time zone -> TDateTime
UTCTime, LocalTime: TSystemTime;
FileTimeToSystemTime(TFileTime(Int64(javatime + 11644473600000) * 10000), UTCTime);
SystemTimeToTzSpecificLocalTime(nil, UTCTime, LocalTime);
Result := SystemTimeToDateTime(LocalTime);

FYI: 11644473600000 * 10000 = 1 Jan 1970 in Windows File Time