【PowerShell】Windows環境での自作プログラム集 (サンプル集)

Windows環境での PowerShell の単体コード集
大半は、挙動を見るために作成するなどした比較的小さなコード集。
行頭に「#!/usr/bin/env pwsh」があるものは、Linux 環境で作成し、動作確認したものです。


1章 標準API
 1.1 実行時の注意点
 1.2 コピー処理
 1.3 ディレクトリ作成
 1.4 コピー、削除、親ディレクトリ名取得、ディレクトリ作成、7z解凍
 1.5 ディレクトリごと削除する
 1.6 スクリプトの引数を受け取る
 1.7 プロセスID を指定して Kill する
 1.8 実行しているスクリプトの dirname を取得する
 1.9 カレントパスの c:\ という文字を /cygdrive/c/ に置換する

2章 VB.NET との連携
 2.1 Microsoft.VisualBasic.Interaction 使用例

3章 .NET Framework との連携
 3.1 キーコード送信
 3.2 メール送信
 3.3 シリアルコンソールの読み出し
 3.4 シリアルコンソールへの書き出し

4章 SQLite3 との連携
 4.1 SQLite3 操作
 4.2 SQLite3 操作(replace)
 4.3 SQLite3 クエリ結果を HTML に変換する

5章 XML との連携
 5.1 XML 操作 (読み書き)

6章 Excel との連携
 6.1 Excel のシート内探索
 6.2 VBAマクロを実行する
7章 文字列の操作
 7.1 空白区切りで文字列を切り出す
 7.2 文字列から指定した文字の位置をポイントする(C言語の strstr 相当)
 7.3 regex を使ったパターンマッチ
 7.4 ANSI Colorエスケープ文字を取り除く

8章 ファイルの操作
 8.1 一行ずつ読み出す

9章 日時の操作
 9.1 フォルダ内のファイルを指定時刻よりも新しいか古いかで振り分ける

 
 

1.1 実行時の注意点

 
実行ポリシーを変更する

デフォルト状態では、PowerShell を実行すると次のように「Execution_Policies」といったログが出てしまい実行できない。

