iT邦幫忙

0

想請問有關用 PowerShell 達成自動化的指令,懇請高手賜教,十分感謝!

  • 分享至 

  • xImage

各位高手,大家午安!
2021年拜讀了「Zero皇」大大的這篇 PowerShell 文章:
https://ithelp.ithome.com.tw/articles/10279723
小弟試著依樣畫葫蘆,把每天早上要做的一件事自動化,不但方便而且還很有成就感...
但自動化的過程中,還是有一些因為才疏學淺而做不到的,上網斷斷續續爬文,始終沒答案。
今天想想,還是來這裡請教各位高手,也許能事半功倍!

我困擾的部份主要發生在 AppActivate 上

TestAppAct.ps1 內容如下:

"測試程序即將於2 秒後啟動,請暫停操作系統"
timeout /t 2

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
#上面應該是呼叫 MS VB 進來

"將 「LINE」 視窗移至前景"
Microsoft.VisualBasic.Interaction::AppActivate("LINE")
#上面有時成功,有時出現錯誤:
以 "1" 引數呼叫 "appactivate" 時發生例外狀況: "找不到處理序 '{0}'。"
位於 H:\TestAppAct.ps1:7 字元:2

" "
"暫停2秒"
Start-Sleep -Seconds 2
" "
"將 「Chrome」 視窗移至前景"
Microsoft.VisualBasic.Interaction::AppActivate("Chrome") #多半成功
" "
"暫停2秒"
Start-Sleep -Seconds 2
" "
"將 「Word」 視窗移至前景" #失敗,在工作到閃動,不會到前景...
Microsoft.VisualBasic.Interaction::AppActivate("Word")
" "
"程序結束,5秒後本視窗將自動關閉"
Start-Sleep -Seconds 5

不知道是不是有更「穩定」的方式(或指令)來將某個執行中的視窗移到前景?

看更多先前的討論...收起先前的討論...
froce iT邦大師 1 級 ‧ 2024-04-15 14:48:03 檢舉
AppActivate 需要這個程式已經啟動,要不然不能執行。你第一個狀況應該就是找不到
解法: try catch去做錯誤捕捉和錯誤處理

第二個原因不明。
terryliu iT邦新手 4 級 ‧ 2024-04-15 14:55:03 檢舉
謝謝 Force 前輩回應,的確 AppActivate 的前提是該程式需要是已經啟動,我測試時也確定 LINE 在執行中;也就是為了比對,我後面才會試試 Chrome 及 Word
這個情境比較適合用PowerAutomate.....真的會比較容易報成
Zero皇 iT邦研究生 3 級 ‧ 2024-04-16 07:43:30 檢舉
嘗試拿process ID試試呢?
[Microsoft.VisualBasic.Interaction]::AppActivate((Get-Process 'WINWORD').ID)
參考https://stackoverflow.com/questions/35679178/appactivate-working-inconsistently-in-powershell
terryliu iT邦新手 4 級 ‧ 2024-04-16 09:18:11 檢舉
謝謝 JaphenChen 前輩回應,我剛剛上網找了一下
PAPAYA 的 YouTube 影片有 Demo 一些例子
我再來研究看看,另一種自動化軟體,謝謝您!
terryliu iT邦新手 4 級 ‧ 2024-04-16 09:21:51 檢舉
哇!邀請 Zero皇 前輩回答,本尊真的出現了!
謝謝您,我來試試用 Get-Process 是否有效...
另外,如果目標視窗是最小化,AppActivate 不能將其還原,想請教是否有解?
謝謝您的回覆!
打錯字,達成,不是報成,哈

power automate 強就強在幾乎不用寫程式,不用在那瞎子摸象
Zero皇 iT邦研究生 3 級 ‧ 2024-04-16 21:37:02 檢舉
對於這些我沒有很熟悉,所以其實不太會回答你的問題,也可以參考留言區的其他大神說的,對於操作UI的自動化有很多比powershell強大的軟體可以用
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

