none
Pass function to register-objectevent action block RRS feed

  • Question

  • # Disables the timer and unregisters the event subscriber
    function RemoveTimer ($timerin, $sourceidentifier) {
    	Write-Host "Inside RemoveTimer $sourceidentifier"
    	try {
    		$timerin.Enabled = $False
    		Unregister-Event -SourceIdentifier $sourceidentifier
    	} Catch {
    		Write-Host "Error occurred while stopping timer $($_.Exception.Message)"
    	}
    }
    
    # Disables the timer and unregisters the event subscriber
    function RemoveTimer1 {
    	Write-Host "Inside RemoveTimer1"
    }
    
    # LMD Timer
    try {
    	$lmdtimer = New-Object Timers.Timer
    	$lmdtimer.Interval = 50000
    	$registerevent = Register-ObjectEvent -InputObject $lmdtimer -EventName Elapsed -SourceIdentifier LMDTimer.Output -Action {
    		Write-Debug "$($Event | Out-String)"
    		Write-Host "Script is running"
    	}
    	$lmdtimer.Enabled = $True
    	Write-Debug "$($lmdtimer | Out-String)"
    } Catch {
        Write-Host "Error occurred while starting LMDTimer $($_.Exception.Message)"
    	RemoveTimer $lmdtimer "LMDTimer.Output"
    }
    
    # CTRLC Timer
    try {
    	[console]::TreatControlCAsInput = $true
    	$ctrlctimer = New-Object Timers.Timer
    	$ctrlctimer.Interval = 1000
    	$params = new-object psobject -property @{RemoveTimer1 = $function:RemoveTimer1}
    	$registerevent = Register-ObjectEvent -InputObject $ctrlctimer -EventName Elapsed -SourceIdentifier CTRLCTimer.Output -MessageData $function:RemoveTimer1 -Action {
    		if ($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))
    		{
    		  Write-Host "Removing LMDTimer and CTRLCTimer"
    		  try {
    			  #RemoveTimer $lmdtimer "LMDTimer.Output"
    			  #RemoveTimer $ctrlctimer "CTRLCTimer.Output"
    			  $Event.MessageData.RemoveTimer1
    		  } Catch {
    			  Write-Host $_.Exception.Message
    		  }
    		  Write-Host "Removing TreatControlCAsInput"
    		  [console]::TreatControlCAsInput = $false
    		  exit
    		}
    	}
    	$ctrlctimer.Enabled = $True
    	Write-Debug "$($ctrlctimer | Out-String)"
    } Catch {
        Write-Host "Error occurred while starting CTRLCTimer $($_.Exception.Message)"
    	RemoveTimer $ctrlctimer "CTRLCTimer.Output"
    	[console]::TreatControlCAsInput = $false
    }
    
    for ($i=0;$i -lt 4000;$i++) {
    	Write-Host "$i"
    }
    
    RemoveTimer $lmdtimer "LMDTimer.Output"
    RemoveTimer $ctrlctimer "CTRLCTimer.Output"
    [console]::TreatControlCAsInput = $false
    I'm actually trying to run a timer (lmd) every 50 sec once. but when i press ctrl+c the timer still continues to print the message in its action block. So i wrote an other timer (ctrlc) which runs every sec and looks for any ctrlc pressed. Then unregisters the lmd timer and ctrl timer both. and resets the TreatControlCAsInput to false. But i have a problem inside the ctrlc timer action block. i'm not able to trigger the RemoveTimer function. Please suggest :)
    Wednesday, May 20, 2015 6:40 PM

Answers

  • There are two ways to solve this quandary.

    #Return the object:
    Function MyTest{
        $myX=99
        Write-Host “MyX = $myX” –fore green
        $myX
    }
    
    $MyX=MyTest
    Write-Host “Now MyX is $myX” –fore black -back white
    
    #Or use a global:
    Function MyTest{
        $global:myX=99
        Write-Host “MyX = $myX” –fore green
    }
    
    MyTest
    Write-Host “Now MyX is $myX” –fore black -back white
    


    \_(ツ)_/

    • Marked as answer by pk_hafeez Thursday, May 21, 2015 5:38 PM
    Thursday, May 21, 2015 9:27 AM

