MegaBites-AI/Windows-powershell
0372
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3using namespace System.Diagnostics4 5function Invoke-AppleScript6{7 param(8 [string]$Script,9 [switch]$PassThru10 )11 12 Write-Verbose "running applescript: $Script"13 14 $result = $Script | osascript15 if($PassThru.IsPresent)16 {17 return $result18 }19}20 21function Get-WindowCountMacOS {22 param(23 [string]$Name24 )25 26 $processCount = @(Get-Process $Name -ErrorAction Ignore).Count27 28 if($processCount -eq 0)29 {30 return 031 }32 33 $title = Get-WindowsTitleMacOS -name $Name34 35 if(!$title)36 {37 return 038 }39 40 $windowCount = [int](Invoke-AppleScript -Script ('tell application "{0}" to count of windows' -f $Name) -PassThru)41 return $windowCount42}43 44function Get-WindowsTitleMacOS {45 param(46 [string]$Name47 )48 49 return Invoke-AppleScript -Script ('tell application "{0}" to get name of front window' -f $Name) -PassThru50}51 52function Stop-ProcessMacOS {53 param(54 [string]$Name,55 [switch]$QuitFirst56 )57 58 if($QuitFirst.IsPresent)59 {60 Invoke-AppleScript -Script ('tell application "{0}" to quit' -f $Name)61 }62 63 Get-Process -Name $Name -ErrorAction Ignore | Stop-Process -Force64}65 66Describe "Invoke-Item basic tests" -Tags "Feature" {67 BeforeAll {68 $powershell = Join-Path $PSHOME -ChildPath pwsh69 70 $testFile1 = Join-Path -Path $TestDrive -ChildPath "text1.txt"71 New-Item -Path $testFile1 -ItemType File -Force > $null72 73 $testFolder = Join-Path -Path $TestDrive -ChildPath "My Folder"74 New-Item -Path $testFolder -ItemType Directory -Force > $null75 $testFile2 = Join-Path -Path $testFolder -ChildPath "text2.txt"76 New-Item -Path $testFile2 -ItemType File -Force > $null77 78 $textFileTestCases = @(79 @{ TestFile = $testFile1; Name='file in root' },80 @{ TestFile = $testFile2; Name='file in subDirectory' })81 }82 83 Context "Invoke a text file on Unix" {84 BeforeEach {85 $redirectErr = Join-Path -Path $TestDrive -ChildPath "error.txt"86 87 if($IsMacOS)88 {89 Stop-ProcessMacOs -Name TextEdit -QuitFirst90 }91 }92 93 AfterEach {94 Remove-Item -Path $redirectErr -Force -ErrorAction SilentlyContinue95 96 }97 98 AfterAll{99 if($IsMacOS)100 {101 Stop-ProcessMacOs -Name TextEdit102 }103 }104 105 ## Run this test only on macOS because redirecting stderr of 'xdg-open' results in weird behavior in our Linux CI,106 ## causing this test to fail or the build to not respond.107 It "Should invoke text file '<Name>' without error on Mac" -Pending -TestCases $textFileTestCases {108 param($TestFile)109 110 $expectedTitle = Split-Path $TestFile -Leaf111 open -F -a TextEdit112 $beforeCount = Get-WindowCountMacOS -Name TextEdit113 Invoke-Item -Path $TestFile114 $startTime = Get-Date115 $title = [String]::Empty116 while (((Get-Date) - $startTime).TotalSeconds -lt 30 -and ($title -ne $expectedTitle))117 {118 Start-Sleep -Milliseconds 100119 $title = Get-WindowsTitleMacOS -Name TextEdit120 }121 $afterCount = Get-WindowCountMacOS -Name TextEdit122 $afterCount | Should -Be ($beforeCount + 1) -Because "There should be one more 'textEdit' windows open than when the tests started and there was $beforeCount"123 $title | Should -Be $expectedTitle124 Invoke-AppleScript -Script ('tell application "{0}" to close window "{1}"' -f 'TextEdit', $expectedTitle)125 }126 }127 128 It "Should invoke an executable file without error" {129 # In case there is a couple of ping executables, we take the first one.130 $ping = (Get-Command "ping" -CommandType Application | Select-Object -First 1).Source131 $redirectFile = Join-Path -Path $TestDrive -ChildPath "redirect2.txt"132 133 if ($IsWindows) {134 if ([System.Management.Automation.Platform]::IsNanoServer -or [System.Management.Automation.Platform]::IsIoT) {135 ## On headless SKUs, we use `UseShellExecute = false`136 ## 'ping.exe' on Windows writes out usage to stdout.137 & $powershell -noprofile -c "Invoke-Item '$ping'" > $redirectFile138 Get-Content $redirectFile -Raw | Should -Match "usage: ping"139 } else {140 ## On full desktop, we use `UseShellExecute = true` to align with Windows PowerShell141 $notepad = Get-Command "notepad.exe" -CommandType Application | ForEach-Object Source142 $notepadProcessName = "notepad"143 Get-Process -Name $notepadProcessName | Stop-Process -Force144 Invoke-Item -Path $notepad145 $notepadProcess = Get-Process -Name $notepadProcessName146 # we need BeIn because multiple notepad processes could be running147 $notepadProcess.Name | Should -BeIn $notepadProcessName148 Stop-Process -InputObject $notepadProcess149 }150 } else {151 ## On Unix, we use `UseShellExecute = false`152 ## 'ping' on Unix write out usage to stderr153 ## some ping show 'usage: ping' and others show 'ping:'154 & $powershell -noprofile -c "Invoke-Item '$ping'" 2> $redirectFile155 Get-Content $redirectFile -Raw | Should -Match "usage: ping|ping:"156 }157 }158 159 Context "Invoke a folder" {160 BeforeAll {161 $supportedEnvironment = $true162 if ($IsLinux)163 {164 $appFolder = "$HOME/.local/share/applications"165 if (Test-Path $appFolder)166 {167 $mimeDefault = xdg-mime query default inode/directory168 Remove-Item $HOME/InvokeItemTest.Success -Force -ErrorAction SilentlyContinue169 Set-Content -Path "$appFolder/InvokeItemTest.desktop" -Force -Value @"170[Desktop Entry]171Version=1.0172Name=InvokeItemTest173Comment=Validate Invoke-Item for directory174Exec=/bin/sh -c 'echo %u > ~/InvokeItemTest.Success'175Icon=utilities-terminal176Terminal=true177Type=Application178Categories=Application;179"@180 xdg-mime default InvokeItemTest.desktop inode/directory181 }182 else183 {184 $supportedEnvironment = $false185 }186 }187 }188 189 AfterAll {190 if ($IsLinux -and $supportedEnvironment)191 {192 xdg-mime default $mimeDefault inode/directory193 Remove-Item $appFolder/InvokeItemTest.desktop -Force -ErrorAction SilentlyContinue194 Remove-Item $HOME/InvokeItemTest.Success -Force -ErrorAction SilentlyContinue195 }196 }197 198 BeforeEach {199 200 if($IsMacOS)201 {202 Get-Process -Name Finder | Stop-Process -Force203 }204 }205 206 AfterAll{207 if($IsMacOS)208 {209 Stop-ProcessMacOs -Name Finder210 }211 }212 213 214 It "Should invoke a folder without error" -Skip:(!$supportedEnvironment) {215 if ($IsWindows)216 {217 if (Test-IsWindowsArm64) {218 Set-ItResult -Pending -Because "Shell.Application errors with COMException: The server process could not be started because the configured identity is incorrect. Check the username and password."219 }220 221 $shell = New-Object -ComObject "Shell.Application"222 $windows = $shell.Windows()223 224 $before = $windows.Count225 Invoke-Item -Path ~226 # may take time for explorer to open window227 Wait-UntilTrue -sb { $windows.Count -gt $before } -TimeoutInMilliseconds (10*1000) -IntervalInMilliseconds 100 | Should -BeTrue228 $after = $windows.Count229 230 $before + 1 | Should -Be $after231 $item = $windows.Item($after - 1)232 $item.LocationURL | Should -Match ((Resolve-Path ~) -replace '\\', '/')233 ## close the windows explorer234 $item.Quit()235 }236 elseif ($IsLinux)237 {238 # validate on Unix by reassociating default app for directories239 Invoke-Item -Path $PSHOME240 # may take time for handler to start241 Wait-FileToBePresent -File "$HOME/InvokeItemTest.Success" -TimeoutInSeconds 10 -IntervalInMilliseconds 100 | Should -BeTrue242 Get-Content $HOME/InvokeItemTest.Success | Should -Be $PSHOME243 }244 else245 {246 Set-TestInconclusive -Message "AppleScript is not currently reliable on Az Pipelines"247 # validate on MacOS by using AppleScript248 $beforeCount = Get-WindowCountMacOS -Name Finder249 Invoke-Item -Path $PSHOME250 $startTime = Get-Date251 $expectedTitle = Split-Path $PSHOME -Leaf252 $title = [String]::Empty253 while (((Get-Date) - $startTime).TotalSeconds -lt 10 -and ($title -ne $expectedTitle))254 {255 Start-Sleep -Milliseconds 100256 $title = 'tell application "Finder" to get name of front window' | osascript257 }258 $afterCount = [int]('tell application "Finder" to count of windows' | osascript)259 $afterCount | Should -Be ($beforeCount + 1)260 $title | Should -Be $expectedTitle261 'tell application "Finder" to close front window' | osascript262 }263 }264 }265}266 267Describe "Invoke-Item tests on Windows" -Tags "CI","RequireAdminOnWindows" {268 BeforeAll {269 $isNanoServer = [System.Management.Automation.Platform]::IsNanoServer270 $isIot = [System.Management.Automation.Platform]::IsIoT271 $isFullWin = $IsWindows -and !$isNanoServer -and !$isIot272 273 if ($isFullWin) {274 $testfilename = "testfile.!!testext!!"275 $testfilepath = Join-Path $TestDrive $testfilename276 $renamedtestfilename = "renamedtestfile.!!testext!!"277 $renamedtestfilepath = Join-Path $TestDrive $renamedtestfilename278 279 cmd.exe /c assoc .!!testext!!=!!testext!!.FileType | Out-Null280 cmd.exe /c ftype !!testext!!.FileType=cmd.exe /c rename $testfilepath $renamedtestfilename | Out-Null281 }282 }283 284 AfterAll {285 if ($IsWindows) {286 cmd.exe /c assoc !!testext!!=287 cmd.exe /c ftype !!testext!!.FileType=288 }289 }290 291 BeforeEach {292 New-Item $testfilepath -ItemType File | Out-Null293 }294 295 AfterEach {296 Remove-Item $testfilepath -ErrorAction SilentlyContinue297 Remove-Item $renamedtestfilepath -ErrorAction SilentlyContinue298 }299 300 It "Should invoke a file without error on Windows full SKUs" -Skip:(-not $isFullWin) {301 Invoke-Item $testfilepath302 # Waiting subprocess start and rename file303 {304 $startTime = [Datetime]::Now305 while (-not (Test-Path $renamedtestfilepath))306 {307 Start-Sleep -Milliseconds 100308 if (([Datetime]::Now - $startTime) -ge [timespan]"00:00:05") { throw "Timeout exception" }309 }310 } | Should -Not -Throw311 }312 313 It "Should start a file without error on Windows full SKUs" -Skip:(-not $isFullWin) {314 Start-Process $testfilepath -Wait315 Test-Path $renamedtestfilepath | Should -BeTrue316 }317}318 