LoginSignup
4
2

More than 1 year has passed since last update.

少しディープなPowershell備忘録

Last updated at Posted at 2020-10-04

これは何

個人的なPowershell備忘録です。
思い出したり記事を探すのが手間だったりするものを中心に。
ディープな部分も含めてとりあえず記録しておこうと思ったものを追記予定。
特に明記してない場合はPowershell 7.xの内容です。

未翻訳ドキュメント要約と私的補足

Powershellの未翻訳ドキュメントからあれこれ
知らなかったそんな機能……って沢山感じました。

About calculated properties

一部コマンドレットのpropertiesパラメーターやGroupbyパラメータでは連想配列で手の込んだ処理が出来ます。
その解説。

連想配列のキー構成

  • name/label - 作成するプロパティの名前を指定する。どちらを使っても良い。
  • expression - プロパティの値を計算するためのスクリプトブロックを指定する。
  • alignment - 表形式の出力を生成するコマンドレットで、値が列にどのように表示されるかを定義するために使用する。値は 'left''center'、または 'right' のいずれかでなければならない。
  • formatstring - フォーマット文字列を指定する。文法は-f演算子、[string]::Formatと同じ。
  • width - カラムの幅を指定する。0より大きい数値を指定しなければならない。
  • depth - Format-Custom-Depthパラメータは全プロパティの展開深度を指定するが、depthキーを使うと個別に深度を設定出来る。
  • ascending / descending - ソート順を指定する。boolean値。

expressionのみが必須。連想配列ではなくScriptblockを指定した場合はexpressionのみが指定される。
連想配列キーは他のPowershellのパラメータ指定と同様に被りが起きないところまで省略可能。
手打ちでは1文字だけで指定していく場合がほとんど。

# 省略なしの場合
ps code | ft id,
            name,
            @{name='Handles';expression={$_.Handles};alignment='left'},
            @{name='CPU';expression={$_.CPU};formatstring="####0.00"}

# 省略した場合
ps code | ft id,name,@{n='Handles';e={$_.Handles};a='left'},@{n='CPU';e={$_.CPU};f="####0.00"}

結果

   Id Name Handles    CPU
   -- ---- -------    ---
 6924 Code 1059    756.02
 7344 Code 213       0.95
 7552 Code 464       1.92
15900 Code 398      49.06
15948 Code 279       7.13
16116 Code 403      33.30
21404 Code 214       1.19
22532 Code 215       0.48
36224 Code 501     274.56
38748 Code 259       1.86
40000 Code 305       0.11
40684 Code 535     210.70
41032 Code 1836    225.59
41332 Code 223       1.45
41564 Code 220     204.81
41724 Code 218       0.53

Compare-Object

  • expression

Compare-Objectはプロパティで比較基準を設定出来る。

[Process]型を様々な方法で比較してみる。

下準備
$ps= get-process code
$ps[0] | fl
$ps[1] | fl

結果

Id      : 6924
Handles : 1065
CPU     : 536.8125
SI      : 1
Name    : Code


Id      : 7344
Handles : 213
CPU     : 0.953125
SI      : 1
Name    : Code

通常はNameが比較対象になるので「同じ」だと判定される。

 Compare-Object  $ps[0] $ps[1]

プロパティ名を指定すると比較対象が変わる。

 Compare-Object  $ps[0] $ps[1] -Property Id

  Id SideIndicator
  -- -------------
7344 =>
6924 <=

Select-Objectと同様に複数プロパティの指定も可能。

 Compare-Object  $ps[0] $ps[1] -Property Name,Id

Name   Id SideIndicator
----   -- -------------
Code 7344 =>
Code 6924 <=

プロパティで演算を行った例。
Idは偶数なので{$_.Id % 2}は両方とも0で同じなのでこの結果になる。

Compare-Object  $ps[0] $ps[1] -Property Name,{$_.Id % 2}

演算なしとの比較

