or1ko's diary

日々を書きます

PSCustomObjectの比較

プロパティ名が同じでも -eq で比較するとFalseになる。
プロパティだけ取り出して、Compare-Objectで比較する。

$a = [PSCustomObject]@{ a = "a" }
$b = [PSCustomObject]@{ a = "a" }
$c = [PSCustomObject]@{ a = "c" }

$np = $a | Get-Member -Type NoteProperty | ForEach-Object { $_.Name }
(Compare-Object -Property $np $a $b).Count -eq 0

# 等しくない例。Falseになる。
(Compare-Object -Property $np $a $c).Count -eq 0

# Equalsおよび-eqでの比較はFalseになる
$a.Equals($b)
$a -eq $b

もう少し簡単な方法ないだろうか

Thunderbirdのメールデータを取得する方法

Import-Module -Name PSSQLite

$database = "C:\Users\<ユーザ名>\AppData\Roaming\Thunderbird\Profiles\<ランダムな文字列>.default\global-messages-db.sqlite"

# 全件取得したい場合はlimit 1を削除する
$query = "select * from messages INNER JOIN messagesText_content ON messages.id = messagesText_content.docid limit 1"

Invoke-SqliteQuery -Query $query -DataSource $database

参考にしたページ
Thunderbirdからメールメッセージを取得するSQLクエリー
Querying Thunderbird's SQLite message database from C# - Stack Overflow

SQLite にアクセスするためのPowerShellのモジュール
PowerShell Gallery | PSSQLite 1.0.3

3秒間ごとにコピーするスクリプト

指定したフォルダ($src)から指定したフォルダ($dest)にコピーするスクリプト
ただし、ファイルやフォルダを一つコピーするたびに3秒待つ。
また、フォルダの更新日付はコピーした日付となる。

$src = "<コピー元のフォルダパス>"
$dest = "<コピー先のフォルダパス>"
$waitSeconds = 3 # 待ち時間(秒)

Get-ChildItem $src -Recurse |
ForEach-Object {
    $isDir = $_.GetType().ToString().Contains("DirectoryInfo")
    $file = $dest + $_.FullName.Substring($src.Length)
    Write-Host "check $file"
    $exists = Test-Path -LiteralPath $file
    if (-not $exists) {
        if ($isDir) {
            Write-Host "make directory -> $file"
            New-Item -Path $file -ItemType Directory
        } else {
            Write-Host "copy file -> $file"
            Copy-Item -Path $_.FullName -Destination $file
        }
        Write-Host "wait $waitSeconds seconds"
        Start-Sleep -Seconds $waitSeconds
    }
}

月ごとのデータをよこ軸に集計する方法

たまに下記のような、月ごとのデータを

name mouth count
Tom 5 2
Jhon 6 3
Tom 6 3

下記のように変換して、
月の遷移を確認したくなることがある。

name 5 6
Tom 2 3
Jhon 0 6

そういう場合は、Group-Objectを使うと便利

PS > $table = [PSCustomObject]@{name="Jhon";mouth=5;count=2},
[PSCustomObject]@{name="Tom" ;mouth=6;count=3},
[PSCustomObject]@{name="Jhon";mouth=6;count=3}

PS > $table

name mouth count
---- ----- -----
Jhon     5     2
Tom      6     3
Jhon     6     3

PS > $table | Group-Object -Property name |
% {
    $a = [PSCustomObject]@{name=$_.name}
    $_.Group | % {
        $a | Add-Member -NotePropertyMembers @{$_.mouth=$_.count}
    }
    $a
}

name 5 6
---- - -
Jhon 2 3
Tom    3

WebページからBodyのテキストを取得する方法

PowerShellでスクレイピング 後編 HTMLをパースする - PowerShell Scripting Weblog

下記の記事で見つけた。
Invoke-WebRequestの結果は、
IEで解析されBody要素のDOMを扱えるとのことなので、
下記の通りすると、できる

$contents = Invoke-WebRequest $url
$contents.ParseHtml.body.innerText

PowerShellすごいなー。

Invoke-RestMethodの文字化け対策

gooラボ 形態素解析APIを試してみる - pierre3のブログ

上のブログに記載されてました。
Invoke-RestMethodは諦めて、下記のようにInvoke-WebRequestを使うようです。

$res = Invoke-WebRequest -Method Post $url -Body $body
$con = [System.Text.Encoding]::Utf8.GetString([System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes($res.Content))
#JSONの場合は下記のように変換する
ConvertFrom-Json $con