Powershell快速入門(三) 實戰應用

好像關于Powershell說的已經差不多了,所以最后一篇文章就來使用Powershell寫一些腳本,幫助我們完成一些日常工作。

文件管理

常用命令

先來看看常用的文件管理命令。

Set-Location命令用于切換工作目錄,它的別名是cd

Get-Location命令用于獲取當前工作目錄,它的別名是pwd

Get-ChildItem命令用于獲取當前目錄下的所有文件。

Get-Item命令用于獲取給定文件的信息。

還有文件移動、刪除、復制、粘貼、重命名等命令,輸入Get-Command -Noun item就可以看到這些命令,這里就不做介紹了。

獲取文件信息

獲取文件信息可以利用命令Get-Item。下面獲取了我電腦上的cmder.exe可執行文件的信息。

λ  Get-Item .\Cmder.exe


    目錄: D:\devtools\cmder_mini


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2016/12/2      7:15         130560 Cmder.exe

默認只列出這么三個屬性,當然其實文件屬性遠不止這些。我們可以通過管道,將文件信息對象傳遞給命令Select-Object,讓它幫我們顯示所有屬性。這里只粘貼了一點點內容,其實文件信息很長,大家可以自行嘗試。

λ  Get-Item .\Cmder.exe|Select-Object *


PSPath            : Microsoft.PowerShell.Core\FileSystem::D:\devtools\cmder_mini\Cmder.exe
PSParentPath      : Microsoft.PowerShell.Core\FileSystem::D:\devtools\cmder_mini

過濾文件

Get-ChildItem顯示當前當前文件的時候,會顯示所有文件。有時候我們可能僅僅需要搜索或者過濾部分文件。

首先,如果是比較簡單的需求,可以使用?*通配符來搞定,問號用于匹配任意單個字符,星號用于匹配任意多個字符。比方說,我想要列出所有.md格式的文件,就可以使用下面的命令。

PS D:\devtools\cmder_mini> Get-ChildItem *.md


    目錄: D:\devtools\cmder_mini


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2016/12/2      7:14          73491 CHANGELOG.md
-a----        2016/12/2      7:14           1784 CONTRIBUTING.md
-a----        2016/12/2      7:14          10039 README.md

有時候可能需要使用正則表達式來查找文件,不過好像Get-ChildItem沒有正則表達式查詢的命令行,不過我們可以使用Where-Object命令來自定義查詢。如果了解C#語言的LINQ的話,應該可以猜到,這個命令對應于LINQ的where語句。

下面同樣是查找所有.md格式的文件,不過這次使用了Where-Object和正則表達式,其中Where-Object里面的$_是形式變量,代表每次迭代的文件。如果了解過C#的LINQ,或者Java 8的流類庫,應該對這種形式會比較熟悉。

Get-ChildItem|Where-Object {$_ -match '\w*.md$'}

如果僅僅為了搜索文件名的話,這種方式好像一點優勢都沒有。實際上Where-Object的功能非常強大。比方說,我現在想查找大于5kb的所有.md格式文件,那么就可以這么寫。這里又用到了Powershell的一個方便的特性,文件大小單位,KB GB MB TB等單位都支持。當然其實并不僅僅可以查詢文件大小屬性,基本上所有文件信息都可以用來查詢。

 Get-ChildItem|Where-Object {$_ -match '\w*.md$' -and $_.Length/1kb -gt 5}

最后,Get-ChildItem不僅可以列出當前文件夾下的所有內容,還可以遞歸查詢所有子文件夾。比方說,我要查找一下迅雷文件夾下所有可執行文件,就可以使用下面的命令。如果添加-Depth參數的話,還可以指定遞歸深度。

 Get-ChildItem -Recurse *.exe

修改hosts

訪問谷歌的一種方式就是更改hosts文件。這里就用Powershell做一個修改hosts的功能。

首先先來介紹一個命令Invoke-WebRequest,利用它我們可以獲取網頁內容、下載文件甚至是填寫表單。這個命令的別名是iwrcurlwget。我們就使用它來下載網上的hosts文件。

剩余就沒有什么難度了,無非就是讀寫文件、追加文件、復制和粘貼這種基本操作。最后寫完這個功能發現有一百多行,就不往這里復制粘貼了。如果有興趣的話,可以直接看我的Github上面的腳本

進程管理

查看進程

首先我們看看有多少和進程相關的命令,這個很簡單,只要查看一下名詞是Process的命令即可。

