Powershell - 如何以编程方式移动 Citrix 窗口并调整其大小

发布于 2025-01-14 00:20:57 字数 14762 浏览 4 评论 0原文

我已经在整个互联网上搜索了两次;)但仍然没有找到解决我的问题的方法。

我创建了一个 powershell 脚本来将打开的窗口放置在桌面上我希望它们位于的位置,它适用于 Outlook 上的 Messenger 等本地应用程序。但移动 Citrix 窗口并不是那么简单。

我可以获得它的 Id、名称和 mainWindowTitle,但 Get-Process 仅返回一个 system.diagnostics.process 类型的对象。 (wfica32)

由此引发的错误是:

无法转换参数“hWnd”,其值为:“System.Object[]”,对于 “GetWindowRect”键入“System.IntPtr”:“无法转换 要键入的“System.Object[]”类型的“System.Object[]”值 “System.IntPtr”。”位于 C:\temp\PlaceMyWindows.ps1:77 字符:9 $Return = [窗口]::GetWindowRect($Handle,[ref]$Rectangle) 类别信息: 未指定:(:) [],MethodException FullQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

关于如何使用 powershell 移动这些 wfica32 citrix 窗口有什么想法吗?或者 CSharp 呢?

    Function Set-Window {
    <#
        .SYNOPSIS
            Sets the window size (height,width) and coordinates (x,y) of
            a process window.
        .DESCRIPTION
            Sets the window size (height,width) and coordinates (x,y) of
            a process window.
        .PARAMETER ProcessName
            Name of the process to determine the window characteristics
        .PARAMETER X
            Set the position of the window in pixels from the top.
        .PARAMETER Y
            Set the position of the window in pixels from the left.
        .PARAMETER Width
            Set the width of the window.
        .PARAMETER Height
            Set the height of the window.
        .PARAMETER Passthru
            Display the output object of the window.
        .NOTES                         
            Name: Set-Window
            Author: Boe Prox
            Version History
                1.0//Boe Prox - 11/24/2015
                    - Initial build
        .OUTPUT
            System.Automation.WindowInfo
        .EXAMPLE
            Get-Process powershell | Set-Window -X 2040 -Y 142 -Passthru
            ProcessName Size     TopLeft  BottomRight
            ----------- ----     -------  -----------
            powershell  1262,642 2040,142 3302,784   
            Description
            -----------
            Set the coordinates on the window for the process PowerShell.exe
        
    #>
    [OutputType('System.Automation.WindowInfo')]
    [cmdletbinding()]
    Param (
        [parameter(ValueFromPipelineByPropertyName=$True)]
        $ProcessName,
        [int]$X,
        [int]$Y,
        [int]$Width,
        [int]$Height,
        [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")]
                public extern static bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
              }
              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
        $Handle = (Get-Process -Name $ProcessName).MainWindowHandle
        $Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)
        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.ContainsKey('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.LEft -lt 0) {
                    Write-Warning "Window is minimized! Coordinates will not be accurate."
                }
                $Object = [pscustomobject]@{
                    ProcessName = $ProcessName
                    Size = $Size
                    TopLeft = $TopLeft
                    BottomRight = $BottomRight
                }
                $Object.PSTypeNames.insert(0,'System.Automation.WindowInfo')
                $Object            
            }
        }
    }
}



Get-Process | Where-Object {$_.mainWindowTitle} | Format-Table Id, Name, mainWindowtitle -AutoSize

Get-Process Messenger | Set-Window -X 2500 -Y 600 -Width 947 -Height 807 -Passthru
Get-Process OUTLOOK | Set-Window -X 1720 -Y 0 -Width 1720 -Height 1400 -Passthru

Get-Process | Where-Object {$_.mainWindowTitle -like '*Oracle*'}  | Set-Window -X 0 -Y 0 -Width 1720 -Height 1400 -Passthru

pause