Compare-Object  $ps[0] $ps[1] -Property Name,{$_.Id % 2},Id

Name $_.Id % 2   Id SideIndicator
---- ---------   -- -------------
Code         0 7344 =>
Code         0 6924 <=
Compare-Object応用
型を比較する

メンバーの型定義をすることによりダックタイピングを実現出来るかも?
[ValidateScript]で使えそう。
※Idは可視化のためにつけている。

Compare-Object  $ps[0] $ps[1] -Property {$_.Name.Gettype()},{$_.Id.Gettype()},{$_.Parent.Gettype()},Id

$_.Name.Gettype()   : System.String
$_.Id.Gettype()     : System.Int32
$_.Parent.Gettype() : System.Diagnostics.Process
Id                  : 7344
SideIndicator       : =>

$_.Name.Gettype()   : System.String
$_.Id.Gettype()     : System.Int32
$_.Parent.Gettype() : System.Diagnostics.Process
Id                  : 6924
SideIndicator       : <=

発想を自由にする

Get-Processをスクリプトブロック内で行うことで、Compare-Object実行時に実行されているプロセス数を比較している。

Compare-Object pwsh code -Property {(get-process $_).count}

(get-process $_).count SideIndicator
---------------------- -------------
                    16 =>
                     4 <=
Compare-Object実践
ファイル比較

準備

PS >"---test.txt---"
>> cat .\test.txt
>>
>> "`n---test.log---"
>> cat .\test.log
---test.txt---
Line 1
Line 2
Line 3
Line 4
Line 5

---test.log---

Name                           Value
----                           -----
args                           {}
e                              System.IO.FileSystemEventArgs
Error                          {}
event                          System.Management.Automation.PSEventArgs
eventArgs                      System.IO.FileSystemEventArgs
eventSubscriber                System.Management.Automation.PSEventSubscriber
false                          False
MyInvocation                   System.Management.Automation.InvocationInfo
null
PSBoundParameters              {[source, System.IO.FileSystemWatcher], [e, System.IO.FileSystemEventArgs]}
PSCommandPath
PSDefaultParameterValues       {}
PSScriptRoot
script:Error                   {}
sender                         System.IO.FileSystemWatcher
source                         System.IO.FileSystemWatcher
true                           True

パス名は文字列比較になってしまう

PS >Compare-Object .\test.txt .\test.log

InputObject SideIndicator
----------- -------------
.\test.log  =>
.\test.txt  <=

公式のドキュメントではこのようにして比較してる


PS >Compare-Object (Get-Content .\test.txt) (Get-Content .\test.log)

InputObject                                                                                                SideIndicator
-----------                                                                                                -------------
                                                                                                           =>
Name                           Value                                                                       =>
----                           -----                                                                       =>
args                           {}                                                                          =>
e                              System.IO.FileSystemEventArgs                                               =>
Error                          {}                                                                          =>
event                          System.Management.Automation.PSEventArgs                                    =>
eventArgs                      System.IO.FileSystemEventArgs                                               =>
eventSubscriber                System.Management.Automation.PSEventSubscriber                              =>
false                          False                                                                       =>
MyInvocation                   System.Management.Automation.InvocationInfo                                 =>
null                                                                                                       =>
PSBoundParameters              {[source, System.IO.FileSystemWatcher], [e, System.IO.FileSystemEventArgs]} =>
PSCommandPath                                                                                              =>
PSDefaultParameterValues       {}                                                                          =>
PSScriptRoot                                                                                               =>
script:Error                   {}                                                                          =>
sender                         System.IO.FileSystemWatcher                                                 =>
source                         System.IO.FileSystemWatcher                                                 =>
true                           True                                                                        =>
                                                                                                           =>
Line 1                                                                                                     <=
Line 2                                                                                                     <=
Line 3                                                                                                     <=
Line 4                                                                                                     <=
Line 5                                                                                                     <=

Propertyパラメータで演算を行うとこうなる
結果が違うのは公式の例はファイル内容の1行ごとの文字列動詞を比較しているのに対し、この例ではファイル内容全体で比較しているため。

PS >Compare-Object .\test.txt .\test.log -Property {cat $_}

cat $_                                                                                                               SideIndicato
                                                                                                                     r
------                                                                                                               ------------
{, Name                           Value, ----                           -----, args                           {}...} =>
{Line 1, Line 2, Line 3, Line 4...}                                                                                  <=

ファイルハッシュの比較も行える

PS >Compare-Object ((Get-FileHash .\test.txt).hash) ((Get-FileHash .\test.log).hash)

InputObject                                                      SideIndicator
-----------                                                      -------------
48B6D671ED303B15C649F94163DD8167280DE44D6673C67A7C1BEE834CEAFFB6 =>
7B2C588D37C473A32203AFAF5C7628EA75EB79B33C799850E509CA37BCBE4195 <=


PS >Compare-Object .\test.txt .\test.log -Property {(Get-FileHash $_).Hash}

(Get-FileHash $_).Hash                                           SideIndicator
----------------------                                           -------------
48B6D671ED303B15C649F94163DD8167280DE44D6673C67A7C1BEE834CEAFFB6 =>
7B2C588D37C473A32203AFAF5C7628EA75EB79B33C799850E509CA37BCBE4195 <=

組み合わせる


$hashParams = @{
    ReferenceObject  = get-item .\test.txt
    DifferenceObject = get-item .\test.log
    Property         = @(
        { $_.name }
        { (Get-FileHash $_).Hash }
        { $_.Attributes }
        { $_.LastWriteTime }
    )
}
Compare-Object @hashParams

結果

 $_.name                 : test.log
 (Get-FileHash $_).Hash  : 48B6D671ED303B15C649F94163DD8167280DE44D6673C67A7C1BEE834CEAFFB6
 $_.Attributes           : Archive
 $_.LastWriteTime        : 2020/09/19 16:00:41
SideIndicator            : =>

 $_.name                 : test.txt
 (Get-FileHash $_).Hash  : 7B2C588D37C473A32203AFAF5C7628EA75EB79B33C799850E509CA37BCBE4195
 $_.Attributes           : Archive
 $_.LastWriteTime        : 2020/10/12 22:12:50
SideIndicator            : <=
`

`IncludeEqual`パラメータで同じものを表示させる事も出来る
ファイルをコピーして比較する

```powershell
copy .\test.txt .\test_copied.txt -Force
$hashParams = @{
    ReferenceObject  = get-item .\test.txt
    DifferenceObject = get-item .\test_copied.txt
    Property         = @(
        { $_.name }
        { (Get-FileHash $_).Hash }
        { $_.Attributes }
        { $_.LastWriteTime }
    )
}

この条件ではname以外は一致

 $_.name                 : test_copied.txt
 (Get-FileHash $_).Hash  : 7B2C588D37C473A32203AFAF5C7628EA75EB79B33C799850E509CA37BCBE4195
 $_.Attributes           : Archive
 $_.LastWriteTime        : 2020/10/12 22:12:50
SideIndicator            : =>

 $_.name                 : test.txt
 (Get-FileHash $_).Hash  : 7B2C588D37C473A32203AFAF5C7628EA75EB79B33C799850E509CA37BCBE4195
 $_.Attributes           : Archive
 $_.LastWriteTime        : 2020/10/12 22:12:50
SideIndicator            : <=

名前以外を比較する

$hashParams = @{
    ReferenceObject  = get-item .\test.txt
    DifferenceObject = get-item .\test_copied.txt
    Property         = @(
        # { $_.name }
        { (Get-FileHash $_).Hash }
        { $_.Attributes }
        { $_.LastWriteTime }
    )
    IncludeEqual     = $true
    ExcludeDifferent = $true
}
Compare-Object @hashParams