PS C:\WINDOWS\system32> Get-Command -Noun process

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Debug-Process                                      3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Get-Process                                        3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Start-Process                                      3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Stop-Process                                       3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Wait-Process                                       3.1.0.0    Microsoft.PowerShell.Management

使用這些命令,我們就可以非常方便的管理進程了。比方說,我想查詢現在運行的所有進程,就可以使用下面的命令,這樣就會列出所有運行的進程,就像任務管理器里顯示的那樣。

PS C:\WINDOWS\system32> Get-ProcessGet-Process

上面這個命令會顯示所有進程。如果需要,我們可以按照某個屬性對進程進行排序顯示,這需要使用另外一個命令Sort-Object。另外,如果只需要顯示前幾個進程,可以使用命令Select-Object來選擇顯示多少數據。比方說,如果我們要查看當前占用CPU前5的chrome進程,就可以使用下面的命令。

Get-Process chrome|Sort-Object cpu -Descending|Select-Object -First 5

利用這幾個命令,我們可以按照任何想要的方式來查詢進程。

管理進程

先來看看MSDN上的一個官方例子。首先先打開三個記事本進程,然后使用名稱獲取這些進程,然后調用進程的Kill()函數即可把這些進程全殺掉。中間調用了Count屬性測試了一下總共獲取到了幾個進程。

PS C:\WINDOWS\system32> notepad;notepad;notepad;
PS C:\WINDOWS\system32> $notepads=Get-Process -Name notepad
PS C:\WINDOWS\system32> $notepads.Count
3
PS C:\WINDOWS\system32> $notepads.Kill()

再學習Powershell編程的時候,我們常常會同時開幾個Powershell窗口。不再使用的時候一個一個關閉它們也是一件麻煩事情,所以官方文檔還為我們介紹了如何關閉除當前窗口外的所有Powershell進程。

每個Powershell進程都有一個變量$PID,用于標志當前進程的進程號,利用這一點我們就可以實現這個功能。這里的-WhatIf參數表示不真正關閉進程,僅列出將要關閉的進程。

PS C:\WINDOWS\system32> Get-Process powershell |Where-Object {$_.Id -ne $PID}|Stop-Process -WhatIf
WhatIf: 正在目標“powershell (2676)”上執行操作“Stop-Process”。

如果既想要關閉進程,還想知道關閉了哪些進程,可以使用-PassThru參數。

PS C:\WINDOWS\system32> Get-Process powershell |Where-Object {$_.Id -ne $PID}|Stop-Process -PassThru

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    573      30    56884      68992       0.92   2676   1 powershell

輪詢關閉進程

如果在死循環中不斷查找任務管理器進程,發現它在運行就把它關閉,就可以做一個小小的“病毒”。代碼很簡單,基本上一下子就能看懂。一開始我沒有加Sleep,然后CPU使用率飚的非常高,加了之后基本上對電腦性能沒有影響了。

$process_name = "taskmgr"
while ($true) {
    $processes = Get-Process
    if ($processes.Name -contains $process_name) {
        Get-Process $process_name|Stop-Process
    }
    else {
        Start-Sleep -Milliseconds 500
    }
    
}

如果把上面代碼中的taskmgr換成英雄聯盟的進程名字,我們就可以做一個簡單的“熊孩子防火墻”,防止熊孩子用電腦來玩游戲了。

注冊表操作

讀寫注冊表

讀取注冊表

首先來介紹一下注冊表根的簡寫,例如HKEY_CURRENT_USER的簡寫就是HKCUHKEY_LOCAL_MACHINE的簡寫就是HKLM。知道了簡寫,我們就可以將Powershell的工作目錄切換到注冊表內。例如,如果我們想查看HKEY_CURRENT_USER\Control Panel\Desktop\MuiCached下的值,就可以先把工作目錄切換到這個位置內部。這里需要將對應的注冊表根修改為對應的簡寫加冒號的形式。

PS C:\WINDOWS\system32> Set-Location 'HKCU:\Control Panel\Desktop\MuiCached'
PS HKCU:\Control Panel\Desktop\MuiCached>

切換到了注冊表內部,我們就可以利用Get-Item命令獲取注冊表的值了。比如說,要獲取這個注冊表鍵的值,就可以直接輸入Get-Item .了。注意這個點不能省去,它代表當前工作目錄。

PS HKCU:\Control Panel\Desktop\MuiCached> Get-Item .


    Hive: HKEY_CURRENT_USER\Control Panel\Desktop


