Read-Host Timeout - Email Reminder

This topic contains 12 replies, has 4 voices, and was last updated by Profile photo of Shaun Morrissey Shaun Morrissey 2 months, 2 weeks ago.

  • Author
    Posts
  • #54075
    Profile photo of Shaun Morrissey
    Shaun Morrissey
    Participant

    Hi All,

    I currently have a PowerShell script i have made which provisions a new user account in Active Directory. The script gets to a stage at the end where it asks whether an account expiry date has been requested using the Read-host method.

    What i am trying to achieve is if the user running the script gets to this stage and forgets to enter the requested input after say 3 minutes i would like the script to send a Reminder email to the user running the script advising that the script is still running and requires their attention.

    I have successfully implemented a timer event which will send the email after 3 minutes but this is without the Read-Host event occurring, when the Read-host occurs waiting for user input the script seems to pause (including the timer) so the reminder email does not get sent.

    The code i have in this section of the script is as follows:

    $ReminderTimer = New-Object System.Timers.Timer
    $ReminderTimer.Interval = 180000

    add-content -Path $pathReminder -Value "The New User PowerShell script is still waiting for your input. A Reminder email will be sent to you every 3 minutes until the PowerShell script is attended to."
    add-content -Path $pathReminder -Value " "
    add-content -Path $pathReminder -Value "Regards"
    add-content -Path $pathReminder -Value " "
    add-content -Path $pathReminder -Value "HPW Account Provisioning Team"
    $fileReminder = Get-Content $pathReminder
    $bodyReminder = ($fileReminder | Out-String)
    $toReminder = $UserRunningThisScriptEmail
    $fromReminder = "HPW-AccountProvisioningTeam@hpw.qld.gov.au"
    $SubjectReminder = "REMINDER: New User Provisioning Script Is Awaiting Your Input"
    $smtpReminder = "smtp"

    $Action = {Send-MailMessage -to $toReminder -Subject $SubjectReminder -body $bodyReminder -smtp $smtpReminder -from $fromReminder}

    Register-ObjectEvent -InputObject $ReminderTimer -EventName Elapsed -SourceIdentifier TimerEmail -Action $Action

    $ReminderTimer.Enabled = $True
    $ReminderTimer.Start()

    $AccountExpiry = Read-Host "Has an end date been specified on the attached Form?"

    All in all is there a way to have the Read-Host event occur with the timer running in the background sending an email every 3 minutes until user input is provided. If user input is provided then the timer will then be disabled and the script can continue.

    Any help would be much appreciated.

    Thanks in advance.

    Shaun

  • #54081
    Profile photo of Anthony
    Anthony
    Participant

    Off the top of my head I don't think you will be able to do that using read-host because as you have found out it pauses the script waiting for input. Could you not just move the capture of the expiry information further up the workflow? Make them fill out the account expiry first before getting them to input the rest of the details.

  • #54110
    Profile photo of Dan Potter
    Dan Potter
    Participant

    There is no timer tick event that I see.

  • #54116
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    The best way to really do validation is using a GUI interface where you can gray out the Submit button until everything has been satisfied.

    If you want to do an email, as you and Anthony have indicated everything stops at Read-Host. So, prior to read host, you would need to start another Powershell process with the timer running. You would need to pass the process ID of the 'waiting' script to another script that would run a loop while that process is running. Some basic pseudo-code:

    New-User.ps1

    Invoke-Expression -Command "C:\Users\Rob\Desktop\Start-Timer.ps1 -Process $([System.Diagnostics.Process]::GetCurrentProcess())" 
    $AccountExpiry = Read-Host "Has an end date been specified on the attached Form?"
    

    Start-Timer.ps1

    param(
        $Process
    )
    
    
    $psScript = Get-Process | Where{$_.ID -eq $process}
    
    while ([boolean]$psScript) {
        
        "Starting process loop..."
        
         Start-Sleep -Seconds 180
         $psScript = Get-Process | Where{$_.ID -eq $process}
        
         "Send-MailMessage"
    }
    
    "Exiting loop"
    

    You could dynamically generate the script in the temp directory or reference a script in the script directory. It's typically a long painful path trying to build solutions around Read-Host.

    • This reply was modified 2 months, 2 weeks ago by Profile photo of Rob Simmers Rob Simmers.
  • #54120
    Profile photo of Dan Potter
    Dan Potter
    Participant
    $timer = new-object timers.timer
    
    $action = {
    	
    	[TimeSpan]$span = $StartTime - (Get-Date)
    	$host.ui.rawui.windowtitle = "{0:mm}:{0:ss}" -f $span
    	
    }
    
    $timer.Interval = 100
    
    $Timer.Enabled = $True
    
    Register-ObjectEvent -InputObject $timer -EventName elapsed `
    					 –SourceIdentifier Timer3 -Action $action | Out-Null
    
    $StartTime = (Get-Date).AddMinutes(10)
    
    $Timer.Start()
    
    
    function notreadhost {
    	
    	write-host 'Hello..waiting on you...Are you still there (Y)?'
    	
    	while (-not $host.ui.RawUI.KeyAvailable) { }
    	
    	[string]$pressanykey = ($host.ui.RawUI.ReadKey("IncludeKeyDown,NoEcho")).character
    	
    	$pressanykey
    	
    }
    
    
    notreadhost
    
    
  • #54122
    Profile photo of Dan Potter
    Dan Potter
    Participant

    sleep for one second before calling the function giving the timer the ability to process the first tick.

    Now all you have to do is detect the span total minutes to meet your conditions and execute your email part. Less than 3 minutes reset the starttime.

  • #54123
    Profile photo of Dan Potter
    Dan Potter
    Participant

    Here is how I do this in forms so I don't have to chase down the user who left it open. The timer is a fun little toy=D

    
    $formmousehover = {
    	
    	$formO365UserProvision.Text = ''
    	$script:StartTime = (Get-Date).AddMinutes(10)
    	[TimeSpan]$span = $script:StartTime - (Get-Date)
    	$statusbar1.Text = "Form timeout: " + "{0:N0}" -f $span.TotalMinutes + " Minute(s)"
    	$picturebox1.remove_MouseHover($formmousehover)
    }
    
    $timer1_Tick = {
    	
    	[TimeSpan]$span = $StartTime - (Get-Date)
    	
    	if ($span.TotalSeconds -gt 30) { $statusbar1.Text = "Form timeout: " + "{0:mm}:{0:ss}" -f $span } else {
    		
    		$statusbar1.Text = "Hover mouse over banner to add time."
    		$formO365UserProvision.Text = "Are you still using this form? " + "{0:N0}" -f $span.TotalSeconds + " Seconds"
    		
    		$picturebox1.add_MouseHover($formmousehover)
    		
    		if ($span.TotalSeconds -le 0) {
    			
    			$formO365UserProvision.Close()
    			
    		}
    		
    		
    	}
    	
    	
    }
    
    
  • #54140
    Profile photo of Shaun Morrissey
    Shaun Morrissey
    Participant

    Hi All,

    Thanks for the replies. I ended up putting something together yesterday. Its pretty messy but its working. I created a small Vb.Net EXE which contains a timer that sends an email to the user running the program every 3 minutes via basic SMTP. In relation to PowerShell the EXE gets called just before the Read-Host occurs and runs in the background (no GUI) and when the Read-Host event completes the process then gets killed.

  • #54151
    Profile photo of Dan Potter
    Dan Potter
    Participant

    ducttapeandbandaids.ps1?

    I gave you near complete code to do it. It's formatted not to be messy. Was there something you don't understand about the timer?

  • #54154
    Profile photo of Dan Potter
    Dan Potter
    Participant

    Rube Goldberg, you could use your webcam to watch the clock on your wall and make a sound every three minutes and train a parrot to invoke your email script.

    • #54158
      Profile photo of Shaun Morrissey
      Shaun Morrissey
      Participant

      It appears you think i have insulted you Dan Potter. When i mentioned the term "Messy" i was referring to my own VB.Net EXE i put together (through trial and error) which had nothing to do with the code you gave me as i hadn't seen your reply until afterwards. I put this together before you even replied to this post.

      Anyways i appreciate your assistance with this and apologise if you thought i was having a dig at you.

      Shaun

  • #54160
    Profile photo of Dan Potter
    Dan Potter
    Participant

    Not offended..just a stickler for doing things the right way:-) I work in government, you should see the solutions I've had to repair over the last two years.

    • #54161
      Profile photo of Shaun Morrissey
      Shaun Morrissey
      Participant

      No worries, i work for the Government myself and i agree a lot of the solutions in place are a mess. I work in the account provisioning team so have had to pretty much put together all the scripts from scratch to automate the whole AP processes. Everything is pretty much in order now though and is working. If i have any further issues i'm sure you will see me back here 😉

      Cheers

You must be logged in to reply to this topic.