元記事:PowerShellでカンタンに勤務時間を割り出す方法 - Qiita
勤怠管理は会社ごとに微妙に違う気がするので、結局自分で魔改造することになるんじゃないかと思った。
コード(原型がほぼない)
.ps1
# powershell -NoProfile -ExecutionPolicy RemoteSigned .\oreGWT.ps1 2016 05
# powershell -NoProfile -ExecutionPolicy RemoteSigned .\oreGWT.ps1 2016 05 -MakeEven
Param
(
[Parameter(Mandatory=$True,HelpMessage="対象年を指定してください。")]
[ValidateRange(0001,9999)]
[int] $Year,
[Parameter(Mandatory=$True,HelpMessage="対象月を指定してください。")]
[ValidateRange(01,12)]
[int] $Month,
[ValidateRange(01,31)]
[int] $Day = 01,
[ValidateRange(00,23)]
[int] $Hour = 04,
[ValidateRange(00,59)]
[int] $Minute = 00,
[ValidateRange(00,59)]
[int] $Second = 00,
[string[]] $LogName = @('System', 'Application'), #, 'Security'),
[string] $Delimiter = ',',
[switch] $MakeEven
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# 主処理
filter main
{
$yyyyMM = '{0:0000}/{1:00}' -f $Year, $Month
$dd = '{0:00}' -f $Day
$HHmmss = '{0:00}:{1:00}:{2:00}' -f $Hour, $Minute, $Second
# イベントログの取得開始日時を指定
$after = try {Get-Date "${yyyyMM}/${dd} ${HHmmss}"}
catch {Get-Date "${yyyyMM}/01 ${HHmmss}" | %{$_.AddMonths(1).AddDays(-1)}} # 月末日
# ヘッダ出力
@(
'#起動日時',
'#終了日時',
'#経過時間',
'#経過時間-休憩(1H)'
) -join $Delimiter
# ShortDate ごとに明細を出力
$LogName |
ForEach-Object {Get-EventLog -LogName $_ -After $after -Before $after.AddMonths(1)} | # 一ヶ月分のイベントログ
Select-Object -ExpandProperty TimeWritten | # 書込日時
Group-Object -Property {Get-ShortDate $_} | # ShortDate ごとに集約
Sort-Object Name | # ShortDate で並び替え
ForEach-Object {New-Record $_.Group} # 明細出力
}
# 時刻補正後に日付の文字列を取得
filter Get-ShortDate ($date)
{$date.AddHours(- $Hour).AddMinutes(- $Minute).AddSeconds(- $Second).ToShortDateString()}
# 新たな明細を作成
filter New-Record ($group)
{
$min, $max = Get-MinMaxDate $group
if ($MakeEven)
{
$min = Get-EvenDate $min
$max = Get-EvenDate $max
}
@(
(Get-Date $min -Format 'yyyy/MM/dd HH:mm:ss'),
(Get-Date $max -Format 'yyyy/MM/dd HH:mm:ss'),
($max - $min),
($max - $min.AddHours(1)) # 休憩一時間
) -join $Delimiter
}
# 最小日時と最大日時を取得
filter Get-MinMaxDate ($times)
{
# $times | Measure-Object -Maximum -Minimum | %{$_.Minimum, $_.Maximum}
$min = Get-Date '9999/12/31 23:59:59'
$max = Get-Date '0001/01/01 00:00:00'
foreach ($t in $times)
{
if ($t -lt $min) {$min = $t}
if ($t -gt $max) {$max = $t}
}
$min, $max
}
# 単位分への切り捨て、切り上げ
filter Get-EvenDate ($date, $unitMinute = 15)
{
$zero = Get-Date $date -Format 'yyyy/MM/dd HH:00:00' | Get-Date
$near = $zero
0..[math]::Floor(60 / $unitMinute) |
ForEach-Object {$_ * $unitMinute} |
ForEach-Object {$zero.AddMinutes($_)} |
Where-Object {($date - $_).Duration() -le ($date - $near).Duration()} |
ForEach-Object {$near = $_}
$near
}
main