PSModuleUtils/Functions/Set-Window.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
# ===========================================================================
# Set-Window.ps1 ----------------------------------------------------------
# ===========================================================================

# function ----------------------------------------------------------------
# ---------------------------------------------------------------------------
Function Set-Window {
    <#
    .SYNOPSIS
    Retrieve/Set the window size and coordinates of a process window.
     
    .DESCRIPTION
    Retrieve/Set the size (height,width) and coordinates (x,y)
    of a process window.
     
    .PARAMETER ProcessName
     
    .PARAMETER Id
     
    .PARAMETER X
     
    .PARAMETER Y
     
    .PARAMETER Width
     
    .PARAMETER Height
      
    .PARAMETER Passthru
     
    .NOTES
    Name: Set-Window
    Author: Boe Prox
    Version History:
        1.0//Boe Prox - 11/24/2015 - Initial build
        1.1//JosefZ - 19.05.2018 - Treats more process instances
                                     of supplied process name properly
        1.2//JosefZ - 21.02.2019 - Parameter Id
    Link: https://superuser.com/questions/1324007/setting-window-size-and-position-in-powershell-5-and-6
 
    .OUTPUTS
    None
    System.Management.Automation.PSCustomObject
    System.Object
     
    .EXAMPLE
    Get-Process powershell | Set-Window -X 20 -Y 40 -Passthru -Verbose
    VERBOSE: powershell (Id=11140, Handle=132410)
     
    Id : 11140
    ProcessName : powershell
    Size : 1134,781
    TopLeft : 20,40
    BottomRight : 1154,821
     
    Description: Set the coordinates on the window for the process PowerShell.exe
     
    .EXAMPLE
    $windowArray = Set-Window -Passthru
    WARNING: cmd (1096) is minimized! Coordinates will not be accurate.
     
        PS C:\>$windowArray | Format-Table -AutoSize
     
      Id ProcessName Size TopLeft BottomRight
      -- ----------- ---- ------- -----------
    1096 cmd 199,34 -32000,-32000 -31801,-31966
    4088 explorer 1280,50 0,974 1280,1024
    6880 powershell 1280,974 0,0 1280,974
     
    Description: Get the coordinates of all visible windows and save them into the $windowArray variable. Then, display them in a table view.
     
    .EXAMPLE
    Set-Window -Id $PID -Passthru | Format-Table
    ​‌‍
      Id ProcessName Size TopLeft BottomRight
      -- ----------- ---- ------- -----------
    7840 pwsh 1024,638 0,0 1024,638
     
    Description: Display the coordinates of the window for the current
                 PowerShell session in a table view.
    #>

    [CmdletBinding(PositionalBinding, DefaultParameterSetName="Name")]

    Param (

        [Parameter(Mandatory=$False, ValueFromPipelineByPropertyName=$True, ParameterSetName="Name", HelpMessage="Name of the process to determine the window characteristics. (All processes if omitted).")]
        [String]$ProcessName="*",

        [Parameter(Mandatory, ValueFromPipeline=$False,       ParameterSetName="Id", HelpMessage="Id of the process to determine the window characteristics. ")]
        [Int]$Id,

        [Parameter(HelpMessage="Set the position of the window in pixels from the left.")]
        [Int]$X,

        [Parameter(HelpMessage="Set the position of the window in pixels from the top.")]
        [Int]$Y,

        [Parameter(HelpMessage="Set the width of the window.")]
        [Int]$Width,

        [Parameter(HelpMessage="Set the height of the window.")]
        [Int]$Height,

        [Parameter(HelpMessage="Returns the output object of the window.")]
        [Switch]$Passthru
    )
    
    Begin {
        Try { 
            [Void][Window]
        } Catch {
        Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    public class Window {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(
        IntPtr hWnd, out RECT lpRect);
 
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public extern static bool MoveWindow(
        IntPtr handle, int x, int y, int width, int height, bool redraw);
 
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ShowWindow(
        IntPtr handle, int state);
    }
    public struct RECT
    {
    public int Left; // x position of upper-left corner
    public int Top; // y position of upper-left corner
    public int Right; // x position of lower-right corner
    public int Bottom; // y position of lower-right corner
    }
"@

        }
    }

    Process {

        $Rectangle = New-Object RECT

        If ( $PSBoundParameters.ContainsKey('Id') ) {
            $Processes = Get-Process -Id $Id -ErrorAction SilentlyContinue
        } Else {
            $Processes = Get-Process -Name "$ProcessName" -ErrorAction SilentlyContinue
        }

        If ( $null -eq $Processes ) {
            If ( $PSBoundParameters['Passthru'] ) {
                Write-Warning 'No process match criteria specified'
            }
        } Else {
            $Processes | ForEach-Object {
                $Handle = $_.MainWindowHandle
                Write-Verbose "$($_.ProcessName) `(Id=$($_.Id), Handle=$Handle`)"
                If ( $Handle -eq [System.IntPtr]::Zero ) { Return }
                $Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)
                If (-NOT $PSBoundParameters.ContainsKey('X')) {
                    $X = $Rectangle.Left            
                }
                If (-NOT $PSBoundParameters.ContainsKey('Y')) {
                    $Y = $Rectangle.Top
                }
                If (-NOT $PSBoundParameters.ContainsKey('Width')) {
                    $Width = $Rectangle.Right - $Rectangle.Left
                }
                If (-NOT $PSBoundParameters.ContainsKey('Height')) {
                    $Height = $Rectangle.Bottom - $Rectangle.Top
                }
                If ( $Return ) {
                    $Return = [Window]::MoveWindow($Handle, $x, $y, $Width, $Height,$True)
                }
                If ( $PSBoundParameters['Passthru'] ) {
                    $Rectangle = New-Object RECT
                    $Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)
                    If ( $Return ) {
                        $Height      = $Rectangle.Bottom - $Rectangle.Top
                        $Width       = $Rectangle.Right  - $Rectangle.Left
                        $Size        = New-Object System.Management.Automation.Host.Size        -ArgumentList $Width, $Height
                        $TopLeft     = New-Object System.Management.Automation.Host.Coordinates -ArgumentList $Rectangle.Left , $Rectangle.Top
                        $BottomRight = New-Object System.Management.Automation.Host.Coordinates -ArgumentList $Rectangle.Right, $Rectangle.Bottom
                        If ($Rectangle.Top    -lt 0 -AND 
                            $Rectangle.Bottom -lt 0 -AND
                            $Rectangle.Left   -lt 0 -AND
                            $Rectangle.Right  -lt 0) {
                            Write-Warning "$($_.ProcessName) `($($_.Id)`) is minimized! Coordinates will not be accurate."
                        }
                        $Object = [PSCustomObject]@{
                            Id          = $_.Id
                            ProcessName = $_.ProcessName
                            Size        = $Size
                            TopLeft     = $TopLeft
                            BottomRight = $BottomRight
                        }
                        $Object
                    }
                }
            }
        }
    }
}