結果

 (Get-FileHash $_).Hash                                           $_.Attributes   $_.LastWriteTime   SideIndicator
------------------------                                         --------------- ------------------  -------------
7B2C588D37C473A32203AFAF5C7628EA75EB79B33C799850E509CA37BCBE4195         Archive 2020/10/12 22:12:50 ==

ConvertTo-Html

  • ConvertTo-Html
  • name/label - optional (added in PowerShell 6.x)
  • expression
  • width - optional
  • alignment - optional

Format-Custom

  • Format-Custom
  • expression
  • depth - optional

Format-List

  • Format-List
  • name/label - optional
  • expression
  • formatstring - optional

This same set of key-value pairs also apply to calculated property values
passed to the GroupBy parameter for all Format-* cmdlets.

Format-Table

  • Format-Table
  • name/label - optional
  • expression
  • formatstring - optional
  • width - optional
  • alignment - optional

Format-Wide

  • Format-Wide
  • expression
  • formatstring - optional

Group-Object

  • Group-Object
  • expression

Measure-Object

  • Measure-Object
  • Only supports a script block for the expression, not a hashtable.
  • Not supported in PowerShell 5.1 and older.

Select-Object

  • Select-Object
  • name/label - optional
  • expression

Sort-Object

  • Sort-Object
  • expression
  • ascending/descending - optional

補足

[!NOTE]
The value of the expression can be a script block instead of a
hashtable. For more information, see the Notes section.

お気に入りの拡張モジュール・Nugetのライブラリ

Powershellの真価はModule/外部ライブラリ取り込める拡張性にあり。
※PowershellGetの扱い方はググると出てくると思います。

ClassExplorer

.NETの型情報を調べるツールです。
何を入れるのがオススメかと聞かれたらClassExplorerと応えます。

  • パラメータ、返り値の型からエラー解析や応用を探る
  • Powershellで行いたいことがあるとき、良い感じのクラス、メソッドなどがあるのか確認
  • インストールしたモジュールが使っているアセンブリの解析
    • 主にNugetで公開されているライブラリ、そのラッパーモジュールで使用。
 gcm -mo ClassExplorer

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Find-Member                                        1.1.0      ClassExplorer
Cmdlet          Find-Namespace                                     1.1.0      ClassExplorer
Cmdlet          Find-Type                                          1.1.0      ClassExplorer
Cmdlet          Get-Assembly                                       1.1.0      ClassExplorer
Cmdlet          Get-Parameter                                      1.1.0      ClassExplorer

使用例:Eventを持つオブジェクトを確認する

