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

Windows環境での PowerShell の単体コード集

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


1章 標準API
 1.1 実行時の注意点
 1.2 コピー処理
   mkdir_foler_with_date.ps1
 1.3 ディレクトリ作成
   copy_item.ps1
 1.4 コピー、削除、親ディレクトリ名取得、ディレクトリ作成、7z解凍
   cp_rm_mkdir_7z_dirname.ps1
 1.5 ディレクトリごと削除する
   rmdir.ps1
 1.6 スクリプトの引数を受け取る
   args1.ps1
 1.7 プロセスID を指定して Kill する
   kill1.ps1

2章 VB.NET との連携
 2.1 [Microsoft.VisualBasic.Interaction]
   appActive.ps1

3章 .NET Framework との連携
 3.1 キーコード送信
   sendKey.ps1
 3.2 メール送信
   sendMail.ps1

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

5章 XML との連携
 5.1 XML 操作 (読み書き)
   xml_rw.ps1
 5.2 XML 操作 (読み書き)
   Watcher.ps1

6章 Excel との連携
 6.1 Excel 操作
   excel1.ps1

7章 文字列の操作
 7.1 空白区切りで文字列を切り出す
   wc1.ps1
 7.2 文字列から指定した文字の位置をポイントする(C言語の strstr 相当)
   IndexOf1.ps1

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

 
 

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

 
"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

 

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 

 
 

2.1

 
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)

 
 

4.1

 
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 のデータベースファイルの内容を更新(編集)する。

  • データベースファイル名は 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

 
【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

 
以下の 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 を使って "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>
Watcher.ps1
class   XMLOprClass
{
    $m_XML      = ''
    $m_filepath = ''

    $m_BINs     = @(
                    @{
                      type      = "main"; 
                      dir       = '';
                      file      = '';
                      tmstmp    = '';
                      pattern   = '';
                      export    = '';
                      found     = $False;
                    },
                    @{
                      type      = "sub"; 
                      dir       = '';
                      file      = '';
                      tmstmp    = '';
                      pattern   = '';
                      export    = '';
                      found     = $False;
                    }
                  )

    XMLOprClass([string] $f)
    {
        $filename           = (Get-Item $f).FullName
        $this.m_filepath    = $filename
        $this.m_XML         = [xml] (Get-Content $filename)
    }

    [void] fn_load()
    {
        for( $i = 0; $i -lt $this.m_BINs.Length; $i++ )
        {
            $bin  = $this.m_XML.BINS.BIN[$i]
            $type = $bin.type
            $idx  = 0
            switch($type)
            {
                "main" { $idx = 0 }
                "sub"  { $idx = 1 }
                default {}
            }

            # 対象フォルダのパターンを取り出してインスンタスに保持する
            $this.m_BINs[$idx].dir      = $bin.DIR

            # 対象ファイルのパターンを取り出してインスンタスに保持する
            $this.m_BINs[$idx].file     = $bin.FILE

            # 基準となる時刻印を取り出してインスンタスに保持する
            $this.m_BINs[$idx].tmstmp   = $bin.TIMESTAMP

            # 判定条件を取り出してインスタンスに保持する
            $this.m_BINs[$idx].mPattern = $bin.MATCH

            # 一致したファイルパスを書き出し先
            $this.m_BINs[$idx].export = $bin.EXPORT
        }
    }

    [void] fn_findFile()
    {
        for( $i = 0; $i -lt $this.m_BINs.Length; $i++ )
        {
            $bin    = $this.m_BINs[$i]

            # XML で定義したファイルパスのパターンに一致した中で、マッチパターンに該当したファイルパスを返す
            $ret    = $this.fn_findFile_matched( $bin.dir, $bin.file, $bin.tmstmp, $bin.mPattern )
            if($ret)
            {   # $ret が空でなければ該当するファイルが見付かったので $True とする
                $bin.found = $True
                Write-Output $ret | Set-Content -Encoding Default $bin.export 
            }
        }
    }

    [string] fn_findFile_matched([string] $dir, [string] $file, [string] $tmstmp, [string] $mPtrn)
    {
        $retPath = ''

        foreach ($d in (Get-Item $dir) )
        {
            # XML で指定したデータのフルパスを取り出す
            $path    = Join-Path $d $file
        
            # XML で指定したデータのフルパスに該当するファイル群を (時刻印順に) 取得する
            $samples = Get-ChildItem $path | Sort-Object { $_.LastWriteTime }
        
            foreach ($c in $samples)
            {
                $t = (Get-ItemProperty $c).LastWriteTime.ToString('yyyy/MM/dd HH:mm')

                if( $mPtrn -eq "newer")
                {   # XML で指定した時刻印よりも1つ新しいものを選択する
                    if($t -gt $($tmstmp))
                    {
#                       write-host "Newer: $c"
                        $retPath = $c
                        return $retPath
                    }
                }
                elseif( $mPtrn -eq "newest" )
                {   # XML で指定した時刻印よりも最も新しいものを選択する
                    if($t -gt $($tmstmp))
                    {
#                       write-host "Newest: $c"
                        $retPath = $c
                    }
                }
                elseif( $mPtrn -eq "same" )
                {   # XML で指定した時刻印と同じものを選択する
                    if($t -eq $($tmstmp))
                    {
                        write-host "Same: $c"
                        $retPath = $c
                    }
                }
            }
        }

        return $retPath
    }

    [void] fn_update()
    {
        for( $i = 0; $i -lt $this.m_BINs.Length; $i++ )
        {
            $bin    = $this.m_BINs[$i]

            if($bin.found -eq $True)
            {   # 更新データが見付かったので XML の要素を書き換える

                $path = Get-Content $bin.export

                # (一度 fn_findFile_matched で取得しているので)冗長だが、再度、時刻印を取り出す
                $t    = (Get-ItemProperty $path).LastWriteTime.ToString('yyyy/MM/dd HH:mm')

                $this.m_XML.BINS.BIN[$i].TIMESTAMP = $t
            }
        }
        $this.m_XML.save( $this.m_filepath )
    }
}


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 2
    }

    # コンストラクタ
    $XML = [XMLOprClass]::new( $xmlFile )

    # XML データの各要素を取得する
    $XML.fn_load()

    # XML で定義した検索パターンに一致するファイルが存在するか調べる
    $XML.fn_findFile()

    # XML ファイルを更新する
    $XML.fn_update()

    return  0
}


$retval = main $args[0]

 
 

6.1

 
以下 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()

 
 

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

 
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 によりパターンマッチにより文字列を抽出する。
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
}

 
 

8.1

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

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

read_oneline1.ps1
#!/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 と { は同一行に書くこと
        $_
    }
}

 

read_oneline2.ps1
#!/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 )
        {
            $_
        }
    }
}