1

In some of my scripts I have a fall-back approach for getting a PSCredential object via the Get-Credential cmdlet. This is very useful when running those scripts interactively, esp. during testing etc.

If & when I run these scripts via a task scheduler, I'd like to ensure that they don't get stuck waiting for interactive input and simply fail if they don't have the necessary credentials. Note that this should never happen if the task is set to run under the correct application account.

Does anyone know of an approach that would allow me to prompt for input with a timeout (and presumably a NULL credential object) so the script doesn't get stuck?

Happy to consider a more general case with Read-Host instead of Get-Credential.

Charlie Joynt
  • 4,411
  • 1
  • 24
  • 46
  • You can store a password as an encrypted text file and use this as input to create a credential object. – Bill_Stewart Feb 05 '16 at 17:09
  • Indeed. Actually, I have been looking at that type of thing recently (see my answer to another question: http://stackoverflow.com/a/34970025/5771128 !). In this case I'm sure that I want to prompt when the script is run interactively, but wanted to make it "safe" in case that prompt is somehow triggered when scheduled. – Charlie Joynt Feb 05 '16 at 17:16
  • You can do that using a mandatory parameter. If you don't include a mandatory parameter when you call a function/script, PowerShell will prompt for it. – Bill_Stewart Feb 05 '16 at 19:27

1 Answers1

1

I use something similar in some of my scripts based around a timeout on read-host, code here :

Function Read-HostTimeout {
#  Description:  Mimics the built-in "read-host" cmdlet but adds an expiration timer for
#  receiving the input.  Does not support -assecurestring

# Set parameters.  Keeping the prompt mandatory
# just like the original
param(
    [Parameter(Mandatory=$true,Position=1)]
    [string]$prompt,

    [Parameter(Mandatory=$false,Position=2)]
    [int]$delayInSeconds=5,

    [Parameter(Mandatory=$false,Position=3)]
    [string]$defaultValue = 'n'
)

# Do the math to convert the delay given into milliseconds
# and divide by the sleep value so that the correct delay
# timer value can be set
$sleep = 250
$delay = ($delayInSeconds*1000)/$sleep
$count = 0
$charArray = New-Object System.Collections.ArrayList
Write-host -nonewline "$($prompt):  "

# While loop waits for the first key to be pressed for input and
# then exits.  If the timer expires it returns null
While ( (!$host.ui.rawui.KeyAvailable) -and ($count -lt $delay) ){
    start-sleep -m $sleep
    $count++
    If ($count -eq $delay) { "`n"; return $defaultValue}
}

# Retrieve the key pressed, add it to the char array that is storing
# all keys pressed and then write it to the same line as the prompt
$key = $host.ui.rawui.readkey("NoEcho,IncludeKeyUp").Character
$charArray.Add($key) | out-null

# Comment this out if you want "no echo" of what the user types
Write-host -nonewline $key

# This block is where the script keeps reading for a key.  Every time
# a key is pressed, it checks if it's a carriage return.  If so, it exits the
# loop and returns the string.  If not it stores the key pressed and
# then checks if it's a backspace and does the necessary cursor 
# moving and blanking out of the backspaced character, then resumes 
# writing. 
$key = $host.ui.rawui.readkey("NoEcho,IncludeKeyUp")
While ($key.virtualKeyCode -ne 13) {
    If ($key.virtualKeycode -eq 8) {
        $charArray.Add($key.Character) | out-null
        Write-host -nonewline $key.Character
        $cursor = $host.ui.rawui.get_cursorPosition()
        write-host -nonewline " "
        $host.ui.rawui.set_cursorPosition($cursor)
        $key = $host.ui.rawui.readkey("NoEcho,IncludeKeyUp")
    }
    Else {
        $charArray.Add($key.Character) | out-null
        Write-host -nonewline $key.Character
        $key = $host.ui.rawui.readkey("NoEcho,IncludeKeyUp")
    }
}
Write-Host ""
$finalString = -join $charArray
return $finalString
}
GodEater
  • 3,445
  • 2
  • 27
  • 30
  • This looks very useful. I was having trouble with this answer but [discovered](http://stackoverflow.com/a/22362868/5771128) that `$Host.UI.RawUI.ReadKey()` doesn't work in PS ISE where I was doing my testing. Seems to be OK in a regular PS prompt (which is all I need). – Charlie Joynt Feb 24 '16 at 10:37
  • Ah yes, I tend to forget other people use the ISE - I never do! – GodEater Feb 24 '16 at 11:58
  • Marked as answer; I was able to use this to get something working that worked for my needs. – Charlie Joynt Mar 03 '16 at 22:38