トップ «前の日記(2025年06月22日) 最新 編集

Masa's blog

検索キーワード:

2026年02月24日 PowershellでのCSVとXMLの扱い方 [長年日記]

_ PowershellでのCSVの扱い方

ヘッダーありCSVを表示

> Get-Content .\test_header.csv
name,email,tel,age
伊藤 太郎,taro@foo.org,090-1111-1111,23
伊藤 次郎,jiro@foo.org,090-2222-2222,22
伊藤 三郎,saburo@foo.org,090-3333-3333,22
伊藤 四郎,siro@foo.org,090-4444-4444,22
伊藤 五郎,goro@foo.org,090-5555-5555,20
伊藤 花子,hanako@foo.org,,9

ヘッダーありCSVをCSVオブジェクトとして取込み

> $csv = (Get-Content test_header.csv | ConvertFrom-Csv)
> $csv

name       email          tel           age
----       -----          ---           ---
伊藤 太郎 taro@foo.org   090-1111-1111 23
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 花子 hanako@foo.org               9

CSVオブジェクトから項目「name」「tel」を取り出し

> $csv | select-object name,tel

name       tel
----       ---
伊藤 太郎 090-1111-1111
伊藤 次郎 090-2222-2222
伊藤 三郎 090-3333-3333
伊藤 四郎 090-4444-4444
伊藤 五郎 090-5555-5555
伊藤 花子

CSVオブジェクトから先頭2行を取り出し

> $csv | select-object name,tel -first 2

name       tel
----       ---
伊藤 太郎 090-1111-1111
伊藤 次郎 090-2222-2222

CSVオブジェクトから最終2行を取り出し

> $csv | select-object name,email -last 2

name       email
----       -----
伊藤 五郎 goro@foo.org
伊藤 花子 hanako@foo.org

CSVオブジェクトから先頭2行をスキップして、そこから先頭1行取り出し

> $csv | select-object name,email -skip 2 -first 1

name       email
----       -----
伊藤 三郎 saburo@foo.org

CSVオブジェクトから「name」の末尾が「次郎」と「email」の先頭が「taro」の行を抽出

> $csv | where-object{$_.name -match "次郎$" -or $_.email -match "^taro"}

name       email        tel           age
----       -----        ---           ---
伊藤 太郎 taro@foo.org 090-1111-1111 23
伊藤 次郎 jiro@foo.org 090-2222-2222 22

CSVオブジェクトを「age」の昇順、「tel」の降順にソート⇒「age」の昇順にならない!?

> $csv | sort-object -property @{expression={$_.age}},@{expression={$_.tel};desc=$true}

name       email          tel           age
----       -----          ---           ---
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 太郎 taro@foo.org   090-1111-1111 23
伊藤 花子 hanako@foo.org               9

CSVオブジェクトを「age」の昇順、「tel」の降順にソート⇒今度はOK!

> $csv | sort-object -property @{expression={[decimal]$_.age}},@{expression={$_.tel};desc=$true}

name       email          tel           age
----       -----          ---           ---
伊藤 花子 hanako@foo.org               9
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 太郎 taro@foo.org   090-1111-1111 23

CSVオブジェクトをCSVに変換

> $csv | convertto-csv
!!TYPE System.Management.Automation.PSCustomObject
"name","email","tel","age"
"伊藤 太郎","taro@foo.org","090-1111-1111","23"
"伊藤 次郎","jiro@foo.org","090-2222-2222","22"
"伊藤 三郎","saburo@foo.org","090-3333-3333","22"
"伊藤 四郎","siro@foo.org","090-4444-4444","22"
"伊藤 五郎","goro@foo.org","090-5555-5555","20"
"伊藤 花子","hanako@foo.org","","9"

