├── .editorconfig ├── .gitignore ├── Add-UIHandler.ps1 ├── ReadMe.md ├── Source ├── Classes │ └── 00 - init.ps1 ├── Private │ └── Formatter.ps1 ├── Public │ ├── Get-ClickablePoint.ps1 │ ├── Remove-UIEventHandler.ps1 │ ├── Select-UIElement.ps1 │ ├── Send-UIKeys.ps1 │ ├── Set-UIFocus.ps1 │ ├── Set-UIText.ps1 │ └── Show-Window.ps1 ├── UIAutomation.Format.ps1xml ├── UIAutomation.Types.ps1xml ├── Wasp.psd1 └── lib │ ├── Interop.UIAutomationClient.dll │ ├── UIAComWrapper.dll │ └── WindowsInput.dll ├── build.ps1 ├── build.psd1 └── resources └── WASP.png /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [0-9]*/ 2 | Generated/ -------------------------------------------------------------------------------- /Add-UIHandler.ps1: -------------------------------------------------------------------------------- 1 | function Add-UIHandler { 2 | [CmdletBinding()] 3 | param( 4 | # The AutomationElement to Register the Event handler for 5 | [Parameter(Mandatory, ValueFromPipeline, Position = 0)] 6 | [Alias('Element', 'AutomationElement')] 7 | [AutomationElement]$InputObject, 8 | 9 | [ValidateSet('DragStart','DragCancel','DragComplete','DropTargetEnter','DropTargetLeave','Dropped','Invoked','InputReachedTarget','InputReachedOtherElement','InputDiscarded','TextChanged','TextSelectionChanged','Invalidated','ElementAddedToSelection','ElementRemovedFromSelection','ElementSelected','WindowClosed','WindowOpened')] 10 | [string]$Event, 11 | 12 | [Parameter(Mandatory, Position = 1)] 13 | [AutomationEventHandler]$Handler, 14 | 15 | [TreeScope]$Scope = "Element" 16 | ) 17 | 18 | $EventId = $UIAEvents.Where{ $_.ProgrammaticName -match $Event } 19 | 20 | [Automation]::AddAutomationEventHandler($EventId, $InputObject, $Scope, $Handler) 21 | } -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # The Original UI Automation Module for PowerShell 2 | 3 | ![The WASP Logo](resources/WASP.png) 4 | 5 | WASP is a wrapper over the [Windows Automation API](https://docs.microsoft.com/en-us/windows/win32/winauto/windows-automation-api-overview) which is part of Windows' modern Accessibility features. 6 | This version is an update of my WASP module to use Microsoft's UI Automation 3.0 via the [TestStack/UIAComWrapper](https://github.com/TestStack/UIAComWrapper). Most of the PowerShell code is generated at build time -- but some parts (particularly the two "Input" commands, and Select-UIElement) are hand-crafted. 7 | 8 | The resulting module loads faster, and has more capabilities than the old WASP 2.x, but you've found it when it's quite not ready yet. 9 | 10 | The parts that _are_ here do all seem to work, but please feel free to play around with the code generation and let me know if anything seems to be missing or broken. I always welcome suggestions or requests, and I'm happy to have additional contributors. 11 | 12 | ## To build 13 | 14 | You need [ModuleBuilder](/PoshCode/ModuleBuilder), but you have to run `build.ps1` to generate the code (you'll see a bunch of files show up in Public\Generated), and then it will run `Build-Module` for you. Once you've generated the ps1 files once, you can work from that if you want. -------------------------------------------------------------------------------- /Source/Classes/00 - init.ps1: -------------------------------------------------------------------------------- 1 | using namespace System.Windows.Automation 2 | using namespace System.Windows.Automation.Text 3 | 4 | $patterns = Get-Type -Assembly UIAComWrapper -Base System.Windows.Automation.BasePattern 5 | 6 | Add-Type -ReferencedAssemblies UIAComWrapper, System.Text.RegularExpressions, System.Management.Automation, mscorlib -TypeDefinition @" 7 | using System; 8 | using System.ComponentModel; 9 | using System.Management.Automation; 10 | using System.Reflection; 11 | using System.Text.RegularExpressions; 12 | using System.Windows.Automation; 13 | using System.Runtime.InteropServices; 14 | 15 | 16 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 17 | public class StaticFieldAttribute : ArgumentTransformationAttribute { 18 | private Type _class; 19 | 20 | public override string ToString() { 21 | return string.Format("[StaticField(OfClass='{0}')]", OfClass.FullName); 22 | } 23 | 24 | public override Object Transform( EngineIntrinsics engineIntrinsics, Object inputData) { 25 | if(inputData is string && !string.IsNullOrEmpty(inputData as string)) { 26 | System.Reflection.FieldInfo field = _class.GetField(inputData as string, BindingFlags.Static | BindingFlags.Public); 27 | if(field != null) { 28 | return field.GetValue(null); 29 | } 30 | } 31 | return inputData; 32 | } 33 | 34 | public StaticFieldAttribute( Type ofClass ) { 35 | OfClass = ofClass; 36 | } 37 | 38 | public Type OfClass { 39 | get { return _class; } 40 | set { _class = value; } 41 | } 42 | } 43 | 44 | public static class UIAutomationHelper { 45 | 46 | [DllImport ("user32.dll", CharSet = CharSet.Auto)] 47 | static extern IntPtr FindWindow (string lpClassName, string lpWindowName); 48 | 49 | [DllImport ("user32.dll", CharSet = CharSet.Auto)] 50 | static extern bool AttachThreadInput (int idAttach, int idAttachTo, bool fAttach); 51 | 52 | [DllImport ("user32.dll", CharSet = CharSet.Auto)] 53 | static extern int GetWindowThreadProcessId (IntPtr hWnd, IntPtr lpdwProcessId); 54 | 55 | [DllImport ("user32.dll", CharSet = CharSet.Auto)] 56 | static extern IntPtr SetForegroundWindow (IntPtr hWnd); 57 | 58 | public static AutomationElement RootElement { 59 | get { return AutomationElement.RootElement; } 60 | } 61 | 62 | 63 | ///Using Win32 to set foreground window because AutomationElement.SetFocus() is unreliable 64 | public static bool SetForeground(this AutomationElement element) 65 | { 66 | if(element == null) { 67 | throw new ArgumentNullException("element"); 68 | } 69 | 70 | // Get handle to the element 71 | IntPtr other = FindWindow (null, element.Current.Name); 72 | 73 | // // Get the Process ID for the element we are trying to 74 | // // set as the foreground element 75 | // int other_id = GetWindowThreadProcessId (other, IntPtr.Zero); 76 | // 77 | // // Get the Process ID for the current process 78 | // int this_id = GetWindowThreadProcessId (Process.GetCurrentProcess().Handle, IntPtr.Zero); 79 | // 80 | // // Attach the current process's input to that of the 81 | // // given element. We have to do this otherwise the 82 | // // WM_SETFOCUS message will be ignored by the element. 83 | // bool success = AttachThreadInput(this_id, other_id, true); 84 | 85 | // Make the Win32 call 86 | IntPtr previous = SetForegroundWindow(other); 87 | 88 | return !IntPtr.Zero.Equals(previous); 89 | } 90 | } 91 | "@ -------------------------------------------------------------------------------- /Source/Private/Formatter.ps1: -------------------------------------------------------------------------------- 1 | function formatter { 2 | end { 3 | $input | Format-Table @{l = "Text"; e = { $_.Text.SubString(0, 25) } }, ClassName, FrameworkId -Auto 4 | } 5 | } -------------------------------------------------------------------------------- /Source/Public/Get-ClickablePoint.ps1: -------------------------------------------------------------------------------- 1 | function Get-ClickablePoint { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(ValueFromPipeline = $true)] 5 | [Alias("Parent", "Element", "Root")] 6 | [AutomationElement]$InputObject 7 | ) 8 | process { 9 | $InputObject.GetClickablePoint() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Source/Public/Remove-UIEventHandler.ps1: -------------------------------------------------------------------------------- 1 | function Remove-UIEventHandler { 2 | [CmdletBinding()] 3 | param() 4 | 5 | [Automation]::RemoveAllEventHandlers() 6 | } -------------------------------------------------------------------------------- /Source/Public/Select-UIElement.ps1: -------------------------------------------------------------------------------- 1 | function Select-UIElement { 2 | [CmdletBinding(DefaultParameterSetName = "FromParent")] 3 | param( 4 | [Parameter(ParameterSetName = "FromWindowHandle", Position = "0", Mandatory = $true)] 5 | [Alias("MainWindowHandle", "hWnd", "Handle", "Wh")] 6 | [IntPtr[]]$WindowHandle = [IntPtr]::Zero, 7 | 8 | [Parameter(ParameterSetName = "FromPoint", Position = "0", Mandatory = $true)] 9 | [System.Windows.Point[]]$Point, 10 | 11 | [Parameter(ParameterSetName = "FromParent", ValueFromPipeline = $true, Position = 100)] 12 | [System.Windows.Automation.AutomationElement]$Parent = [UIAutomationHelper]::RootElement, 13 | 14 | [Parameter(ParameterSetName = "FromParent", Position = "0")] 15 | [Alias("WindowName")] 16 | [String[]]$Name, 17 | 18 | [Parameter(ParameterSetName = "FromParent", Position = "1")] 19 | [Alias("Type", "Ct")] 20 | [ArgumentCompleter({ 21 | param($command, $param, $word, $ast) 22 | $Word = "$Word".Trim('"'' ') 23 | [System.Windows.Automation.ControlType].GetFields( 'Static,Public' ).Where({$_.Name -like "${Word}*"}).ForEach({ 24 | try { 25 | $Value = $_.GetValue($null) 26 | $Tooltip = $Value.ProgrammaticName + $(if ($Value.LocalizedControlType) { " ($($Value.LocalizedControlType))" }) 27 | } finally { 28 | # The actual things we output are always CompletionResults: 29 | [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, 'ParameterValue', $Tooltip) 30 | } 31 | }) 32 | })] 33 | [System.Windows.Automation.ControlType] 34 | [StaticField(([System.Windows.Automation.ControlType]))]$ControlType, 35 | 36 | [Parameter(ParameterSetName = "FromParent")] 37 | [Alias("UId")] 38 | [String[]]$AutomationId, 39 | 40 | ## Removed "Id" alias to allow get-process | Select-Window pipeline to find just MainWindowHandle 41 | [Parameter(ParameterSetName = "FromParent", ValueFromPipelineByPropertyName = $true )] 42 | [Alias("Id")] 43 | [Int[]]$PID, 44 | 45 | [Parameter(ParameterSetName = "FromParent")] 46 | [Alias("Pn")] 47 | [String[]]$ProcessName, 48 | 49 | [Parameter(ParameterSetName = "FromParent")] 50 | [Alias("Cn")] 51 | [String[]]$ClassName, 52 | 53 | [switch]$Recurse, 54 | 55 | [switch]$Bare, 56 | 57 | # An easy way to return just the first element, because that's usually all we want 58 | [switch]$First, 59 | 60 | [Parameter(ParameterSetName = "FromParent")] 61 | #[Alias("Pv")] 62 | [Hashtable]$PropertyValue 63 | 64 | ) 65 | process { 66 | 67 | Write-Debug "Parameters Found" 68 | Write-Debug ($PSBoundParameters | Format-Table | Out-String) 69 | 70 | $search = "Children" 71 | if ($Recurse) { 72 | $search = "Descendants" 73 | } 74 | 75 | $condition = [System.Windows.Automation.Condition]::TrueCondition 76 | 77 | Write-Verbose $PSCmdlet.ParameterSetName 78 | switch -regex ($PSCmdlet.ParameterSetName) { 79 | "FromWindowHandle" { 80 | Write-Verbose "Finding from Window Handle $HWnd" 81 | $Element = $( 82 | foreach ($hWnd in $WindowHandle) { 83 | [System.Windows.Automation.AutomationElement]::FromHandle( $hWnd ) 84 | } 85 | ) 86 | continue 87 | } 88 | "FromPoint" { 89 | Write-Verbose "Finding from Point $Point" 90 | $Element = $( 91 | foreach ($pt in $Point) { 92 | [System.Windows.Automation.AutomationElement]::FromPoint( $pt ) 93 | } 94 | ) 95 | continue 96 | } 97 | "FromParent" { 98 | Write-Verbose "Finding from Parent!" 99 | ## [System.Windows.Automation.Condition[]]$conditions = [System.Windows.Automation.Condition]::TrueCondition 100 | [ScriptBlock[]]$filters = @() 101 | if ($AutomationId) { 102 | [System.Windows.Automation.Condition[]]$current = $( 103 | foreach ($aid in $AutomationId) { 104 | New-Object System.Windows.Automation.PropertyCondition ([System.Windows.Automation.AutomationElement]::AutomationIdProperty), $aid 105 | } 106 | ) 107 | if ($current.Length -gt 1) { 108 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 109 | } elseif ($current.Length -eq 1) { 110 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 111 | } 112 | } 113 | if ($PID) { 114 | [System.Windows.Automation.Condition[]]$current = $( 115 | foreach ($p in $PID) { 116 | New-Object System.Windows.Automation.PropertyCondition ([System.Windows.Automation.AutomationElement]::ProcessIdProperty), $p 117 | } 118 | ) 119 | if ($current.Length -gt 1) { 120 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 121 | } elseif ($current.Length -eq 1) { 122 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 123 | } 124 | } 125 | if ($ProcessName) { 126 | if ($ProcessName -match "\?|\*|\[") { 127 | [ScriptBlock[]]$filters += { $(foreach ($p in $ProcessName) { 128 | (Get-Process -Id $_.GetCurrentPropertyValue([System.Windows.Automation.AutomationElement]::ProcessIdProperty)).ProcessName -like $p 129 | }) -contains $true } 130 | } else { 131 | [System.Windows.Automation.Condition[]]$current = $( 132 | foreach ($p in Get-Process -Name $ProcessName) { 133 | New-Object System.Windows.Automation.PropertyCondition ([System.Windows.Automation.AutomationElement]::ProcessIdProperty), $p.id 134 | } 135 | ) 136 | if ($current.Length -gt 1) { 137 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 138 | } elseif ($current.Length -eq 1) { 139 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 140 | } 141 | } 142 | } 143 | if ($Name) { 144 | Write-Verbose "Name: $Name" 145 | if ($Name -match "\?|\*|\[") { 146 | [ScriptBlock[]]$filters += { $(foreach ($n in $Name) { 147 | $_.GetCurrentPropertyValue([System.Windows.Automation.AutomationElement]::NameProperty) -like $n 148 | }) -contains $true } 149 | } else { 150 | [System.Windows.Automation.Condition[]]$current = $( 151 | foreach ($n in $Name) { 152 | New-Object System.Windows.Automation.PropertyCondition ([System.Windows.Automation.AutomationElement]::NameProperty), $n, "IgnoreCase" 153 | } 154 | ) 155 | if ($current.Length -gt 1) { 156 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 157 | } elseif ($current.Length -eq 1) { 158 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 159 | } 160 | } 161 | } 162 | if ($ClassName) { 163 | if ($ClassName -match "\?|\*|\[") { 164 | [ScriptBlock[]]$filters += { $(foreach ($c in $ClassName) { 165 | $_.GetCurrentPropertyValue([System.Windows.Automation.AutomationElement]::ClassNameProperty) -like $c 166 | }) -contains $true } 167 | } else { 168 | [System.Windows.Automation.Condition[]]$current = $( 169 | foreach ($c in $ClassName) { 170 | New-Object System.Windows.Automation.PropertyCondition ([System.Windows.Automation.AutomationElement]::ClassNameProperty), $c, "IgnoreCase" 171 | } 172 | ) 173 | if ($current.Length -gt 1) { 174 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 175 | } elseif ($current.Length -eq 1) { 176 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 177 | } 178 | } 179 | } 180 | if ($ControlType) { 181 | if ($ControlType -match "\?|\*|\[") { 182 | [ScriptBlock[]]$filters += { $(foreach ($c in $ControlType) { 183 | $_.GetCurrentPropertyValue([System.Windows.Automation.AutomationElement]::ControlTypeProperty) -like $c 184 | }) -contains $true } 185 | } else { 186 | [System.Windows.Automation.Condition[]]$current = $( 187 | foreach ($c in $ControlType) { 188 | New-Object System.Windows.Automation.PropertyCondition ([System.Windows.Automation.AutomationElement]::ControlTypeProperty), $c 189 | } 190 | ) 191 | if ($current.Length -gt 1) { 192 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 193 | } elseif ($current.Length -eq 1) { 194 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 195 | } 196 | } 197 | } 198 | if ($PropertyValue) { 199 | $Property = $PropertyValue.Keys[0] 200 | $Value = $PropertyValue.Values[0] 201 | if ($Value -match "\?|\*|\[") { 202 | [ScriptBlock[]]$filters += { $(foreach ($c in $PropertyValue.GetEnumerator()) { 203 | $_.GetCurrentPropertyValue( 204 | [System.Windows.Automation.AutomationElement].GetField( 205 | $c.Key).GetValue(([system.windows.automation.automationelement])) 206 | ) -like $c.Value 207 | }) -contains $true } 208 | } else { 209 | [System.Windows.Automation.Condition[]]$current = $( 210 | foreach ($c in $PropertyValue.GetEnumerator()) { 211 | New-Object System.Windows.Automation.PropertyCondition ( 212 | [System.Windows.Automation.AutomationElement].GetField( 213 | $c.Key).GetValue(([system.windows.automation.automationelement]))), $c.Value 214 | } 215 | ) 216 | if ($current.Length -gt 1) { 217 | [System.Windows.Automation.Condition[]]$conditions += New-Object System.Windows.Automation.OrCondition $current 218 | } elseif ($current.Length -eq 1) { 219 | [System.Windows.Automation.Condition[]]$conditions += $current[0] 220 | } 221 | } 222 | } 223 | 224 | if ($conditions.Length -gt 1) { 225 | [System.Windows.Automation.Condition]$condition = New-Object System.Windows.Automation.AndCondition $conditions 226 | } elseif ($conditions) { 227 | [System.Windows.Automation.Condition]$condition = $conditions[0] 228 | } else { 229 | [System.Windows.Automation.Condition]$condition = [System.Windows.Automation.Condition]::TrueCondition 230 | } 231 | 232 | If ($VerbosePreference -gt "SilentlyContinue") { 233 | 234 | function Write-Condition { 235 | param([Parameter(ValueFromPipeline = $true)]$condition, $indent = 0) 236 | process { 237 | Write-Debug ($Condition | fl * | Out-String) 238 | if ($condition -is [System.Windows.Automation.AndCondition] -or $condition -is [System.Windows.Automation.OrCondition]) { 239 | Write-Verbose ((" " * $indent) + $Condition.GetType().Name ) 240 | $condition.GetConditions().GetEnumerator() | Write-Condition -Indent ($Indent + 4) 241 | } elseif ($condition -is [System.Windows.Automation.PropertyCondition]) { 242 | Write-Verbose ((" " * $indent) + $Condition.Property.ProgrammaticName + " = '" + $Condition.Value + "' (" + $Condition.Flags + ")") 243 | } else { 244 | Write-Verbose ((" " * $indent) + $Condition.GetType().Name + " where '" + $Condition.Value + "' (" + $Condition.Flags + ")") 245 | } 246 | } 247 | } 248 | 249 | Write-Verbose "CONDITIONS =============" 250 | $global:LastCondition = $condition 251 | foreach ($c in $condition) { 252 | Write-Condition $c 253 | } 254 | Write-Verbose "============= CONDITIONS" 255 | } 256 | 257 | if ($First -and $filters.Count -eq 0) { 258 | $Element = $Parent.FindFirst( $search, $condition ) 259 | } elseif ($filters.Count -gt 0) { 260 | $Element = $Parent.FindAll( $search, $condition ).Where{ 261 | $item = $_ 262 | foreach ($f in $filters) { 263 | $item = $item | Where-Object $f 264 | } 265 | $item 266 | } 267 | } else { 268 | $Element = $Parent.FindAll( $search, $condition ) 269 | } 270 | } 271 | } 272 | 273 | Write-Verbose "Element Count: $(@($Element).Count)" 274 | if ($Element) { 275 | if ($First) { 276 | $Element = @($Element)[0] 277 | } 278 | 279 | foreach ($el in $Element) { 280 | if ($Bare) { 281 | Write-Output $el 282 | } else { 283 | $e = New-Object PSObject $el 284 | foreach ($prop in $e.GetSupportedProperties() | Sort-Object ProgrammaticName) { 285 | ## TODO: make sure all these show up: [System.Windows.Automation.AutomationElement] | gm -sta -type Property 286 | $propName = [System.Windows.Automation.Automation]::PropertyName($prop) 287 | Add-Member -InputObject $e -Type ScriptProperty -Name $propName -Value ([ScriptBlock]::Create( "`$this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationProperty]::LookupById( $($prop.Id) ))" )) -EA 0 288 | } 289 | foreach ($patt in $e.GetSupportedPatterns() | Sort-Object ProgrammaticName) { 290 | Add-Member -InputObject $e -Type ScriptProperty -Name ($patt.ProgrammaticName.Replace("PatternIdentifiers.Pattern", "") + "Pattern") -Value ([ScriptBlock]::Create( "`$this.GetCurrentPattern( [System.Windows.Automation.AutomationPattern]::LookupById( '$($patt.Id)' ) )" )) -EA 0 291 | } 292 | Write-Output $e 293 | } 294 | } 295 | } 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /Source/Public/Send-UIKeys.ps1: -------------------------------------------------------------------------------- 1 | function Send-UIKeys { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(Position = 0)] 5 | [string]$Keys, 6 | 7 | [Parameter(ValueFromPipeline = $true)] 8 | [Alias("Parent", "Element", "Root")] 9 | [AutomationElement]$InputObject, 10 | 11 | [Parameter()] 12 | [Switch]$Passthru, 13 | 14 | [Parameter()] 15 | [Switch]$Async 16 | ) 17 | process { 18 | if (!$InputObject.Current.IsEnabled) { 19 | Write-Warning "The Control is not enabled!" 20 | } 21 | if (!$InputObject.Current.IsKeyboardFocusable) { 22 | Write-Warning "The Control is not focusable!" 23 | } 24 | Set-UIFocus $InputObject 25 | 26 | if ($Async) { 27 | [SendKeys]::Send( $Keys ) 28 | } else { 29 | [SendKeys]::SendWait( $Keys ) 30 | } 31 | 32 | if ($passthru) { 33 | $InputObject 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/Public/Set-UIFocus.ps1: -------------------------------------------------------------------------------- 1 | function Set-UIFocus { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(ValueFromPipeline = $true)] 5 | [Alias("Parent", "Element", "Root")] 6 | [AutomationElement]$InputObject, 7 | 8 | [Parameter()] 9 | [Switch]$Passthru 10 | ) 11 | process { 12 | try { 13 | [UIAutomationHelper]::SetForeground( $InputObject ) 14 | $InputObject.SetFocus() 15 | } catch { 16 | Write-Verbose "SetFocus fail, trying SetForeground" 17 | } 18 | if ($passthru) { 19 | $InputObject 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Source/Public/Set-UIText.ps1: -------------------------------------------------------------------------------- 1 | using namespace System.Windows.Forms 2 | function Set-UIText { 3 | [CmdletBinding()] 4 | param( 5 | [Parameter(Position = 0)] 6 | [string]$Text, 7 | 8 | [Parameter(ValueFromPipeline = $true)] 9 | [Alias("Parent", "Element", "Root")] 10 | [AutomationElement]$InputObject, 11 | 12 | [Parameter()] 13 | [Switch]$Passthru 14 | ) 15 | process { 16 | if (!$InputObject.Current.IsEnabled) { 17 | Write-Warning "The Control is not enabled!" 18 | } 19 | if (!$InputObject.Current.IsKeyboardFocusable) { 20 | Write-Warning "The Control is not focusable!" 21 | } 22 | 23 | $valuePattern = $null 24 | if ($InputObject.TryGetCurrentPattern([ValuePattern]::Pattern, [ref]$valuePattern)) { 25 | Write-Verbose "Set via ValuePattern!" 26 | $valuePattern.SetValue( $Text ) 27 | } elseif ($InputObject.Current.IsKeyboardFocusable) { 28 | Set-UIFocus $InputObject 29 | [SendKeys]::SendWait("^{HOME}"); 30 | [SendKeys]::SendWait("^+{END}"); 31 | [SendKeys]::SendWait("{DEL}"); 32 | [SendKeys]::SendWait( $Text ) 33 | } 34 | if ($passthru) { 35 | $InputObject 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/Public/Show-Window.ps1: -------------------------------------------------------------------------------- 1 | function Show-Window { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(ValueFromPipeline = $true)] 5 | [Alias("Parent", "Element", "Root")] 6 | [AutomationElement]$InputObject, 7 | 8 | [Parameter()] 9 | [Switch]$Passthru 10 | ) 11 | process { 12 | Set-UIFocus $InputObject 13 | if ($passthru) { 14 | $InputObject 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Source/UIAutomation.Format.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AutomationElement 6 | 7 | System.Windows.Automation.AutomationElement 8 | 9 | 10 | 11 | 12 | 11 13 | 14 | Left 15 | 16 | 17 | 9 18 | Left 19 | 20 | 21 | 12 22 | Left 23 | 24 | 25 | 20 26 | Left 27 | 28 | 29 | 18 30 | Left 31 | 32 | 33 | Left 34 | 35 | 36 | 37 | 38 | 39 | 40 | ControlTypeName 41 | 42 | 43 | Framework 44 | 45 | 46 | AutomationId 47 | 48 | 49 | ClassName 50 | 51 | 52 | SupportedPatterns 53 | 54 | 55 | Name 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Source/UIAutomation.Types.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | System.Windows.Automation.AutomationElement 5 | 6 | 7 | ControlType 8 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::ControlTypeProperty) 9 | 10 | 11 | ControlTypeLocalized 12 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::ControlTypeProperty).LocalizedControlType 13 | 14 | 15 | ControlTypeName 16 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::ControlTypeProperty).ProgrammaticName.Split(".")[-1] 17 | 18 | 19 | Framework 20 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::FrameworkIdProperty) 21 | 22 | 23 | Name 24 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::NameProperty) 25 | 26 | 27 | ClassName 28 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::ClassNameProperty) 29 | 30 | 31 | IsContentElement 32 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::IsContentElementProperty ) 33 | 34 | 35 | IsKeyboardFocusable 36 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::IsKeyboardFocusableProperty ) 37 | 38 | 39 | HasKeyboardFocus 40 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::HasKeyboardFocusProperty ) 41 | 42 | 43 | AutomationId 44 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::AutomationIdProperty ) 45 | 46 | 47 | NativeWindowHandle 48 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::NativeWindowHandleProperty ) 49 | 50 | 51 | RuntimeId 52 | $this.GetCurrentPropertyValue( [System.Windows.Automation.AutomationElement]::RuntimeIdProperty ) 53 | 54 | 55 | SupportedPatterns 56 | $this.GetSupportedPatterns() | % { $_.ProgrammaticName -replace 'PatternIdentifiers.Pattern(.*)','$1'} 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /Source/Wasp.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'Wasp' 3 | # 4 | # Generated by: Joel Bennett 5 | # 6 | # Generated on: 3/24/2014 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'Wasp.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '3.0.0' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '4f6fd93e-42b7-4548-b522-3ad6759aa62a' 19 | 20 | # Author of this module 21 | Author = 'Joel Bennett' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'PoshCode.org' 25 | 26 | # Copyright statement for this module 27 | Copyright = 'Copyright (c) 2008-2020, Joel Bennett, released under the Ms-PL' 28 | 29 | # Description of the functionality provided by this module 30 | Description = 'A Windows Automation Script module for Powershell' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | PowerShellVersion = '5.0' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | CLRVersion = '4.0' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | ProcessorArchitecture = 'None' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | RequiredAssemblies = @( 55 | '.\lib\Interop.UIAutomationClient.dll', 56 | '.\lib\UIAComWrapper.dll', 57 | '.\lib\WindowsInput.dll' 58 | ) 59 | 60 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 61 | # ScriptsToProcess = @() 62 | 63 | # Type files (.ps1xml) to be loaded when importing this module 64 | TypesToProcess = @('UIAutomation.Types.ps1xml') 65 | 66 | # Format files (.ps1xml) to be loaded when importing this module 67 | FormatsToProcess = @('UIAutomation.Format.ps1xml') 68 | 69 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 70 | NestedModules = @('lib\WindowsInput.dll') 71 | 72 | # Functions to export from this module 73 | FunctionsToExport = @('*') 74 | 75 | # Cmdlets to export from this module 76 | CmdletsToExport = @('Add-Input', 'Send-Input') 77 | 78 | # Variables to export from this module 79 | VariablesToExport = @() 80 | 81 | # Aliases to export from this module 82 | AliasesToExport = @() 83 | 84 | # List of all modules packaged with this module 85 | # ModuleList = @() 86 | 87 | # List of all files packaged with this module 88 | # FileList = @() 89 | 90 | # Private data to pass to the module specified in RootModule/ModuleToProcess 91 | PrivateData = @{ 92 | PSData = @{ 93 | ReleaseNotes = ' 94 | ' 95 | Prerelease = '' 96 | } 97 | } 98 | 99 | # HelpInfo URI of this module 100 | # HelpInfoURI = '' 101 | 102 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 103 | # DefaultCommandPrefix = '' 104 | 105 | } 106 | 107 | -------------------------------------------------------------------------------- /Source/lib/Interop.UIAutomationClient.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/WASP/aaf14d3077d705398f88b16bc8ccf6a7d6b49c08/Source/lib/Interop.UIAutomationClient.dll -------------------------------------------------------------------------------- /Source/lib/UIAComWrapper.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/WASP/aaf14d3077d705398f88b16bc8ccf6a7d6b49c08/Source/lib/UIAComWrapper.dll -------------------------------------------------------------------------------- /Source/lib/WindowsInput.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/WASP/aaf14d3077d705398f88b16bc8ccf6a7d6b49c08/Source/lib/WindowsInput.dll -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | #requires -Module @{ ModuleName = "ModuleBuilder"; ModuleVersion = "2.0" } 2 | using namespace System.Windows.Automation 3 | using namespace System.Windows.Automation.Text 4 | [CmdletBinding()] 5 | param() 6 | $ErrorActionPreference = "STOP" 7 | # WASP 3.0 is based on UIAutomation 3 using UIAComWrapper https://github.com/TestStack/UIAComWrapper 8 | Add-Type -Path $PSScriptRoot\Source\lib\*.dll 9 | # -- a lot of commands have weird names because they're being generated based on pattern names 10 | # -- eg: Invoke-Toggle.Toggle and Invoke-Invoke.Invoke 11 | 12 | New-Item -Type Directory $PSScriptRoot\Source\Public\Generated -Force -ErrorAction Stop 13 | New-Item -Type Directory $PSScriptRoot\Source\Private\Generated -Force -ErrorAction Stop 14 | Push-Location $PSScriptRoot\Source\Public\Generated -ErrorAction Stop 15 | Remove-Item *.ps1 16 | 17 | $patterns = Get-Type -Assembly UIAComWrapper -Base System.Windows.Automation.BasePattern 18 | 19 | ## TODO: Write Get-SupportedPatterns or rather ... 20 | ## Get-SupportedFunctions (to return the names of the functions for the supported patterns) 21 | ## TODO: Support all the "Properties" too 22 | ## TODO: Figure out why Notepad doesn't support SetValue 23 | ## TODO: Figure out where the menus support went 24 | foreach ($pattern in $patterns) { 25 | $PatternName = $Pattern.Name -Replace "Pattern", "." 26 | Write-Information "Generating $PatternName" 27 | 28 | $PatternFullName = $pattern.FullName 29 | $newline = "`n " 30 | $FunctionName = "ConvertTo-$($Pattern.Name)" 31 | Write-Information " $FunctionName" 32 | New-Item -Type File -Name "$FunctionName.ps1" -Value @" 33 | function $FunctionName { 34 | [CmdletBinding()] 35 | param( 36 | # The AutomationElement to convert 37 | [Parameter(Mandatory, ValueFromPipeline)] 38 | [Alias('Element','AutomationElement')] 39 | [AutomationElement]`$InputObject 40 | ) 41 | process { 42 | trap { 43 | if(`$_.Exception.Message -like '*Unsupported Pattern.*') { 44 | Write-Error "Cannot get ``"$($Pattern.Name)``" from that AutomationElement, `$(`$_)` You should try one of: `$(`$InputObject.GetSupportedPatterns()|%{``"'``" + (`$_.ProgrammaticName.Replace(``"PatternIdentifiers.Pattern``",``"``")) + ``"Pattern'``"})"; continue; 45 | } 46 | } 47 | Write-Output `$InputObject.GetCurrentPattern([$PatternFullName]::Pattern).Current 48 | } 49 | } 50 | "@ 51 | 52 | 53 | # $pattern.GetFields().Where{ $_.FieldType -eq [AutomationEvent] }.ForEach{ 54 | # $FunctionName = "Add-$($_.Name -replace "Event$")Handler" 55 | # New-Item -Type File -Name "$FunctionName.ps1" -Value @" 56 | # function $FunctionName { 57 | # [CmdletBinding()] 58 | # param( 59 | # # The AutomationElement to Register the Event handler for 60 | # [Parameter(Mandatory, ValueFromPipeline)] 61 | # [Alias('Element','AutomationElement')] 62 | # [AutomationElement]`$InputObject, 63 | # 64 | # [AutomationEventHandler]`$Handler, 65 | # 66 | # [TreeScope]`$Scope = "Element" 67 | # ) 68 | # 69 | # [Automation]::AddAutomationEventHandler(([$($pattern.FullName)]::$($_.Name)), `$InputObject, `$Scope, `$Handler) 70 | # } 71 | # "@ 72 | 73 | # $FunctionName = "Remove-$($_.Name -replace "Event$")Handler" 74 | # New-Item -Type File -Name "$FunctionName.ps1" -Value @" 75 | # function $FunctionName { 76 | # [CmdletBinding()] 77 | # param( 78 | # # The AutomationElement to Register the Event handler for 79 | # [Parameter(Mandatory, ValueFromPipeline)] 80 | # [Alias('Element','AutomationElement')] 81 | # [AutomationElement]`$InputObject, 82 | 83 | # [AutomationEventHandler]`$Handler 84 | # ) 85 | 86 | # [Automation]::RemoveAutomationEventHandler(([$($pattern.FullName)]::$($_.Name)), `$InputObject, `$Handler) 87 | # } 88 | # "@ 89 | 90 | # } 91 | 92 | 93 | Write-Information " Generating Property Functions" 94 | $pattern.GetProperties().Where{ $_.DeclaringType -eq $_.ReflectedType -and $_.Name -notmatch "Cached|Current" }.ForEach{ 95 | $FunctionName = "Get-$PatternName$($_.Name)".Trim('.') 96 | Write-Information " $FunctionName" 97 | 98 | New-Item -Type File "$FunctionName.ps1" -Value @" 99 | function $FunctionName { 100 | [CmdletBinding()] 101 | param( 102 | [Parameter(ValueFromPipeline)] 103 | [AutomationElement]`$AutomationElement 104 | ) 105 | process { 106 | trap { Write-Warning "$PatternFullName `$_"; continue } 107 | `$pattern = `$AutomationElement.GetCurrentPattern([$PatternFullName]::Pattern) 108 | if(`$pattern) { 109 | `$pattern.'$($_.Name)' 110 | } 111 | } 112 | } 113 | "@ 114 | } 115 | 116 | Write-Information " Generating Field Functions" 117 | ## So far this seems to be restricted to Text (DocumentRange) elements 118 | $pattern.GetFields().Where{ $_.FieldType.Name -like "*TextAttribute" }.ForEach{ 119 | $FunctionName = "Get-Text$($_.Name -replace 'Attribute')" 120 | Write-Information " $FunctionName" 121 | New-Item -Type File "$FunctionName.ps1" -Value @" 122 | function $FunctionName { 123 | [CmdletBinding()] 124 | param( 125 | [Parameter(ValueFromPipeline)] 126 | [AutomationElement]`$AutomationElement 127 | ) 128 | process { 129 | trap { Write-Warning "$PatternFullName `$_"; continue } 130 | `$AutomationElement.GetAttributeValue([$PatternFullName]::$($_.Name)) 131 | } 132 | } 133 | "@ 134 | } 135 | 136 | Write-Information " Generating Method Functions" 137 | 138 | $pattern.GetMethods().Where{ $_.DeclaringType -eq $_.ReflectedType -and !$_.IsSpecialName }.ForEach{ 139 | $Position = 1 140 | $FunctionName = "Invoke-$PatternName$($_.Name)" 141 | Write-Information " $FunctionName" 142 | 143 | $Parameters = @("$newline[Parameter(ValueFromPipeline)]" + 144 | "$newline[Alias('Parent', 'Element', 'Root', 'AutomationElement')]" + 145 | "$newline[AutomationElement]`$InputObject" 146 | ) + 147 | @( 148 | "[Parameter()]$newline[Switch]`$Passthru" 149 | ) + 150 | @($_.GetParameters().ForEach{ "[Parameter(Position=$($Position; $Position++))]$newline[$($_.ParameterType.FullName)]`$$($_.Name)" }) 151 | $Parameters = $Parameters -Join ",$newline" 152 | $ParameterValues = '$' + ($_.GetParameters().Name -Join ', $') 153 | New-Item -Type File "$FunctionName.ps1" -Value @" 154 | function $FunctionName { 155 | [CmdletBinding()] 156 | param( 157 | $Parameters 158 | ) 159 | process { 160 | ## trap { Write-Warning "`$(`$_)"; break } 161 | `$pattern = `$InputObject.GetCurrentPattern([$PatternFullName]::Pattern) 162 | if(`$pattern) { 163 | `$Pattern.$($_.Name)($(if($ParameterValues.Length -gt 1){ $ParameterValues })) 164 | } 165 | if(`$passthru) { 166 | `$InputObject 167 | } 168 | } 169 | } 170 | "@ 171 | 172 | trap { 173 | Write-Warning $_ 174 | Write-Host $definition -fore cyan 175 | } 176 | } 177 | } 178 | 179 | $Event = $patterns.ForEach{ 180 | $Pattern = $_.FullName -replace "System\.Windows\.Automation\." 181 | $_.GetFields().Where{ $_.FieldType -eq [AutomationEvent] }.ForEach{ 182 | # $Event = $_.Name -replace "Event$" 183 | # $EventId = "[$Name]::$($_.Name)" 184 | "[$Pattern]::$($_.Name)" 185 | } 186 | } 187 | 188 | Write-Information " Generating Variable File" 189 | New-Item -Type File "$PSScriptRoot\Source\Private\Generated\01 - Variables.ps1" -Value @" 190 | `$UIAEvents = @( 191 | $($Event -join "`n ") 192 | ) 193 | "@ 194 | 195 | Write-Information " Generating Add-UIHandler File" 196 | New-Item -Type File "Add-UIHandler.ps1" -Value @" 197 | function Add-UIHandler { 198 | [CmdletBinding()] 199 | param( 200 | # The AutomationElement to Register the Event handler for 201 | [Parameter(Mandatory, ValueFromPipeline, Position = 0)] 202 | [Alias('Element', 'AutomationElement')] 203 | [AutomationElement]`$InputObject, 204 | 205 | [ValidateSet('$($Event -replace "^.*::(.*)Event", '$1' -join "','")')] 206 | [string]`$Event, 207 | 208 | [Parameter(Mandatory, Position = 1)] 209 | [AutomationEventHandler]`$Handler, 210 | 211 | [TreeScope]`$Scope = "Element" 212 | ) 213 | 214 | `$EventId = `$UIAEvents.Where{ `$_.ProgrammaticName -match `$Event }[0] 215 | 216 | [Automation]::AddAutomationEventHandler(`$EventId, `$InputObject, `$Scope, `$Handler) 217 | } 218 | "@ 219 | 220 | 221 | Write-Information " Generating Remove-UIHandler File" 222 | New-Item -Type File "Remove-UIHandler.ps1" -Value @" 223 | function Remove-UIHandler { 224 | [CmdletBinding()] 225 | param( 226 | # The AutomationElement to Register the Event handler for 227 | [Parameter(Mandatory, ValueFromPipeline, Position = 0)] 228 | [Alias('Element', 'AutomationElement')] 229 | [AutomationElement]`$InputObject, 230 | 231 | [ValidateSet('$($Event -replace "^.*::(.*)Event", '$1' -join "','")')] 232 | [string]`$Event, 233 | 234 | [Parameter(Mandatory, Position = 1)] 235 | [AutomationEventHandler]`$Handler, 236 | 237 | [TreeScope]`$Scope = "Element" 238 | ) 239 | 240 | `$EventId = `$UIAEvents.Where{ `$_.ProgrammaticName -match `$Event } 241 | 242 | [Automation]::RemoveAutomationEventHandler(`$EventId, `$InputObject, `$Handler) 243 | } 244 | "@ 245 | 246 | 247 | # $FalseCondition = [Condition]::FalseCondition 248 | # $TrueCondition = [Condition]::TrueCondition 249 | # $AutomationProperties = [System.Windows.Automation.AutomationElement+AutomationElementInformation].GetProperties() 250 | 251 | # Set-Alias Invoke-UIElement Invoke-Invoke.Invoke 252 | Write-Information "Build Module" 253 | Set-Location $PSScriptRoot 254 | Build-Module 255 | Pop-Location 256 | 257 | # [Cmdlet(VerbsCommon.Add, "UIAHandler")] 258 | # public class AddUIAHandlerCommand : PSCmdlet 259 | # { 260 | # private AutomationElement _parent = AutomationElement.RootElement; 261 | # private AutomationEvent _event = WindowPattern.WindowOpenedEvent; 262 | # private TreeScope _scope = TreeScope.Children; 263 | # 264 | # [Parameter(ValueFromPipeline = true)] 265 | # [Alias("Parent", "Element", "Root")] 266 | # public AutomationElement InputObject { set { _parent = value; } get { return _parent; } } 267 | # 268 | # [Parameter()] 269 | # public AutomationEvent Event { set { _event = value; } get { return _event; } } 270 | # 271 | # [Parameter()] 272 | # public AutomationEventHandler ScriptBlock { set; get; } 273 | # 274 | # [Parameter()] 275 | # public SwitchParameter Passthru { set; get; } 276 | # 277 | # [Parameter()] 278 | # public TreeScope Scope { set { _scope = value; } get { return _scope; } } 279 | # 280 | # protected override void ProcessRecord() 281 | # { 282 | # Automation.AddAutomationEventHandler(Event, InputObject, Scope, ScriptBlock); 283 | # 284 | # if (Passthru.ToBool()) 285 | # { 286 | # WriteObject(InputObject); 287 | # } 288 | # 289 | # base.ProcessRecord(); 290 | # } 291 | # } 292 | -------------------------------------------------------------------------------- /build.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | SourcePath = "Source/Wasp.psd1" 3 | OutputDirectory = ".." 4 | SourceDirectories = @( "Classes", "Generated", "Private", "Public" ) 5 | CopyPaths = @( "lib" ) 6 | } -------------------------------------------------------------------------------- /resources/WASP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/WASP/aaf14d3077d705398f88b16bc8ccf6a7d6b49c08/resources/WASP.png --------------------------------------------------------------------------------