今天实际编辑了它,它运行没有错误,但仍然没有移动任何 Citrix 窗口 (wfica32.exe)`

Clear

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
Name of the process to determine the window characteristics. 
(All processes if omitted).

.PARAMETER Id
Id of the process to determine the window characteristics. 

.PARAMETER X
Set the position of the window in pixels from the left.

.PARAMETER Y
Set the position of the window in pixels from the top.

.PARAMETER Width
Set the width of the window.

.PARAMETER Height
Set the height of the window.

.PARAMETER Passthru
Returns the output object of the window.

.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

.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(DefaultParameterSetName='Name')]
Param (
    [parameter(Mandatory=$False,
        ValueFromPipelineByPropertyName=$True, ParameterSetName='Name')]
    [string]$ProcessName='*',
    [parameter(Mandatory=$True,
        ValueFromPipeline=$False,              ParameterSetName='Id')]
    [int]$Id,
    [int]$X,
    [int]$Y,
    [int]$Width,
    [int]$Height,
    [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
                }
            }
        }
    }
}
}


Get-Process | Where-Object {$_.mainWindowTitle} | Format-Table Id, Name, mainWindowtitle -AutoSize
Get-Process | Where-Object {$_.mainWindowTitle -like '*Oracle*'} | Set-Window -X 20 -Y 40 -Width 100 -Height 100 -Passthru -Verbose
Get-Process | Where-Object {$_.mainWindowTitle -like '*Messenger*'} | Set-Window -X 20 -Y 40 -Width 600 -Height 600 -Passthru -Verbose

返回以下内容:


   Id Name                 MainWindowTitle                                                                                    
   -- ----                 ---------------                                                                                    
 6432 ApplicationFrameHost Kalkulator                                                                                         
 9060 Calculator           Kalkulator                                                                                         
11860 chrome               Powershell - How to programatically move and resize Citrix windows - Stack Overflow - Google Chrome
 8616 Messenger            Messenger                                                                                                                                                  
16692 powershell           Administrator: Windows PowerShell                                                                  
 4188 powershell_ise       Windows PowerShell ISE                                                                             
11272 SystemSettings       Innstillinger                                                                                      
13824 Teams                Regnskap (4819) | Microsoft Teams                                                                  
10804 TextInputHost        Microsoft Text Input Application                                                                   
16036 wfica32              Oracle SQL Developer : Welcome Page - \\Remote                                                     
10320 WWAHost              Netflix                                                                                            


VERBOSE: wfica32 (Id=2340, Handle=0)
VERBOSE: wfica32 (Id=16036, Handle=723242)

VERBOSE: Messenger (Id=8616, Handle=132416)

Id          : 16036
ProcessName : wfica32
Size        : 2161,1400
TopLeft     : 3138,90
BottomRight : 5299,1490

Id          : 8616
ProcessName : Messenger
Size        : 600,600
TopLeft     : 20,40
BottomRight : 620,640

I've searched through the entire internet twice ;) but still haven't found a solution to my issue.

I have created a powershell script to place open windows where I want them to be on the desktop, it works fine for the local applications like Messenger on Outlook. But moving a Citrix window is not that straightforward.

I can get the Id, name and mainWindowTitle for it, but Get-Process just returns an object of type system.diagnostics.process. (wfica32)

The error thrown from this is:

Cannot convert argument "hWnd", with value: "System.Object[]", for
"GetWindowRect" to type "System.IntPtr": "Cannot convert the
"System.Object[]" value of type "System.Ob ject[]" to type
"System.IntPtr"." At C:\temp\PlaceMyWindows.ps1:77 char:9 $Return =
[Window]::GetWindowRect($Handle,[ref]$Rectangle) CategoryInfo :
NotSpecified: (:) [], MethodException FullyQualifiedErrorId :
MethodArgumentConversionInvalidCastArgument

Any ideas on how to move these wfica32 citrix windows using powershell? Or CSharp for that matter?

    Function Set-Window {
    <#
        .SYNOPSIS
            Sets the window size (height,width) and coordinates (x,y) of
            a process window.
        .DESCRIPTION
            Sets the window size (height,width) and coordinates (x,y) of
            a process window.
        .PARAMETER ProcessName
            Name of the process to determine the window characteristics
        .PARAMETER X
            Set the position of the window in pixels from the top.
        .PARAMETER Y
            Set the position of the window in pixels from the left.
        .PARAMETER Width
            Set the width of the window.
        .PARAMETER Height
            Set the height of the window.
        .PARAMETER Passthru
            Display the output object of the window.
        .NOTES                         
            Name: Set-Window
            Author: Boe Prox
            Version History
                1.0//Boe Prox - 11/24/2015
                    - Initial build
        .OUTPUT
            System.Automation.WindowInfo
        .EXAMPLE
            Get-Process powershell | Set-Window -X 2040 -Y 142 -Passthru
            ProcessName Size     TopLeft  BottomRight
            ----------- ----     -------  -----------
            powershell  1262,642 2040,142 3302,784   
            Description
            -----------
            Set the coordinates on the window for the process PowerShell.exe
        
    #>
    [OutputType('System.Automation.WindowInfo')]
    [cmdletbinding()]
    Param (
        [parameter(ValueFromPipelineByPropertyName=$True)]
        $ProcessName,
        [int]$X,
        [int]$Y,
        [int]$Width,
        [int]$Height,
        [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")]
                public extern static bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
              }
              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
        $Handle = (Get-Process -Name $ProcessName).MainWindowHandle
        $Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)
        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.ContainsKey('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.LEft -lt 0) {
                    Write-Warning "Window is minimized! Coordinates will not be accurate."
                }
                $Object = [pscustomobject]@{
                    ProcessName = $ProcessName
                    Size = $Size
                    TopLeft = $TopLeft
                    BottomRight = $BottomRight
                }
                $Object.PSTypeNames.insert(0,'System.Automation.WindowInfo')
                $Object            
            }
        }
    }
}



Get-Process | Where-Object {$_.mainWindowTitle} | Format-Table Id, Name, mainWindowtitle -AutoSize

Get-Process Messenger | Set-Window -X 2500 -Y 600 -Width 947 -Height 807 -Passthru
Get-Process OUTLOOK | Set-Window -X 1720 -Y 0 -Width 1720 -Height 1400 -Passthru

Get-Process | Where-Object {$_.mainWindowTitle -like '*Oracle*'}  | Set-Window -X 0 -Y 0 -Width 1720 -Height 1400 -Passthru

pause

Actually edited it today, and it runs without errors, but still does not move any Citrix windows (wfica32.exe)`