All replies

  • What is the purpose of all of this timers chasing times?  It sounds like you are inventing a Rube Goldberg contraption. If so, have fun.  If there is a purpose then describe it..


    \_(ツ)_/

    Wednesday, May 20, 2015 10:55 PM
  • I have a important purpose to do this. ;) Its obvious. i'm trying to print something for every elapsed time interval.
    Thursday, May 21, 2015 4:46 AM
  • $lmdtimer = New-Object Timers.Timer
    $lmdtimer.Interval = 50000
    $registerevent = Register-ObjectEvent -InputObject $lmdtimer -EventName Elapsed -SourceIdentifier LMDTimer.Output -Action {
    	Write-Debug "$($Event | Out-String)"
    	Write-Host "Script is running"
            $lmdtimer.Enabled=$false
    }
    
    $lmdtimer.Enabled=$true
    

    I have a important purpose to do this. ;) Its obvious. i'm trying to print something for every elapsed time interval.

    Which explains nothing.

    Just set a timer to run on every elapsed interval.  That is all you need to do to accomplish that.

    Here is a timer that fires once.


    \_(ツ)_/

    Thursday, May 21, 2015 7:46 AM
  • Again. My initial question was that i'm not able to access any variables or functions in the action script block. The above piece of code does not work. $lmdtimer is not accessible inside action block.
    Thursday, May 21, 2015 8:57 AM
  • It works fine for me.  Did you try it? Open a new console and past this in.  It will fire once after two seconds and stop.

    $lmdtimer = New-Object Timers.Timer
    $lmdtimer.Interval = 2000
    $registerevent = Register-ObjectEvent -InputObject $lmdtimer -EventName Elapsed -SourceIdentifier LMDTimer.Output -Action {
    	Write-Debug "$($Event | Out-String)"
    	Write-Host "Script is running"
            $lmdtimer.Enabled=$false
    }
    
    $lmdtimer.Enabled=$true


    \_(ツ)_/

    Thursday, May 21, 2015 9:05 AM
  • An alternate method for running one-shot timer.

    $lmdtimer = New-Object Timers.Timer
    $lmdtimer.Interval = 2000
    # the following makes this a one-shot timer
    $lmdtimer.AutoReset=$false
    $registerevent = Register-ObjectEvent -InputObject $lmdtimer -EventName Elapsed -SourceIdentifier LMDTimer.Output -Action {
    	Write-Debug "$($Event | Out-String)"
    	Write-Host "Script is running"
    }
    
    $lmdtimer.Start()
    


    \_(ツ)_/


    • Edited by jrv Thursday, May 21, 2015 9:09 AM
    Thursday, May 21, 2015 9:08 AM

  • Most of your problems come from trying to use a “Rube Goldberg” to manage a timer.  By using functions that call functions you are building a snake that eats its tail.  This a common issue for non-programmers when scripting at first.  Try to step back and understand the object.  How is it designed and how do you think the designers intended it to be used.  If an object is to be useful it must address the elements of its normal usage.

    Timers are re-setable (autoreset) or one-shot.  You want a one shot timer so set it up that way.

    If you want to define a timer inside of a function then, by default, the timer object reference will not exist after the function exits.  You will have orphaned the timer but it will continue to run.  This is due to scoping.

    Function MyTest{
        $myX=99
        Write-Host “MyX = $myX” –fore green
    }
    MyTest
    Write-Host “Now MyX is $myX” –fore black -back white


    \_(ツ)_/


    • Edited by jrv Thursday, May 21, 2015 9:22 AM
    Thursday, May 21, 2015 9:22 AM
  • There are two ways to solve this quandary.

    #Return the object:
    Function MyTest{
        $myX=99
        Write-Host “MyX = $myX” –fore green
        $myX
    }
    
    $MyX=MyTest
    Write-Host “Now MyX is $myX” –fore black -back white
    
    #Or use a global:
    Function MyTest{
        $global:myX=99
        Write-Host “MyX = $myX” –fore green
    }
    
    MyTest
    Write-Host “Now MyX is $myX” –fore black -back white
    


    \_(ツ)_/

    • Marked as answer by pk_hafeez Thursday, May 21, 2015 5:38 PM
    Thursday, May 21, 2015 9:27 AM
  • Thank you. Making it global solved the purpose. :)
    Thursday, May 21, 2015 5:39 PM