2019年4月29日月曜日

powershellメモ

まだ整理しきれてないことをBloggerためしがてらとりあえずメモ

基礎的なこと

  • $_

    パイプラインに渡されたオブジェクトを指す。

    #ps結果でNameが"powershell"のオブジェクトを出力 ps | Where-Object {$_.Name -eq "powershell"}
  • %

    • ForEach-Objectのエイリアス
      例は後述

    • 割り算の余り

      10 % 3 #1
  • @

    • 配列

      $arr = @("aaa","bbb","ccc") $arr[1] # bbb $arr.Count # 3 $arr += "ccc" # 配列に追加 $arr.Count # 4
    • 連想配列

      $map = @{key1="aaa"; key2="bbb"; key3="ccc"} $map.key2 # bbb $map.Add("key4","ddd") # 追加 $map["key4"] # "ddd" $map["key3"] = "eee" # 変更 $map["key3"] # eee $map.Count # 4 $map.Remove("key2") # 削除 $map.Count # 3 $map["key2"] = "fff" # これでも追加される $map.Count # 4
    • ヒアドキュメント(複数行のテキストを1つの文字列に)

      $var = "です" #変数が展開され、1行目が"1行目です"になる $message = @" 1行目$var 2行目 "@ #変数が展開されず、1行目が"1行目$var"になる $message = @' 1行目$var 2行目 '@
  • 例外処理

    1. 例外処理(キャッチされない)

      powershellコマンドのエラーは標準エラー出力に出るが、何もしないとキャッチできない。

      try{ Move-Item "aaaaa" "bbbbb" }catch{ # キャッチしない Write-Error("エラーをキャッチしました:"+$_.Exception) }finally{ Write-Output "終了" }
    2. 例外処理(キャッチされる)

      キャッチしたい場合は、-ErrorAction Stopオプションを付ける。
      ただ標準エラー出力に出ないので、$_.Exceptionで出す。

      try{ Move-Item "aaaaa" "bbbbb" -ErrorAction Stop }catch{ Write-Error("エラーをキャッチしました:"+$_.Exception) }finally{ Write-Output "終了" }
    3. 例外処理(exe)

      pingなど、個別のexeが動く場合は、$LASTEXITCODEを見てエラーを投げる。

      try{ ping 111.222.333.444 if($LASTEXITCODE -ne 0){ throw } }catch{ Write-Error("エラーをキャッチしました:"+$_.Exception) }finally{ Write-Output "終了" }
  • 関数

    • 引数

      参照渡しの場合は変数の前に[ref]を付ける。関数内では.valueをつけて処理する。

      # 通常 function convertFileNameNormal { Param( $fileName ) $fileName = "bbbb" } # 参照渡し function convertFileNameRef { Param( $fileName ) $fileName.value = "cccc" # 参照渡しされた変数の書き換え $fileName = "dddd" # 書き換わらない } $filename = "aaaa" convertFileNameNormal($filename) # 通常呼び出し echo ("1:[" + $filename + "]") # 1:[aaaa] 変わらず convertFileNameRef([ref]$filename) # 参照渡し echo ("2:[" + $filename + "]") # 2:[cccc] 変わる。
    • 戻り値

      関数の戻り値は、標準出力も含めて全て返ってくる。
      returnしたものだけではない。
      個別に返して欲しい場合は参照渡しのほうがマシ。

      function returntest { Write-Output "1個目" echo "2個目" return "3個目" } $ret = returntest echo ("結果:"+$ret) # 結果:1個目 2個目 3個目
  • よく使うエイリアス

    コマンド エイリアス
    Select-Object select
    Select-String sls
    Where-Object Where
    ?
    ForEach-Object %
    Out-String -Stream oss
    #エイリアス一覧 Get-Item Alias: Get-Item Alias: | oss | sls "Select-String"

疑問・ひっかかったこと

  • PowerShell ISE

    PowerShell ISEで試しに書いたコマンドを実行したら、コンソールにコマンドも出力された

    • ファイルを保存しないで「無題.ps1」のままだとそうなる。
      ファイルを保存してから実行すれば出ない。
  • なぜだめなのかわからなかったケース

    #「式は、パイプラインの最初の要素としてのみ許可されます。」のエラー "aaaaa,bbbb" | $_-split(",")[0]

    要は、複数要素が渡された時に処理できないからダメ。

    # これはOK "aaaaa,bbbb" | %{ $_-split(",")[0] }
  • split等の演算子について

    文字列分割する方法が複数ある

    $str = "aaaa,bbbb" #1 $str | %{$_ -split(",")} #2 $str.split(",")

    こう書かれると、先頭の要素を取得したい時にこう書きたくなる

    #1 $str | %{$_ -split(",")[0]} #2 $str.split(",")[0]

    しかし、#1は目的の結果が得られない。理由は -split が演算子だから。

    • #1
      演算子
      -eqとか-matchとかと一緒

    • #2
      .NETのメソッド

    混同しないためにもカッコを付けないほうがいい

    $str | %{$_ -split "," } $str | %{ @($_ -split ",")[0] } #先頭の要素
  • Select-Stringされない

    Remove-Itemのエイリアスを探そうとしてこう書いたが、何も出力されなかった。

    Get-Item Alias: | sls "Remove-Item"

    これはGet-Itemでパイプラインに渡される内容が単純な文字列でないから。

    Get-Item Alias: | oss | sls "Remove-Item" # oss: Output-String -Stream

    これで目的の結果が得られた。
    Output-Stringで出力結果を文字列に変換することができる。
    -Streamを入れることで1行ずつ配列に入れてくれる。
    パイプラインはどのような形で渡されるか意識することが大事。

  • Test-Pathについて

    ファイルの存在チェックでTest-Pathを使用した時に
    確実に存在するのにfalseが返却されたケースがあった。
    理由は、そのファイル名に "[111-222]" のような文字が入っていて
    それを正規表現として解釈してしまったため。
    ファイル名に正規表現として解釈されそうな文字が確実に入らないことが分かっている場合以外は
    -LiteralPath をつけたほうがよい。

    if(!(Test-Path -LiteralPath $srcfile ) ){ Move-Item $srcfile $dstfile }

使用したコマンドメモ

  • ps結果でNameが"powershell"のオブジェクトを出力

    ps | Where-Object {$_.Name -eq "powershell"} ps | Where {$_.Name -eq "powershell"} # 簡易表記 ps | ? Name -eq "powershell" # 簡易表記
  • ネットワークドライブ接続

    # ユーザー名・パスワード入力 $Credential = Get-Credential # ネットワークドライブ接続 New-PSDrive -Name "Z" -PSProvider FIleSystem -Root "\\192.0.0.1\c$" -Credential $Credential # スクリプト内でのみ有効 # -Persist を付けると永続的に有効になる # 使用しているドライプ一覧表示 Get-PSDrive
  • grep

    Select-String "searchString" -Path *.csv # 検索文字列が日本語の場合、「-Encoding default」を付ける
  • システム種類(32/64bit)判別

    if( $Env:PROCESSOR_ARCHITECTURE -eq "AMD64" ){ # 64bit }else{ #32bit }
  • tail

    Get-Content .\test.txt -Wait -Tail 1
  • tail結果を"aaaa"で検索し、カンマで分割した個数が2より大きい場合に、カンマで分割した要素の0番目と1番目をスペースで連結して出力

    Get-Content .\test.txt -Wait -Tail 1 | Select-String "aaaa" | ?{ @($_-split(",")).Length -gt 2 } | %{$($_-split(","))[0] + " " + $($_-split(","))[1] }
  • 20日前以降の更新日時のファイル検索

    dir | where { $_.LastWriteTime -ge ((get-date).AddDays(-20)).ToString("yyyy/mm/dd") }
  • ファイルリストの先頭10行

    dir | select -first 10
  • ファイル名に"(1)"が入ったファイル・フォルダを削除

    dir -Recurse "*(1)*" | Remove-Item -recurse -force
  • 全プロパティ出力

    ps | select -Property * ps | where {$_.Name -eq "powershell"} | select -property *
  • 横並びの結果をリスト表示(Format-List ( エイリアス:fl ))

    PS C:\work> ps | ? Name -eq "powershell" | select -First 1 Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 864 32 131944 149296 1.84 23500 1 powershell
    PS C:\work> ps | ? Name -eq "powershell" | select -First 1 | fl Id : 23500 Handles : 907 CPU : 1.84375 SI : 1 Name : powershell
    PS C:\work> ps | ? Name -eq "powershell" | select -First 1 | fl * Name : powershell Id : 23500 PriorityClass : Normal FileVersion : 10.0.17134.765 (WinBuild.160101.0800) HandleCount : 939 ... #以降、全部出る
  • json読み込み

    { name:"test", id:"12345", array:[ { name:"test1", id:"id1" }, { name:"test2", id:"id2" } ] }
    PS C:\work> $json = cat "C:\work\test.json" | ConvertFrom-Json PS C:\work> $json.name test PS C:\work> $json.array[1].id id2
  • jsonに変換

    $testchild3 = @{ testchild3_1 = "3_1" } $testchild2 = @{ testchild2_1 = "2_1" testchild2_2 = $testchild3 } $testchild1 = @{ testchild1_1 = "1_1" testchild1_2 = $testchild2 } $test = @{ item1 = "1" item2 = $testchild1 } ConvertTo-Json $test
    { "item1": "1", "item2": { "testchild1_1": "1_1", "testchild1_2": { "testchild2_1": "2_1", "testchild2_2": "System.Collections.Hashtable" } } }

    展開される深さが決まっている(デフォルト:2)なので"testchild2_2"が展開されない。
    展開したい場合は「-Depth 数値」を付ける。今回の例では「-Depth 3」。

  • フォルダ判定

    # PSIsContainer # 例)C:\WORK以下でフォルダでないものをget # 判定の否定は ! Get-ChildItem -Recurse "C:\WORK" | ? { ! $_.PSIsContainer } # PathType if( Test-Path "C:\work" -PathType Container){ echo "フォルダです" }
  • ファイル・フォルダ操作

    • ファイルパスからファイルオブジェクト取得

      Get-Item -Path "c:\work.test.log"
    • ファイル移動

      Move-Item "旧パス" "新パス"
    • フォルダ作成

      if(!(Test-Path "フォルダパス")){ New-Item "フォルダパス" -ItemType Directory # 複数階層でもOK }
    • フォルダ削除

      Remove-Item "フォルダパス" -Recurse
  • ログ出力

    # Start-Transcript、Stop-Transcript # すべてのコマンド、およびコンソールに表示されるすべての出力を取得 # コンソールに出しつつ、ログも出したい時はこれが楽 # 複数スクリプトで同じファイルが指定された場合は先勝ち(エラーにならない・・・) Start-Transcript c:\work\powershell.log -append date Stop-Transcript
    # Tee-Object # 追記モードがない! date | Tee-Object -FilePath test.log
  • ハッシュ取得

    Get-FileHash -Path "C:\work\test.log" -Algorithm "SHA512" Algorithm Hash Path --------- ---- ---- SHA512 6AAFB3E... C:\work\test.log
  • パス取得

    # フルパスから親フォルダ取得 Split-Path "C:\work\test.log" -Parent # C:\work # フルパスからファイル名・フォルダ名取得 Split-Path "C:\work\test.log" -Leaf # test.log Split-Path "C:\work" -Leaf # work # 相対パス取得 cd "c:\work" Resolve-Path "c:\test\exam\sum.ps1" -Relative # ..\test\exam\sum.ps1
  • 自分(シェル)の格納場所に移動

    cd (Split-Path -Parent ($MyInvocation.MyCommand.Path))
  • スリープ

    Start-Sleep 5 # デフォルトは秒 Start-Sleep -Milliseconds 100 # 100ミリ秒

0 件のコメント:

コメントを投稿

katalon studio 画面が静的になるまで待つ?smart waitという機能がある。これがあると入力動作が遅くなる。 停止方法 プロジェクト全体の設定 [Project]-[Settings]-[Execution]-[WebUI] 、一番上の [Default Sma...