├── .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 | 
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
--------------------------------------------------------------------------------