Invoke Click Button at same time

Sep 3, 2013 at 10:16 PM
Hello for everyone.

I' m Searching a right mode for invoke a click event into button Get-UIAButton object, the conditions are:
  • The buttons belong to a differents Get-UIAWindow same application.
  • The invoke should be applied at the same time or almost same time.
  • Both buttons have same automation id
I have tried using different runspaces but it does not work, apparently the buttons does not receive the event.

Here is the code
Best Regards...
cls;
#Function that will be used to process runspace jobs
Function Get-RunspaceData {
  [cmdletbinding()]
  Param(
    [System.Collections.ArrayList]$runspaces,
    [switch]$Wait
  )
  Do {
    $more = $false         
    Foreach($runspace in $runspaces) {
      If ($runspace.Runspace.isCompleted) {
        $runspace.powershell.EndInvoke($runspace.Runspace)
        $runspace.powershell.dispose()
        $runspace.Runspace = $null
        $runspace.powershell = $null
        #$Script:i++                  
      } ElseIf ($runspace.Runspace -ne $null) {
        $more = $true
      }
    }
    If ($more -AND $PSBoundParameters['Wait']) {
      Start-Sleep -Milliseconds 100
    }   
    #Clean out unused runspace jobs
    $temphash = $runspaces.clone()
    $temphash | Where {
      $_.runspace -eq $Null
    } | ForEach {
      Write-Verbose ("Removing {0}" -f $_.computer)
      $Runspaces.remove($_)
    }             
  } while ($more -AND $PSBoundParameters['Wait'])
}


$ScriptBlock = 
{
Param ($WindowName)                 
    
    Start-Sleep -seconds 10   
    Write-Host "Saving Data into Window :" $WindowName
    # =============== Save Changes =================
    # Save Change
    Get-UIAWindow -name $WindowName | `
    Get-UIAButton -AutomationId 'btnSave' | `
   Invoke-UIAButtonClick;
}

Function Process-AsyncWorkload{
  [cmdletbinding()]
  Param(
    [ScriptBlock]$ScriptBlock,
    [Array]$Instances,
    [int]$Throttle = 15
  )
  Begin {
    # Define hash table for Get-RunspaceData function
    $runspacehash = @{}
    # Define async job pools
    $sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
    $runspacepool = [runspacefactory]::CreateRunspacePool(1, $Throttle, $sessionstate, $Host)
    $runspacepool.Open()  
    $runspaces = New-Object System.Collections.ArrayList        
  }
  Process {
    write-verbose "Starting async processing"
    ForEach ($Parameter in $Instances) {
      # Create the powershell instance and supply the scriptblock with the other parameters
      Try{
        $powershell = [powershell]::Create().AddScript($ScriptBlock)
        if ($Parameter -is [System.Collections.Hashtable]){
          $Parameter.Keys | foreach{
            $powershell.AddArgument($Parameter[$_]) | Out-Null
          }
        } else {
          write-verbose "Setting up async job with parameter: $Parameter"
          $powershell.AddArgument($Parameter) | Out-Null
        }
        
        # Add the runspace into the powershell instance
        $powershell.RunspacePool = $runspacepool
        # Create a temporary collection for each runspace
        $temp = "" | Select-Object PowerShell,Runspace
        $temp.PowerShell = $powershell
        
        # Save the handle output when calling BeginInvoke() that will be used later to end the runspace
        $temp.Runspace = $powershell.BeginInvoke()
        #Write-Verbose ("Adding {0} to collection" -f $temp.Computer)
        $runspaces.Add($temp) | Out-Null
      } Catch {
        Write-Warning ("{0} Error" -f $_.Exception.Message)
        Break
      }
      # Verifying async job status
      Write-Verbose ("Checking status of runspace jobs")
      Get-RunspaceData -runspaces $runspaces -Verbose
    }                        
  }
  End {                     
    Write-Verbose (
      "Finish processing the remaining runspace jobs: {0}" -f (
        @(($runspaces | Where {$_.Runspace -ne $Null}).Count)))
        
    Get-RunspaceData -runspaces $runspaces -Wait -Verbose
    Write-Verbose ("Closing the runspace pool")
    $runspacepool.close()
  }
}
 

$windowA = "*Silo*"
$windowB= "*Scale*"


#$Button2 = Get-UIAWindow -name *Scale* | `
#Get-UIAButton -AutomationId 'btnSave'

$Windows = @($windowA , $windowB)

Process-AsyncWorkload -ScriptBlock $ScriptBlock  -Instances $Windows -Verbose___
Coordinator
Sep 4, 2013 at 2:56 PM
Hi juan_ramon_m,
the first idea on how to click anything in another window was to store the button from another window in a variable:
ipmo C:\......\UIAutomation.dll
# button 1 from the first app instance
$button1inWindow1 = Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton 1;
# button 2 from the second app instance
$button2inWindow2 = Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton 2;
# you could move one of windows just now to watch both clicks
$button1inWindow1 | Invoke-UIAButtonClick; $button2inWindow2 | Invoke-UIAButtonClick;
The second example is how to click a button that is under a modal window:
# Just button 1
$button1inWindow1 = Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton 1;
# opening the About window
Get-UIAMenuItem -Name help | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name *about* | Invoke-UIAMenuItemClick;
# clicking our previously saved button 1
$button1inWindow1 | Invoke-UIAButtonClick;
Please notice that some (rare) application's windows could perform a kind of self-refresh, after which some controls could be re-painted and given a new handle.

Regarding your script (ahh, if it'd been based on something globally available like calc.exe! :)), I'd say that palying with runspaces, threads and so on may be fatal for GUI automation: it is sensitive whether it's running on a wrong thread...