CSVオブジェクトをCSVに変換(「#TYPE System.Management.Automation.PSCustomObject」の行は省略)

> $csv | convertto-csv -NoTypeInformation
"name","email","tel","age"
"伊藤 太郎","taro@foo.org","090-1111-1111","23"
"伊藤 次郎","jiro@foo.org","090-2222-2222","22"
"伊藤 三郎","saburo@foo.org","090-3333-3333","22"
"伊藤 四郎","siro@foo.org","090-4444-4444","22"
"伊藤 五郎","goro@foo.org","090-5555-5555","20"
"伊藤 花子","hanako@foo.org","","9"

ヘッダーなしCSVを表示

> Get-Content .\test_noheader.csv
伊藤 太郎,taro@foo.org,090-1111-1111,23
伊藤 次郎,jiro@foo.org,090-2222-2222,22
伊藤 三郎,saburo@foo.org,090-3333-3333,22
伊藤 四郎,siro@foo.org,090-4444-4444,22
伊藤 五郎,goro@foo.org,090-5555-5555,20
伊藤 花子,hanako@foo.org,,9

ヘッダーなしCSVをCSVオブジェクトとして取込み⇒1行目がヘッダーとして認識されている!?

> $csv = (Get-Content test_noheader.csv | ConvertFrom-Csv)
> $csv

伊藤 太郎 taro@foo.org   090-1111-1111 23
---------- ------------   ------------- --
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 花子 hanako@foo.org               9

ヘッダーなしCSVをヘッダーを指定してCSVオブジェクトとして取込み⇒ヘッダーが正しく認識されている!

> $csv = (Get-Content test_noheader.csv | ConvertFrom-Csv -header @("name","email","tel","age"))
> $csv

name       email          tel           age
----       -----          ---           ---
伊藤 太郎 taro@foo.org   090-1111-1111 23
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 花子 hanako@foo.org               9

_ PowershellでのXMLの扱い方

サンプルXML(test.xml)の表示

> Get-Content .\test.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <record id="1">
    <name version="1">伊藤 太郎</name>
    <email>ito-taro@foo.org</email>
    <tel>090-1234-1111</tel>
     <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>]]></detail>
  </record>
  <record id="2">
    <name version="1">伊藤 次郎</name>
    <email>ito-jiro@foo.org</email>
    <tel>090-1234-2222</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/02/02</birthday></root>]]></detail>
  </record>
  <record id="3">
    <name version="1">伊藤 三郎</name>
    <email>ito-saburo@foo.org</email>
    <tel>090-1234-3333</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>]]></detail>
  </record>
</root>

サンプルXML(test.xml)をXMLオブジェクト($xml1)に取込み

> [xml]$xml1 = Get-Content .\test.xml

XMLオブジェクトを表示

> $xml1

xml                            root
---                            ----
version="1.0" encoding="UTF-8" root

XMLオブジェクトのノード(xml)を表示

> $xml1.xml
version="1.0" encoding="UTF-8"

XMLオブジェクトのノード(root)を表示

> $xml1.root

record
------
{name, name, name}

XMLオブジェクトのノード(record)を表示

> $xml1.root.record

id     : 1
name   : name
email  : ito-taro@foo.org
tel    : 090-1234-1111
detail : detail

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

id     : 3
name   : name
email  : ito-saburo@foo.org
tel    : 090-1234-3333
detail : detail

XMLオブジェクトのノード(record)の2番目を表示

> $xml1.root.record[1]

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

XMLオブジェクトのノード(name)を表示

> $xml1.root.record.name

version #text
------- -----
1       伊藤 太郎
1       伊藤 次郎
1       伊藤 三郎

XMLオブジェクトのノード(name)の値を表示

> $xml1.root.record.name.'#text'
伊藤 太郎
伊藤 次郎
伊藤 三郎

XMLオブジェクトのノード(detail)を表示

> $xml1.root.record.detail

#cdata-section
--------------
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/02/02</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>

XMLオブジェクトのノード(detail)の値を表示

> $xml1.root.record.detail.'#cdata-section'
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/02/02</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>

XMLオブジェクトのノード(record)の属性(id)を表示

> $xml1.root.record.id
1
2
3

XMLオブジェクトのノード(record)を検索して表示

> $xml1.root.record | where-object{$_.name.'#text' -eq "伊藤 次郎"}

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

XMLオブジェクトのノード(record)から「伊藤 次郎」を検索して、「伊藤 花子」に変更

