捐血一袋救人一命

2021年2月18日 星期四

使用 PowerShell 批次執行 IE ,自動登入 Synology NAS

這次會想寫這個程式,是因為公司打算將 G Workspace 轉移到 Synology NAS

公司本來也沒有使用 AD or LDAP 做驗證,打算將帳號整合到 LDAP 做未來準備。

轉移郵件的功能 MailPlus 本身的功能就很完整,不需要太多操心

但是Synology Drive 卻沒辦法自動批次轉移全公司的 Google Drive!

使用Cloud Sync ,必須讓使用者自行操作,也沒辦法限制使用者只能加入指定的 Google Workspace

幸運的是,Synology Active Backup for G Suite可以將全部使用者的Google Drive 都備份下來,只要把使用者備份檔案複製到使用者家目錄,就可以正常在Synology Drive 使用。

只是因為整合了 LDAP 驗證,所以家目錄變成 "帳號-LDAP uidNumber" 這樣的格式。

手動去建立家目錄也很麻煩(一兩百個帳號),用PowerShell 讀取 LDAP 也有點麻煩,所以最簡單的方法就是使用者登入Synology NAS,Synology NAS 會自動建立家目錄。

以下不多說,就直接看程式吧

之前在每個 Page 變動後,都去偵測 $ie.ReadyState = 4 或是 $ie.Busy = $False 程式才繼續執行,都會發生錯誤

後來改成檢查 $ie.Document.getElementById('ext-gen84') 是否為物件也會誤判

再改成檢查 $ie.Document.getElementById('ext-gen84') 是否存在,也還是會誤判

最後改成判斷 $ie.Document.getElementById('ext-gen84')的 Type 才成功。

# 指定 帳號清單的 csv 檔案
# 格式:"信箱","家目錄","帳號","密碼"
Clear-Host
$Error.Clear()
Remove-Variable * -ErrorAction SilentlyContinue

$List = Get-ChildItem -Path "$PSScriptRoot\AccountList-*.csv" | Sort-Object -Property name -Descending | Select-Object -First 1
$Count  = 0

# Synology NAS 的登入頁面網址
$Login = "http://192.168.1.123:5000/"

Get-Content -Path $List.FullName | ForEach{
    $Count++
    $Line = $_
    # 取得四欄資料
    $fields = $Line -split ","
    $EMail = $fields[0]
    $UserHome = $fields[1]
    $account = $fields[2]
    $password = $fields[3] -replace [regex]"`r`n",""
    # 顯示目前處理的帳號資訊
    $msg = "{0:000} {1} {2}" -f $Count, $account, $password 
    Write-Host $msg

    # 使用 COM 物件呼叫 IE (Chrome 沒有 COM 物件,所以這個方法不適用 Chrome.exe)
    $ie = New-Object -com "InternetExplorer.Application"
    #$ie.Navigate("about:blank")
    $ie.Visible = $True
    
    $ie.Navigate($Login)
    
    # 設定 IE 視窗位置及大小
    # 您可以先用程式開啟 IE 之後,將 IE 視窗調整到你喜歡的位置,再去讀取Left, Top, Width, Height 等屬性
    # 然後將數值寫在程式中
    $ie.Left = -8
    $ie.Top = -8
    $ie.Width = 1296
    $ie.Height = 1056
    
    # 等待 DOM Ready,才能進行 Javascript 相關指令操作
    Do{ 
        #"$($ie.ReadyState) $($ie.Busy)"; 
        Start-Sleep -Milliseconds 100 
    }While($ie.ReadyState -ne 4)

    
    # 如果前一個使用者沒登出,就會停在登入畫面;如果找到登出 Button,就按下登出鈕
    # 雖然 瀏覽器 ReadyState = 4 或是 Busy = $False,但是  JScript Engine/COM Object/DOM 似乎都不一定 Ready
    # 單純只判斷 $ie.Document.getElementById('ext-gen84') 是否存在或者是否為物件都會有誤判機率發生
# 一定要確認該元素的 Type 不等於 "DBNull"
    If((($ie.Document.getElementById('ext-gen84')).GetType()).Name -ne "DBNull"){
        $ie.Document.getElementById("ext-gen84").click()
    }

    # 等待登入畫面的登入鈕出現,而且 Type 不等於 DBNull 才能繼續下去
    Do{
        Start-Sleep -Milliseconds 100
    }While((($ie.Document.getElementById('ext-gen47')).GetType()).Name -eq "DBNull")

    # 自動填入帳號密碼,並按下登入鈕
    $ie.Document.getElementById("login_username").value = $account
    $ie.Document.getElementById("login_passwd").value = $password
    $ie.Document.getElementById("ext-gen47").click()

    # 等待登出鈕出現,而且 Type 不等於 DBNull 才能繼續下去
    Do{
        Start-Sleep -Milliseconds 100
    }While((($ie.Document.getElementById('ext-gen84')).GetType()).Name -eq "DBNull")  

    # 按下登出鈕
    $ie.Document.getElementById("ext-gen84").click()

# 等待登入畫面的登入鈕出現,而且 Type 不等於 DBNull ,才算完成登出
    Do{
        Start-Sleep -Milliseconds 100
    }While((($ie.Document.getElementById('ext-gen47')).GetType()).Name -eq "DBNull")

    # 結束 IE
    $ie.Quit()
    # 清除變數 ie
    Remove-Variable ie, account, password
}



$LoginURL = "http://192.168.1.123:5000"
$login = Invoke-WebRequest -Uri $LoginURL -WebSession $synology

    $PostParams = @{username="$account";passwd="$password"}
    $Method = $login.Forms['login-form'].Method
    $Action = $login.Forms['login-form'].Action

    $Content = Invoke-WebRequest -Uri "$LoginURL/$Action" -Body $PostParams -Method $Method -WebSession $synology

    $C = Invoke-WebRequest -Uri "$LoginURL/webapi/encryption.cgi" -Body $PostParams -Method Post -WebSession $synology

    $D = Invoke-WebRequest -Uri "$LoginURL/webman/login.cgi?enable_syno_token=yes" -Body $PostParams -Method Post -WebSession $synology
    $Token = ($D.Content | ConvertFrom-Json).SynoToken

    $Entry = "$LoginURL/webapi/entry.cgi?api=SYNO.Core.Desktop.Defs&version=1&method=getjs&SynoToken={0}&v=1614173144" -f $Token
    $E = Invoke-WebRequest -Uri $Entry  -Method Get -WebSession $synology
    $E.RawContent

使用 Invoke-WebRequest 可以登入 Synology NAS,但是不會觸發 DSM 自動建立使用者家目錄,歡迎大家來討論

0 意見: