Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PowerShellのパワー

 PowerShellのパワー

2018.12.15 CLR/H #108 ~力こそパワー~ で発表したスライドです。

ソースコードはGitHubに上げています。
https://github.com/stknohg/PowerShellSamples/tree/master/community/clrh108

Takuya Shibata

December 15, 2018
Tweet

More Decks by Takuya Shibata

Other Decks in Technology

Transcript

  1. 自己紹介 しばた (a.k.a. 素敵なおひげ) • Blog : https://blog.shibata.tech/ • Twitter

    : @stknohg CLR/H と きたあず の裏方をやってます 今月から 所属 Microsoft MVP for Cloud and Datacenter Management (2016.07 - ) 2
  2. PowerShellの歴史 11 2006 2006年11月、PowerShell 1.0リリース ・・・ ・・・中略・・・ 2016 2016年8月、GitHubにオープンソースとして公開される •

    公開時の最新リリースは PowerShell 6.0 Alpha 9 2018 2018年1月、PowerShell Core 6.0リリース • WindowsだけではなくLinuxやmacOSで動作するクロスプラットフォームなアプリケーションに 2018 2018年9月、PowerShell Core 6.1リリース • 2018年12月現在、最新バージョンは 6.1.1
  3. PowerShellの歴史 12 PowerShell 1.0 PowerShell 6.0 Desktop Edition Core Edition

    PowerShell 5.1 Editionなし Windows Linux Mac PowerShell 6.1 Core Edition Core Edition Core Edition Core Edition Core Edition Core Edition
  4. 2つのPowerShell 13 Windows PowerShell (powershell.exe) ✓PowerShell 1.0 ~5.1 ✓Desktop Edition

    ✓Windows専用 ✓.NET Framework PowerShell Core (pwsh.exe / pwsh) ✓PowerShell 6.0 ~ 6.1 ✓Core Edition ✓Windows, Linux, macOS ✓.NET Core ※1 厳密にはNano Server向けのPowerShell 5.1もPowerShell Coreに含まれるのですが、ここではわかりやすさのために除外しています ※1
  5. Windows PowerShellを利用可能なOS バージョンを問わなければほぼすべてのWindowsに標準搭載 • PowerShell 2.0は既に非推奨 OS 2.0 3.0 4.0

    5.0 5.1 Window 7 SP1 Windows Server 2008 R2 SP1 インストール 済み 〇 (更新可) 〇 (更新可) 〇 (更新可) 〇 (更新可) Windows 8 Windows Server 2012 非推奨 インストール 済み 〇 (更新可) 〇 (更新可) 〇 (更新可) Windows 8.1 Windows Server 2012 R2 非推奨 - インストール 済み 〇 (更新可) 〇 (更新可) Windows 10 (初期リリース~Ver. 1511) 非推奨 - - インストール 済み 〇 (更新可) Windows 10 (Ver.1607~) Windows Server 2016 Windows Server 2019 非推奨 - - - インストール 済み 15
  6. PowerShell Core 6.1.1を利用可能なOS • Windows 7/8.1/10 • Windows Server 2008R2/2012/2012R2/2016/2019

    • Windows Server Semi-Annual Channel (SAC) • macOS 10.12+ • Ubuntu 14.04/16.04/18.04 • Debian 8.7+/9 • CentOS 7 • Red Hat Enterprise Linux (RHEL) 7 • Fedora 27/28 • openSUSE 42.3 16 以下はコミュニティサポートのみ • Ubuntu 18.10 • Arch Linux • Raspbian (ARM32) • Kali Linux • Alpine (2018.12.15時点)
  7. PowerShellの基本 25 # 現在時刻を取得 $now = Get-Date Write-Output $now #

    $now 変数は System.Datetime 型 Write-Output ($now.GetType().FullName) # Datetime型のプロパティやメソッドを使って # 翌日の日付を計算 $tomorrow = $now.Date.AddDays(1) Write-Output $tomorrow 簡単なお題で最低限必要なことを知る
  8. PowerShellの基本 1. 変数定義は $変数名 2. 変数は.NET Frameworkの型を持つ • 型の持つプロパティやメソッドを使うことができる 3.

    PowerShell独自のコマンドレット • Command + Let (小さい) からの造語、Cmdletとも • 内部コマンド • コマンドレットは 動詞-名詞 の命名規則を持つ 26
  9. PowerShellの基本 他にもスクリプト言語として様々な要素がある • 配列、ハッシュテーブル • フロー制御 • If文 • for文、foreach文、while文、do文、switch文

    • trap文、try-catch-finally • 関数、高度な関数、フィルター • クラス、列挙型 • リダイレクト • パイプライン • etc.. 27 詳細は過去の登壇資料を見てください :) https://www.slideshare.net/stknohg/powershell-77893763
  10. 便利なコマンドレット コマンドレットを組み合わせて様々な処理を自動化 30 # # OSの起動と停止のイベントログを抽出してメール送信 # 勤怠の管理なんかに使えるかもしれませんね(: # #

    イベントログを抽出して $mailMessage 変数に設定 Get-WinEvent -LogName System -FilterXPath "*[System[Provider[@Name='Microsoft-Windows-Kernel-General'] and (EventID=12 or EventID=13)]]" | Select-Object TimeCreated, Id, Message | Format-Table -Autosize | Out-String | Set-Variable -Name mailMessage # outlook.jp からメールを送信 $params = @{ To = '宛先メールアドレス’; From = '<あなたのアカウント>@outlook.jp’; Subject = 'PCの起動・停止ログ’; Body = $mailMessage; Encoding = 'utf8’ SmtpServer = 'smtp-mail.outlook.com’; Port = 587; UseSsl = $true Credential = New-Object PSCredential -ArgumentList ('<あなたのアカウント>@outlook.jp', (ConvertTo-SecureString '<あなたのパスワード>' - AsPlainText -Force)); } Send-MailMessage @params
  11. Add-Type .NET Frameworkのアセンブリ(.dllや.exe)の機能を 取り込むことができる • PowerShell 2.0から • コマンドレットで提供されない.NET Framework

    / .NET Coreの機能を直接使用できる • 若干開発者向け 33 # Add-Type で外部のアセンブリを取り込むことができる Add-Type -Path '<使用したいアセンブリ名>.dll' # GAC等、アセンブリ名だけで解決できる場合は -AssemblyName パラメーターでも可 Add-Type -AssemblyName 'System.Windows.Forms'
  12. PowerShellでSelenium WebDriver(Chrome) 34 # # PowerShellでSelenium WebDriver(Chrome) # * https://blog.shibata.tech/entry/2018/06/13/233932

    # # Add-Type Add-Type -Path .¥WebDriver.dll $url = 'https://googlesamples.github.io/web-fundamentals/fundamentals/security/prevent-mixed-content/active-mixed-content.html' #$url = 'https://blog.shibata.tech/' # 警告ログなしの場合 try { # 開始 $options = [OpenQA.Selenium.Chrome.ChromeOptions]::new() # ヘッドレス、log-level=3(LOG_FATAL) $options.AddArguments("headless", "disable-gpu", "log-level=3") $driver = [OpenQA.Selenium.Chrome.ChromeDriver]::new($options) # ブラウザログチェック Write-Host ("{0} をチェックします..." -f $url) -ForegroundColor Green $driver.Url = $url $logs = $driver.Manage().Logs.GetLog('browser’) $mixedContentLogs = $logs | Where-Object { $_.Message -like "*Mixed Content:*"} if (@($mixedContentLogs).Count -eq 0) { Write-Host 'Mixed Contentではありませんでした。' -ForegroundColor Green } else { Write-Warning ('Mixed Contentログが{0}件ありました。' -f @($mixedContentLogs).Count) $mixedContentLogs | Format-List } } finally { # 終了 $driver.Quit() }
  13. Add-Type C#やVB.NETのソースコードを取り入れることも可能 • PowerShell CoreではC#のみ(VB.NETのサポートは廃止) • P/Invoke • 完全に開発者向け 35

    # 直接C#などのソースコードを取り込み可能 Add-Type -TypeDefinition 'C#等のソースコードによるクラス定義' # -MemberDefinition パラメーターなんてのもある Add-Type -MemberDefinition 'C#等のソースコードによるStaticな関数定義' ` -Namespace 'ルート名前空間' -Name 'クラス名'
  14. PowerShellでC# 簡単なクラスを例に 36 # # C#で書いたクラスをAdd-Typeする # $Source = @"

    public class BasicTest { public static int Add(int a, int b) { return (a + b); } public int Multiply(int a, int b) { return (a * b); } } "@ Add-Type -TypeDefinition $Source # BasicTestクラスの静的メソッドを使う [BasicTest]::Add(4, 3) # もちろんインスタンスを生成することも可能 $BasicTestObject = New-Object BasicTest $BasicTestObject.Multiply(5, 2)
  15. 様々なデータフォーマットを扱う組み込みコマンドレット 1. CSV • Export-Csv / Import-Csv • ConvertFrom-Csv /

    ConvertTo-Csv 2. XML • ConvertTo-Xml / Select-Xml • Invoke-WebRequest 3. JSON • ConvertFrom-Json / ConvertTo-Json • Invoke-RestMethod 4. Markdown (Coreのみ) • ConvertFrom-Markdown / Show-Markdown 38 PowerShellのデータ処理
  16. PowerShellでJSON JSON(Web API) を扱う簡単な例 39 # Livedoorお天気Webサービスから札幌の天気予報を取得 Invoke-RestMethod -Uri 'http://weather.livedoor.com/forecast/webservice/json/v1?city=016010'

    | ForEach-Object { # 概要の出力 Write-Host '天気情報の概要' -ForegroundColor Green [PSCustomObject]@{ PublicTime = $_.publicTime; Area = $_.location.area; Prefecture = $_.location.prefecture; City = $_.location.city; Description = $_.description.text; } | Format-List # 天気予報の出力 Write-Host '天気予報' -ForegroundColor Green $_.forecasts | ForEach-Object { [PSCustomObject]@{ Date = [Datetime]$_.date DateLabel = $_.datelabel Telop = $_.telop MinTemperature = $_.temperature.min.celsius MaxTemperature = $_.temperature.max.celsius } } | Format-Table -AutoSize }
  17. Component Object Model (COM) よく使われるCOMオブジェクト • Microsoft Office Object: Office操作

    • InternetExplorer Object : IE操作 • Shell Object : Explorer周りの機能 • WUA Objects : Windows Update New-ObjectコマンドレットでCOMオブジェクトを生成 43 # New-Object –ComeObject でCOMを扱う $excel = New-Object -ComObject 'Excel.Application'
  18. PowerShellでExcel COMを使った よくある実装例 44 $excel = New-Object -ComObject 'Excel.Application' try

    { # シート作成 $workbook = $excel.Workbooks.Add() $sheet = $workbook.ActiveSheet # シート名の設定 $sheet.Name = '容量’ # セルに書き込み $sheet.Cells.Item(1, 1) = 'ドライブ’ $sheet.Cells.Item(1, 2) = '使用量(GB)’ $sheet.Cells.Item(1, 3) = '容量(GB)’ $i = 2 Get-PSDrive -PSProvider FileSystem | ForEach-Object { $sheet.Cells.Item($i, 1) = $_.Name $sheet.Cells.Item($i, 2) = [int]($_.Used / 1024 / 1024 / 1024) $sheet.Cells.Item($i, 3) = [int](($_.Used + $_.Free) / 1024 / 1024 / 1024) $i++ } # 名前を付けて上書き保存 $excel.DisplayAlerts = $false $workbook.SaveAs('C:¥Temp¥sample.xlsx’) $excel.Quit() } finally { # COMオブジェクトの解放は非常にめんどうくさい... [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet) [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) [GC]::Collect() }
  19. より良いExcel操作 COMよりモジュール(EPPlusベース)を使う 45 # # ImportExcelモジュールを使ったパターン # このモジュールならWindows以外でも動作する # Install-Module

    ImportExcel -scope CurrentUser Get-PSDrive -PSProvider FileSystem | ForEach-Object { [PSCustomObject]@{ 'ドライブ' = $_.Name; '使用量(GB)' = [int]($_.Used / 1024 / 1024 / 1024); '容量(GB)' = [int](($_.Used + $_.Free) / 1024 / 1024 / 1024); } } | Export-Excel -Path C:¥Temp¥sample2.xlsx -WorksheetName '容量'
  20. Microsoft Windows Installer (MSI) 大抵のWindowsアプリケーションはMSI形式で提供され、 サイレントインストールが可能 msiexec.exe • msiファイルを実行するプログラム •

    主なオプション • /i : インストールするMSIファイルを指定 • /quiet : Quiet モード – 画面表示、ユーザー操作一切なし • /passive :無人モード - 進行状況ダイアログのみ表示 • etc… 48
  21. PowerShell Coreをサイレントインストール 49 # MSIファイルをダウンロード $msiSource = 'https://github.com/PowerShell/PowerShell/releases/download/v6.1.1/PowerShell-6.1.1-win-x64.msi' $msiOutPath =

    'C:¥Temp¥PowerShell-6.1.1-win-x64.msi' Invoke-WebRequest -Uri $msiSource -OutFile $msiOutPath # ダウンロードしたMSIファイルを実行し、サイレントインストール $params = @{ FilePath = 'msiexec.exe’; ArgumentList = @('/i', $msiOutPath, '/passive', '/le', 'C:¥Temp¥PowerShell-6.1.1-win-x64-install.log’); Wait = $true; PassThru = $true; } $proc = Start-Process @params switch ($proc.ExitCode) { 0 { # インストール成功 break } 3010 { # インストール成功 : 要再起動 break } 1602 { # インストールが途中でキャンセルされた Write-Warning "Installation canceled." break } Default { # その他のエラー Write-Error ("Failed to install.(Exit code={0})" -f $_) break } }
  22. 残念ながら開発停止 • Windowsのみ • 情報は少ない • 簡単ではない • 機能は強力 51

    UI Automation PowerShell Extensions https://archive.codeplex.com/?p=uiautomation
  23. テキスト処理 56 コマンド 概ね代替可能な PowerShell コマンドレット 特記事項 grep Where-Object オブジェクトの検索

    Select-String オブジェクトやファイル中の 文字列の検索 awk ForEach-Object sed ForEach-Object + 正規表現 コマンドレット単体では代替不可 diff - Compare-Objectはオブジェクト の比較なので代替不可 PowerShellで概ね代替可能なコマンドは以下 ※正直高度な操作はできないと考えた方が良い WindowsであればWSLやフリーソフトの使用を検討すべき
  24. 大量データ処理 PowerShellで大量データを扱うときはできるだけ 変数にデータをためない様にする 58 # 変数に大量のデータをためない処理 # 124,249件から227件抽出してもメモリの消費はほとんどない $rows =

    Get-Content -LiteralPath 'KEN_ALL.CSV' ` | Where-Object { $_ -like '*新発田市*'} ※それでも限度はあるのでどうしてもダメな場合は PowerShellを諦めてC#などを使用する
  25. 各種文字コード一覧 61 コマンド プロンプト Windows PowerShell PowerShell Core Bash シェル内部の

    文字コード 多分UCS-2 UTF-16 UTF-16 環境依存 (大抵UTF-8) コンソール出力の 文字コード ロケール依存 (日本だとShift-JIS) ロケール依存 (日本だとShift-JIS) ロケール/環境依存 (Shift-JIS / UTF-8) 環境依存 (大抵UTF-8) $OutputEncoding - ASCII UTF-8 - リダイレクトの 文字コード ロケール依存 (日本だとShift-JIS) UTF-16 UTF-8 環境依存 (大抵UTF-8) -Encoding の既定値 - UTF-16 UTF-8 - ※環境の切り分けが雑なのと一部内容に自信のない部分があります… 本表の内容については正確なものではなく、おおまかな雰囲気を捉えるためのものとお考えください。
  26. 文字コードで気を付けるところ 1. リダイレクト(> , >>) • Windows PowerShellのリダイレクトは内部的に `Out-File -Encoding

    unicode`を呼び出している • PowerShell 5.1までは文字コードの変更不可 PowerShell 5.1では以下の様にして変更可能 • PowerShell Core 6.0からは `Out-File -Encoding Utf8NoBom`の呼び出しに変更 62 # パラメーターのデフォルト値を指定することで変更 $PSDefaultParameterValues["Out-File:Encoding"] = 'utf8'
  27. 文字コードで気を付けるところ 63 PowerShellの基本はパイプライン Out-File –Encoding でエンコーディングを明示する # PowerShellはパイプラインが基本 # リダイレクトの代わりに

    Out-File でエンコーディングを明示する Write-Output "力こそパワー" | Out-File -FilePath '.¥output.txt' -Encoding utf8 # PowerShell CoreならEncodingオブジェクトをそのまま指定できる $encoding = [System.Text.Encoding]::GetEncoding(51932) # EUC Write-Output "力こそパワー" | Out-File -FilePath '.¥output.txt' -Encoding $encoding
  28. 文字コードで気を付けるところ 2. UnicodeのBOM • Windows PowerShellでのUnicodeは基本BOM付き • .NET FrameworkのEncodingクラスがそうであるため •

    PowerShell Coreでも基本は変わらないが、ファイル出力 などの処理ではBOM無しUTF-8が使われる様に改善 64 # Windows PowerShellにおいてBOM無しUTF-8でファイル保存する方法 # 詳細は https://blog.shibata.tech/entry/2016/10/02/154329 @' 2018.12.15 CLR/H #108 ~力こそパワー~ '@ | ForEach-Object { [Text.Encoding]::UTF8.GetBytes($_) } ` | Set-Content -Path ".¥Utf8NoBOM.txt" -Encoding Byte
  29. -Pathパラメーター コマンドレットのパラメーターにはワイルドカード 文字を使うことができる (実装は任意だがMicrosoft製のものはほぼ100%利用可) • * : 0文字以上の任意の文字列 • ?

    : 1文字の任意の文字 • [] : []内で指定したパターンにマッチする文字列 65 ファイルを取り扱うコマンドレットの -Pathパラメーター ではワイルドカード文字が有効
  30. ポリシー一覧 ポリシー 内容 Restricted • コマンド実行可能 • スクリプト実行は一切不可 AllSigned •

    コマンド実行可能 • 署名されたスクリプトのみ実行可能 RemoteSigned • コマンド実行可能 • インターネットからダウンロードした スクリプトを実行するには署名が必要 Unrestricted • コマンド実行可能 • スクリプト実行可能(警告が出る場合あり) Bypass • コマンド実行可能 • スクリプト実行可能(警告は一切出ない) Undefined • ポリシー未設定 スコープ一覧 スコープ 内容 Process • 現在のプロセス CurrentUser • 現在のユーザー LocalMachine • コンピューターの 全ユーザー 75 実行ポリシー
  31. Windows PowerShell OS ポリシー (設定スコープ) Windows 7 Restricted (All undefined)

    Windows 8, 8.1 Restricted (All undefined) Windows 10 Restricted (All undefined) Windows Server 2008 R2 Restricted (All undefined) Windows Server 2012 Restricted (All undefined) Windows Server 2012 R2 RemoteSigned (LocalMachine) Windows Server 2016 RemoteSigned (LocalMachine) Windows Server 2019 RemoteSigned (LocalMachine) PoweShell Core OS ポリシー (設定スコープ) Windows RemoteSigned (LocalMachine) Linux Unrestricted (All scopes) macOS Unrestricted (All scopes) 76 既定のポリシー
  32. 実行ポリシーの大事な点 1. 実行ポリシーを設定するのに管理者権限は必須では ない • LocalMachineスコープの設定時のみ管理者権限が必要 2. 実行ポリシーがあれば悪意あるスクリプトを完全に 防げるわけではない •

    実行ポリシーを迂回する方法は多数ある • 悪意を持った攻撃者に対しては割と無力 • ユーザーが誤って意図しないスクリプトを実行しない 様にするためのもの 79
  33. Antimalware Scan Interface (AMSI) Windows 10から導入された、マシンにインストール されているアンチウィルスソフトの機能を利用する ためのAPI Windows 10

    + PowerShell 5.0以降の環境であれば PowerShell内部でこのAPIを使い悪意あるスクリプト を検出できる • Windows 10 + PowerShell Core 6.0も対象 • LinuxやmacOSは対象外 82 ただし現時点では抜け道が結構ある…
  34. ダウングレードアタック Windows 10 + PowerShell 5.0 – 5.1だとAMSIが働く ため、PowerShell 2.0を起動して悪意あるスクリプト

    を実行させようとする攻撃 84 # -Version 2.0 でPowerShell 2.0のランタイムで実行 powershell.exe -Version 2.0 -Command {"悪意あるスクリプト"} PowerShell 2.0は既に非推奨なので 使わない・有効にしない