Clear

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
Name of the process to determine the window characteristics. 
(All processes if omitted).

.PARAMETER Id
Id of the process to determine the window characteristics. 

.PARAMETER X
Set the position of the window in pixels from the left.

.PARAMETER Y
Set the position of the window in pixels from the top.

.PARAMETER Width
Set the width of the window.

.PARAMETER Height
Set the height of the window.

.PARAMETER Passthru
Returns the output object of the window.

.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

.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(DefaultParameterSetName='Name')]
Param (
    [parameter(Mandatory=$False,
        ValueFromPipelineByPropertyName=$True, ParameterSetName='Name')]
    [string]$ProcessName='*',
    [parameter(Mandatory=$True,
        ValueFromPipeline=$False,              ParameterSetName='Id')]
    [int]$Id,
    [int]$X,
    [int]$Y,
    [int]$Width,
    [int]$Height,
    [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
                }
            }
        }
    }
}
}


Get-Process | Where-Object {$_.mainWindowTitle} | Format-Table Id, Name, mainWindowtitle -AutoSize
Get-Process | Where-Object {$_.mainWindowTitle -like '*Oracle*'} | Set-Window -X 20 -Y 40 -Width 100 -Height 100 -Passthru -Verbose
Get-Process | Where-Object {$_.mainWindowTitle -like '*Messenger*'} | Set-Window -X 20 -Y 40 -Width 600 -Height 600 -Passthru -Verbose

Returns the following:


   Id Name                 MainWindowTitle                                                                                    
   -- ----                 ---------------                                                                                    
 6432 ApplicationFrameHost Kalkulator                                                                                         
 9060 Calculator           Kalkulator                                                                                         
11860 chrome               Powershell - How to programatically move and resize Citrix windows - Stack Overflow - Google Chrome
 8616 Messenger            Messenger                                                                                                                                                  
16692 powershell           Administrator: Windows PowerShell                                                                  
 4188 powershell_ise       Windows PowerShell ISE                                                                             
11272 SystemSettings       Innstillinger                                                                                      
13824 Teams                Regnskap (4819) | Microsoft Teams                                                                  
10804 TextInputHost        Microsoft Text Input Application                                                                   
16036 wfica32              Oracle SQL Developer : Welcome Page - \\Remote                                                     
10320 WWAHost              Netflix                                                                                            


