Windowsの型定義情報
WindowsはC/C++言語の標準的な型をほぼ使用していません。
Windows開発でよく使う型の情報は以下のようになっています。
■8bit
typedef char CHAR; typedef char TCHAR, *PTCHAR; typedef char CCHAR; typedef char *PSZ; typedef unsigned char UINT8, *PUINT8; typedef unsigned char UCHAR; typedef unsigned char BYTE; typedef unsigned char *LPBYTE; typedef unsigned char *PBYTE; typedef unsigned char uint8_t
16bit、32bit以降は現在環境がないため、後日記載。
■便利(と思われる)マクロ
■■min()、max()は既に宣言済み
NOMINMAX宣言がない場合、以下のマクロが使用可能。
#ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif
■■WINDOWSの最大パス長は260まで
#define MAX_PATH 260
■■BOOL変数の実態はintである。
BOOL変数に設定するのは以下の2つ。
#define FALSE 0 #define TRUE 1
■■コードには影響しないが、可読性が上がるマクロ
void hogehoge( IN int input, OUT int& response, OPTIONAL OUT LPVOID lpvResult);
のように、引数の方向を(無害に)示すことができる。
#define IN #define OUT #define OPTIONAL
■■いまや、near far は無意味である。
#define far #define near
https://docs.microsoft.com/ja-jp/cpp/cpp/stdcall?view=vs-2019
Stdcall呼び出し規約は、Win32 API 関数を呼び出すために使用されます。
呼び出し先がスタックを消去するので、コンパイラによって vararg 関数が cdeclされます。
この呼び出し規則を使用する関数には、関数プロトタイプが必要です。
__Stdcall修飾子は Microsoft 固有です。
#define CALLBACK __stdcall #define WINAPI __stdcall #define APIENTRY WINAPI #define APIPRIVATE __stdcall #define PASCAL __stdcall
https://docs.microsoft.com/ja-jp/cpp/cpp/stdcall?view=vs-2019
cdeclは、C および C++ プログラムの既定の呼び出し規約です。
スタックは呼び出し元によってクリーンアップされるため、機能をvararg実行できます。
cdecl呼び出し規約では、各関数呼び出しにスタック クリーンアップ コードを含める必要があるため、
stdcallよりも大きな実行可能ファイルが作成されます。 次の一覧は、この呼び出し規約の実装例を示しています。
cdecl修飾子は、マイクロソフト固有です。
#define WINAPIV __cdecl
検索しても、ほとんど見つからない。
□検索条件 "WINAPIV" 検索対象 *.* フォルダ C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0 除外ファイル *.msi;*.exe;*.obj;*.pdb;*.ilk;*.res;*.pch;*.iobj;*.ipdb 除外フォルダ .git;.svn;.vs (サブフォルダも検索) (英大文字小文字を区別する) (正規表現:bregonig.dll Ver.4.20 with Onigmo 6.2.0) (文字コードセットの自動判別) (一致した行を出力) C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\shared\minwindef.h(118,9) [UTF-8]: #define WINAPIV CDECL C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\shared\minwindef.h(129,9) [UTF-8]: #define WINAPIV __cdecl C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\shared\minwindef.h(136,9) [UTF-8]: #define WINAPIV C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\celib.h(172,5) [UTF-8]: int WINAPIV ceDbgPrintf(BOOL fDebug, char const *pszfmt, ...); C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\t2embapi.h(139,24) [UTF-8]: typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long ); C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\t2embapi.h(140,24) [UTF-8]: typedef unsigned long( WINAPIV *WRITEEMBEDPROC ) ( void*, const void*, const unsigned long ); C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\Vfw.h(59,17) [UTF-8]: #define VFWAPIV WINAPIV C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\WinUser.h(325,1) [UTF-8]: WINAPIV C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\WinUser.h(332,1) [UTF-8]: WINAPIV 9 個が検索されました。
■■ビット操作マクロ
BYTE変数2つからWORD変数を作ったり、WORD変数2つからLONG変数を作ったりするときに使用する。逆のLONGから上半分、下半分を抽出するマクロもある。
Windowsのメッセージ系API(PostMessageやGetMessage、SendMessageなど)で活用していた。 今、この関数を使う人は少ないと思われる。
#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8)) #define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16)) #define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff)) #define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff)) #define LOBYTE(w) ((BYTE)(((DWORD_PTR)(w)) & 0xff)) #define HIBYTE(w) ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
■■各変数の最小値、最大値は既に宣言されている。
流石に、32Bitまで。
#define MINCHAR 0x80 #define MAXCHAR 0x7f #define MINSHORT 0x8000 #define MAXSHORT 0x7fff #define MINLONG 0x80000000 #define MAXLONG 0x7fffffff #define MAXBYTE 0xff #define MAXWORD 0xffff #define MAXDWORD 0xffffffff
■■64Bit変数は、__int64がプリミティブ宣言
大半はtypedefされたものを使用する。
typedef unsigned __int64 size_t; typedef __int64 LONGLONG; typedef unsigned __int64 ULONGLONG;
■■64bit化させるための構造体もある
WIN32APIとしては、こちらが、多用される。
例えば、QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCounter)など。
演算は.QuadPartでまとめたものを使います。数値が小さいはずだからと、LowPartだけで演算しようとすると、痛い目に遭います。
typedef union _LARGE_INTEGER { struct { DWORD LowPart; LONG HighPart; } DUMMYSTRUCTNAME; struct { DWORD LowPart; LONG HighPart; } u; LONGLONG QuadPart; } LARGE_INTEGER; typedef LARGE_INTEGER *PLARGE_INTEGER; typedef union _ULARGE_INTEGER { struct { DWORD LowPart; DWORD HighPart; } DUMMYSTRUCTNAME; struct { DWORD LowPart; DWORD HighPart; } u; ULONGLONG QuadPart; } ULARGE_INTEGER; typedef ULARGE_INTEGER *PULARGE_INTEGER;
ハンガリアン記法について
ハンガリアン記法はオワコンなのか?
そんなことはない、現時点でもgithubで検索すると、現在進行中のプロジェクトで、Linux/Windows両対応のソースコードにもまだまだ使用されている。ただ、提唱者の意図していない形になってしまったのは残念ではあるが。
ハンガリアン記法のルールは?
基本は、変数名の先頭(プレフィックス)に付けるキーワードのルールとなる。型が複数(ポインタなど)になってくると、プレフィックスも複数になってくる。
■ルール1:スコープに応じたプレフィックスをつける。
WIN32APIの仮引数で登場した記法なので、グローバル変数に関しては見たことがない。
”m_" は、今でもよく見るルールである。MFCでは、MS製ソースコードもサンプルでよく見たが、ほとんどこれが記載されていた。
- グローバル変数…"g_"をつける
- メンバー変数..."m_"をつける
- ローカル変数...以下で説明
- 関数の引数...ローカル変数のルールに準ずる。
ただ、もっとシンプルにしたいと願うのも確かである。以下のルールでも十分役目を果たせると思うが、如何だろうか。
- グローバル変数は "__" アンダーバーを2つ付ける。
- メンバー変数は "_" アンダーバーを1つ付ける。
■ルール2:ポインタの場合は "lp" ないし、"p" をつける。
今の時代に "near" だの "far" だの、意味があるのだろうかと思うわけだが、 "l" はロングのLで、意味するところは、near/far の far の方を指していたのは、はるか昔のWIN16APIの話となる。現在のVisual Studioでは、near/far は無意味である。だが、Visual Studio で "LPCVOID" と記載して、右クリックして、「定義へ移動」を選択してみて欲しい。"typedef CONST void far LPCVOID;"の行にたどり着いたと思うが、そのもうちょっと上の行にはまだ、「near」の文字が散見される。 "typedef BOOL near PBOOL;" の行を見て、「今どき "far" もないよな。」と "LP" でなく、"P" を使用した場合、もれなく "near" が付いてくることになる。 これを見て、ポインタ宣言の時は "P" ではなく、"LP" で宣言するようにしている。重ねて言うが、"near"は意味がないキーワードである。
昔(WIN16API)の名残で、"lp" と "p" の両方をWindowsのヘッダーファイルは宣言しているが、実は1つないものがある。 LPCVOIDは宣言されているが、PCVOIDはないのである。よく使いそうなのにない。これも、自作関数で "P" に統一できない理由である。
■ルール3:const などの定数の場合は、"c"をつける。
const もWindowsでは、"CONST" と宣言されているので、これを使う。
■ルール4:wide char/multi byteの両方を意識した変数の場合は "t"をつける。
UNICODEの宣言あり/なしで変数(実は関数も変わる)の型が変わる場合、プレフィックスとして "t" を付与する。 予想だが、"transparent:透過的"の t ではなかろうか。 UNICODE関数の場合は、文字数を返したり、wchar_t*型を返してくることになるので、サイズや内容操作時は注意が必要である。
■ルール5:ここからは、変数毎の命名規約になる。
ハンガリアン記法とは全く関係がないが、Windowsはプリミティブな変数に対しても、大文字で再定義しているものが多い。将来を見越しての対処だったのだと思うが、今までスムーズに16bit~32bit~64bitに遷移してこれているので、杞憂だったのではないか。しかし、ほとんどのWIN32APIはこの大文字変数型を使用しているので、これに追従していくしかない。
■■8bit変数の場合
- signed char の場合は、"c" をプレフィックスに付ける。宣言は CHAR を使う。
- unsigned char の場合は、"by" をプレフィックスに付ける。宣言は UCHAR/BYTE を使う。
変数名 | 型 |
---|---|
cSize | CHAR |
byBuffer | UCHAR/BYTE |
// winnt.h typedef char CHAR; // minwindef.h typedef unsigned char UCHAR; typedef unsigned char BYTE;
■■16bit変数の場合
- signed short の場合は、"s" をプレフィックスに付ける。宣言は SHORT を使う。
- unsigned short の場合は、"w" をプレフィックスに付ける。宣言は USHORT/WORD を使う。
変数名 | 型 |
---|---|
sSize | SHORT |
wParam | USHORT/WORD |
// winnt.h typedef short SHORT; // minwindef.h typedef unsigned short USHORT; typedef unsigned short WORD;
■■32bit変数の場合
- signed int の場合は、"i" をプレフィックスに付ける。宣言は INT を使う。
- unsigned int の場合は、"ui"をプレフィックスに付ける。宣言は UINT を使う。
- signed long の場合は、"l" をプレフィックスに付ける。宣言はLONG を使う。
- unsigned long の場合は、"ul" をプレフィックスに付ける。宣言はULONG を使う。
- unsigned long の場合は、"dw"をプレフィックスに付ける。宣言は DWORD を使う。
変数名 | 型 |
---|---|
iDataSize | INT |
uiPathLength | UINT |
lTableSize | LONG |
ulAreaSize | ULONG |
dwBufferLen | DWORD |
※Windowsは "long"の宣言でも32ビットである。逆にLinuxは "long" の宣言で64ビットとなる。
https://marycore.jp/prog/c-lang/data-type-ranges-and-bit-byte-sizes/
// minwindef.h typedef int INT; typedef unsigned int UINT; typedef unsigned long ULONG; typedef unsigned long DWORD; // winnt.h typedef long LONG;
■■64bit変数の場合
- signed long long の場合、"ll" をプレフィックスに付ける。宣言は LONGLONG を使う。
- unsigned long long の場合、"ull" をプレフィックスに付ける。宣言はULONGLONG を使う。
※32Bitの時代に生まれたハンガリアン記述のため、64Bitに関しては諸説あり、な状況である。
// winnt.h typedef __int64 LONGLONG; typedef unsigned __int64 ULONGLONG;
WIN32で64ビットを扱うために、以下の宣言を使用する場合があるが、これはユニオンである。
LARGE_INTEGER は、ユニオン(_LARGE_INTEGER)をtypedef宣言したもので、以下のようになっている。
typedef union _LARGE_INTEGER { struct { DWORD LowPart; LONG HighPart; } DUMMYSTRUCTNAME; struct { DWORD LowPart; LONG HighPart; } u; LONGLONG QuadPart; } LARGE_INTEGER;
同様にULARGE_INTEGER も、以下のように宣言されている。
typedef union _ULARGE_INTEGER { struct { DWORD LowPart; DWORD HighPart; } DUMMYSTRUCTNAME; struct { DWORD LowPart; DWORD HighPart; } u; ULONGLONG QuadPart; } ULARGE_INTEGER;
で、LowとHighをどう使い分けるのか?
これは、入れる場合と、出す場合を統一すれば、問題ない。ここであえて、エンディアンを考える必要はない。
もし、Intel系のビッグエンディアンで作成して、非Intel系のリトルエンディアンで取り出す場合を想像しているなら、それは16ビットの変数から検討しなければならない。
■■実数の場合
※なぜ、doubleに対して"DOUBLE"を用意しなかったのか?
変数名 | 型 |
---|---|
fLeftPos | FLOAT |
dMaxWidth | double |
■■bool変数の場合
- boolの場合は、"b"をプレフィックスに付ける。宣言はBOOLを使用する。
変数名 | 型 |
---|---|
bShowWindow | BOOL |
なお、BOOLはint型である。
// minwindef.h typedef int BOOL;
■■void型の場合
- voidの場合は、"v"をプレフィックスに付ける。宣言はVOIDを使用する。
変数名 | 型 |
---|---|
lpvParam | LPVOID |
宣言で使用するVOIDは主にアドレスの取得として用いられる。32Bit/64Bitの影響をモロに受ける変数であるが、そもそもサイズ感のない変数なので32→64に換装する場合は要注意変数である。
■■文字列の場合
文字列の場合、基本的には「ヌルターミネーション」であることが、C/C++の標準なので、一位にプレフィックス"sz"が決まる。
ちなみに、string zero termination の省略形である。
通常の文字列とは違う形式としてBSTR型が存在する。BSTR型の文字列の持ち方は特殊で、先頭に文字列長、その後に文字列、という持ち方をしている。この変数の場合、NULLで終端を閉じていないため、'z'は付かないことになる。
変数名 | 型 |
---|---|
szPath | char [ ] |
tszPath | wchar_t [ ] |
■WIN32APIによく登場する変数宣言
変数名 | 型 | cSize | char/CHAR |
---|---|
sParam | short/SHORT |
iCounter | int/INT |
lpvParam | void* |
lpcszFilePath | char*/CHAR* |
lpctszFilePath | const char*/CONST CHAR* |
szBuffer | char [ ] |
tszBuffer | wchar_t [ ] |
cSize sParam iCounter lpvParam lpcszFilePath lpctszFilePath
ポートフォリオについて
ポートフォリオというのは、株のあれとは違うのか?
■どこで見る?
クラウドワークスでよく見る。全く気にしていなかったが、いつかは本腰入れて調べようと思ってた。
「クラウドワークス」に関しては、腕に自信ありの強者が、飯のネタを求めて集う場所。ここで仕事を取り続けられる者は本当に「勇者」だと思う。
■結局これはなに?
自分の実力や能力を、形となるようにして、他者に閲覧してもらい、その能力、実力を認めてもらって契約に結び付ける強力なアイテム。だから、クラウドワークスで見るわけで。
そもそものポートフォリオは、株式購入の際の値の動きをグラフ化したものを指していたはず。 それが「値の動き」ではなく、「己の能力」に変わった感じである。
つまり、「ポートフォリオを見せてください。」と言われたら、すぐにできるものではなく、これまで培ってきたものを自分なりに体系化し、ブラッシュアップしていく事が必要である。
■バックエンドエンジニアには?
自分は全くフロントエンドに縁がなかった。全くと言っては語弊があるが、それはAdobeのFlashで業務アプリを作っていたので、今の時代にはノーカウントだと思う。そういう意味では、フロントエンドエンジニアには将来一人でやっていけそうでいいなぁ、と思うわけです。だがしかし、自分のキャリアをまとめ、体系化して後の人々の礎になるのもそれはそれでありかと思うわけでありまして、これから定年までの数年は、この「ポートフォリオ」を築き上げていこうと思う次第な訳です。
出力系(Out-*, Write-*)
出力に関する基本事項のピックアップ&スニペット
Write-Output
出力はパイプラインに送出可能。
出力結果を変数に格納可能。
意識しなくても、Write-Outputするコマンドレットは多い。
配列は改行されて出力される。コンソールもファイルも。
$message = @("This is my long long message.", "How about you?", "I am very fine.") Write-Output $message Write-Output $message > temp.log
コンソール出力
This is my long long message. How about you? I am very fine.
ファイル出力
This is my long long message. How about you? I am very fine.
Write-Host
前景/背景の色指定が可能
コンソール直接出力なので、後で加工することができない。
改行されずに出力されるが、-Separatorで指定は可能。背景色は見ての通り。
$message = @("This is my long long message.", "How about you?", "I am very fine.") Write-Host $message -ForegroundColor Red -BackgroundColor Blue Write-Host $message -ForegroundColor Yellow -BackgroundColor Green -Separator "`r`n"
This is my long long message. How about you? I am very fine. This is my long long message. How about you? I am very fine.
Write-Warning
黄色文字で出力され、先頭に"WARNING: "が出力される。
リダイレクトでなにも出力されなかったので、Write-Host -Foreground Yellow と同じ。
$message = "You must shutdown and sleep now. You work too hard." Write-Warning $message
WARNING: You must shutdown and sleep now. You work too hard.
Write-Error
例外を投げるのは、throw "エラー"のようにthrowで投げる。
出力が例外発生時に似ているが、むしろ例外発生後のエラー出力用と思われる。
see also http://suyamasoft.blue.coocan.jp/PowerShell/Tutorial/index.html#try
function testRaiseError() { throw "testRaiseError" } try { Write-Host "Before testRaiseError()" -ForegroundColor Yellow testRaiseError Write-Host "After testRaiseError()" -ForegroundColor Yellow } catch [System.Net.WebException], [System.IO.IOException] { # Never come this line. This is a sample. } catch { Write-Error -Message $Error[0].Exception.Message -Category InvalidArgument } finally { Write-Host "finally section." }
出力結果を分かりやすくするために、example.ps1にて実行
Before testRaiseError() ・・・\example.ps1 : testRaiseError + CategoryInfo : InvalidArgument: (:) [Write-Error]、WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,example.ps1 finally section.
Write-Progress
プログレスバー的に進捗表示
see also https://www.forsenergy.com/ja-jp/windowspowershellhelp/html/3f2737ad-2984-4e03-ab2f-ecbd14518b3e.htm
for ($i = 1; $i -lt 101; $i++ ) { Start-Sleep -Milliseconds 200 $message = "{0}% Complete:" -F $i Write-Progress -activity "Search in Progress" -status $message -percentcomplete $i }
Search in Progress 48% Complete: [ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo ]
Out-GridView
スクリプトらしからぬ、グリッドウィンドウを使ってデータを表示します。
$message = @{ "Key1" = "This is my long long message."; "Key2" = "How about you?"; "Key3" = "I am very fine." } $message | Out-GridView -Title 連想配列の中身
Out-Host
-Paging があるので、more/less的に使える。(Get-Helpには、なぜか使えなかった)
でも、Qで終了すると例外メッセージが出力される...
Get-Process | Out-Host -Paging
PS C:\Users\User01\Documents\PowerShell\Basic> Get-Process | Out-Host -Paging Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 420 19 9660 20744 0.41 440 1 Code 653 132 289244 279864 593.94 3640 1 Code 807 46 39904 77788 39.16 6080 1 Code 221 15 6900 9448 0.23 6528 1 Code 384 39 47500 66644 4.33 8444 1 Code 419 33 24980 54944 126.38 9736 1 Code 321 53 63872 75708 15.17 9828 1 Code 305 15 11320 12624 0.19 6776 1 CodeHelper 133 9 4544 7924 127.61 2404 1 conhost 132 9 4020 6596 0.83 3724 1 conhost 115 8 5448 7192 0.05 10060 1 conhost <Space> 次のページ、<CR> 次の行、Q 終了
Out-File
エンコードは、Unicode(既定値),UTF7,UTF8,UTF32,ASCII,OEM…
UnicodeはUTF-16 LE、UTF8はBOM付き、OEMはSHIFT-JISになる(Windows)。
-Appendで追加モードになります。
-Forceで読み取り専用でも書き込みます。
-NoClobberで既存のファイルを上書きしません。
-Width
Get-Help | Out-File -FilePath "Get-Help_OEM.log" -Encoding OEM Get-Help | Out-File -FilePath "Get-Help_UTF8.log" -Encoding UTF8 Get-Help | Out-File -FilePath "Get-Help_Unicode.log" -Encoding Unicode
Out-Null
なにも出力されない。F8でピンポイント実行しても、ステートメントが出力されない。
> NULL 的な用途。
Get-Process | Out-Null
Out-String
出力されるオブジェクトを文字列配列に変換する場合に使用します。
-Streamを付けると、オブジェクト毎に文字列を送ります。
Get-Alias | Out-String | Select-String "Get-" Get-Alias | Out-String -Stream | Select-String "Get-"
Date、Time → Get-Date
日付と時刻に関する基本事項のピックアップ&スニペット
MS-DOSバッチからPowerShellに移行するにあたり、一番恩恵を受けるのが「日時の取得と加工」だと思います。
日時の取得
Get-Date Get-Date -DisplayHint Date Get-Date -DisplayHint Time Get-Date -DisplayHint DateTime
コマンドレット | 出力結果 |
---|---|
Get-Date | 2020年6月24日 12:41:47 |
Get-Date -DisplayHint Date | 2020年6月24日 |
Get-Date -DisplayHint Time | 12:41:47 |
Get-Date -DisplayHint DateTime | 2020年6月24日 12:41:47 |
フォーマットによる出力形式変更
Get-Date -Format "yyyyMMdd_hhmmss"
20200624_124624
変数に格納して使用する
for ($i = 0; $i -lt 10; $i++) { $currentDateTime = "{0}_{1}" -F (Get-Date -Format "yyyyMMdd_hhmmss"), $i Write-Output $currentDateTime Start-Sleep -Seconds 1 }
20200624_124729_0 20200624_124730_1 20200624_124731_2 20200624_124732_3 20200624_124733_4 20200624_124734_5 20200624_124735_6 20200624_124736_7 20200624_124737_8 20200624_124738_9
DIR → Get-ChildItem
ファイルとディレクトリに関する基本事項のピックアップ&スニペット
エラーの扱い方について
他のプロセスが出力中で、読み込むことができないファイルをスキップする場合は、
" -ErrorAction SilentlyContinue"を付加します。
あるいは、$ErrorActionPreference = "SilentlyContinue"を実行しておきます。
とは言っても、エラー情報を捨てる訳にも行きませんので、エラー情報を変数に格納しておき、後で出力します。
-ErrorVariable errorInfo # エラー情報を上書きしていく場合 (ここで$を付けない) -ErrorVariable +errorInfo # エラー情報を追記していく場合 (ここで$を付けない) Write-Host $errorInfo[0]
ディレクトリ一覧を取得する。
$targetDirectory = "C:\windows\Temp" Get-ChildItem $targetDirectory
ディレクトリ: C:\windows\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2020/06/19 22:32 FA345C83-F785-4C40-AB34-2323134FE882-Sigs d----- 2020/06/19 22:38 MsEdgeCrashpad -a---- 2020/06/19 22:38 53 af397ef28e484961ba48646a5d38cf54.db.ses -a---- 2020/06/07 1:54 12621 CompatibilityList.xml -a---- 2020/06/16 23:01 4554 dd_setup_20200616230105.log -a---- 2020/06/16 23:01 0 dd_setup_20200616230105_errors.log -a---- 2020/06/16 23:07 1398494 dd_setup_20200616230115.log -a---- 2020/06/16 23:01 5392 dd_setup_20200616230115_000_Microsoft.VisualStudio.Product.Community.log -a---- 2020/06/16 23:01 258926 dd_setup_20200616230115_001_Microsoft.VisualStudio.LiveShare.log -a---- 2020/06/16 23:02 726558 dd_setup_20200616230115_002_Microsoft.VisualStudio.LiveShare.log -a---- 2020/06/16 23:06 165 dd_setup_20200616230115_003_Unity3d.x64.log
ディレクトリを再帰しながら、全ての一覧を取得する。 [-Recurse]
+ファイル名にワイルドカードを使用して対象選択+文字列の連結。
$targetDirectory = "C:\windows\Temp" $targetFileName = "*.log" Get-ChildItem -Recurse $targetDirectory\$targetFileName
ディレクトリ: C:\windows\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2020/06/16 23:01 4554 dd_setup_20200616230105.log -a---- 2020/06/16 23:01 0 dd_setup_20200616230105_errors.log -a---- 2020/06/16 23:07 1398494 dd_setup_20200616230115.log -a---- 2020/06/16 23:01 5392 dd_setup_20200616230115_000_Microsoft.VisualStudio.Product.Community.log -a---- 2020/06/16 23:01 258926 dd_setup_20200616230115_001_Microsoft.VisualStudio.LiveShare.log -a---- 2020/06/16 23:02 726558 dd_setup_20200616230115_002_Microsoft.VisualStudio.LiveShare.log -a---- 2020/06/16 23:06 165 dd_setup_20200616230115_003_Unity3d.x64.log -a---- 2020/06/16 23:07 11227 dd_setup_20200616230115_004_Microsoft.VisualStudio.Product.Community.log -a---- 2020/06/16 23:01 0 dd_setup_20200616230115_errors.log
ディレクトリのみをリストアップする。 [-Directory]
$targetDirectory = "C:\windows\Temp" Get-ChildItem -Directory $targetDirectory
ディレクトリ: C:\windows\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2020/06/19 22:32 FA345C83-F785-4C40-AB34-2323134FE882-Sigs d----- 2020/06/19 22:38 MsEdgeCrashpad
ファイルのみをリストアップする。 [-File]
$targetDirectory = "C:\windows\Temp" Get-ChildItem -File $targetDirectory
ディレクトリ: C:\windows\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2020/06/19 22:38 53 af397ef28e484961ba48646a5d38cf54.db.ses -a---- 2020/06/07 1:54 12621 CompatibilityList.xml -a---- 2020/06/16 23:01 4554 dd_setup_20200616230105.log -a---- 2020/06/16 23:01 0 dd_setup_20200616230105_errors.log -a---- 2020/06/16 23:07 1398494 dd_setup_20200616230115.log -a---- 2020/06/16 23:01 5392 dd_setup_20200616230115_000_Microsoft.VisualStudio.Product.Community.log
ファイル名を相対パスのみで一覧取得する。[-Name]
$targetDirectory = "C:\windows\Temp" Get-ChildItem -Recurse -File -Name $targetDirectory
af397ef28e484961ba48646a5d38cf54.db.ses CompatibilityList.xml dd_setup_20200616230105.log dd_setup_20200616230105_errors.log dd_setup_20200616230115_000_Microsoft.VisualStudio.Product.Community.log dd_setup_20200616230115_002_Microsoft.VisualStudio.LiveShare.log VSIXodgqpfok.vsix MsEdgeCrashpad\metadata MsEdgeCrashpad\settings.dat
ファイル名を絶対パスのみで一覧取得する。
$targetDirectory = "C:\windows\Temp" Get-ChildItem -Recurse $targetDirectory | Select-Object -property FullName
FullName -------- C:\windows\Temp\FA345C83-F785-4C40-AB34-2323134FE882-Sigs C:\windows\Temp\MsEdgeCrashpad C:\windows\Temp\af397ef28e484961ba48646a5d38cf54.db.ses C:\windows\Temp\CompatibilityList.xml C:\windows\Temp\dd_setup_20200616230105_errors.log C:\windows\Temp\dd_setup_20200616230115.log C:\windows\Temp\dd_setup_20200616230115_001_Microsoft.VisualStudio.LiveShare.log C:\windows\Temp\dd_setup_20200616230115_003_Unity3d.x64.log C:\windows\Temp\dd_setup_20200616230115_errors.log C:\windows\Temp\dd_VSIXInstaller_20200616225936_0ff4.log C:\windows\Temp\mat-debug-7936.log C:\windows\Temp\MsEdgeCrashpad\settings.dat
Excludeを使用して不要なディレクトリを外して一覧取得する。[-Exclude]
$targetDirectory = "C:\Windows\system32" Get-ChildItem -Recurse -Exclude @("*.exe", "*.dll", "*.cpl") -Name $targetDirectory
DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV3B-PropertyBag.bag DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV3C-manifest.ini DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV3C-PropertyBag.bag DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV3D-manifest.ini DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV3I-manifest.ini DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV5B-manifest.ini DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saMV5B-PropertyBag.bag DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\saSP-pipelineconfig.xml DriverStore\FileRepository\prnsacl1.inf_amd64_01567720b35ae842\smpclrc2.gpd DriverStore\FileRepository\prntscl2.inf_amd64_64886520e82c3cce\prntscl2.cat DriverStore\FileRepository\prntscl2.inf_amd64_64886520e82c3cce\prntscl2.inf
そもそも、Get-ChildItem はなにを返すのか?
出力内容から"Get-Member"を使って、propertyだけを抽出します。
$targetDirectory = ".." Get-ChildItem $targetDirectory | Get-Member | Where-Object { $_.MemberType -eq "Property"}
TypeName: System.IO.DirectoryInfo Name MemberType Definition ---- ---------- ---------- Attributes Property System.IO.FileAttributes Attributes {get;set;} CreationTime Property datetime CreationTime {get;set;} CreationTimeUtc Property datetime CreationTimeUtc {get;set;} Exists Property bool Exists {get;} Extension Property string Extension {get;} FullName Property string FullName {get;} LastAccessTime Property datetime LastAccessTime {get;set;} LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;} LastWriteTime Property datetime LastWriteTime {get;set;} LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;} Name Property string Name {get;} Parent Property System.IO.DirectoryInfo Parent {get;} Root Property System.IO.DirectoryInfo Root {get;}
これだけの情報を返してくれます。これらを駆使して、スクリプトを書いていきます。
また、Get-Menberは「こいつ、なにを返すんだ?」というときによく使います。
再帰しながら、ファイル情報を取得します。
自力で再帰するので、カレントディレクトリから 深い階層に移動するタイミングで状況判断ができます。つまり、制御はディレクトリ移動の際にこちらに戻される訳です。そのタイミングで、サマリを取ったり、プログレスを出したりできます。
function recursiveFileSearch($targetFolderName, $targetExtension) { Write-Host $targetFolderName -ForegroundColor Green $collection = Get-ChildItem $targetFolderName -ErrorAction SilentlyContinue -ErrorVariable errorInfo if ($errorInfo.Length -gt 0) { Write-Warning $errorInfo[0] Start-Sleep -Seconds 1 } foreach ($item in $collection) { if ($item.Extension.trim() -eq $targetExtension) { $output = "{0}`t{1}`t{2}" -F $item.FullName, $item.Extension, $item.LastWriteTime Write-Output $output Start-Sleep -Milliseconds 200 } if ($item.Attributes -eq "Directory") { # ディレクトリを再帰調査します。 recursiveFileSearch $item.FullName $targetExtension } } } recursiveFileSearch "C:\Windows" ".ps1" > ExecuteFileList.log
コンソール出力
C:\Windows\Containers C:\Windows\Containers\serviced C:\Windows\CSC WARNING: パス 'C:\Windows\CSC' へのアクセスが拒否されました。 C:\Windows\Cursors C:\Windows\debug C:\Windows\diagnostics
ファイル出力
C:\Windows\diagnostics\scheduled\Maintenance\CL_Utility.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\RS_AdminDiagnosticHistory.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\RS_MachineWERQueue.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\RS_SyncSystemTime.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\RS_UserDiagnosticHistory.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\RS_UserWERQueue.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\TS_DiagnosticHistory.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\TS_InaccurateSystemTime.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\scheduled\Maintenance\TS_WERQueue.ps1 .ps1 2018/04/12 8:34:38 C:\Windows\diagnostics\system\AERO\CL_AeroFeature.ps1 .ps1 2018/04/12 8:34:37
コマンドプロンプトからWindows PowerShellへ移行準備
cmd.exeのメンテナンスもあまり行われていないということで、本腰入れてPowerShell移行計画を行おうと思います。
cmd.exe(コマンドプロンプト)のヘルプを参照する
C>help
と入力して、エンター押下することで、コマンドプロンプトのヘルプが一覧出力されます。
特定のコマンドの詳細情報は、"HELP コマンド名" を入力してください ASSOC ファイル拡張子の関連付けを表示または変更します。 ATTRIB ファイルの属性を表示または変更します。 BREAK 拡張 CTRL+C チェックを設定または解除します。 BCDEDIT ブート データベースのプロパティを設定して起動時の読み込みを制御します。 CACLS ファイルのアクセス制御リスト (ACL) を表示または変更します。 CALL バッチ プログラム中から、別のバッチ プログラムを呼び出します。 CD 現在のディレクトリを表示または変更します。 … 以下、省略 VOL ディスクのボリューム ラベルとシリアル番号を表示します。 XCOPY ファイルやディレクトリ構造をコピーします。 WMIC 対話型コマンド シェルで WMI 情報を表示します。 ツールの詳細な情報については、オンライン ヘルプのコマンド ライン リファレンスを参照してください。
この中には、実際はEXEで機能を提供(外部コマンド)されているものも散見されるため、WHEREコマンドで応答がないものを内部コマンドとして調査してみます。
C>where <コマンド名>
whereコマンドで
C:\Users\User01>where dir 情報: 与えられたパターンのファイルが見つかりませんでした。
と返ってくれば、それはCMD.EXEの内部コマンドの説明とみてよいでしょう。
CMD.EXE 内部コマンド |
説明 |
---|---|
ASSOC | ファイル拡張子の関連付けを表示または変更します。 |
BREAK | 拡張 CTRL+C チェックを設定または解除します。 |
BCDEDIT | ブート データベースのプロパティを設定して起動時の読み込みを制御します。 |
CALL | バッチ プログラム中から、別のバッチ プログラムを呼び出します。 |
CD | 現在のディレクトリを表示または変更します。 |
CHDIR | 現在のディレクトリを表示または変更します。 |
CLS | 画面を消去します。 |
COLOR | コンソールの文字と背景の既定の色を設定します。 |
COPY | 1 個以上のファイルを別の場所にコピーします。 |
DATE | 日付を表示または変更します。 |
DEL | 1 個以上のファイルを削除します。 |
DIR | ディレクトリ中のファイルやサブディレクトリの一覧を 表示します。 |
ECHO | メッセージの表示、コマンド エコーのオン、オフの 指定をします。 |
ENDLOCAL | バッチ ファイルで、環境変数のローカル化を終了します。 |
ERASE | 1 個以上のファイルを削除します。 |
EXIT | CMD.EXE プログラム (コマンド インタープリター) を 終了します。 |
FOR | 指定されたコマンドを、ファイルの集合の各ファイルに 対して実行します。 |
FTYPE | ファイル拡張子の関連付けで使われるファイル タイプを 表示または変更します。 |
GOTO | バッチ プログラム中で、ラベルで定義されている行へ Windows コマンドインタープリターの実行を移します。 |
GRAFTABL | Windows がグラフィック モードで拡張文字セットを 表示できるようにします。 |
IF | バッチ ファイル中で、条件処理を実行します。 |
MD | ディレクトリを作成します。 |
MKDIR | ディレクトリを作成します。 |
MKLINK | シンボリック リンクおよびハード リンクを作成します。 |
MOVE | 1 個以上のファイルをディレクトリから別の ディレクトリに移動します。 |
PATH | 実行可能ファイルの検索パスを表示または設定します。 |
PAUSE | バッチ ファイルの処理を一時停止し、メッセージを表示します。 |
POPD | 現在のディレクトリを PUSHD で保存したディレクトリに戻します。 |
PROMPT | Windows コマンド プロンプトを変更します。 |
PUSHD | 現在のディレクトリを保存して、変更します。 |
RD | ディレクトリを削除します。 |
REM | バッチ ファイルや CONFIG.SYS の中で、コメント (注釈) を 記録します。 |
REN | ファイルの名前を変更します。 |
RENAME | ファイルの名前を変更します。 |
RMDIR | ディレクトリを削除します。 |
SET | Windows 環境変数を表示、設定、または削除します。 |
SETLOCAL | バッチ ファイルで、環境変数のローカル化を開始します。 |
SHIFT | バッチ ファイルで、置き換え可能パラメーターの位置を シフトします。 |
START | 別のウィンドウを起動して、指定したプログラム またはコマンドを実行します。 |
TIME | システム時刻を表示または変更します。 |
TITLE | コマンド プロンプト ウィンドウのタイトルを設定します。 |
TYPE | テキスト ファイルの内容を表示します。 |
VER | Windows のバージョンを表示します。 |
VERIFY | ファイルがディスクへ正しく書き込まれたかを 照合するかどうかWindows へ指定します。 |
VOL | ディスクのボリューム ラベルとシリアル番号を表示します。 |
次章(?)より、よく使う内部コマンドのPowerShell置き換えスクリプトを検討していきます。