Windowsでなにかちょっとしたことをしたいとき。
コンパイラを使うまでもなく。
なにか別パッケージをいれるまでもなく。
Windows付属のPowerShellで、データのモデリングを細かくできて。
表示や加工も問題ないことに気づきましたので。
覚書など。
PowerShellの覚書
祝日の一覧を返すスクリプトブロック
日付オブジェクトの生成
日付を扱いたいとき。
DateTimeにキャストしても、うまく取り込めない場合があります。
こちらの方法なら
[datetime]::parse("2025年8月14日 午後1時20分20秒")
漢字や、「午後」が入っていても、たいてい取り込めるようです。
祝日の一覧をダウンロードして変数に格納
Shift-JisのCSVをダウンロードして、モデリングで使えるようにするには。
# 祝日をダウンロード
$tempfile = "$env:temp/syukujitsu.csv"
Invoke-WebRequest `
-Uri 'https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv' `
-OutFile $tempfile
# Shift-JISからUTF8に変換
$text = [System.IO.File]::ReadAllText($tempfile,[Text.Encoding]::GetEncoding(932))
# ファイルは削除
Remove-item -Path $tempfile
Remove-Variable -Name 'tempfile'
# 行ごとに分割してCSVとして読み込み すべてStringとして読み込み
# 型変換する場合は 次の節の方法を使用する
$csv = ($text -replace "`r`n","`n") | ConvertFrom-Csv
# フィルタしてみる
$csv | Where-object { $_.'国民の祝日・休日月日' -eq '2025/8/11' }
まず、Shift-JISからUTF-8の変換は、ファイルである必要があるため、ファイルとして保存後、エンコーディングを変換して$text変数に格納します。
次に、改行コードごとに分割ですが、CR(0xD)が邪魔のため、LF(0xA)のみに変換して、$csv変数に配列として格納します。
配列に入れてしまえば、あとは好きなようにモデリングしたり、集計やフィルタリングが可能です。
おそらく、PSCustomObjectの配列、というデータの持ち方が、最も汎用的。
Select-ObjectやGroup-Objectを使用したり、ForEach-Objectを使用したり、色々と応用が効くと思いますが。
すべてテキストで読み込んでいます。モデリングして型変換しましょう。
モデリングしながらPSCustomObjectの配列を作成
先程の$csvは、単にImport-Csvで読み込んだだけで、型の変換はしていません。
使いやすいように、型変換、モデリングするとこんな感じでしょうか。
#モデリングしながらCSVを配列に読み込み
$typedCsv = ($text -replace "`r`n","`n") | ConvertFrom-Csv `
| Select-Object `
-Property @{Name = '国民の祝日・休日月日' ; Expression = { [datetime]::parse($_.'国民の祝日・休日月日') }},`
@{Name = '国民の祝日・休日名称' ; Expression = { $_.'国民の祝日・休日名称' } }
# フィルタしてみる
$typedCsv | `
Where-object { ($_.'国民の祝日・休日月日').ToString('yyyyMMdd') -eq (Get-Date).AddDays(-3).ToString('yyyyMMdd') }
$csvは、すべてのメンバーをテキストとして読み込みましたが。
$typedCSVは、日付の部分をDateTime型に変換して読み込んだ形になります。
このような感じで、Get-Dateのような、DateTimeオブジェクトを比較が可能になりますが。
元々のデータは時刻が無いため、00:00:00として扱われます。
Get-Dateには時刻も入っているため、比較する場合は、トリムする必要がありますが。
まあ日付として扱ったほうが、利便性は高いと思います。
祝日の一覧を返すスクリプトブロック
というわけで、祝日のダウンロードから、モデリング、変数として格納するところを、スクリプトブロックにしてみましょう。
#祝日が入った配列を返します
$GetTypedSyukujitsu = {
param ([String]$uri)
# 祝日をダウンロード
$tempfile = "$env:temp/syukujitsu.csv"
Invoke-WebRequest `
-Uri $uri `
-OutFile $tempfile
# Shift-JISからUTF8に変換
$text = [System.IO.File]::ReadAllText($tempfile,[Text.Encoding]::GetEncoding(932))
# ファイルは削除
Remove-item -Path $tempfile
Remove-Variable -Name 'tempfile'
#モデリングしながらCSVを配列に読み込み
return ($text -replace "`r`n","`n") | ConvertFrom-Csv `
| Select-Object `
-Property @{Name = '国民の祝日・休日月日' ; Expression = { [datetime]::parse($_.'国民の祝日・休日月日') }},`
@{Name = '国民の祝日・休日名称' ; Expression = { $_.'国民の祝日・休日名称' } }
}
# 祝日のダウンロードとモデリングはこの1行でおけ
$typedSyukujitsu = & $GetTypedSyukujitsu -uri 'https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv'
# フィルタしてみる
$typedSyukujitsu | `
Where-object { ($_.'国民の祝日・休日月日').ToString('yyyyMMdd') -eq (Get-Date).AddDays(-3).ToString('yyyyMMdd') }
スクリプトブロックにまとめると、こんな感じです。
このスクリプトブロックがあれば、いつでも最新の祝日一覧が取れる感じです。
スクリプトブロックを作る流れができれば。フィルタしているところも、日付が祝日かどうかを返す、スクリプトブロックを作れるわけですね。
日付から祝日名称を返すスクリプトブロック
というわけで、日付を入力すると、祝日の場合は名称を返すスクリプトブロックです。
#祝日が入った配列を返します
$GetTypedSyukujitsu = {
param ([String]$uri)
# 祝日をダウンロード
$tempfile = "$env:temp/syukujitsu.csv"
Invoke-WebRequest `
-Uri $uri `
-OutFile $tempfile
# Shift-JISからUTF8に変換
$text = [System.IO.File]::ReadAllText($tempfile,[Text.Encoding]::GetEncoding(932))
# ファイルは削除
Remove-item -Path $tempfile
Remove-Variable -Name 'tempfile'
#モデリングしながらCSVを配列に読み込み
return ($text -replace "`r`n","`n") | ConvertFrom-Csv `
| Select-Object `
-Property @{Name = '国民の祝日・休日月日' ; Expression = { [datetime]::parse($_.'国民の祝日・休日月日') }},`
@{Name = '国民の祝日・休日名称' ; Expression = { $_.'国民の祝日・休日名称' } }
}
$GetHolidayName = {
param([datetime] $date)
if ($script:holidays -eq $empty) {
Write-Host '祝日CSをダウンロードします'
# 祝日のダウンロード
$script:holidays = & $GetTypedSyukujitsu -uri 'https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv'
}
return $script:holidays | Where-object { ($_.'国民の祝日・休日月日').ToString('yyyyMMdd') -eq $date.ToString('yyyyMMdd') }
}
& $GetHolidayName -date (Get-Date -Year 2025 -Month 8 -Day 11)
最初のスクリプトロックは、祝日の一覧のダウンロードとモデリング
2つ目のスクリプトブロックが、日付が祝日かどうか調べる内容です。
使用するのは2つ目ですが、毎回ダウンロードするのも無意味のため、$scriptスコープに祝日の一覧を入れて、値があれば、2回目からはダウンロードしない設計にしてみました。
クラスを作ればstaticを使えたり、GetClosureを使う方法もありそうですが。
まあスコープを工夫してでなんとか。
日付については、曜日は、Excelと同じでAAAで表示できますので、全く問題ありません。
Windowsが使えて、インターネットに接続していれば、祝日を調べる問題はほとんど解決しそうです。
祝日一覧のグリッド表示
ダウンロードした祝日のCSVをモデリング。
モデリングした祝日の一覧を、グリッド表示するとこのような感じになります。
#祝日が入った配列を返します
$GetTypedSyukujitsu = {
param ([String]$uri = 'https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv')
if ($script:holidays -ne $empty) {
return $script:holidays
}
Write-Host '祝日CSをダウンロードします'
# 祝日をダウンロード
$tempfile = "$env:temp/syukujitsu.csv"
Invoke-WebRequest `
-Uri $uri `
-OutFile $tempfile
# Shift-JISからUTF8に変換
$text = [System.IO.File]::ReadAllText($tempfile,[Text.Encoding]::GetEncoding(932))
# ファイルは削除
Remove-item -Path $tempfile
Remove-Variable -Name 'tempfile'
#モデリングしながらCSVを配列に読み込み
$script:holidays = ($text -replace "`r`n","`n") | ConvertFrom-Csv `
| Select-Object `
-Property @{Name = '国民の祝日・休日月日' ; Expression = { [datetime]::parse($_.'国民の祝日・休日月日') }},`
@{Name = '国民の祝日・休日名称' ; Expression = { $_.'国民の祝日・休日名称' } }
return $script:holidays
}
& $GetTypedSyukujitsu | Out-GridView
一度ダウンロードしたCSVは、モデリング後に変数に入れておいて、次に使う場合は再利用という最終型のスクリプトブロックです。
これで、シェルを終了するまでは、無駄に何回もダウンロードせず、再利用が可能になります。
あれ?でもグリッドにて日付でソートすると、順番がおかしいような。
プロパティのMemberTypeは、確かにSystem.DateTimeになっていますから
型の変換は合っていると思います。グリッドの仕様なのかも?
インストール済みパッケージの一覧表示
PCにインストールされたパッケージの一覧を扱いたい場合。
Get-Package | Out-GridView
時差の計算
タイムゾーンの一覧表示
Get-TimeZone -ListAvailable | Out-GridView
海外の時刻を知りたいとき、こちらの「Id」を使用して計算します。
あれ?「PDT」米国太平洋標準時って存在しないのですね。代わりに「US Mountain Standard Time」が「PDT」になる感じでしょうか。
米国太平洋標準時が日本時間で何日何時か表示
[datetime]::ParseExact( `
('2025-08-26T11:00:00{0}' -f (Get-TimeZone -Id 'US Mountain Standard Time').BaseUtcOffset.ToString()), `
'yyyy-MM-ddTHH:mm:sszzz:00', $null)
この場合、PDT 2025年8月26日 11:00:00 が、日本時間で何日の何時かを表示しています。
タイムゾーン付きの日時の文字列を取り込むことで、取り込まれた値は日本時間に変換されます。
8月27日の3:00であることがわかります。
UTCが日本時間で何日何時か表示
[datetime]::ParseExact( `
('2025-08-26T18:00:00+{0}' -f (Get-TimeZone -Id 'UTC').BaseUtcOffset.ToString()), `
'yyyy-MM-ddTHH:mm:sszzz:00', $null)
同様に、UTCの2025年8月26日 18:00:00を取り込んでみますと。
同じように、8月27日の3:00であることがわかります。
うむ。火曜日の深夜ですね。
ゲームの無料配布の時刻ですが。翌日寝不足になりそうです。
UTCとPDTとの違いですが、UTCは{0}の部分が「00:00:00」になりますが、PDTは「-07:00:00」になります。
プラスはないけど、マイナスが付くため、プラスがない方に「+」を足しているわけですが。
これは見苦しいため、時差判定のスクリプトブロックを作って、汎用性をもたせたほうが格好良いと思います。(作ってナイ
PoweShellですが
ClassやFunctionを使って、ちまちま作っていたのですが。
セキュリティの関係で、Moduleがほぼ使えないため。
最近はScriptBlockを使用しています。
便利なScriptBlockは、追々追記しようと思いますが。
今はMacがメインなので、まあぼちぼち[amazonjs asin=”B0F2Y98MHW” locale=”JP” title=”【整備済み品】 Microsoft Surface Go2 / 10.5インチ タブレットPC/CPU:Pentium Gold 4425Y / メモリ:4GB / ストレージ:64GB / Win11 / MS Office 2021 / サーフィス サーフェス ゴー/Webカメラ(顔認証対応) / タイプカバーセット/PC King”]







コメントを残す