VERBOSE: wfica32 (Id=2340, Handle=0)
VERBOSE: wfica32 (Id=16036, Handle=723242)

VERBOSE: Messenger (Id=8616, Handle=132416)

Id          : 16036
ProcessName : wfica32
Size        : 2161,1400
TopLeft     : 3138,90
BottomRight : 5299,1490

Id          : 8616
ProcessName : Messenger
Size        : 600,600
TopLeft     : 20,40
BottomRight : 620,640

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

余生共白头 2025-01-21 00:20:57

使用 https://github 中的脚本时,我收到了相同的错误消息.com/proxb/PowerShell_Scripts/blob/master/Set-Window.ps1
显然有一个较新的版本 1.2 可在 https://www.powershellgallery.com/packages/SciProfile/0.3.0/Content/PSModuleUtils%5CFunctions%5CSet-Window.ps1 声称可以更好地处理多个进程。我不知道,因为我没有尝试过。

问题在于第 78 行:

    $Handle = (Get-Process -Name $ProcessName).MainWindowHandle

Get-Process 可能返回多个窗口句柄。当第 89 行:

        $Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)

尝试使用单个句柄时,它会得到多个句柄。我打开一个powershell窗口,查看Get-process的输出:

>> Get-Process -Name "cmd" | Format-Table MainWindowHandle, StartTime, Id -AutoSize
MainWindowHandle StartTime              Id
---------------- ---------              --
          855904 20.10.2022 10.34.39  4324
               0 13.10.2022 14.16.05  5028
        13240562 20.10.2022 10.39.39  7708
          987022 20.10.2022 10.37.39 15508

看来Id 5028绝对不合适,因为它的句柄是0。我知道我刚刚生成了一个新的“cmd.exe”窗口,这就是我想要的使用。这些进程中最新的一个是 7708,所以我需要一个系统来自动选择该进程。这是通过将第 78 行更改为:

    $HandleArray = Get-Process -Name $ProcessName | Sort-Object -Property StartTime -Descending
    if ($HandleArray.Length -Gt 1) {
        $Handle = $HandleArray[0].MainWindowHandle
    } else {
        $Handle = $HandleArray.MainWindowHandle
    }

非常感谢 Dan at https://blog.osull.com/2019/07/18/resize-browser-window-with-powershell/ 谁写了这个具体问题并帮助了我找到解决方案。

I had the same error message when using the script from https://github.com/proxb/PowerShell_Scripts/blob/master/Set-Window.ps1.
Apparently there is a newer version 1.2 available at https://www.powershellgallery.com/packages/SciProfile/0.3.0/Content/PSModuleUtils%5CFunctions%5CSet-Window.ps1 that claims to handle multiple processes better. I don't know, because I didn't try it.

The problem is that on the line 78:

    $Handle = (Get-Process -Name $ProcessName).MainWindowHandle

Get-Process may return multiple window handles. When the line 89:

        $Return = [Window]::GetWindowRect($Handle,[ref]$Rectangle)

tries to use a single handle, it gets multiple. I opened an powershell window and looked at the output of Get-process:

>> Get-Process -Name "cmd" | Format-Table MainWindowHandle, StartTime, Id -AutoSize
MainWindowHandle StartTime              Id
---------------- ---------              --
          855904 20.10.2022 10.34.39  4324
               0 13.10.2022 14.16.05  5028
        13240562 20.10.2022 10.39.39  7708
          987022 20.10.2022 10.37.39 15508

It seems that Id 5028 is definitely not suitable, because it's handle is 0. I know that I just spawned a new "cmd.exe" window and that's what I want to use. The latest of these processes is 7708, so I need a system to select that one automatically. This was accomplished by changing line 78 to:

    $HandleArray = Get-Process -Name $ProcessName | Sort-Object -Property StartTime -Descending
    if ($HandleArray.Length -Gt 1) {
        $Handle = $HandleArray[0].MainWindowHandle
    } else {
        $Handle = $HandleArray.MainWindowHandle
    }

Big thanks to Dan at https://blog.osull.com/2019/07/18/resize-browser-window-with-powershell/ who wrote about this specific problem and helped me to find a solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文