> $record1 = $xml1.root.record | where-object{$_.name.'#text' -eq "伊藤 次郎"}
> $record1.name.'#text' = "伊藤 花子"
> $xml1.root.record.name

version #text
------- -----
1       伊藤 太郎
1       伊藤 花子
1       伊藤 三郎

XMLオブジェクトのノード(record)から「伊藤 花子」を検索して、入れ子のXMLオブジェクト内のbirthdayを変更

> $record2 = $xml1.root.record | where-object{$_.name.'#text' -eq "伊藤 花子"}
> [xml]$xml2 = $record2.detail.'#cdata-section'
> $xml2.root.birthday = "2002/01/23"
> $record2.detail.'#cdata-section' = $xml2.outerXML
> $xml1.root.record.detail

#cdata-section
--------------
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/01/23</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>

「id」が「2」のnode(レコード)を指定して削除する

> $recordToRemove = $xml1.root.record | where-object{$_.id -eq "2"}
> $xml1.root.RemoveChild($recordToRemove)

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

上記の削除結果を確認する

> $xml1.root.record

id     : 1
name   : name
email  : ito-taro@foo.org
tel    : 090-1234-1111
detail : detail

id     : 3
name   : name
email  : ito-saburo@foo.org
tel    : 090-1234-3333
detail : detail

ノード(record)を作成し、属性(id)に「4」をセットする

> $record = $xml1.CreateElement("record")
> $record.SetAttribute("id","4")
> $record

id
--
4

ノード(name)を作成し、属性(version)に「1」をセットし、値に「伊藤 四郎」をセットする

> $name = $xml1.CreateElement("name")
> $name.SetAttribute("version","1")
> $name.innerXML = "伊藤 四郎"
> $name

version #text
------- -----
1       伊藤 四郎

ノード(email)を作成し、値に「ito-siro@foo.org」をセットする

> $email = $xml1.CreateElement("email")
> $email.innerXML = "ito-siro@foo.org"
> $email

#text
-----
ito-siro@foo.org

ノード(tel)を作成し、値に「090-1234-4444」をセットする

> $tel = $xml1.CreateElement("tel")
> $tel.innerXML = "090-1234-4444"
> $tel

#text
-----
090-1234-4444

ノード(record)にノード(name)を追加する

> $record.AppendChild($name)

version #text
1       伊藤 四郎

ノード(record)にノード(email)を追加する

> $record.AppendChild($email)

#text
ito-siro@foo.org

ノード(record)にノード(tel)を追加する

> $record.AppendChild($tel)

#text
090-1234-4444

ノード(record)の内容を確認する

> $record

id name email                  tel
-- ---- -----                  ---
4  name ito-siro@foo.org 090-1234-4444

ノード(root)にノード(record)を追加する

> $xml1.root.AppendChild($record)

id name email                  tel
-- ---- -----                  ---
4  name ito-siro@foo.org 090-1234-4444

ノード(root)にノード(record)が追加されたことを確認する

> $xml1.root.record

id     : 1
name   : name
email  : ito-taro@foo.org
tel    : 090-1234-1111
detail : detail

id     : 3
name   : name
email  : ito-saburo@foo.org
tel    : 090-1234-3333
detail : detail

id    : 4
name  : name
email : ito-siro@foo.org
tel   : 090-1234-4444

いろいろ更新したXMLオブジェクトを「test2.xml」にセーブ

> $xml1.Save("$pwd/test2.xml")

更新したXML(test2.xml)を表示

> Get-Content .\test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <record id="1">
    <name version="1">伊藤 太郎</name>
    <email>ito-taro@foo.org</email>
    <tel>090-1234-1111</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>]]></detail>
  </record>
  <record id="3">
    <name version="1">伊藤 三郎</name>
    <email>ito-saburo@foo.org</email>
    <tel>090-1234-3333</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>]]></detail>
  </record>
  <record id="4">
    <name version="1">伊藤 四郎</name>
    <email>ito-siro@foo.org</email>
    <tel>090-1234-4444</tel>
  </record>
</root>