捐血一袋救人一命

江蘇拙政園

江蘇 拙政園

全家福

日本 和歌山城

賞楓之旅

千燈 夕照

水鄉千燈

蘆洲 微風運河

破曉時分

2024年4月2日 星期二

VMware Workstation 與 Hyper-V 混合環境

VMware Workstation 與 Hyper-V 共存於 Windows 10 Pro x64 上的奇異狀況

VMware Workstation 要與 Hyper-V 共存於 Windows 10 Pro x64 上需要一番設定

但我今天不是要講這個設定,而是講網路的奇怪狀況

我建立了一個 Ubuntu Desktop Guest,採用 Bridge 模式。
然後看到 Ubuntu Desktop 也取得了與 Win 10 Pro 同網段的 IP Address

這台 Ubuntu Desktop 可以連接到網路上任何其他的電腦,唯獨無法連接到 Win 10 Host。

  1. Ubuntu Desktop Guest 與 Win10 Pro Host互 ping 不到
  2. Ubuntu Desktop ufw/iptables 都沒有設定啟用
  3. Win 10 Pro 防火牆的 ping 規則也有啟用

檢查 VMware Virtual Network Editor 的網路設定,看到 VMnet0 Type Bridge Bridged to 我的 Win 10 Pro 實體網卡名稱 Realtek PCIe GbE Family Controller 看起來也沒錯

突然心血來潮,在命令提示字元下,執行 ipconfig /all
檢查 IP 設定,卻發現Win 10 Pro 取得 DHCP 的網卡是 Hyper-V Virtual Ethernet Adapter #4
而 Realtek PCIe GbE Family Controller 的 IP 卻是 169.254.199.175…

然後我在 VMware Virtual Network Editor 調整 Bridged to Hyper-V Virtual Ethernet Adapter #4 之後,Ubuntu Desktop Guest 與 Win10 Pro x64 就可以正常互連了

至於 Hyper-V Virtual Ethernet Adapter #4 虛擬網卡是如何喧賓奪主,搶走 Realtek PCIe GbE Family Controller 實體網卡的 IP,就不得而知了

rsync

rsync 使用簡介

功能簡介:

Linux中的rsync(remote sync)是一個用於在本地系統之間或本地系統和遠程系統之間同步文件和目錄的強大工具。它可以在局域網中高效地傳輸大量數據,並且具有許多功能,使得文件同步和備份變得非常方便。

特點和用途:

  1. 增量備份:rsync可以將文件和目錄從源同步到目標,僅傳輸已更改或新增的部分,這種增量備份方式大大節省了帶寬和時間。
  2. 遠程同步:rsync支持通過SSH等協議在本地和遠程系統之間同步文件和目錄,這使得在不同主機之間進行文件同步變得非常方便。
  3. 保留文件屬性:rsync可以保留文件的屬性,包括權限、時間戳和所有者等信息。
  4. 多種選項:rsync具有多種選項,可以根據需要進行配置,例如遞歸同步、壓縮傳輸、忽略特定文件等。
  5. 傳輸加密:通過使用SSH等加密協議,rsync可以確保在本地和遠程系統之間的安全傳輸。

參數說明:

-a:表示以遞歸方式同步目錄,保留所有檔案屬性。
-v:表示輸出詳細信息,讓您可以看到正在複製的文件。
-z:表示在傳輸過程中壓縮檔案,以節省頻寬。
-h:表示以人類可讀的格式輸出信息。
-e “ssh”:指定使用SSH加密協議。
–ignore-existing:表示在目標目錄中忽略已經存在的文件,不再複製。
–bwlimit:指定一個限制,以Bytes為單位,指定每秒允許的最大傳輸速率。
–delete:刪除目的端不存在於原始路徑的檔案。
–remove-source-files:在成功搬移檔案後,從原始路徑中刪除這些檔案。

指令範例:

