捐血一袋救人一命

江蘇拙政園

江蘇 拙政園

全家福

日本 和歌山城

賞楓之旅

千燈 夕照

水鄉千燈

蘆洲 微風運河

破曉時分

2021年2月18日 星期四

使用 PowerShell 讀取 Synology NAS LDAP Server

網路上查到的PowerShell 讀取 LDAP 資訊,幾乎清一色都是讀取 Active Directory....

很少講到如何讀取 Linux LDAP Server

找了好久,終於找到 C# 讀取 LDAP 的資訊,改成 PowerShell 

使用 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 才成功。

2020年12月3日 星期四

使用 PowerShell 對文字進行Escape編碼、Unescape解碼

 這個編碼解碼結果,與 JavaScript Escape() 及 Unescape() 相同

 

$Original = '“Instead of going back to business as usual, Uber is taking this moment as an opportunity to reduce our environmental impact.” The company said in a press release.[p]Uber 在新聞稿中表示:「Uber並沒有像往常一樣重返市場,而是以此為契機,減少對環境的影響。」'

$Encode = ""

$Alphabet = @(42,43,45,46,47,48,49,50,51,52,53,54,55,56,57,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,95,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122)

$Symbol = @(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,44,58,59,60,61,62,63,91,92,93,94,96,123,124,125,126,127)

# 編碼文字

for($i = 0; $i -lt $Original.Length; $i++){

    If($([int]$($Original[$i])) -in $Alphabet){

        $Encode += $Original[$i]

    }ElseIf($([int]$($Original[$i])) -in $Symbol){

        $Encode += [System.String]::Format("%{0:X2}", [int]$Original[$i])

    }Else{

        $Encode += [System.String]::Format("%u{0:X4}", [int]$Original[$i])

    }

}

Write-host $Encode

Write-Host "`r`n"

# 還原文字

Add-Type -AssemblyName System.Web

[System.Web.HttpUtility]::UrlDecode($Encode)

使用 PowerShell 讀取 GMail 摘要 RSS

使用 PowerShell 讀取 GMail 信箱資訊,需要先設定應用程式密碼,包括使用 Outlook或是使用Windows 10內建的 Mail 程式收發郵件。

 或是想要讓事物機把掃描產生的圖檔,以電子郵件寄出,也需要設定應用程式密碼。

紅字部分,請自行更換成適當的資訊喔

Clear-Host

# 讀取 GMail Samples

$webclient = new-object System.Net.WebClient

 

# 這裡輸入的密碼,是 Application Password (應用程式密碼)

# 如何產生 Application Password (應用程式密碼)

# https://support.google.com/mail/answer/185833?hl=tw

$webclient.Credentials = new-object System.Net.NetworkCredential ("my@email.address", "MyApplicationPassword")

 之前使用 .DownloadString Method,會發現中文字都被破壞掉,所以改用 .DownloadData

# 下載 RSS,這裡得到的是一堆十進位數字的陣列,Unicode 文字是三組大於127的10進位數字

$xml= $webclient.DownloadData("https://mail.google.com/mail/feed/atom")

 


 所以,接下來就是要將變數 $xml 的資訊轉換成文字(包含 Unicode)

$s = ""

For($l=0;$l -lt $xml.Count; $l++){

    If($xml[$l] -gt 127){ # 當數值大於 127,表示是 Unicode,所以轉換成16進位格式字串

        $s += "%" + $xml[$l].ToString('x2')

    }Else{ # 小於等於 127 ,就直接轉成 Ascii 字元

        $s += [char]$xml[$l]

    }

}

# 將 Unicode 編碼進行解碼,還原成中文字

$xml = ([URI]::UnescapeDataString($s))


 

這樣 $xml 就變成 XML 格式的字串了

# 輸出成 XML 檔案

$xml | Out-File -FilePath "D:\test.xml" -Encoding utf8

 

接下來要解析 XML內容,分欄顯示

# 雖然字串是 XML 格式,但不代表變數是 XML 型態,所以要進行轉換型態

$xml = [xml]$xml

 

# 設定 Format-Table 要輸出的格式

$format= @{Expression={$_.author.name};Label="Name"},

         @{Expression={"|"};Label="|"},

         @{Expression={$_.author.email};Label="E-Mail"},

         @{Expression={"|"};Label="|"},

         @{Expression={$_.title};Label="Title"},

         @{Expression={"|"};Label="|"},

         #@{Expression={$_.link|Select 'href'};Label="Link"},

         # 當你使用瀏覽器開啟 Link 的連結,就會直接讀取該郵件

         @{Expression={$_.link|Select-XML -XPath "@href"};Label="Link"},

         @{Expression={"|"};Label="|"},

         @{Expression={$_.summary};Label="summary"}

