hakeの日記

Windows環境でプログラミングの勉強をしています。

PowerShell - ForEach-Objectの多重使用 - CSVファイルを読み取りデータに1を加算して出力する

Get-Content ".\test.csv" | %{
    (   # 1行ごとの処理
        $_ -split "," | %{
            # 1データごとの処理
            [int]$_ + 1
        }
    ) -join ","
} | Write-Output

test.csv

1,2,3
4,5,6
7,8,9

結果

2,3,4
5,6,7
8,9,10

普通のプログラムっぽい書き方(ForEach-Objectは使用しない)

$lines = Get-Content ".\test.csv"
foreach ($line in $lines) {
    $data = $line -split ","
    $ary = @()
    foreach ($datum in $data) {
        $ary += [int]$datum + 1
    }
    Write-Host ($ary -join ",")
}

CSVにヘッダがある場合

$isHeader = $true
Get-Content ".\test.csv" | %{
    if($isHeader){
        $isHeader = $false
        $_
    } else {
        ( $_ -split "," | %{ [int]$_ + 1} ) -join ","
    }
}

PowerShell - Excelの操作

EXCEL用のCOMオブジェクトを作成して、あとはVBAと同じ感覚で操作できるっぽいです。
一点、配列やコレクションの括弧の形状がVBAだと( )ですが、[ ]にしないとメソッドと間違えられてエラーになるので注意。

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true

$book = $excel.Workbooks.Add()
$sht = $excel.Worksheets[1] # 括弧の形状に注意
$sht.Name = "PowerShell"

$sht.Cells(1,1).Value = "Hello World"
$sht.Range("A2").Value = "PowerShell"


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

プロセスの解放

$excel = $null
[GC]::Collect()

または

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($sht)

PowerShell - GUIプログラム

ボタンをクリックすると文字を表示するプログラム。
デフォルトで使用できないクラスは、Add-Typeで読み込む。Formに設定したフォントはForm上の部品にも適用される。イベント登録はAdd_イベント名(処理)と記述する。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Font
#$font = New-Object Drawing.Font("MS Pゴシック",12)
#$font = New-Object Drawing.Font("MS P明朝",12)
#$font = New-Object Drawing.Font("MS 明朝",12)
$font = New-Object Drawing.Font("MS ゴシック",12)

# Form
$form = New-Object Windows.Forms.Form 
$form.Text = "Hello"
$form.Size = "400,500" 
$form.Font = $font

# Text
$txt = New-Object Windows.Forms.TextBox
$txt.Location = "10,10"
$txt.Size = "360,380" 
$txt.Multiline = $true
$txt.ScrollBars = [Windows.Forms.ScrollBars]::Vertical
$txt.Focus()

# イベント動作
$proc1 = { $txt.AppendText("Hello Powershell World!!`r`n") }
$proc2 = { $txt.AppendText("Focus In`r`n") }

# Button
$btn = New-Object Windows.Forms.Button
$btn.Location = "40,400"
$btn.Size = "300,30"
$btn.Text = "Hello"
$btn.Add_Click($proc1)
$btn.Add_GotFocus($proc2)


# Formに部品を追加
$form.Controls.Add($txt)
$form.Controls.Add($btn)

# 表示
$form.ShowDialog()

PowerShell - クラス

バージョン5からクラスが使用可能になったようです。

class Person {
    [string] $name
    [int] $age

    # コンストラクタ
    Person() {
        $this.name = "No Name"
        $this.age = 0
    }

    Person([string]$name, [int]$age) {
        $this.name = $name
        $this.age = $age
    }

    # メソッド
    [string]getName(){
        return $this.name
    }

    [int]getAge(){
        return $this.age
    }

    [void]talk([string]$str){
        Write-Host "${str}, I'm $($this.name), $($this.age) years old."
    }
}

$someone = New-Object Person
Write-Host $someone.getName()        # No Name
Write-Host $someone.getAge()         # 0

$taro = New-Object Person("Taro",20) 
$taro.talk("Hello")                  # Hello, I'm Taro, 20 years old.

継承

続きを読む

PowerShell - クロージャ

戻り値となるブロック内の変数$cntをscriptスコープ宣言することでfunction内の変数$cntへアクセスできるようになる?

function generator($step = 1){
    $cnt = 0
    return { $script:cnt += $step
            return $cnt
            }.GetNewClosure()
}

$a = generator
&($a)     # 1
&($a)     # 2
&($a)     # 3

$b = generator(2)
&($b)     # 2
&($b)     # 4
&($b)     # 6

&($a)     # 4
&($b)     # 8

PowerShell - 独自オブジェクトの作成

PSObjectにプロパティやメソッドを追加していくことで独自のオブジェクトが作成できます。

# Hashでプロパティを追加
$hash = @{name = "Taro"; age = 20}
$obj = New-Object PSObject -Property $hash

# Add-Memberでプロパティを追加
$obj | Add-Member -MemberType NoteProperty -Name str -Value "Hello"
$obj | Add-Member -MemberType ScriptProperty -Name talk `
            -Value {Write-Host "$($This.str), My Name is $($This.name)."} 

# プロパティのgetter/setterを追加
Add-Member -InputObject $obj `
           -MemberType ScriptProperty -Name nenrei `
           -Value { $this.age } `
           -SecondValue {
                param($age)
                $This.age = $age
             } 

# メソッドを追加
Add-Member -InputObject $obj `
           -MemberType ScriptMethod -Name greeting `
           -Value {
                param($str)
                $This.str = $str
             } 



$obj.GetType()
# IsPublic IsSerial Name                    BaseType
# -------- -------- ----                    --------
# True     False    PSCustomObject          System.Object

$obj.name           # Taro
$obj.age            # 20
$obj.str            # Hello
$obj.talk           # Hello, My Name is Taro.

# プロパティを直接変更
$obj.name = "Jiro"
$obj.talk           # Hello, My Name is Jiro.

# プロパティを直接変更
$obj.age = 25
$obj.age            # 25

# プロパティsetterで変更
$obj.nenrei = 30
$obj.nenrei         # 30

# プロパティをメソッドで変更
$obj.greeting("Good Morning")
$obj.talk           # Good Morning, My Name is Jiro.