Name                           Property
----                           --------
MuiCached                      MachinePreferredUILanguages : {zh-CN}

如果要獲取當前注冊表項的屬性值,可以利用Get-ItemProperty命令。

PS HKCU:\Control Panel\Desktop\MuiCached> Get-ItemProperty .  MachinePreferredUILanguages


MachinePreferredUILanguages : {zh-CN}
PSPath                      : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Control Panel\Desktop\MuiCached
PSParentPath                : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Control Panel\Desktop
PSChildName                 : MuiCached
PSDrive                     : HKCU
PSProvider                  : Microsoft.PowerShell.Core\Registry

當然,切換工作目錄這件事情也可以不做。直接利用Get-ItemProperty命令通過路徑參數來獲取屬性。

Get-ItemProperty -Path 'HKCU:\Control Panel\Desktop\MuiCached' -Name MachinePreferredUILanguages

編輯注冊表項

下面這個路徑是一個安全的注冊表路徑,在這里修改注冊表不會造成嚴重的系統問題。所以我們把它保存為一個變量。

 $path = "HKCU:\Control Panel\Desktop"

如果要新建注冊表項,可以使用New-Item命令。我們可以使用注冊表編輯器regedit來驗證項是否創建成功。

 New-Item –Path $path –Name HelloKey

如果要修改項的屬性,使用Set-ItemProperty命令。

Set-ItemProperty -path $path\hellokey -name Fake -Value fuck

最后,如果要刪除項的屬性,使用Remove-ItemProperty命令。

Remove-ItemProperty -path $path\hellokey -name Fake

如果要刪除整個注冊表項,使用Remove-Item命令。

Remove-Item -path $path\hellokey -Recurse

獲取當前.NET版本

下面的參考資料中列出了一個MSDN上的文檔,告訴我們如何讀取注冊表的值來判斷當前安裝了.NET Framework的版本,并給出了相應的C#代碼。下面的代碼做的就是將C#代碼改寫成Powershell腳本。

# 判斷系統當前安裝.NET框架版本的腳本

$path = 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full'
$not_found_msg = ".net framework 4.5 or later not installed on your system"

function CheckFor45PlusVersion([int] $releaseKey) {
    if ($releaseKey -ge 460798) {
        return "4.7 or later";
    }
    if ($releaseKey -ge 394802) {
        return "4.6.2";
    }   
    if ($releaseKey -ge 394254) {
        return "4.6.1";
    }
    if ($releaseKey -ge 393295) {
        return "4.6";
    }
    if (($releaseKey -ge 379893)) {
        return "4.5.2";
    }
    if (($releaseKey -ge 378675)) {
        return "4.5.1";
    }
    if (($releaseKey -ge 378389)) {
        return "4.5";
    }
    return $not_found_msg;
}

   
try {
    $key = get-item $path
    $releaseKey = Get-ItemPropertyValue $path 'release'
    if ($releaseKey -is [int]) {
        $releaseKey = [int]$releaseKey
        $version = CheckFor45PlusVersion($releaseKey)
        Write-Host ".NET framework ${version}"
    }
    else {
        Write-Host $not_found_msg
    }
}catch {
    Write-Host $not_found_msg
}

Office互操作

操作Excel

雖然Powershell可以通過COM接口和Office程序交互,不過最常用的還是操作Excel,所以我這里只介紹如何控制Excel表。下面最后一個參考資料就是我參考的操作Excel的文章,可能需要梯子才能訪問。需要注意一點,既然是操作Excel,當然首先電腦上需要先安裝Excel才能正常使用。

打開和關閉

首先,我們來創建一個Excel對象,這樣實際上會創建一個Excel應用程序。

$excel = New-Object -ComObject Excel.Application

執行了上面的命令,什么事情都沒有發生。這是因為默認啟動的實例是隱藏的,要顯示Excel的窗口的話,將它設置為可見即可。

$excel.Visible=$true

如果要打開一個現成的工作簿,使用Open函數。

$workbook = $excel.Workbooks.Open("XXX.xlsx")

如果要創建一個新的工作簿,使用Add函數。

$workbook = $excel.Workbooks.Add()

一個工作簿可以有多個工作表,要選擇某一個工作表,使用Worksheets.Item屬性,需要注意這里的下標從一開始。

$worksheet = $workbook.Worksheets.Item(1)

對數據完成操作之后,需要保存的話,使用SaveAs函數。

$workbook.SaveAs("D:\Desktop\hello.xlsx")