# 輸出成 Table ,缺點是過長的欄位資訊就不會出現

$xml.feed.entry | format-table $format

 


 

再來就是將 XML 內容,轉換成簡單的 HTML 檔案

# 所以底下將 XML 資訊轉換成 HTML 表格

$mail = @()

$xml.feed.entry | ForEach {

    $hash = @{

        "name" = $_.author.name

        "email" = $_.author.email

        "title" = $_.title

        "link" = ($_.link|Select-XML -XPath "@href")

        "summary" = $_.summary

    }

    $Line = New-Object -TypeName PSObject -Property $Hash

    $mail += $Line

}

$mail | ConvertTo-Html | Out-File -FilePath "D:\testxml.html" -Encoding oem

 


 

 

 

 

2020年12月2日 星期三

使用PowerShell 呼叫 ffmpeg,將串流影片合併起來,並轉換成 MP4 格式

 串流影片,就是將原始影片切分成多個小影片 *.ts,然後將多個小影片寫在一個清單檔案 *.m3u8檔案

 

當你辛苦下載了每個 .ts 影片,想要合併所有檔案,以便管理,可以使用ffmpeg來處理。

合併所有 .ts 檔案之後,要再轉換成普遍的mp4格式,也還是使用ffmpeg 來處理。

 

紅字部分,請自行評估環境修改

# 要讓產生的字串帶有雙引號括起來,是因為路徑有可能包含空白

# 如果不用雙引號括起來,後面程式會發生錯誤

$ffmpeg = """C:\Users\User\Desktop\ffmpeg-4.1.4-win64-static\bin\ffmpeg.exe"""

# 目錄不要用中文,ffmpeg 會不認得

$Root = "D:\[tts 影片存放的目錄路徑]"

If(Test-Path -Path "$Root\list.txt"){

    Remove-Item -Path "$Root\list.txt"

}

# 輸出檔案格式一定要是 utf8 (with no BOM),不然 ffmpeg 會找不到檔案

Get-ChildItem -Path $Root -Filter *.ts | Sort-Object -Property Name | ForEach{

    "file '$Root\$_'" | Out-File -FilePath "$Root\list.txt" -Append -Encoding oem

}

Write-Host "Combine Files.... Please Wait"

# 如果有設定路徑,就需要加 -safe 0 參數

$CombineArgu = "-f concat -safe 0 -i ""{0}\list.txt"" -c copy ""{0}\Combine.ts""" -f $Root

Write-Host "$ffmpeg $CombineArgu" -ForegroundColor Red

Start-Process -FilePath $ffmpeg -ArgumentList $CombineArgu -Wait -WindowStyle Normal -WorkingDirectory $Root

 

Write-Host "Convert Files.... Please Wait"

$ConvertArgu = "-i ""{0}\Combine.ts"" -acodec copy -vcodec copy ""{0}\Combine.mp4""" -f $Root

Write-Host "$ffmpeg $ConvertArgu" -ForegroundColor Red

Start-Process -FilePath $ffmpeg -ArgumentList $ConvertArgu -Wait -WindowStyle Hidden -WorkingDirectory $Root

 

2020年12月1日 星期二

用 Powershell 使用 Google Cloud Text to Speech API 服務

程式主要有兩個部分

1. 驗證(擇一)

l 使用 Service Account 方法

n 在GCP Console設定服務帳號之後,產生金鑰檔,並下載金鑰檔

l 使用 API Key 方法

n 設定可使用 API Key 的 IP清單,以及可使用的 API服務項目

2. 傳送文字設定資料,並取得音效資料進行處理

 

Google Cloud Text to Speech API 服務是要收費的,所以需要經過驗證

使用 Service Account

# 載入 Google Cloud SDK 的 GoogleCloud Module for PowerShell
Import-Module GoogleCloud
# 設定 GAC 環境變數,指定服務金鑰檔案路徑
$env:GOOGLE_APPLICATION_CREDENTIALS = "D:\完整金鑰路徑檔名.json"
# 讀取金鑰後產生隨機的認證碼
$gauth = gcloud auth application-default print-access-token
# 將認證碼加到 header hashtable
$headers = @{"Authorization", "Bearer $gauth"}
$url = "https://texttospeech.googleapis.com/v1/text:synthesize" 
# ContentType 指定說明傳輸的資料格式是 JSON,編碼是 utf-8
$response = Invoke-RestMethod -ContentType 'application/json;charset=utf-8' -headers $headers -Uri $url -Method Post -body $JSON