0
mobone
iT邦新手 5 級 ‧ 2024-04-16 11:18:41
最佳解答

稍微打一下程式,你在自己按照需求修改就好了

Add-Type @"
    using System;
    using System.Runtime.InteropServices;

    public class User32 {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
    }
"@
#使用WinAPI來讓視窗達到最大化跟前台顯示
#https://learn.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-showwindow
#https://learn.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-setforegroundwindow

##等待Line啟動
do{
    if ((Get-Process -Name "Line" -WarningAction SilentlyContinue |measure).Count >0){
        Write-Host ("偵測到有LINE出現");
        break;
    }
}while($true)

##下一步偵測有沒有在前景執行
if (((Get-Process -Name "Line").MainWindowTitle).Length==0){
    #沒有在前台執行,再次執行APP,並且等待LINE前台執行成功
    Start-Process  -Wait  "Line的程式路徑"
    #如果預設在appdata底下,可用 Start-Process  -Wait ($env:LOCALAPPDATA+"\LINE\bin\LineLauncher.exe")
    #下方為確認LINE有執行出來
    do{
        if (((Get-Process -Name "Line").MainWindowTitle).Length>0){
            break
        }
    }while($true)
}

#Word視窗狀況調整
$WORD = Get-Process -Name "WINWORD" -WarningAction SilentlyContinue
if ($WORD -ne $null){
    $hwnd = $WORD.MainWindowHandle
    ##讓視窗放大
    [User32]::ShowWindow($hwnd, 3)
    ##讓視窗在前面
    [User32]::SetForegroundWindow($hwnd)
}

備註:Line縮小到工作表(Tray),跟WORD縮小到工作表(TaskBar),兩種程式狀態啟動到前台的方式不一樣。

看更多先前的回應...收起先前的回應...
terryliu iT邦新手 4 級 ‧ 2024-04-17 12:59:00 檢舉

Dear mobone前輩,謝謝您的回應,我照您的指點試了;但在第一關就卡住了,我加了一些提示當「執行指標」,請您幫忙看一下,是不是有哪裡要修改?(卡在檢查 LINE 是否啟動)
程式如下: (TestAppAct2.ps1)

"測試程序即將於2 秒後啟動,請暫停操作系統"
timeout /t 2
" "
Add-Type @"
using System;
using System.Runtime.InteropServices;

public class User32 {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetForegroundWindow(IntPtr hWnd);
}

"@
" "
"使用「WinAPI」來讓視窗達到最大化跟前台顯示"
" "
#參考: https://learn.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-showwindow
#參考: https://learn.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-setforegroundwindow

"步驟一,檢查 LINE 是否已啟動?"
do{
if ((Get-Process -Name "Line" -WarningAction SilentlyContinue |measure).Count >0){
Write-Host ("偵測到有LINE出現");
break;
}
}while($true)
" "
Pause
" "
"下一步偵測有沒有在前景執行,若否,則啟動 LINE"
if (((Get-Process -Name "Line").MainWindowTitle).Length==0){
#沒有在前台執行,再次執行APP,並且等待LINE前台執行成功
"$env:LOCALAPPDATA"
Start-Process -Wait ($env:LOCALAPPDATA+"\LINE\bin\LineLauncher.exe")
#如果預設在appdata底下,可用 Start-Process -Wait ($env:LOCALAPPDATA+"\LINE\bin\LineLauncher.exe")
#C:\Users\TeRRy\AppData\Local\LINE\bin

#下方為確認LINE有執行出來
do{
    if (((Get-Process -Name "Line").MainWindowTitle).Length>0){
        break
    }
}while($true)

}

#Word視窗狀況調整
$WORD = Get-Process -Name "WINWORD" -WarningAction SilentlyContinue
if ($WORD -ne $null){
$hwnd = $WORD.MainWindowHandle
##讓視窗放大
[User32]::ShowWindow($hwnd, 3)
##讓視窗在前面
[User32]::SetForegroundWindow($hwnd)
}