~
 Find-Member -MemberType Event

   ReflectedType: System.AppContext

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
UnhandledException   Event         True    Void UnhandledExceptionEventHandler.Invoke(Object sender, UnhandledExc
FirstChanceException Event         True    Void EventHandler`1.Invoke(Object sender, FirstChanceExceptionEventArg
ProcessExit          Event         True    Void EventHandler.Invoke(Object sender, EventArgs e)

   ReflectedType: System.AppDomain

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
UnhandledException   Event        False    Void UnhandledExceptionEventHandler.Invoke(Object sender, UnhandledExc
DomainUnload         Event        False    Void EventHandler.Invoke(Object sender, EventArgs e)
FirstChanceException Event        False    Void EventHandler`1.Invoke(Object sender, FirstChanceExceptionEventArg
ProcessExit          Event        False    Void EventHandler.Invoke(Object sender, EventArgs e)
AssemblyLoad         Event        False    Void AssemblyLoadEventHandler.Invoke(Object sender, AssemblyLoadEventA
AssemblyResolve      Event        False    Assembly ResolveEventHandler.Invoke(Object sender, ResolveEventArgs ar
ReflectionOnlyAssem Event        False    Assembly ResolveEventHandler.Invoke(Object sender, ResolveEventArgs ar
TypeResolve          Event        False    Assembly ResolveEventHandler.Invoke(Object sender, ResolveEventArgs ar
ResourceResolve      Event        False    Assembly ResolveEventHandler.Invoke(Object sender, ResolveEventArgs ar

   ReflectedType: System.Progress`1[T]

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
ProgressChanged      Event        False    Void EventHandler`1.Invoke(Object sender, T e)

   ReflectedType: System.Threading.Tasks.TaskScheduler

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
UnobservedTaskExcep Event         True    Void EventHandler`1.Invoke(Object sender, UnobservedTaskExceptionEvent

   ReflectedType: System.Runtime.Loader.AssemblyLoadContext

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
ResolvingUnmanagedD Event        False    IntPtr Func`3.Invoke(Assembly arg1, String arg2)
Resolving            Event        False    Assembly Func`3.Invoke(AssemblyLoadContext arg1, AssemblyName arg2)
Unloading            Event        False    Void Action`1.Invoke(AssemblyLoadContext obj)

   ReflectedType: System.Reflection.Assembly

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
ModuleResolve        Event        False    Module ModuleResolveEventHandler.Invoke(Object sender, ResolveEventArg

# (中略)

   ReflectedType: Microsoft.Windows.HostGuardianService.Diagnostics.Synthesizer`2[TTrace,THost]

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
TargetDiscovered     Event        False    Void EventHandler`1.Invoke(Object sender, TargetDiscoveredEventArgs e)

   ReflectedType: Microsoft.Windows.RemoteAttestation.Core.TcgPcrEvent

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
UnknownPcrEvent      Event         True    Void EventHandler`1.Invoke(Object sender, TcgParserEventArgs e)

   ReflectedType: System.Drawing.Printing.PrintDocument

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
BeginPrint           Event        False    Void PrintEventHandler.Invoke(Object sender, PrintEventArgs e)
EndPrint             Event        False    Void PrintEventHandler.Invoke(Object sender, PrintEventArgs e)
PrintPage            Event        False    Void PrintPageEventHandler.Invoke(Object sender, PrintPageEventArgs e)
QueryPageSettings    Event        False    Void QueryPageSettingsEventHandler.Invoke(Object sender, QueryPageSett
Disposed             Event        False    Void EventHandler.Invoke(Object sender, EventArgs e)

   ReflectedType: System.IO.FileSystemWatcher

Name                 MemberType  IsStatic  Definition
----                 ----------  --------  ----------
Changed              Event        False    Void FileSystemEventHandler.Invoke(Object sender, FileSystemEventArgs 
Created              Event        False    Void FileSystemEventHandler.Invoke(Object sender, FileSystemEventArgs 
Deleted              Event        False    Void FileSystemEventHandler.Invoke(Object sender, FileSystemEventArgs 
Error                Event        False    Void ErrorEventHandler.Invoke(Object sender, ErrorEventArgs e)
Renamed              Event        False    Void RenamedEventHandler.Invoke(Object sender, RenamedEventArgs e)
Disposed             Event        False    Void EventHandler.Invoke(Object sender, EventArgs e)

ImportExcel

Excelファイルを生成するならこのモジュール一択です。

使用例:パイプラインでExcelファイル生成

Find-Member -MemberType Event | select * | Export-Excel Temp:/Events.xlsx -AutoSize -Show

オプション豊富です。一番気に入っているのは複数テーブル構成のExcelを作るのが苦痛ではなくなることです。

Find-Member -MemberType Event | group {$_.ReflectedType.Namespace  -replace "(^[^\.]+\.[^\.]+)\..+$",'$1'} | % {
 $_.Group | Export-Excel Temp:/ObjectEventsGroupByNameSpace.xlsx -WorksheetName $_.Name -AutoSize -TableStyle Medium1
}

AngleParse

PowerShellから簡単にスクレイピングするためのツールを作った
Powershellの考え方でスクレイピング出来るありがたいモジュール。パイプラインセレクタが嬉しい。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2