使用 API Key

# 就是在 API 網址後面增加 Key參數

$url = "https://texttospeech.googleapis.com/v1/text:synthesize?key=你的金鑰字串"

# ContentType 指定說明傳輸的資料格式是 JSON,編碼是 utf-8

$response = Invoke-RestMethod -ContentType 'application/json;charset=utf-8' -headers $headers -Uri $url -Method Post -body $JSON

使用 API Key 程式會簡單很多,而且不用安裝 Google Cloud Library or Cloud SDK等
但是要記得設定允許使用此金鑰的 IP及服務,以確保資訊安全

 

接下來就是將文字及設定資訊傳送給Google Cloud Text to Speech API

格式一定要照規矩來,不然API會回覆錯誤

$content = "你想要讓 Google Text to Speech 唸出來的文字"

$AudioEncoding = "MP3"

$LanguageCode = "cmn-TW"

$VoiceName = "$LanguageCode-Wavenet-A"

$Effect="large-home-entertainment-class-device"

 

$JSON = @{

    audioConfig = @{

        audioEncoding = $AudioEncoding;

        effectsProfileId = $Effect;

        pitch = 0;

        speakingRate = 0.9;  # speakingRate = 0.25 ~ 4.0

        volume_gain_db = +6;  # volume_gain_db = -96.0 ~ 16.0

    };

    input = @{

    };

    voice = @{

        languageCode = $LanguageCode;

        name = $VoiceName;

    }

}

 

# 如果 Content 不是使用 SSML XML 格式, input 裡的 key 就必須使用 text

# 如果 Content 使用 SSML XML 格式, input 裡的 key 就必須使用 ssml

# 所以用程式來判斷 key 是要用 text or ssml

If($content -match [regex]"^\<speak\>" -AND $content -match [regex]"\<\/speak\>$"){

    $body.input.Add("ssml",$content)

}Else{

    $body.input.Add("text", $content)

}

 

$JSON = ConvertTo-Json ($JSON)

 

Try{

    # Content Type 除了要告知是 JSON 資料之外,還要加上 charset=utf-8,不然只會唸中文字串中的數字

    $response = Invoke-RestMethod -ContentType 'application/json;charset=utf-8' -headers $headers -Uri $target -Method Post -body $JSON

    # 回傳的 Audio Data 是 Base64 編碼的

    $base64Audio = $response.audioContent

 

# 讀取系統環境變數,取得桌面路徑

$Dest = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Desktop)

 

    # 在桌面產生 PlayTTS.html 網頁檔案(語音資料以 Data URI  方式內嵌在網頁裡)

    "<html><head><title>Providing HTML5 audio with a base64 encoded Data URI as source</title><meta charset='utf-8'></head><body><h1>Providing HTML5 audio with a base64 encoded Data URI as source</h1><audio controls='' src='data:audio/ogg;base64,{0}'></audio></body></html>" -f $base64Audio | Out-File -FilePath "$Dest\PlayTTS.html" -Encoding oem

 

    # 使用系統預設關聯,呼叫預設瀏覽器開啟網頁檔案,不需要任何外掛JS,即可播放

    & "$Dest\PlayTTS.html"

 

    # 將 Base64 Audio Data 存成文字檔

$base64Audio | Out-File -FilePath "./google.txt" -Encoding ascii -Force

 

# 設定音效檔檔名

$convertedFileName = 'PlayTTS-{0}.mp3' -f (get-date -f yyyy-MM-dd-hh-mm-ss)

 

# 呼叫 Windows 內建 certutil.exe 將 Base64 編碼檔案解碼,檔案輸出到桌面

certutil -decode google.txt "$Dest\$convertedFileName"

 

# 開啟檔案總管,並選取輸出的音效檔

Start-Process -FilePath "$($env:WinDir)\explorer.exe" -ArgumentList "/select, $Dest\$convertedFileName"

 

}Catch {

    # 如果 Request 發生錯誤,就印出錯誤碼

    Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__

    Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription

}

 

audioConfig 參考資料

SSML 參考資料

2020年11月23日 星期一

使用 PowerShell 呼叫 ffmpeg,將多個 .ts 檔案合併,並轉換成 mp4 影片

使用 PowerShell 呼叫 ffmpeg,將多個 .ts 檔案合併,並轉換成 mp4 影片