Pause
" "
"程序結束,5秒後本視窗將自動關閉"
Start-Sleep -Seconds 5

terryliu iT邦新手 4 級 ‧ 2024-04-17 13:27:11 檢舉

P.S. 程式執行時,有一個現象,在 TestAppAct2.ps1 資料夾中,會自動新增一個檔案,檔名是「0」,大小是 0 byte

terryliu iT邦新手 4 級 ‧ 2024-04-17 14:02:34 檢舉

Dear mobone 前輩:
我也單獨試了一下 WORD 的部份,如果 WORD 沒執行會報錯(正常)
如果WORD「最小化」或是「還原」,它會變成「最大化」
如果小弟只是希望它「還原」,請問指令應如何修改呢?

mobone iT邦新手 5 級 ‧ 2024-04-17 16:01:49 檢舉

你要不要把你的程式碼丟到github上我在幫你確認,在留言這邊看有點亂

mobone iT邦新手 5 級 ‧ 2024-04-17 16:03:42 檢舉

如果你沒有git 你就丟到google文件分享給我看

mobone iT邦新手 5 級 ‧ 2024-04-17 16:12:32 檢舉

可參考備註的nf-winuser-showwindow的網址,內有寫到
1為還原2為最小3為最大,
[User32]::ShowWindow($hwnd, 3)
把數字3改掉就好

mobone iT邦新手 5 級 ‧ 2024-04-17 16:14:28 檢舉

你先開起LINE,然後打這行指令在PS內是否有顯示
Get-Process -Name "line"
正常應該有1個以上才對

mobone iT邦新手 5 級 ‧ 2024-04-17 18:04:12 檢舉

https://github.com/moboneOnIT/Questions10215516/blob/main/ithelp.ps1
剛剛下班後稍微修改成func模式你應該會比較好用,你可以參考看看

terryliu iT邦新手 4 級 ‧ 2024-04-18 09:20:56 檢舉

謝謝 mobone 前輩,
慚愧!慚愧!
[User32]::ShowWindow($hwnd, 3) 我只試了2
因為我猜「1為最小、2為還原、3為最大」 (猜錯...)

mobone iT邦新手 5 級 ‧ 2024-04-18 11:07:24 檢舉

那個數字你要參照微軟的資料,
https://learn.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-showwindow#parameters
我也沒全部講解完就是了

terryliu iT邦新手 4 級 ‧ 2024-04-18 11:20:16 檢舉

有,試了 Get-Process -Name "line"
回報有1個 LINE

mobone iT邦新手 5 級 ‧ 2024-04-18 11:35:02 檢舉

那你現在就看你要用哪種叫出來的模式,下面有兩種
ShowAppFromTaskBar "EXE名稱" 模式數字 #從工作表叫出
ShowAppFromTray "EXE名稱" 模式數字 #從右下角小圖區域叫出

mobone iT邦新手 5 級 ‧ 2024-04-18 11:35:29 檢舉

我上面GIT裡面的程式碼記得要copy進去你的ps1內

terryliu iT邦新手 4 級 ‧ 2024-04-18 22:15:53 檢舉

Dear mobone前輩,謝謝您的回應!
我試了一下,有把您的程式加入到我的ps1檔案中了
整合及測試完成再回覆您,謝謝您寶貴的時間!
先將您的回覆設為最佳解法,感謝您,也謝謝其他前輩們的幫忙!

mobone iT邦新手 5 級 ‧ 2024-04-19 21:04:05 檢舉

有問題再問沒問題,我看到我會回答的

terryliu iT邦新手 4 級 ‧ 2024-04-29 23:37:46 檢舉

Dear mobone 前輩:
又來請教您了,請問您上次賜教的這一段,用意是什麼?

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class User32 {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"@

再麻煩您如果看到,撥冗回覆小弟,謝謝您!

我要發表回答

立即登入回答