> .\a.ps1
このシステムではスクリプトの実行が無効になっているため、
ファイル C:\work\a.ps1 を読み込むことができません。詳細については、
「about_Execution_Policies」(http://go.microsoft.com/fwlink/?LinkID=135170) 
を参照してください。

 
そこで、次の対策を採る必要がある。
 
恒久的に PowerShell を実行できるようにする
次の A, B という2通りの方法がある。

A. コマンドプロンプトあるいはバッチファイルから以下を実行して PowerShell を管理者モードで起動させる
参考

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process powershell.exe -Verb runas"

 
B. PowerShell が実行できるように制限を変更する

Set-ExecutionPolicy RemoteSigned

 
一時的に PowerShell を実行できるようにする

参考

> powershell -ExecutionPolicy RemoteSigned .\test.ps1

 
 

1.2 コピー処理

 
日時をディレクトリ名に付与して、新規ディレクトリを作成する。
また、そのときのパス情報を result.txt に出力する。

 

mkdir_foler_with_date.ps1
$now     = (Get-Date -UFormat "%Y-%m-%d-%H-%M-%S")
$target  = "\\PC_WORK_1\share\$now"
$output  = "result.txt"

mkdir $target

if( Test-Path $output )
{
  Remove-Item $output
}

Add-Content -path $output -value $target -encoding String

 
 

1.3 ディレクトリ作成

 
result.txt に書かれたパスを取り出して、そのパスにデータをコピーする。

result.txt の記述例

c:\work\temp

 

copy_item.ps1
$output = (Get-Content result.txt)
Copy-Item -r "C:\User\neko\Download\data" $output

 
 

1.4 コピー、削除、親ディレクトリ名取得、ディレクトリ作成、7z解凍

 
"c:\User\neko\Download\*.7z" を "c:\User\neko\work\." にコピーして展開するプログラム。
ここにエラーチェックを加えただけである。
なお、7z.exe は事前にインストールし, %PATH% を通しておくこと。
 

cp_rm_mkdir_7z_dirname.ps1
# 定数
set-variable -name REPOS -value "c:\User\neko\Download" -option constant
set-variable -name WORK  -value "c:\User\neko\work"     -option constant

# Linux の dirname コマンド相当の処理をする
$dirname = (Split-Path -Parent $WORK)
if( !(Test-Path $dirname) )
{
  exit
}

# $WORK が存在しなければ作成する
if( -not (Test-Path $WORK))
{
  New-Item -ItemType Directory $WORK 2>&1
  exit
}

# *.7z をコピーし、展開する
cd $WORK
Remove-Item *.7z
Copy-Item -Path $REPOS/*.7z -Destination .

7z x -y *.7z

 
 

1.5 ディレクトリごと削除する

 
anydir というディレクトリごと削除する
 

rmdir.ps1
Remove-Item -Recurse -Force .\anydir

 
 

1.6 スクリプトの引数を受け取る

 

args1.ps1
#!/usr/bin/env pwsh

# 引数に a を入力した場合
Write-Host "argc   : " $Args.Length     #=> 1
Write-Host "argv[0]: " $Args[0]         #=> a

 
 

1.7 プロセスID を指定して Kill する

 

kill1.ps1

上記のうち、PowerShell、かつ、ウィンドウタイトルが「OleMainThreadWndName」となっている PowerShell を削除する。

イメージ名           PID セッション名   セッション#  メモリ使用量  状態      ユーザー名  CPU 時間  ウィンドウ タイトル                                      
================ ====== ============= =========== ============ ======== =========== ======== =========================================================
System                4 Services                0     12,096 K Unknown  N/A          0:07:02 N/A                                                      
略

powershell.exe    11796 Console                 1     48,456 K Running  Neko         0:00:00 C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe
WmiPrvSE.exe       6620 Services                0     11,424 K Unknown  N/A          0:00:02 N/A
powershell.exe     2432 Console                 1     48,488 K Running  Neko         0:00:00 OleMainThreadWndName
$TPID = Get-Process powershell | `
        Select-Object Id,MainWindowTitle | ? { $_.mainWindowTitle -match "Olemainthreadwndname" } |`
        Select-Object Id                 | Out-String -Stream | ? { $_ -match "[0-9].+" }

Stop-Process -id $TPID 

 

1.8 実行しているスクリプトの dirname を取得する

dirname_0.ps1
$basedir = Split-Path $script:myInvocation.MyCommand.path -parent

 

1.9 カレントパスの c:\ という文字を /cygdrive/c/ に置換する

replace_c_drive.ps1

get-location (pwd コマンド) の結果より Path フィールドを取り出して置換する。
なお、Out-String によってコンソールに表示されたログをそのまま(修飾することなく)置換処理に渡している。

get-location | % { $_.Path } | Out-String -Stream | % { $_ -replace 'C:\\' ,'/cygdrive/c/' }

 
次のように文字列オブジェクトに対して replace メソッドを使っても良い

(Get-Location).ToString().Replace('c:\', '/cygdrive/c/')

複数行に分けて書くと次のようになる

$d = (Get-Location).ToString()
$d.Replace('c:\', '/cygdrive/c/')

 
  

2.1 Microsoft.VisualBasic.Interaction 使用例

 
nvim プロセスが存在しているか判定し、nvim プロセスが存在していれば nvim プロセスをアクティブ(=マウスでクリックして選択した状態)にする

参考にしたサイト

以下のように nvim が起動しており、SendKey クラスを使って nvim のツールバーを操作する。

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
      0     0.00      14.11       0.15    5410 033 nvim

 

appActive.ps1
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms

# nvim プロセスが存在しているか判定する
$ps = Get-Process | Where-Object { $_.Name -eq "nvim"}
Write-Host $ps

if( $ps -eq $null )
{
  return $FALSE
}
else
{
  # nvim プロセスが存在していれば、nvim プロセスをアクティブ(=マウスでクリックして選択した状態) にする。
  [Microsoft.VisualBasic.Interaction]::AppActivate($ps.ID);
  Start-Sleep 5
  return $TRUE
}

 
 

3.1 キーコード送信

 
nvim に対して、 Alt キーを送信して、右カーソルを2回送信して、Enter を 2回送信してメニュを選択する。
% が Alt を表す。

 

sendKey.ps1
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms

# nvim プロセスが存在しているか判定する
$ps = Get-Process | Where-Object { $_.Name -eq "nvim"}
Write-Host $ps

if( $ps -eq $null )
{
  return $FALSE
}
else
{
  # nvim プロセスが存在していれば、nvim プロセスをアクティブ(=マウスでクリックして選択した状態) にする。
  [Microsoft.VisualBasic.Interaction]::AppActivate($ps.ID);
  Start-Sleep 5
}

# nvim に対して、 Alt キーを送信して、右カーソルを2回送信して、Enter を 2回送信してメニュを選択する。
# % が Alt を表す。
Start-Sleep -s 2
add-type -AssemblyName System.Windows.Forms

Start-Sleep -s 2
[System.Windows.Forms.SendKeys]::SendWait("%")

Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{RIGHT}")

Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{RIGHT}")

Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")

Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")

return $TRUE

 
 

3.2 メール送信

 
メールを送信する。なお、メールの件名は subject.txt、本文は body.txt に書いている。
 

sendMail.ps1
$to       = "wanchango@example.com"
$subject  = Get-Content subject.txt
$body     = Get-Content body.txt -Raw
$smtpHost = "my.smtp.server.com"
$from     = "nekochango@example.com"

$email = New-Object System.Net.Mail.MailMessage

$email.To.Add($to)
$email.From       = $from
$email.Subject   = $subject
$email.Body       = $body

$client = New-Object System.Net.Mail.SmtpClient $smtpHost
$client.UseDefaultCredentials = $true
$client.Send($email)

 

3.3 シリアルコンソールの読み出し

SerialPortRead.ps1

ポート番号=COM1、ボーレート=115200、パリティなし、ビット長=8、ストップビット=1 の場合。

$port= New-Object System.IO.Ports.SerialPort COM1,115200,None,8,one
if( $port.IsOpen )
{
  Write-Host 'オープン失敗'
  exit $False
}

# シリアルコンソールを開く
$port.Open()

# 入力がある限り読み出し続ける
do
{
  $line = $port.Readline()

  # 一行目($num -eq 0)はヘッダのため読み飛ばす
  if( $num -gt 0 )
  {
    Write-Host   $line
  }
  $num ++
}
while( $line )

 

3.4 シリアルコンソールの書き出し

SerialPortWrite.ps1
$port= New-Object System.IO.Ports.SerialPort COM1,115200,None,8,one
if( $port.IsOpen )
{
  Write-Host 'オープン失敗'
  exit $False
}

# シリアルコンソールを開く
$port.Open()

# ls -ltr コマンドを書き込む
$port.Write( "ls -ltr" + "`r")

 

4.1 SQLite3 操作

 
SQLite3 のデータベースファイルからデータを取り出す。

  • データベースファイル名は output.db とする
  • テーブル名は OTBL とする
  • 「No」「Title」「Result」の情報が取り出せなかったら、エラーメッセージを表示して終了する
  • SQL コマンドは予め sql_cmd_summary.txt に定義しておく
  • 出力形式は csv とする
  • sqlite3.exe はこちらの手順で入手しておく

 

sql_cmd_body.txt
.mode csv
select No, Title, Result from OTBL;

 

sqlite3_get_body.ps1
$DB = 'output.db'
$line = '.read sql_cmd_body.txt' | .\sqlite3.exe $DB
$len  = $line.Lenght
if ($len -gt 1)
{
  Write-Output '[DEBUG] OK'
  Write-Output $line
}
else
{
  Write-Error "[DEBUG] NG"
  Write-Error "Could not get result from $DB"
  exit
}

 
 

4.2 SQLite3 操作(replace)

 
SQLite3 のデータベースファイルの内容を更新(編集)する。

  • データベースファイル名は output.db とする
  • テーブル名は OTBL とする
  • 「Details」レコードの "http://www" を "https://www" に変更する。OTBL は上書き更新する。
  • SQL コマンドは予め sql_cmd_replace.txt に定義しておく
  • sqlite3.exe はこちらの手順で入手しておく


 

sql_cmd_replace.txt
update OTBL set Details = replace ( Details, 'http://www', 'https://www' ); 

 

sqlite3_replace_details.ps1
$DB = 'output.db'
'.read sql_cmd_replace.txt'  | .\sqlite3.exe $DB

 
 

4.3 SQLite3 クエリ結果を HTML に変換する

 
【SQLite】SQLite3 データを HTML で出力する (Windows10 環境)【SW】 - 4f938672-cb1c-4c5a-8233-192c4ec901df のコードに以下の変更を追加したものである。

  • 入力ファイルの妥当性チェック
  • 出力ファイルは Result.html 固定にした

 

sqlite3_html_ext.ps1
function    main()
{
    param( [string] $DB )

    if( [string]::IsNullOrEmpty($DB) )
    {
      Write-Host "Error: `$DB was empty"
      exit 2
    }

    if( !(Test-Path $DB))
    {
      Write-Host "Error: could not found $DB"
      exit 3
    }
}

if ( $args[0] -eq $null )
{
  Write-Host 'Error: Could not found DB'
  exit
}
elseif( !(Test-Path $args[0]) )
{
  Write-Host "Error: Could not found $args[0]"
  exit
}

$DB = $args[0]

$output = 'Result.html'

if ( !(Test-Path $output) )
{
  New-Item -type file $output > $null
}

'<html><body>' | Out-File -Append $output

foreach ( $i in ( sqlite3 $DB ".tables" ).Split() )
{
    if( [string]::IsNullOrEmpty($i) )
    {
        continue
    }
    "<h2>$i</h2>"      | Out-File -Append $output
    "<table border=1>" | Out-File -Append $output
    "<tr>"             | Out-File -Append $output

    foreach ( $j in ( sqlite3 $DB "PRAGMA table_info($i);" ))
    {
        if( [string]::IsNullOrEmpty($j) )
        {
            continue
        }
        $j = $j.Split('|')[1]
        "<th>$j</th>" | Out-File -Append $output
    }
    "</tr>" | Out-File -Append $output

    sqlite3 -html $DB "select * from $i ;" | Out-File -Append $output
    "</table>" | Out-File -Append $output
}
"</body></html>" | Out-File -Append $output

 
 

5.1 XML 操作 (読み書き)

 
以下の 1 ~ 3 の処理をするプログラム。
実行形式

> .\xml_rw.ps1 sample.xml

 
処理内容

1. 引数に指定した sample.xml を読み出す。
2. 1番目の要素 (配列なので[0]) の TAG と REV タグの内容を「DOG」「44」で書き換える。
3. そして sample.xml.[日時] という形式でファイル出力する。

 
sample.xml

<?xml version="1.0" encoding="UTF-8"?>
<CATS>
  <Cat type="MIKE">
    <TARGET>mike-robo</TARGET>
    <REV>10</REV>
  </Cat>
  <Cat type="SHIRO">
    <TARGET>shiro-robo</TARGET>
    <REV>20</REV>
  </Cat>
  <Cat type="Hachiware">
    <TARGET>hachi-robo</TARGET>
    <REV>30</REV>
  </Cat>
</CATS>

 
sample.xml.20180904-002428

<?xml version="1.0" encoding="UTF-8"?>
<CATS>
  <Cat type="MIKE">
    <TARGET>DOG-robot</TARGET>
    <REV>44</REV>
  </Cat>
  <Cat type="SHIRO">
    <TARGET>shiro-robo</TARGET>
    <REV>20</REV>
  </Cat>
  <Cat type="Hachiware">
    <TARGET>hachi-robo</TARGET>
    <REV>30</REV>
  </Cat>
</CATS>

 

xml_rw.ps1
class   XmlOprClass
{
  $m_XML         = ''       # XML インスタンス
  $m_InputFile   = ''       # 入力ファイルである XML のパス
  $m_Idx         = -1       # Cats[i] のインデックス
  $m_Target      = ''       # タグ <TARGET>
  $m_Rev         = ''       # タグ <REV>

  # コンストラクタ
  XmlOprClass([string] $f)
  {
    $filename         = (Get-Item $f).FullName
    $this.m_XML       = [xml] (Get-Content $filename)
    $this.m_InputFile = $filename
  }

  [void] fn_load_one([int]$i)
  {
    if( $i -lt 3 ) 
    {
      $this.m_Idx     = $i
      $this.m_Target  = $this.m_XML.Cats.Cat[$i].TARGET
      $this.m_Rev     = $this.m_XML.Cats.Cat[$i].REV
    }
  }

  [void] fn_change([string]$target, [int]$rev)
  {
    $this.m_Target = $target
    $this.m_Rev    = $rev
  }

  [void] fn_update()
  {
    $now    = (Get-Date -UFormat ".%Y%m%d-%H%M%S")
    $i  	= $this.m_Idx
    if( ( $i -ge 0 ) -And ( $i -lt 3 ) )
    {
      $ofile = $this.m_InputFile + $now
      $this.m_XML.Cats.Cat[$i].TARGET   = $this.m_Target
      $this.m_XML.Cats.Cat[$i].REV      = $this.m_Rev
#     write-host "[DEBUG] $this.m_XML.Cats.Cat[$i].TARGET"
#     write-host "[DEBUG] $this.m_XML.Cats.Cat[$i].REV"
      $this.m_XML.save($ofile)
      Write-Host "[SAVE] $ofile"
    }
  }
}

function    main()
{
  param([string] $xmlFile)

  if( [string]::IsNullOrEmpty($xmlFile) )
  {
    Write-Host "Error: `$xmlFile was empty"
    exit 2
  }

  if( !(Test-Path $xmlFile))
  {
    Write-Host "Error: could not found $xmlFile"
    exit 3
  }

  $X = [XmlOprClass]::new( $xmlFile )
  $X.fn_load_one(0)             # XML の /Cats/Cat[0] をバッファに書き込む
  $X.fn_change("DOG-robot", 44) # バッファリングしている内容を引数のもので上書きする
  $X.fn_update()                # XML を更新する
  return 0
}

$retval = main $args[0]
if( $retval -eq 0 )
{
  Write-Host "Success"
}
else
{
  Write-Host "Failure"
}

 
 

5.2 XML 操作 (読み書き)

以下のように XML を使って "main" "sub" という2種類のバイナリの生成を監視するプログラム。

1. <MATCH>タグが "newer" なら <TIMESTAMP> で指定した時刻よりも1つ新しいものを選択する。
2. <MATCH>タグが "newest" なら <TIMESTAMP> で指定した時刻よりも最も新しいものを選択する。
3. <MATCH>タグが "same" なら <TIMESTAMP> で指定した時刻と同時刻のものを選択する。

上記 1, 2, 3 のいずれかに該当すれば、XML の <TIMESTAMP> を更新する
<?xml version="1.0" encoding="UTF-8"?>
<BINS>
  <BIN type="main">
    <DIR>C:\work\PowerShellGui\output\rel-main-*_*</DIR>
    <FILE>main_*-*.bin</FILE>
    <MATCH>newest</MATCH>
    <TIMESTAMP>2018/10/06 23:08</TIMESTAMP>
    <EXPORT>C:\work\PowerShellGui\result\main.txt</EXPORT>
  </BIN>
  <BIN type="sub">
    <DIR>C:\work\PowerShellGui\output\rel-sub-*_*</DIR>
    <FILE>sub*-*.bin</FILE>
    <MATCH>newer</MATCH>
    <TIMESTAMP>2018/10/06 20:41</TIMESTAMP>
    <EXPORT>C:\work\PowerShellGui\result\sub.txt</EXPORT>
  </BIN>
</BINS>

6.1 Excel のシート内探索

 
以下 1, 2, 3 の操作をするプログラムである.
なお、実行していないので文法ミスや実行誤りがあるかも知れない.

1. sample.xlsx の sheet1 シートを開く。

2. B3セルに $n の値が記述されていれば、M3セルに "HIT" と入力する。
  あるいは B3セルが空っぽであれば、"MISS" と入力する。
   
3. B4 から B20 セルまで 2 を繰り返す

 

excel1.ps1
$B = "B3"                        # 始点となるセル
$E = "AZ20"                      # 終点となるセル
$Nums = @(1, 4, 5, 7, 13, 18)    # 探索する番号とする

$excel                = New-Object -ComObject Excel.Application
$excel.Visible        = $false
$excel.DisplayAlerts  = $false

$book     = $excel.Workbooks.Open("sample.xml")
$sheet    = $excel.Worksheets.Item("sheet1")

# 始点となる列・行を取得する
$beginX   = $sheet.Range($B).Column
$beginY   = $sheet.Range($B).Row

# 終点となる列・行を取得する
$endX     = $sheet.Range($E).Column
$endY     = $sheet.Range($E).Row

$M = 13  # M列

# B3 から B4, B5, B6 ... と B20 までを辿って $n と一致する項目であれば、
# M列に結果( "HIT" もしくは "MISS" )を入力する
for( $y = $beginY; $y -le $endY; $y++ )
{
  foreach( $n in $Nums )
  {
    $pos = $sheet.Cells.Item($y, $beginX).text  # 文字列で比較する. 整数値のみであるならば Int でも良い

    if( [string]::IsNullOrEmpty($pos) ) # 対象のセルが空の場合. 文字色を赤にする
    {
      $sheet.Cells.Item($y, $M)                     = "MISS"
      $sheet.Cells.Item($y, $M).font.ColorIndex     = 3
      break
    }
    elseif( $pos -like $n ) # セルの内容が一致した場合. 文字色は黒にする
    {
      $sheet.Cells.Item($y, $M)                     = "HIT"
      $sheet.Cells.Item($y, $M).font.ColorIndex     = 1
      break
    }
  }
}

$excel.ActiveWorkbook.Save()
$book.Close()

 
 

6.2 VBAマクロを実行する

下記の Excel ファイルのシートを開き、チェックボックスにチェックを入れてイベントを実行する。

ファイル C:\user\neko\sample.xlsm
シート sheet1
チェックボックス debug
イベント名 build

 

exec_vba.ps1
$excel                = New-Object -ComObject Excel.Application
$excel.Visible        = $false
$excel.DisplayAlerts  = $false

# sample.xlsm の sheet1 シートを開く
$book  = $excel.Workbooks.Open("C:\user\neko\sample.xlsm")
$sheet = $excel.Worksheets.Item("sheet1")

# sheet1 シートにある debug というチェックボックスにチェックを入れる
$sheet.CheckBoxes("debug").Value = 1

# ボタンに割り当てられたイベントである build を実行する
$excel.run( "build" )

# 保存する場合は下記を有効にする
# $excel.ActiveWorkbook.Save()

# 後始末をする
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
Remove-Variable excel

 
 

7.1 空白区切りで文字列を切り出す

 
文字列を空白区切りで抽出する。wc, や awk コマンドのデフォルトの挙動である。
 

wc1.ps1
#!/usr/bin/env pwsh

# 空白区切りで抽出し、[] で括って表示する。
# なお、空白文字(文字長0) は表示せずスキップする。

if ( $Args -eq $null )
{
    Write-Error 'Error: Could not found $Args'
}

for ($i = 0; $i -lt $Args.Length; $i++ )
{
    Get-Content $Args[0] | Foreach-Object { # Foreach-Object と { は同一行に書くこと
        $matches = [Regex]::Split($_," ")
        $matchCount = $matches.Length
#       Write-Host "[DEBUG] " $_
#       Write-Host "Count=> $matchCount"
        for( $j = 0; $j -lt $matchCount; $j++ )
        {
            if( $matches[$j].Length -ne 0 )
            {
                $line = '[' + $matches[$j] + ']'
                Write-Host $line
            }
        }
    }
}

 
 

7.2 文字列から指定した文字の位置をポイントする(C言語の strstr 相当)

 
dirname 相当をする (末尾から辿って最初に見つかった / 以降を削除する)
 
例:

http://xxxx/yyyy/zzzz
↓
http://xxxx/yyyy

 

IndexOf1.ps1
#!/usr/bin/env pwsh

$url = 'https://msdn.microsoft.com/ja-jp/library/system.string.indexof(v=vs.110).aspx'

$url.IndexOf("/")   #=> 6

# dirname 相当をする (末尾から辿って最初に見つかった / 以降を削除する)
$url.Substring(0,$url.LastIndexOf("/") + 1)

 
 

7.3 regex を使ったパターンマッチ

 
regex によりパターンマッチにより文字列を抽出する。
sed 's#http://\(.*\)#\1#g' と同じことだが、取り出したパターンを使える。

http://msdn.microsoft.com/ja-jp/library/system.string.indexof(v=vs.110).aspx
↓
msdn.microsoft.com/ja-jp/library/system.string.indexof(v=vs.110).aspx

 

regex1.ps1
#!/usr/bin/env pwsh

# 使用するパターンマッチ
$regex   = "https://(.*)"

# 解析対象の文字列データ (ヒアドキュメント)
$content = '@
https://msdn.microsoft.com/ja-jp/library/system.string.indexof(v=vs.110).aspx
HTTPS://translate.google.co.jp/?hl=ja
https://yahoo.co.jp
@'

# 大小文字の区別なしでパターンマッチする
$resultingMatches = [Regex]::Matches($content, $regex, "IgnoreCase")

# パターンマッチ判定の結果を1つずつ取り出す
foreach($match in $resultingMatches)
{
    $match.Groups[1].Value
    #=> msdn.microsoft.com/ja-jp/library/system.string.indexof(v=vs.110).aspx
    #   translate.google.co.jp/?hl=ja
    #   yahoo.co.jp
}

 

7.4 ANSI Colorエスケープ文字を取り除く

$line に含まれる文字から ANSI Color エスケープを取り除き、a.txt に書き出す

項目 文字コード Vimでの入力方法 Emacs での入力方法
下記の◇ ^M を表す Ctrl-V Ctrl-M で入力できる Ctrl-Q Ctrl-M で入力できるはず(未確認)
下記の■ ^[ を表す Ctrl-V Ctrl-[ で入力できる Ctrl-Q Ctrl-[ で入力できるはず(未確認)

見易さのために改行している

trim_ansi_color_code.ps1
    # ANSI Color escape key を削除する
    $line | % { $_ -replace '\[\d+(;\d+)?m' } | `
      % { $_ -replace '■' } | `
      % { $_ -replace '◇' } | `
      Out-File -Encoding Default -Append a.txt

 

8.1 一行ずつ読み出す

 
read_oneline1.ps
引数で指定したファイルの内容を一行ずつ読み出す

read_oneline2.ps
引数で指定したファイルの内容を一行ずつ読み出し、空行はスキップする。
 

#!/usr/bin/env pwsh

if ( $Args -eq $null )
{
    Write-Error 'Error: Could not found $Args'
}

for ($i = 0; $i -lt $Args.Length; $i++ )
{
    Get-Content $Args[0] | Foreach-Object { # Foreach-Object と { は同一行に書くこと
        if( $_.Length -ne 0 )
        {
            $_
        }
    }
}

 

9.1 フォルダ内のファイルを指定時刻よりも新しいか古いかで振り分ける

file_is_newer.ps1
  # 基準日時
  $target = 2018/01/01 00:00
  # カレントフォルダ内に存在するファイル群を時刻印順に取得する
  $files = Get-ChildItem . | Sort-Object { $_.LastWriteTime }
  # 1ファイルずつチェックしていく
  foreach ($f in $files)
  {
    # 時刻印を指定フォーマットで取り出す
    $t = (Get-ItemProperty $f).LastWriteTime.ToString('yyyy/MM/dd HH:mm')

    # 指定した時刻印よりも新しいファイルの場合
    if($t -gt $($target))
    {
      write-host "[New] $f"
    }
    # 時刻印が同じ場合
    elseif($t -eq $($target))
    {
      write-host "[SAME] $f"
    }
  }