操作數據

前面只說了打開和關閉操作,下面來看看如何具體讀取和寫入數據。首先回到上面那步工作表,因為如果要操作數據,需要在工作表對象上進行操作。

$worksheet = $workbook.Worksheets.Item(1)

要操作數據,調用工作表對象的Cells屬性即可。比方說我要打印九九乘法表,那么就可以用類似下面的代碼來迭代寫入數據。

for ($i = 1; $i -le 9; ++$i) {
    # 第一行
    $worksheet.Cells(1, $i + 1) = $i
    # 第一列
    $worksheet.Cells($i + 1, 1) = $i
    # 它們的乘積
    for ($j = 1; $j -le 9; ++$j) {
        $worksheet.Cells($i + 1, $j + 1) = $i * $j
    }
}

操作之后,Excel表中應該存在如圖所示的數據。

寫入數據

類似的,讀取數據也很簡單,只要讀取Cells屬性即可。

for ($i = 1; $i -le 10; ++$i) {
    for ($j = 1; $j -le 10; ++$j) {
        Write-Host -NoNewline $worksheet.Cells($i, $j).Text "`t"
    }
    Write-Host
}

上面的代碼獲取了我們剛才寫入Excel的數據,然后將其轉換為文本并輸出,每個數據之間使用制表符\t分隔,注意Powershell中的轉義字符使用的這個特殊字符。結果應該類似如圖所示。

讀取數據

繪制圖表

Excel很常用的一種操作就是繪制圖表,這里也簡單說說。不過由于這種資料在網上面實在太少,我就算用谷歌搜索英文網頁也搜不出來多少資料,大部分都屬于一點小腳本。所以這里只能隨便說說了。

首先準備一下數據,我準備了如圖所示的數據。

準備數據

然后來創建一個圖表對象。如果使用交互式環境Powershell ISE的話,智能提示會顯示這里有AddChartAddChart2兩個方法,不過我看了下文檔,前面那個過時了,所以這里使用帶2的那個版本。

$chart=$worksheet.Shapes.AddChart2().Chart

創建了圖表對象之后,我們為它指定數據源。

$chart.SetSourceData($worksheet.Range('a1', 'd5'))

這時候如果觀察Excel的話,會發現已經出現了一個初步的圖形。如果希望改變圖形樣式的話,設置圖標的類型即可。這里將圖表類型保存為一個變量,之后就可以省略長長的類名了。這里推薦使用Powershell ISE,因為自動補全可以顯示所有類型的圖標,只需要修改一下圖表類型并觀察Excel中圖標類型的變化就可以明白類型和圖標的對應關系了。

$chartTypes = [Microsoft.Office.Interop.Excel.XLChartType]
$chart.ChartType = $chartTypes::xlColumnClustered

最后效果如圖所示,我看到人家可以使用ApplyDataLabels方法顯示圖例。但是我使用這個方法卻不知道為什么顯示不了。所以這里只能將就一下了。

最終效果圖

最后再來畫個餅狀圖,數據還是上面的數據,不過這次只使用語文那一列的數據。基本上和上面的一樣,只有類型那里改成xlPie

$chartTypes = [Microsoft.Office.Interop.Excel.XLChartType]
$chart = $worksheet.Shapes.AddChart2().Chart
$chart.SetSourceData($worksheet.Range('a1', 'b5'))
$chart.ChartType = $chartTypes::xlPie
$chart.ApplyDataLabels(5)

最終效果圖如下。

餅狀圖

ImportExcel

上面的方法好像只能在安裝Excel的環境下運行,如果沒有安裝Office,但是也想使用編程功能,可以使用第三方的模塊。這就是這里要介紹的ImportExcel。使用它,我們可以在沒有安裝Excel的情況下編輯Excel文件。

首先需要安裝它,可以利用Powershell的包管理器方便的安裝。

Install-Module ImportExcel -scope CurrentUser

如果想讓所有用戶都可以使用這個模塊,需要安裝到全局位置,不過這需要管理員權限,所以需要在管理員模式的Powershell窗口中運行。

Install-Module ImportExcel

這個模塊如何使用我就不作介紹了,這個項目的README文件上基本列出了所有功能和對應的GIF圖,需要什么功能只要看一看應該就可以使用了。

參考資料

https://4sysops.com/archives/interacting-with-the-registry-in-powershell/

https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx

https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.aspx

http://www.lazywinadmin.com/2014/03/powershell-read-excel-file-using-com.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容