5151
5252Add-Type - Assembly System.Windows.Forms
5353Add-Type - Assembly System.Drawing
54- Add-Type - MemberDefinition ' [DllImport("gdi32.dll")] public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);' - Name GDI32 - Namespace W;
55- Add-Type - MemberDefinition ' [DllImport("User32.dll")] public static extern int GetDC(IntPtr hWnd);[DllImport("User32.dll")] public static extern int ReleaseDC(IntPtr hwnd, int hdc);[DllImport("User32.dll")] public static extern bool SetProcessDPIAware();' - Name User32 - Namespace W;
54+ Add-Type - MemberDefinition ' [DllImport("User32.dll")] public static extern bool SetProcessDPIAware();' - Name User32 - Namespace W;
5655
57- $global :PowerRemoteDesktopVersion = " 1.0.beta.3 "
56+ $global :PowerRemoteDesktopVersion = " 1.0.3. beta.4 "
5857
5958enum TransportMode {
6059 Raw = 1
@@ -97,7 +96,7 @@ function Test-PasswordComplexity
9796 . DESCRIPTION
9897 To return True, Password must follow bellow complexity rules:
9998 * Minimum 12 Characters.
100- * One of following symbols: "!@#$ %^&*_".
99+ * One of following symbols: "!@#%^&*_".
101100 * At least of lower case character.
102101 * At least of upper case character.
103102
@@ -109,7 +108,7 @@ function Test-PasswordComplexity
109108 [string ] $PasswordCandidate
110109 )
111110
112- $complexityRules = " (?=^.{12,}$)(?=.*[!@#$ %^&*_]+)(?=.*[a-z])(?=.*[A-Z]).*$"
111+ $complexityRules = " (?=^.{12,}$)(?=.*[!@#%^&*_]+)(?=.*[a-z])(?=.*[A-Z]).*$"
113112
114113 return ($PasswordCandidate -match $complexityRules )
115114}
@@ -501,24 +500,6 @@ function Resolve-AuthenticationChallenge
501500 return $solution
502501}
503502
504- function Get-ResolutionScaleFactor
505- {
506- <#
507- . SYNOPSIS
508- Return current screen scale factor
509- #>
510-
511- $hdc = [W.User32 ]::GetDC(0 )
512- try
513- {
514- return [W.GDI32 ]::GetDeviceCaps($hdc , 117 ) / [W.GDI32 ]::GetDeviceCaps($hdc , 10 )
515- }
516- finally
517- {
518- [W.User32 ]::ReleaseDC(0 , $hdc ) | Out-Null
519- }
520- }
521-
522503function Get-LocalMachineInformation
523504{
524505 <#
@@ -531,30 +512,42 @@ function Get-LocalMachineInformation
531512
532513 This function is expected to be progressively updated with new required session information.
533514 #>
534- $screenBounds = [System.Windows.Forms.Screen ]::PrimaryScreen.Bounds
515+
516+ $screens = @ ()
517+
518+ $i = 0
519+ foreach ($screen in ([System.Windows.Forms.Screen ]::AllScreens | Sort-Object - Property Primary - Descending))
520+ {
521+ $i ++
522+
523+ $screens += New-Object - TypeName PSCustomObject - Property @ {
524+ Id = $i
525+ Name = $screen.DeviceName
526+ Primary = $screen.Primary
527+ Width = $screen.Bounds.Width
528+ Height = $screen.Bounds.Height
529+ X = $screen.Bounds.X
530+ Y = $screen.Bounds.Y
531+ }
532+ }
535533
536534 return New-Object PSCustomObject - Property @ {
537535 MachineName = [Environment ]::MachineName
538536 Username = [Environment ]::UserName
539537 WindowsVersion = [Environment ]::OSVersion.VersionString
540-
541- ScreenInformation = New-Object - TypeName PSCustomObject - Property @ {
542- Width = $screenBounds.Width
543- Height = $screenBounds.Height
544- X = $screenBounds.X
545- Y = $screenBounds.Y
546- }
538+ Screens = ($screens )
547539 }
548540}
549541
550542class ServerSession {
551543 <#
552544 . SYNOPSIS
553545 PowerRemoteDesktop Session Class.
554- #>
546+ #>
555547
556548 [string ] $Id = " "
557549 [string ] $TiedAddress = " "
550+ [string ] $Screen = " "
558551
559552 ServerSession([string ] $RemoteAddress ) {
560553 <#
@@ -567,11 +560,10 @@ class ServerSession {
567560 #>
568561
569562 $this.Id = (SHA512FromString - String (-join ((33 .. 126 ) | Get-Random - Count 128 | ForEach-Object {[char ] $_ })))
570- $this.TiedAddress = $RemoteAddress
563+ $this.TiedAddress = $RemoteAddress
571564 }
572565
573- [bool ] CompareWith([string ] $Id , [string ] $RemoteAddress )
574- {
566+ [bool ] CompareWith([string ] $Id , [string ] $RemoteAddress ) {
575567 return ($this.Id -eq $Id ) -and ($this.TiedAddress -eq $RemoteAddress )
576568 }
577569}
@@ -777,6 +769,15 @@ class ClientIO {
777769
778770 $this.Writer.WriteLine (($sessionInformation | ConvertTo-Json - Compress))
779771
772+ if ($sessionInformation.Screens.Length -gt 1 )
773+ {
774+ Write-Verbose " Current system have $ ( $sessionInformation.Screens.Length ) Screens. Waiting for Remote Viewer to choose which screen to capture."
775+
776+ $screenName = $this.Reader.ReadLine ()
777+
778+ $session.Screen = $screenName
779+ }
780+
780781 Write-Verbose " Handshake done."
781782
782783 return $session
@@ -1043,24 +1044,28 @@ $global:DesktopStreamScriptBlock = {
10431044 . SYNOPSIS
10441045 Return a snapshot of primary screen desktop.
10451046
1046- . DESCRIPTION
1047- Notice:
1048- At this time, PowerRemoteDesktop only supports PrimaryScreen.
1049- Even if multi-screen capture is a very easy feature to implement, It will probably be present
1050- in final version 1.0
1047+ . PARAMETER Screen
1048+ Define target screen to capture (if multiple monitor exists).
1049+ Default is primary screen
10511050 #>
1051+ param (
1052+ [System.Windows.Forms.Screen ] $Screen = $null
1053+ )
10521054 try
10531055 {
1054- $primaryDesktop = [System.Windows.Forms.Screen ]::PrimaryScreen
1056+ if (-not $Screen )
1057+ {
1058+ $Screen = [System.Windows.Forms.Screen ]::PrimaryScreen
1059+ }
10551060
10561061 $size = New-Object System.Drawing.Size(
1057- $primaryDesktop .Bounds.Size.Width ,
1058- $primaryDesktop .Bounds.Size.Height
1062+ $Screen .Bounds.Size.Width ,
1063+ $Screen .Bounds.Size.Height
10591064 )
10601065
10611066 $location = New-Object System.Drawing.Point(
1062- $primaryDesktop .Bounds.Location.X ,
1063- $primaryDesktop .Bounds.Location.Y
1067+ $Screen .Bounds.Location.X ,
1068+ $Screen .Bounds.Location.Y
10641069 )
10651070
10661071 $bitmap = New-Object System.Drawing.Bitmap($size.Width , $size.Height )
@@ -1087,6 +1092,10 @@ $global:DesktopStreamScriptBlock = {
10871092 }
10881093
10891094 $imageQuality = 100
1095+ if ($syncHash.Param.ImageQuality -ge 0 -and $syncHash.Param.ImageQuality -lt 100 )
1096+ {
1097+ $imageQuality = $syncHash.Param.ImageQuality
1098+ }
10901099 try
10911100 {
10921101 [System.IO.MemoryStream ] $oldImageStream = New-Object System.IO.MemoryStream
@@ -1102,7 +1111,7 @@ $global:DesktopStreamScriptBlock = {
11021111 {
11031112 try
11041113 {
1105- $desktopImage = Get-DesktopImage
1114+ $desktopImage = Get-DesktopImage - Screen $syncHash .Param.Screen
11061115
11071116 $imageStream = New-Object System.IO.MemoryStream
11081117
@@ -1509,6 +1518,11 @@ function Invoke-RemoteDesktopServer
15091518
15101519 . PARAMETER DisableVerbosity
15111520 Disable verbosity (not recommended)
1521+
1522+ . PARAMETER ImageQuality
1523+ JPEG Compression level from 0 to 100
1524+ 0 = Lowest quality.
1525+ 100 = Highest quality.
15121526 #>
15131527
15141528 param (
@@ -1523,7 +1537,9 @@ function Invoke-RemoteDesktopServer
15231537 [TransportMode ] $TransportMode = " Raw" ,
15241538 [switch ] $TLSv1_3 ,
15251539
1526- [switch ] $DisableVerbosity
1540+ [switch ] $DisableVerbosity ,
1541+
1542+ [int ] $ImageQuality = 100
15271543 )
15281544
15291545
@@ -1546,10 +1562,7 @@ function Invoke-RemoteDesktopServer
15461562
15471563 Write-Banner
15481564
1549- if (Get-ResolutionScaleFactor -ne 1 )
1550- {
1551- [W.User32 ]::SetProcessDPIAware()
1552- }
1565+ [W.User32 ]::SetProcessDPIAware() | Out-Null
15531566
15541567 if (-not (Test-Administrator ) -and -not $CertificateFile -and -not $EncodedCertificate )
15551568 {
@@ -1572,8 +1585,8 @@ function Invoke-RemoteDesktopServer
15721585 if (-not $Password )
15731586 {
15741587 $Password = (
1575- # a-Z, 0-9, !@#$ %^&*_
1576- -join ((48 .. 57 ) + (64 .. 90 ) + ( 35 .. 38 ) + 33 + 42 + 94 + 95 + (97 .. 122 ) | Get-Random - Count 18 | ForEach-Object {[char ] $_ })
1588+ # a-Z, 0-9, !@#%^&*_
1589+ -join ((48 .. 57 ) + (64 .. 90 ) + 35 + ( 37 .. 38 ) + 33 + 42 + 94 + 95 + (97 .. 122 ) | Get-Random - Count 18 | ForEach-Object {[char ] $_ })
15771590 )
15781591
15791592 Write-Host - NoNewLine " Server password: "" "
@@ -1586,7 +1599,7 @@ function Invoke-RemoteDesktopServer
15861599 {
15871600 throw " Password complexity is too weak. Please choose a password following following rules:`r`n `
15881601 * Minimum 12 Characters`r`n `
1589- * One of following symbols: "" !@#$ %^&*_""`r`n `
1602+ * One of following symbols: "" !@#%^&*_""`r`n `
15901603 * At least of lower case character`r`n `
15911604 * At least of upper case character`r`n "
15921605 }
@@ -1635,11 +1648,16 @@ function Invoke-RemoteDesktopServer
16351648 # Remote Viewer will then need to establish a new session from scratch.
16361649 $clientControl = $server.PullClient (10 * 1000 );
16371650
1651+ # Grab desired screen to capture
1652+ $screen = [System.Windows.Forms.Screen ]::AllScreens | Where-Object - FilterScript { $_.DeviceName -eq $server.Session.Screen }
1653+
16381654 # Create Runspace #1 for Desktop Streaming.
16391655 $param = New-Object - TypeName PSCustomObject - Property @ {
16401656 Client = $clientDesktop
1657+ Screen = $screen
1658+ ImageQuality = $ImageQuality
16411659 }
1642-
1660+
16431661 $newRunspace = (New-RunSpace - ScriptBlock $global :DesktopStreamScriptBlock - Param $param )
16441662 $runspaces.Add ($newRunspace )
16451663
0 commit comments