概要
初学者がpowershellを学習にするにあたって躓きやすい注意点を記載しています。
注意点1 オブジェクト指向言語だということ
コマンドプロンプトやbash等の習熟者がpowershellを学習するにあたり躓きやすいのがこの点だと思われます。
powershellはオブジェクト指向を取り入れた言語であり、コマンドの実行結果の多くが文字列ではなくクラスのインスタンスを戻します。 ざっくりですがクラスのインスタンスとは変数と関数の集合を変数に入れたもの、と考えると理解しやすいと思います。
例えば、powershellでbashの「ls」コマンドに相当するのはGet-ChildItem
コマンドになりますが、
Get-ChildItem
で「*.txt」の情報を取得しようとすると以下の結果が表示されます。
PS D:\temp> Get-ChildItem *.txt
ディレクトリ: D:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2021/06/22 17:57 0 aaa.txt
-a---- 2021/06/22 17:57 0 abc.txt
表示された「aaa.txt」や「abc.txt」はそれぞれ変数と関数を持っており、
どのクラスでどういった変数や関数を持っているかはget-member
コマンドで確認できます。
(TypeNameがクラス、MemberType がMethodと表示されるものが関数、~Propertyと表示されているのが変数)
Get-ChildItemのメンバーを調べる
PS D:\temp> Get-ChildItem *.txt | get-member
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
LinkType CodeProperty System.String LinkType{get=GetLinkType;}
Mode CodeProperty System.String Mode{get=Mode;}
Target CodeProperty System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=...
AppendText Method System.IO.StreamWriter AppendText()
CopyTo Method System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(s...
Create Method System.IO.FileStream Create()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
CreateText Method System.IO.StreamWriter CreateText()
Decrypt Method void Decrypt()
Delete Method void Delete()
Encrypt Method void Encrypt()
Equals Method bool Equals(System.Object obj)
GetAccessControl Method System.Security.AccessControl.FileSecurity GetAccessControl(), System.Secur...
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, Sys...
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
MoveTo Method void MoveTo(string destFileName)
Open Method System.IO.FileStream Open(System.IO.FileMode mode), System.IO.FileStream Op...
OpenRead Method System.IO.FileStream OpenRead()
OpenText Method System.IO.StreamReader OpenText()
OpenWrite Method System.IO.FileStream OpenWrite()
Refresh Method void Refresh()
Replace Method System.IO.FileInfo Replace(string destinationFileName, string destinationBa...
SetAccessControl Method void SetAccessControl(System.Security.AccessControl.FileSecurity fileSecurity)
ToString Method string ToString()
PSChildName NoteProperty string PSChildName=aaa.txt
PSDrive NoteProperty PSDriveInfo PSDrive=D
PSIsContainer NoteProperty bool PSIsContainer=False
PSParentPath NoteProperty string PSParentPath=Microsoft.PowerShell.Core\FileSystem::D:\temp
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\FileSystem::D:\temp\aaa.txt
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
Directory Property System.IO.DirectoryInfo Directory {get;}
DirectoryName Property string DirectoryName {get;}
Exists Property bool Exists {get;}
Extension Property string Extension {get;}
FullName Property string FullName {get;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
Length Property long Length {get;}
Name Property string Name {get;}
BaseName ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Re...
VersionInfo ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVer...
このようにコマンドごとに様々なプロパティがクラスが定義されており、これらをwhere-object
(条件による行の絞り込み)やselect-object
(抽出項目の指定)で自由に抽出、選択することができます
ファイルのフルパス(fullnameプロパティ)を選択
PS D:\temp> Get-ChildItem *.txt |select-object fullname
FullName
--------
D:\temp\aaa.txt
D:\temp\abc.txt
ディレクトリパスとファイル名(DirectoryName、nameプロパティ)を選択
PS D:\temp> Get-ChildItem *.txt |select-object DirectoryName,name
DirectoryName Name
------------- ----
D:\temp aaa.txt
D:\temp abc.txt
ファイル名に"abc"を含むものを抽出($_.name -like 'abc')し、ベースファイル名と拡張子(basename、Extensionプロパティ)を選択
PS D:\temp> Get-ChildItem *.txt |where-object {$_.name -like '*abc*' }|select-object basename,Extension
BaseName Extension
-------- ---------
abc .txt
注意点2 性能が悪い
上述のオブジェクト指向であることに起因しているのかもしれませんが powershellはcmdやbashと比べると処理が遅いことが多いです。
感覚的には処理対象が数万件規模になってくると遅さを体感するケースが多いです。 工夫すれば改善するケースも多くありますが言語として性能が求められる処理向きではありませんで注意が必要です。
注意点3 一般感覚と微妙にずれた挙動
powershellは他の言語を使っているとなぜこの仕様にしたのだろうか・・と疑問に思う挙動にかなり遭遇します。
- 関数内の標準出力が関数の戻り値になる
以下の関数を実行した戻り値は「3」にならず'1+2='と3の配列が戻ります。 型宣言を強制しない言語のためこのコードもエラーにはなりません。
関数の戻り値テスト
function func1($a,$b){
echo ("$a+$b=")
return $a+$b
}
# 引数に1と2を渡す
$ret = func1 1 2
結果
PS D:\git\powreshell-script> $ret
1+2=
3
※'1+2='という文字と 3 という数字の配列が戻っている
-
リダイレクト(>)の出力文字コードがUTF16
-
ソースコードの文字コードがデフォルトBOM有のUTF8(powrshell6からBOM無UTF8になりました)