List=`ls -ld /volume1/Class/*[0-9] | awk -F' ' '{print $9}'`
for Path in $List; do rsync -avzh --ignore-existing /path/to/source/directory/* user@linux_b_server:/path/to/destination/directory/; done

2024年3月23日 星期六

Powershell 變數特性

Power shell 是一個弱型別的 Script Language

不需要宣告,變數存甚麼,就是甚麼型態

$a="123"
$a.GetType()

$a = 456
$a.GetType()

Result:

IsPublic IsSerial Name    BaseType                              
-------- -------- ----    --------                              
True     True     String  System.Object                         
True     True     Int32   System.ValueType

要注意的是,變數初始值設定的方法

$a, $b = 1, 2 ,3

Result:

$a = 1      # 數值
$b = 2, 3   # 是陣列

function abc{
    return 1,"A","C"
}

$a, $b = abc
$a.GetType()
$b.GetType()

Result:

IsPublic IsSerial Name       BaseType                              
-------- -------- ----       --------                              
True     True     Int32      System.ValueType                      
True     True     Object[]   System.Array 

一個變數在沒有使用之前,變數等於 $null

Clear-Host
Remove-Variable * -ErrorAction SilentlyContinue

$var -eq $null
$var = 3
$var -eq $null
Clear-Variable var
$var -eq $null

Result:

True
False
True

Powershell 變數型態_String

Powershell 的字串,可以使用對稱的 雙引號,或是單引號

* 如果字串本身包含大括號 { 或 },就要改成 {{ 或 }}
* 如果字串本身有雙引號,就要使用 Double 雙引號 ""
* 如果字串本身有單引號,就要使用 Double 單引號 ''
* 經過格式化字串之後,得到的資料型態為字串
* 如果字串本身有 $,請使用 Double $ 或是跳脫字元 `
* 如果字串本身有 `,請使用 Double `
* 如果字串中要輸出跳行,請使用 `r`n
* 如果字串中要輸出TAB,請使用 `t

例如:

"他的外號叫做""豬頭"""

Result:

他的外號叫做"豬頭"

格式化字串

格式化字串的方法

第一種方式,字串中夾變數

$age = 52
"我的年齡是 $age 歲"

Result:

我的年齡是 52 歲

第二種方式

"格式字串" -f 參數

第三種方法

[string]::format("格式字串", 參數)

數值格式化字串

代號 說明
#
nm m 表示小數位數,不足會補零對齊
dm m 表示數值位數,不足的位數會補零

"{0:n2}" -f 123.5
"{0:n2}" -f 3.14

Result:

123.50
3.14

"{0:d2}" -f 123
"{0:d2}" -f 1

Result:

123
01

"{0:0##,###.#0}" -f 12345.5
"{0:0##,###.#0}" -f 123456.7
"{0:0##,###.#0}" -f 1234567.579

Result:

  • 整數位數,不足會補零
  • 小數位數,不足會補零
  • 小數位數超過的,會四捨五入
012,345.50
123,456.70
1,234,567.58

日期型態資料的格式化字串

代號 說明
y yyyy年MM月
yy yy 兩位數西元年
yyyy yyyy 四位數西元年
M MM月dd日
MM MM 兩位數月份,不足兩位數,前面會補0
d yyyy/MM/dd
dd dd 兩位數日期,不足兩位數,前面會補0
hh 兩位數12小時制(不足兩位數,前面會補0)不會顯示 AM/PM 或上午/下午
HH 兩位數24小時制(不足兩位數,前面會補0)
mm 兩位數分鐘(不足兩位數,前面會補0)
s yyyy-MM-ddTHH:mm:ss
ss 兩位數秒(不足兩位數,前面會補0)
f yyyy年M月dd日 上午/下午 hh:mm
ff 兩位數毫秒
fff 三位數毫秒
ddd 周一、周二、周三…
dddd 星期一、星期二、星期三…

小百岳

小百岳列表

編號 山名 縣市別 鄉鎮市區別 別名 難度 座標 標高(m) 備註
1 大屯山 台北市、新北市 北投區、淡水區 1.3 1092
2 七星山 台北市 北投區 1.4 1120
3 大武崙山 基隆市 安樂區 砲台山 0.6 231 近中山區界
4 槓子寮山 基隆市 中正區 槓子寮砲台 0.1 25.143730986822487, 121.7819003870428 163
5 觀音山 新北市 八里區 硬漢嶺 1.5 25.135933897405756, 121.42666847085579 616 2023/11/19已達成
6 基隆山 新北市 瑞芳區 大肚美人山 0.9 588
7 紅淡山 基隆市 仁愛區 0.8 210
8 大崙頭山 台北市 士林區、內湖區 0.3 478
9 劍潭山 台北市 士林區 0.3 153 2024/01/27已達成
10 五分山 新北市 瑞芳區、平溪區 0.1 757
11 姜子寮山 基隆市 七堵區 三角架山 0.9 729
12 汐止大尖山 新北市 汐止區 0.5 460
13 南港山 台北市 信義區、南港區 0.8 375 2024/01/20已達成
14 土庫岳 新北市 深坑區 大坪山 0.2 389 近南港區界
15 大棟山 新北市、桃園市 樹林區、龜山區 1.2(0) 405
16 南勢角山 新北市 中和區、新店區 風爐塞山 2.1 302
17 二格山 台北市、新北市 文山區、石碇區 石尖山 2.4 678[1]
18 天上山 新北市 土城區 皇帝山 0.4 429
19 福德坑山 新北市 三峽區 鳶山 0.3 321 並非標高300公尺之鳶山
20 獅仔頭山 新北市 新店區、三峽區 1.7 858
21 金面山 桃園市 大溪區 鳥嘴尖 1.4 667
22 東眼山 新北市、桃園市 三峽區、復興區 0.7 1212 2024/02/03已達成
23 溪洲山 桃園市 大溪區 1.8 577
24 石門山 桃園市 龍潭區 小竹坑山 1.6 551
25 石牛山 桃園市、新竹縣 復興區、關西鎮 1.5 671
26 十八尖山 新竹市 東區 0.1 130
27 飛鳳山 新竹縣 芎林鄉 中坑山 1.7 462 非423m的飛鳳山,而是二等三角點的中坑山
28 李崠山 桃園市、新竹縣 復興區、尖石鄉 李棟山 1.2 1914
29 獅頭山 苗栗縣 三灣鄉、南庄鄉 0.3 492
30 五指山 新竹縣 竹東鎮、北埔鄉、五峰鄉 1.8 1062
31 鵝公髻山 新竹縣、苗栗縣 五峰鄉、南庄鄉 1.8 1579
32 向天湖山 苗栗縣 南庄鄉 1.9 1225
33 仙山 苗栗縣 獅潭鄉 紅毛館山 0.5 967
34 加里山 苗栗縣 南庄鄉、泰安鄉 加里仙山 2.4 2210 台灣富士山,注意可能有高山症
35 火炎山 苗栗縣 苑裡鎮、三義鄉 1.7 596
36 關刀山 苗栗縣 三義鄉、大湖鄉 1 889
37 馬那邦山 苗栗縣 大湖鄉、泰安鄉 馬拉邦山 2 1407 近卓蘭鎮界
38 鐵砧山 台中市 外埔區 0.2 236 跨大甲區境
39 稍來山 台中市 和平區 0.7 2307 注意可能有高山症
40 聚興山 台中市 潭子區 0.8 500
41 頭嵙山 台中市 北屯區、新社區 0.7 859
42 南觀音山 台中市 北屯區 0.3 318
43 三汀山 台中市 太平區 1.5 480
44 暗影山 台中市 太平區 酒桶山 1 997
45 大橫屏山 台中市、南投縣 太平區、國姓鄉 2.1 1205
46 阿罩霧山 台中市 霧峰區 0.1 249
47 九份二山 南投縣 中寮鄉、國姓鄉 0.6 1174
48 橫山 南投縣 南投市、名間鄉 1.5(0.2) 444 近彰化縣社頭鄉界
49 貓囒山 南投縣 魚池鄉 0.8 1016
50 集集大山 南投縣 集集鎮、中寮鄉 0(2.8) 1392 近水里鄉界
51 松柏坑山 彰化縣、南投縣 二水鄉、名間鄉 松柏嶺 1(0) 430
52 後尖山 南投縣 魚池鄉、水里鄉 1 1008
53 鳳凰山 南投縣 鹿谷鄉 2.1 1696
54 金柑樹山 南投縣 竹山鎮、信義鄉 2.8 2091
55 石壁山 雲林縣、嘉義縣 古坑鄉、阿里山鄉 1.5 1751 近竹山鎮界
56 雲嘉大尖山 雲林縣、嘉義縣 古坑鄉、梅山鄉 1.5 1299
57 梨子腳山 嘉義縣 梅山鄉 掘尺嶺山、 祝壽山 0.2 1176
58 獨立山 嘉義縣 竹崎鄉 1 840
59 大塔山 嘉義縣、南投縣 阿里山鄉、信義鄉 1.7 2663 注意可能有高山症
60 大凍山 嘉義縣 梅山鄉、阿里山鄉 畚箕山、糞箕山 0.8 1967 近竹崎鄉界
61 大湖尖山 嘉義縣 竹崎鄉、番路鄉 0.9-2 1313
62 紅毛埤山 嘉義市 東區 0.5(0.1) 150
63 大凍山 臺南市、嘉義縣 白河區、大埔鄉 凍頭山 1.5 1241
64 崁頭山 臺南市 東山區 0.5 844
65 三腳南山 嘉義縣、臺南市 大埔鄉、南化區 2.1 1186
66 西阿里關山 臺南市、高雄市 南化區、甲仙區 小林山 0.5 973
67 竹子尖山 臺南市 楠西區、南化區 1.1 1090
68 東藤枝山 高雄市 桃源區 藤枝山 0.7 1565 新入選
69 白雲山 高雄市 甲仙區 廓亭山 1.1 1044
70 烏山嶺 臺南市、高雄市 南化區、杉林區 刣牛湖山、烏山步道 2.2 730
71 鳴海山 高雄市 茂林區 2.9 1411
72 旗尾山 高雄市 旗山區 0.3 318
73 尾寮山 屏東縣、高雄市 茂林區、三地門鄉 2.5 1427
74 大崗山 高雄市 岡山區、阿蓮區、田寮區 0.6 312
75 觀音山 高雄市 大社區、仁武區 2 169
76 笠頂山 屏東縣 瑪家鄉 1.4 659
77 壽山 高雄市 鼓山區 柴山 0.5 356
78 棚集山 屏東縣 來義鄉 1.8 899
79 女仍山 屏東縣 獅子鄉、牡丹鄉 2.2 804
80 里龍山 屏東縣 獅子鄉、牡丹鄉 里瀧山 1.4 1062
81 大山母山 屏東縣 滿州鄉 萬里得山 #N/A 325 新入選
82 灣坑頭山 宜蘭縣 頭城鎮 2.5 616 2024/02/10已達成
83 三角崙山 新北市 坪林區 2.2 1029
84 鵲子山 宜蘭縣 礁溪鄉 鴻子山 0.3 679 礁溪富士山
85 三星山 宜蘭縣 大同鄉 0.9 2352
86 卡拉寶山 花蓮縣 秀林鄉 祖輪山 #N/A 2397 注意可能有高山症
87 立霧山 花蓮縣 秀林鄉 2.5 1274
88 初音山 花蓮縣 吉安鄉、秀林鄉 0.2(0.3) 906
89 鯉魚山 花蓮縣 壽豐鄉 1 601
90 月眉山 花蓮縣 壽豐鄉 0.6 614
91 八里灣山 花蓮縣 豐濱鄉、瑞穗鄉 貓公富士山 2.8 924
92 萬人山 花蓮縣 富里鄉 0.1 886
93 都蘭山 台東縣 東河鄉、延平鄉 都巒山 1.9 1190 台東富士山
94 太麻里山 台東縣 太麻里鄉 金針山 0 1340
95 加奈美山 台東縣 大武鄉 1.6 780
96 巴塱衛山 台東縣 大武鄉 0 324
97 紅頭山 台東縣 蘭嶼鄉 1.7 552
98 雲台山 連江縣 南竿鄉 0 248
99 太武山 金門縣 金湖鎮 0.6 253 已達成
100 蛇頭山 澎湖縣 馬公市 0 20

2024年3月13日 星期三

Powershell 變數型態_Array

Array

  • 同一陣列內,可以混合儲存各種形態資料
  • 陣列起始註標為 0

陣列的表示法

$a1 = 1..3
$a2 = 1,2,3
$a3 = @(1,2,3)
$a4 = (1..3), "ABC", (7..9), @{'name'="tom"; "age"=51}

Result

$a4[0] = 1, 2, 3
$a4[1] = "ABC"
$a4[2] = 7, 8, 9

宣告空陣列

$a5 = @()
$a5.Count -eq 0    # True

只有一個變數值,要設定為陣列

$a6 = , "Hello"
$a7 = @("Hello")
# 輸出 $a6 變數註標值為0的元素
$a6[0]
# 輸出 $a7 變數註標值為0的元素
$a7[0]
$a6.GetType()
$a7.GetType()

Result:

Hello
Hello

IsPublic IsSerial Name     BaseType                  
-------- -------- ----     --------                  
True     True     Object[] System.Array              
True     True     Object[] System.Array

反向取得陣列值

$array = "Tom", "Kate", "Dylan"
$array[-1]   # 陣列最後一個值
$array[-2]   # 陣列倒數第二個值

Result:

Dylan
Kate

計算陣列中符合條件值的數量(篩選等於 100,再計算 Count)

$a8 = @(100, 59, 95, 60, 100, 88, 76)
($a8 -eq 100).Count # 統計滿分人數

Array 元素的增加

雖然 Array 有 Add Method,但是當你使用 Add() 時,會出現"集合屬於固定大小"的錯誤
所以當你要在 Array 增加元素時,請使用數學運算 +

$a=@()
$a += 1
$a.GetType()
$a.Add(5)
$a += 5
$a

Result:

IsPublic IsSerial Name                                     BaseType                  
-------- -------- ----                                     --------                  
True     True     Object[]                                 System.Array              
以 "1" 引數呼叫 "Add" 時發生例外狀況: "集合屬於固定大小。"
位於 線路:4 字元:1
+ $a.Add(5)
+ ~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NotSupportedException
 
1
5

雖然空一格,但不占空間

$a = @(1,2,3, ,5)
$a.count
$a

Result

4
1
2
3
5

Array 元素的減少

$a = @(1,2,3,4,5,6,7,8,9)
# 用註標來選擇
$a = $a[1,3,5]
$a

Result:

2
4
6

移除陣列中的空字串

# 宣告一個陣列
$a = @(1, 2, "", 4)
# 以下三種方法都可以移除空字串
$a = $a.Where( { $_ -ne ""} )
$a = $a | Where-Object { $_ -ne "" }
$a = $a -ne ""

Arrary 與 ArrayList 型態互換

$a = @()
$a.GetType()
# 將 [System.Array] 轉換成 [System.Collections.ArrayList]
$a = [System.Collections.ArrayList]$a
$a.GetType()
# [System.Collections.ArrayList] 轉換成 [System.Array]
$a = [System.Array]$a

Result:

IsPublic IsSerial Name       BaseType                  
-------- -------- ----       --------                  
True     True     Object[]   System.Array              
True     True     ArrayList  System.Object             

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_arrays?view=powershell-7.3

Powershell 變數型態_Hashtable

三種 Hash Table 的表示方式

為什麼要用 Hash Table 這種資料結構?
因為Powershell 可以很方便的將 Hash Table 陣列轉換換成 PSObject
而 PSObject可以很方便的轉換成各種格式,例如 .csv .html table .json .xml
$v1 = @{}
$v2 = New-Object -TypeName Hashtable
$v3= @{
	"Key1" = 3
	"Key2" = "String"
	"Key3" = @("array",5,"string")
}

$v2.Add("Key1",5)
$v2.Add("Key2","string")

$v2 | Format-List
$v3 | Format-Table

Hash Tables
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-5.1

2024年3月12日 星期二

Powershell 系統內建變數

Automatic Variables 自動變數 (系統內建變數)

變數 說明
$$
$? 查詢前一次指令的執行狀態
$^ 查詢前一次執行的指令
$_ 迴圈或是 Pipe 的暫存變數
$args
$ConsoleFileName
$Error
$Event
$EventSubscriber
$ExecutionContext
$true
$false
$null
$foreach
$HOME 使用者帳號家目錄路徑
$Host 用來判斷Powershell運行的環境
$input
$inputScript
$IsCoreCLR v7
$IsLinux v7 判斷作業系統是否為 Linux
$IsMacOS v7 判斷作業系統是否為 MacOS
$IsWindows v7 判斷作業系統是否為 Microsoft Windows
$LastExitCode
$Matches 正規式比對的結果
$MyInvocation
$PSScriptRoot
$PSCommandPath
$NestedPromptLevel
$PID 取得目前Powershell 或是 Powershell ISE 的 Process ID
$PROFILE
$PSBoundParameters
$PSCmdlet
$PSCulture 顯示系統的語系
$PSDebugCoNtext
$PSEdition
$PSHOME 顯示系統預設的 Powershell Home Path
$PSItem
$PSSenderInfo
$PSUICulture 顯示系統的語系
$PSVersionTable 顯示Powershell的版本資訊
$PWD 取得目前路徑位置
$Sender
$ShellId
$StackTrace
$switch
$this
$ast
$cursorColumn
$MaximumAliasCount
$MaximumDriveCount
$MaximumErrorCount
$MaximumFunctionCount
$MaximumVariableCount
$options
$positionOfCursor
$psISE 在 Powershell Console,此系統變數為 $null,可以用來判斷執行環境是 Powershell ISE 還是 Pwoershell Console
$psUnsupportedConsoleApplications
$tokens
$ConfirmPreference High, Medium, Low, None
$CurrentlyExecutingCommand
$DebugPreference Break: Enter the debugger, Continue: 顯示偵錯訊息,並繼續執行, Ignore: Ignore the evenet completely, SilentlyContinue: 沒有作用。 偵錯訊息不會顯示,而且不會中斷執行, Stop: 顯示偵錯訊息並停止執行。 將錯誤寫入主控台, Suspend: Reserved for future use.
$ErrorActionPreference
$ErrorView
$InformationPreference
$LogCommandHealthEvent
$LogCommandLifecycleEvent
$LogEngineHealthEvent
$LogEngineLifecycleEvent
$LogProviderHealthEvent
$LogProviderLifecycleEvent
$LogSettingsEvent
$PSLogUserData
$MaximumHistoryCount
$NestedPromptLevel
$OFS
$OutputEncoding
$ProgressPreference
$PSDebugContext
$PSDefaultParameterValues
$PSEmailServer
$PSItem
$PSModuleAutoLoadingPreference
$VerboseHelpErrors
$VerbosePreference
$WarningPreference
$WhatIfPreference
$Alias:
$Cert:
$Function:
$HKLM:
$HKCU:
$Variable:
$WSMan:
$Global:
$Local:
$Script:
$Private:
$env:ALLUSERSPROFILE C:\ProgramData
$env:APPDATA C:\Users\使用者帳號\AppData\Roaming
$env:ChocolateyInstall C:\ProgramData\chocolatey
$env:ChocolateyLastPathUpdate
$env:COMPUTERNAME 電腦名稱
$env:ComSpec C:\WINDOWS\system32\cmd.exe
$env:DriverData C:\Windows\System32\Drivers\DriverData
$env:HOMEDRIVE C:
$env:HOMEPATH \Users\使用者帳號
$env:LOCALAPPDATA C:\Users\使用者帳號\AppData\Local
$env:LOGONSERVER \電腦名稱
$env:NUMBER_OF_PROCESSORS 電腦CPU核心數
$env:OS Windows_NT
$env:Path Path環境變數
$env:PATHEXT 可執行的副檔名列表
$env:POWERSHELL_DISTRIBUTION_CHANNEL MSI:Windows 10 Pro
$env:PROCESSOR_ARCHITECTURE AMD
$env:PROCESSOR_IDENTIFIER Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
$env:PROCESSOR_LEVEL 6
$env:PSModulePath Powershell Modules安裝的路徑
$env:SystemDrive C:
$env:SystemRoot C:\WINDOWS
$env:TEMP C:\Users\使用者帳號\AppData\Local\Temp
$env:USERNAME 使用者帳號
$env:USERPROFILE C:\Users\使用者帳號
$env:windir C:\WINDOWS
$env:ProgramFiles C:\Program Files
${env:ProgramFiles(x86)} C:\Program Files (x86)
$env:ProgramW6432 C:\Program Files

Powershell 命名規定

命名基本規定

  • Powershell 是不會區分大小寫
  • 系統有一些內建系統變數、環境變數、關鍵字,變數的命名上是不能使用的,不然變數值會被系統覆蓋掉。
  • 變數名稱中最好不要有特殊字元,例如:- (破折號),會被當成運算元減號,如果一定要用破折號,請將變數名稱用大括號括起,但這樣寫起來挺麻煩的,也容易出錯,還是不建議這樣搞!
${Saved-Items} = "a","b","c"
${Saved-Items}
  • Powershell Cmdlet/Function 命名有一定規矩,就是 Verb-Noun (動詞/動作-名詞),而且有規範只能使用哪些動詞(雖然,使用規範以外的動詞,不會發生甚麼錯誤,但是在 Visual Studio Code 裡執行時,會一直出現警告)
  • 如果要知道Powershell 規範哪些動詞,可以執行
Get-Verb

如果要知道,有哪些命令可以使用,可以執行

Get-Command -Noun restmethod*
Get-Command -Verb Split

如果要知道特定命令,有哪些組成、屬性、方法等,可以執行

Cmdlet | Get-Member

例如:

Get-Process | Get-Member -MemberType Method | Select-Object Name, Definition

enter image description here

查詢跟 CSV 格式相關的 Cmdlet

Get-Command -Noun CSV

查詢跟 JSON 格式相關的 Cmdlet

Get-Command -Noun JSON

查詢跟 HTML 格式相關的 Cmdlet

Get-Command -Noun HTML

查詢轉換格式相關的 Cmdlet

Get-Command -Verb Convert*

PowerShell 簡介

什麼是 PowerShell?

Powershell 是一個微軟發展的跨平台的語言,可以在 Windows、Linux、MacOS 上運行。
雖然號稱是跨平台,但是在不同的平台上,程式需要些許調整!
就我個人的經驗,在 Linux 平台上,可以運行 Powershell 但是,我還是會建議盡量使用 bash shell script 或是其他程式語言

PowerShell 能夠管理那些系統?

  • Microsoft Azure
  • Windows Server/Client
  • Exchange Server
  • SQL Server
  • Hyper-V
  • VMware
  • AWS
  • VMware
  • GCP

Powershell 能做那些事?

  • 呼叫 API 讀取網頁(無法讀取前端Javascript Render 的網頁資料)
  • 使用 Selenium 網頁爬蟲
  • 讀寫資料庫
  • 存取 FTP、SSH、SMTP、POP3 發送郵件(有些需要特過 Third Party)
  • 透過 Web Server GCI 執行 透過 HTTP Listener
  • 建立 Web Service (需要自己處理 MIME Type File)
  • 讀寫 CSV, JSON, XML, HTML
  • 壓縮/解壓縮 ZIP
  • 檔案管理
  • 註冊機碼管理
  • 連接/中斷網芳
  • 透過WinRM,管理遠端電腦
  • 載入 DLL,使用 Third Party Function

Powershell 流程控制

If

If (<test1>)
    {<statement list 1>}
[elseif (<test2>)
    {<statement list 2>}]
[else
    {<statement list 3>}]

簡略寫法

<condition> ? <if-true> : <if-false>

Switch

基本語法

Switch ( <test-expression> ){ 
	<result1-to-be-matched> {<action>} 
	<result2-to-be-matched> {<action>}
	Default {<action>} # optional
}

特別參數及語法

Switch [-regex | -wildcard | -exact] [-casesensitive] ( <test-expression> ){
    "string1" | number1 | variable1 | { <value-scriptblock1> } { <action-scriptblock> }
    "string2" | number2 | variable2 | { <value-scriptblock2> } { <action-scriptblock> }
    Default { <action-scriptblock> } # optional
}

從檔案取得資料

Switch [-regex | -wildcard | -exact] [-casesensitive] -file filename {
    "string" | number | variable | { <value-scriptblock> } { <action-scriptblock> }
    default { <action-scriptblock> }  # optional
}

說明:

參數 說明
-regex <test-expression> 的符合條件是正規式;如果 <test-expression> 變數型態不是字串,此參數會無效
-wildcard 使用萬用字元去比對,這裡不分大小寫;如果 <test-expression> 變數型態不是字串,此參數會無效
-exact 必須完全符合字串大小寫;如果 <test-expression> 變數型態不是字串,此參數會無效
-casesensitive 區分大小寫;如果 <test-expression> 變數型態不是字串,此參數會無效
-file 從文字型檔案讀取每一行來比較,這裡不分大小寫
  • 範例1:使用 Script Blocks 來媒合,Switch 會執行所有吻合條件的部分

    $a = 1,2,3
    $Variable = 2
    Switch($Variable){
    	{ $_ -in $a }{
            "Variable is in Array"
    	}
    	{ $_ -match "[0-9]" }{
            "Variable is matched regexp"
    	}
    	{ $_ -lt 10 -and $_ -gt 1 }{
            "Variable is bigger than 1, and smaller than 10"
    	}
    	Default {
            "Otherwise"
    	}
    }
    

    enter image description here

  • 範例二:要中斷Switch繼續媒合所有 Script Block,要使用 Break

    $a = 1,2,3
    $Variable = 2
    Switch($Variable){
    	{ $_ -in $a }{
            "Variable is in Array"
            break
    	}
    	{ $_ -match "[0-9]" }{
            "Variable is matched regexp"
            break
    	}
    	{ $_ -lt 10 -and $_ -gt 1 }{
            "Variable is bigger than 1, and smaller than 10"
            break
    	}
    	Default {
            "Otherwise"
    	}
    }
    

    enter image description here

  • 範例三:

    $Variable = 42
    Switch($Variable){
    	{ 0..20 -contains $_ }{
            "Variable is between 0~20"
    	}
    	{ 21..40 -contains $_ }{
            "Variable is between 21~40"
    	}
    	{ 41..60 -contains $_ }{
            "Variable is between 41~60"
    	}
    	{ 61..80 -contains $_ }{
            "Variable is between 61~80"
    	}
    	{ 81..100 -contains $_ }{
            "Variable is between 81~100"
    	}
    	Default{
            "Variable is not in 0~100"
    	}
    }
    

    enter image description here

  • 範例四:媒合條件為正規式

    $month = (Get-Date).Month
    $month
    switch -regex ([string]$month) {
     "^[1-3]$" {"Q1"}
     "^[4-6]$" {"Q2"}
     "^[7-9]$" {"Q3"}
     "^1[0-2]$" {"Q4"}
    }
    

    enter image description here

Comparison Operators 比較運算說明

比較 說明
-and 進行邏輯運算 AND
-or 進行邏輯運算 OR
-not 進行邏輯運算 NOT
-xor 進行邏輯運算 XOR,而非 bit XOR運算
-is 判斷變數型態是否與比對的型態相同
-isnot 判斷變數型態是否與比對的型態不相同
-like 字串匹配通配符模式,忽略大小寫
-ilike 字串匹配通配符模式,忽略大小寫
-clike 字串匹配通配符模式,比較大小寫
-notlike 字串與通配符模式不匹配,忽略大小寫
-inotlike 字串與通配符模式不匹配,忽略大小寫
-cnotlike 字串與通配符模式不匹配,比較大小寫
-match 字串與正規表示式模式匹配,忽略大小寫
-imatch 字串與正規表示式模式匹配,忽略大小寫
-cmatch 字串與正規表示式模式匹配,比較大小寫
-notmatch 字串與正規表示式模式不匹配,忽略大小寫
-inotmatch 字串與正規表示式模式不匹配,忽略大小寫
-cnotmatch 字串與正規表示式模式不匹配,比較大小寫
-in 變數值存在於集合之中,忽略大小寫
-iin 變數值存在於集合之中,忽略大小寫
-cin 變數值存在於集合之中,比較大小寫
-notin 變數值不存在於集合之中,忽略大小寫
-inotin 變數值不存在於集合之中,忽略大小寫
-cnotin 變數值不存在於集合之中,比較大小寫
-contains 集合中包含變數值,忽略大小寫
-icontains 集合中包含變數值,忽略大小寫
-ccontains 集合中包含變數值,比較大小寫
-eq Equal 等於(忽略大小寫)
-ieq Equal 等於,忽略大小寫
-ceq Equal 等於,比較大小寫
-ne Not Equal 不等於,忽略大小寫
-ine Not Equal 不等於,忽略大小寫
-cne Not Equal 不等於,比較大小寫
-gt Great Than 大於,忽略大小寫
-igt Great Than 大於,忽略大小寫
-cgt Great Than 大於,比較大小寫
-ge Great Equal 大於等於,忽略大小寫
-ige Great Equal 大於等於,忽略大小寫
-cge Great Equal 大於等於,比較大小寫
-lt Less Than 小於,忽略大小寫
-ilt Less Than 小於,忽略大小寫
-clt Less Than 小於,比較大小寫
-le Less Equal 小於等於,忽略大小寫
-ile Less Equal 小於等於,忽略大小寫
-cle Less Equal 小於等於,比較大小寫
  • 仔細觀察可以發現,只要加上 i 就是不區分大小寫;加上 c 就是區分大小寫

  • 從範例來理解 -in & -contains

    $a = 5
    
    1..3 -contains $a
    1..10 -contains $a
    
    $a -in 1..3
    $a -in 1..10
    
  • 從範例來了解 -is & -isnot

    $a = 5
    $b = "5"
    $a.GetType()
    $b.GetType()
    $a -is [int]
    $a -isnot $b.GetType()
    

    enter image description here

  • 需要特別注意的特例

$a = 1, 2, $null, 4, $null, 6
$a.GetType()
$a -ne $null

$null -ne $a

enter image description here

"abc" -eq "abc"         # Output: True
"abc" -eq "abc", "def"  # Output: False
"abc" -ne "def"         # Output: True
"abc" -ne "abc"         # Output: False
"abc" -ne "abc", "def"  # Output: True

"abc", "def" -eq "abc"  # Output: abc
"abc", "def" -ne "abc"  # Output: def

enter image description here
說明:當集合在運算子左邊時,其結果會是過濾變數值

  • 再來一個自訂類別的比較
class MyFileInfoSet {
    [String]$File
    [Int64]$Size
}
$a = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$b = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$a -eq $b

上面程式碼雖然透過自訂類別,設定了兩個變數,兩個變數的屬性值雖然都一樣,但這兩個變數是不同的物件, -eq 會認為這不是同一個物件。

所以要讓 -eq 能判斷物件"值" 是否一致,要改用以下程式,讓程式知道使用 -eq 比較時,是要比較兩個變數的值

class MyFileInfoSet : System.IEquatable[Object]{ 
	[String]$File 
	[Int64]$Size 
	[bool] Equals([Object] $obj){ 
		return ($this.File -eq  $obj.File) -and ($this.Size -eq  $obj.Size) 
	}
}
$c = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$d = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$c -eq  $d

我們再來看看兩個類別宣告出來的物件變數的方法有甚麼不同

class MyFileInfoSet {
    [String]$File
    [Int64]$Size
}
$a = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$a | Get-Member

class MyFileInfoSet2 : System.IEquatable[Object]{ 
	[String]$File 
	[Int64]$Size 
	[bool] Equals([Object] $obj){ 
		return ($this.File -eq  $obj.File) -and ($this.Size -eq  $obj.Size) 
	}
}

$c = [MyFileInfoSet2]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$c | Get-Member

($c | Get-Member) | Where-Object { $_.Name -eq "Equals" } | Select-Object -Property Definition

enter image description here

Break、Continue、Return、Exit

Break 中斷迴圈或是 Switch,或是 Trap

  • 範例一:

    $i=0
    $varB = 10,20,30,40
    foreach ($val in $varB) {
      if ($val -eq 30) {
        break
      }
      $i++
    }
    Write-Host "30 was found in array index $i"
    
  • 範例二:中斷指定的迴圈(這是很差的程式習慣,請盡量不要使用)

    Remove-Variable * -ErrorAction SilentlyContinue
    $b = 3
    :red while ($true) {
      :yellow while ($true) {
        while ($true) {
          if ($a) {break}
          if ($b) {break yellow}
          if ($c) {break red}
        }
        Write-Host "中斷最內層迴圈"
      }
      Write-Host "中斷 :yellow 迴圈"
    }
    Write-Host "中斷 :red 迴圈"
    

如果有定義 $a,就會中斷最內層迴圈
如果有定義 $b,就會中斷 :yellow 迴圈
如果有定義 $c,就會中斷 :red 迴圈

  • 範例三:
    function test {
      trap [DivideByZeroException] {
        Write-Host 'divide by zero trapped'
        break
      }
    
      $i = 3
      'Before loop'
      while ($true) {
         "1 / $i = " + (1 / $i--)
      }
      'After loop'
    }
    test
    
    enter image description here
    當除數為0的例外被觸發時,印出 “divide by zero trapped”
    然後就終止函式
    如果沒有使用 Break,就會在發生錯誤之後,繼續執行印出 “After loop”

請不要在迴圈(不包含 ForEach-Object)、Switch、Trap 之外使用 Break!這會目前的 Runspace 被終止!

function test {
 "TEST"
 break
}

test
"After Test"

當程式執行 test 函式時,輸出 “TEST” 之後,整個程式就被 break 終止了!所以 “After Test” 永遠不會被執行到。

1..10 | ForEach-Object{
    If ($_ -eq 3){
        Break
    }
    $_
}

"迴圈之後,繼續執行"

在 ForEach-Object 內使用 Break,也會導致整個程式被終止!

ForEach ($v in 1..10){
    If ($v -eq 3){
        Break
    }
    $v
}

"迴圈之後,繼續執行"

但是在 ForEach ($variable in <collection>){} 迴圈卻不會中斷整個程式

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_continue?view=powershell-7.3

Powershell 迴圈的額外說明

Powershell 迴圈的額外說明

以下三種 Powershell 迴圈程式,先試著猜猜結果為何

Function loop1{
    1..3 | ForEach-Object{
        If ($_ -eq 2){
            Return "Y", $_
        }Else{
            Return "N", $_
        }
    }
}

loop1
Function loop2{
    For($i=1; $i -le 3; $i++){
        If ($_ -eq 2){
            Return "Y", $i
        }Else{
            Return "N", $i
        }
    }
}

loop2
Function loop3{
    ForEach($num in 1..3){
        If ($_ -eq 2){
            Return "Y", $num
        }Else{
            Return "N", $num
        }
    }
}

loop3

當你分別執行上面的程式之後,會發現
ForEach-Object{ }
會跑完每一個 Object,所以它會回傳三次!
而 For 或是 ForEach 迴圈,則是如同預期的,只會跑一次

這個 ForEach-Object { } 的用法,就很像 Python 的 yield

Powershell 迴圈

Powershell 迴圈

第一種迴圈

For (<Init 變數初始值>; <Condition 迴圈繼續執行條件>; <Repeat/Step 變數增減運算式>){
    <Statement list>
}

例如:
設定變數 $v = 1,$a = 10
當 $v 數值小於等於 5 時,執行迴圈內指令
變數 $v 的值,每次累加 2

For ($v, $a=1,10; $v -le 5; $v = $v + 2){
    "`$v = $v"
    $a += $v
    "`$a = $a"
}

因為要程式輸出 $,所以 $ 前面要加上 ` 跳脫符號
enter image description here

第二種迴圈

ForEach (<item> in <collection>){
    <Statement list>
}

第三種迴圈

先判斷是否吻合條件

While (<condition){
	<Statement list>
}

第四種迴圈

至少會執行一次,執行後判斷是否吻合條件,條件吻合時繼續執行

Do {
	<Statement list>
} While (<condition>)

第五種迴圈

至少會執行一次,執行後判斷是否吻合條件,條件吻合時結束執行

Do {
	<Statement list>
} Until (<condition>)

第六種迴圈

透過 Pipe 來源,對每個 Object 執行 Statement list

| ForEach-Object{
	<Statement list>
}
$Events = Get-EventLog -LogName System -Newest 1000
$events | ForEach-Object -Begin {Get-Date} -Process {Out-File -FilePath Events.txt -Append -InputObject $_.Message} -End {Get-Date}
Get-Module -ListAvailable | ForEach-Object -MemberName Path

執行字串物件的 Split 方法,參數 “.”

"Microsoft.PowerShell.Host" | ForEach-Object -MemberName Split -ArgumentList  "."
1..2 | ForEach-Object -Begin { '開始' } -Process { '程序 A' } { '程序 B' } -End { '結束' }

Begin 與 End Script Blocks 都只會執行一次,而 Process 後面可以接多個 Script Blocks,會依照傳遞物件的數量來執行次數

以下只有 Powershell v7 才有

$Message = "Output:"

1..8 | ForEach-Object -Parallel {
    "$using:Message $_"
    Start-Sleep 10
} -ThrottleLimit 10

採用多執行緒 -Parallel
執行緒數量 -ThrottleLimit 10
所以程式會一次把 1~8 都輸出,最後等上 10秒才結束程式

如果修改 -ThrottleLimit 為 2,就會每次只輸出兩個數值,並等上 10秒

取得系統事件紀錄(需要以管理者權限執行)

$logNames = 'Security','Application','System','Windows PowerShell','Microsoft-Windows-Store/Operational'

$logEntries = $logNames | ForEach-Object -Parallel {
    Get-WinEvent -LogName $_ -MaxEvents 10000
} -ThrottleLimit 5

$logEntries.Count

當使用多執行緒時,要注意系統資源使用量會拉高!

$job = 1..10 | ForEach-Object -Parallel {
    "Output: $_"
    Start-Sleep 3
} -ThrottleLimit 2 -AsJob

$job | Receive-Job -Wait

使用多執行緒,並丟到背景執行,然後用 Receive-Job -Wait 等待並取得執行結果