Last active
December 27, 2018 21:05
-
-
Save nyanshiba/d21a1e1affe8ef9cdfb3568eb843a07a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #181228 | |
| <# | |
| ParentCountMin = 1 | |
| ParentInterval = 3 | |
| IfParentCountOver = "rendiff" | |
| Gen: 0123456789A... | |
| Parent: PPPPPPR <-Rename | |
| Child: CCCCCX <-Delete | |
| CCCCX <-Delete | |
| | PPPPPPR | |
| Gen CCCCCX | |
| | CCCCX | |
| | PPPP | |
| Gen CCC | |
| | CC | |
| P | |
| #> | |
| [array]$Content += "Start: $((Get-Date).ToString("yyyy/MM/dd (ddd) HH:mm:ss"))" | |
| $Content | Select-Object -Last 1 | |
| #====================ユーザ設定==================== | |
| #設定用の連想配列 | |
| $Settings = | |
| @{ | |
| #バックアップに関する設定 | |
| Backup = | |
| @{ | |
| #世代ディレクトリ用の日付 | |
| MyDateTime = (Get-Date).ToString("yyMMdd_HHmmss") | |
| #除外ディレクトリ | |
| ExclPath = 'logs','tsfiles' | |
| #親(Parent)世代の最小数(世代グループ数)(ge 1) | |
| ParentCountMin = 4 | |
| #P世代を挟む間隔(1世代グループ内の世代数)(ge 2) | |
| ParentInterval = 5 | |
| #古いP世代の扱い(delfull|rendiff) | |
| IfParentCountOver = "rendiff" | |
| } | |
| #ログに関する設定 | |
| Log = | |
| @{ | |
| #$True:有効 $False:無効 | |
| Toggle = $True | |
| #ログ保存ディレクトリ | |
| Path = 'C:\DTV\BackupLog' | |
| #ログローテの閾値 | |
| CntMax = 100 | |
| } | |
| #通知に関する設定 | |
| Post = | |
| @{ | |
| #$True:有効 $False:無効 | |
| TwitterToggle = $False | |
| #ruby.exeのパス | |
| rubyPath = 'C:\Ruby25-x64\bin\ruby.exe' | |
| #tweetモジュールのパス | |
| ModulePath = 'C:\DTV\EDCB\tweet.rb' | |
| #SSL_CERT_FILEのパス | |
| cert = 'C:\DTV\EDCB\cacert.pem' | |
| #$True:有効 $False:無効 | |
| DiscordToggle = $True | |
| #Webhook Url | |
| hookUrl = 'https://discordapp.com/api/webhooks/XXXXXXXXXX' | |
| #$True:有効 $False:無効 | |
| BalloonTipToggle = $True | |
| } | |
| #Tempディレクトリ内のファイルの削除 | |
| TempDelToggle = $True | |
| } | |
| #バックアップリスト(ハッシュ) | |
| $BackupDirHash = | |
| @( | |
| <# | |
| コピー元 -> コピー先の親ディレクトリ\日付_世代種\コピー先の子ディレクトリ | |
| @{ | |
| src = "コピー元"; | |
| dstparent = "コピー先の親ディレクトリ"; | |
| dst = "コピー先の子ディレクトリ" | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\Desktop\CDrive\enclog"; | |
| dstparent = "C:\Users\sbn\Desktop\DDrive"; | |
| dst = "\enclog" | |
| } | |
| #> | |
| @{ | |
| src = "C:\DTV"; | |
| dstparent = "D:"; | |
| dst = "\DTV" | |
| }, | |
| @{ | |
| src = "C:\Src"; | |
| dstparent = "D:"; | |
| dst = "\Src"; | |
| }, | |
| @{ | |
| src = "C:\Rec"; | |
| dstparent = "D:"; | |
| dst = "\Rec"; | |
| }, | |
| @{ | |
| src = "C:\MCServer"; | |
| dstparent = "D:"; | |
| dst = "\MCServer"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\Desktop"; | |
| dstparent = "D:"; | |
| dst = "\Desktop"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\Documents"; | |
| dstparent = "D:"; | |
| dst = "\Documents"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\Pictures"; | |
| dstparent = "D:"; | |
| dst = "\Pictures"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\Music"; | |
| dstparent = "D:"; | |
| dst = "\Music"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\AppData\Roaming\.minecraft"; | |
| dstparent = "D:"; | |
| dst = "\AppData\Roaming\.minecraft"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\AppData\Roaming\Code"; | |
| dstparent = "D:"; | |
| dst = "\AppData\Roaming\Code"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\AppData\Roaming\obs-studio"; | |
| dstparent = "D:"; | |
| dst = "\AppData\Roaming\obs-studio"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\AppData\Roaming\discord\Cache"; | |
| dstparent = "D:"; | |
| dst = "\AppData\Roaming\discord\Cache"; | |
| }, | |
| @{ | |
| src = "C:\Users\sbn\.ssh"; | |
| dstparent = "D:"; | |
| dst = "\.ssh"; | |
| }, | |
| @{ | |
| src = "C:\Windows\System32\drivers\etc"; | |
| dstparent = "D:"; | |
| dst = "\System32\drivers\etc"; | |
| }, | |
| @{ | |
| src = "C:\Windows\System32\Tasks"; | |
| dstparent = "D:"; | |
| dst = "\System32\Tasks"; | |
| } | |
| ) | |
| #====================差分バックアップ関数==================== | |
| function Backup-Difference | |
| { | |
| param | |
| ( | |
| [string]$src, | |
| [string]$dst | |
| ) | |
| Write-Output "Robocopy $src -> $dst" | |
| Robocopy $src $dst /E /PURGE /COPY:DAT /XO /NP /XA:SH /R:0 /XD "C:\Rec\mp4" "C:\Rec\ts" "C:\Rec\ShadowPlay" /FFT /BYTES /NFL /NP | |
| } | |
| #====================増分バックアップ関数==================== | |
| function Backup-Incremental | |
| { | |
| param | |
| ( | |
| [string]$src, | |
| [string]$dst, | |
| [string]$link | |
| ) | |
| Write-Output "Copy-Item $src -> $dst (参照:$link)" | |
| $rbcStd = Robocopy $src $link /L /E /NS /FP /XD "C:\Rec\mp4" "C:\Rec\ts" "C:\Rec\ShadowPlay" /FFT | |
| #robocopy /Lのstdを1行ずつループ | |
| $rbcstd | %{ | |
| #行に"新しいファイル"が含まれる場合 | |
| if ($_ -match "新しいファイル") | |
| { | |
| #ファイルのフルパス(スペース区切り且つスペースを含むパスに対応させている) | |
| $SrcFile = ($_ -split '\s+',3)[2] | |
| #ファイルのフルパス->コピー先\ファイルの相対パス | |
| try | |
| { | |
| Copy-Item -LiteralPath "$SrcFile" "${dst}$($SrcFile.Replace("$src",$null))" -Recurse -ErrorAction SilentlyContinue | |
| } catch | |
| { | |
| #Copy-Itemでディレクトリが存在しない場合の例外 | |
| $MakeDir = Split-Path "${dst}$($SrcFile.Replace("$src",$null))" -Parent | |
| $null = New-Item -Path $MakeDir -ItemType Directory -Force | |
| Write-Output "Maked Directory: $MakeDir" | |
| Copy-Item -LiteralPath "$SrcFile" "${dst}$($SrcFile.Replace("$src",$null))" -Recurse -ErrorAction SilentlyContinue | |
| } | |
| } | |
| } | |
| #変数のクリア | |
| $rbcStd = $null | |
| } | |
| #====================NotifyIcon==================== | |
| #System.Windows.FormsクラスをPowerShellセッションに追加 | |
| Add-Type -AssemblyName System.Windows.Forms | |
| #NotifyIconクラスをインスタンス化 | |
| $balloon = New-Object System.Windows.Forms.NotifyIcon | |
| #powershellのアイコンを使用 | |
| $balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon('C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe') | |
| #タスクトレイアイコンのヒントにファイル名を表示 | |
| #NotifyIcon.Textが64文字を超えると例外、String.Substringの開始値~終了値が文字数を超えると例外 | |
| switch (([string]($MyInvocation.MyCommand.Name) + ":$($Settings.Backup.MyDateTime)").Length) | |
| { | |
| {$_ -ge 64} {$TextLength="63"} | |
| {$_ -lt 64} {$TextLength="$_"} | |
| } | |
| $balloon.Text = ([string]($MyInvocation.MyCommand.Name) + ":$($Settings.Backup.MyDateTime)").SubString(0,$TextLength) | |
| #タスクトレイアイコン表示 | |
| $balloon.Visible = $True | |
| #====================Log==================== | |
| if ($Settings.Log.Toggle) | |
| { | |
| #ログ取り開始 | |
| Start-Transcript -LiteralPath "$($Settings.Log.Path)\$($Settings.Backup.MyDateTime).txt" | |
| #古いログの削除 | |
| Get-ChildItem "$($Settings.Log.Path)\*.txt" | Sort-Object LastWriteTime -Descending | Select-Object -Skip $Settings.Log.CntMax | %{ | |
| Remove-Item -LiteralPath "$_" | |
| Write-Output "ログ削除:$_" | |
| } | |
| } | |
| #====================TempDel==================== | |
| if ($Settings.TempDelToggle) | |
| { | |
| Write-Output "Tempディレクトリ内のファイルを削除" | |
| Remove-Item "$env:temp\*.*" -Recurse -Force | |
| } | |
| #====================ディレクトリ作成・リネーム==================== | |
| #配列の展開 | |
| $BackupDirHash | foreach { | |
| #自動変数が使えない部分があるため変数に入れとく | |
| $DstParent = $_.dstparent | |
| #親ディレクトリ下のP世代数 | |
| $ParentGen = Get-ChildItem -Directory "$DstParent\*_P" -Name -Exclude $Settings.Backup.ExclPath | |
| #世代ディレクトリの存在確認 | |
| if (Test-Path "$DstParent\$($Settings.Backup.MyDateTime)_P") | |
| { | |
| #P世代ディレクトリが既にある場合 | |
| Backup-Difference -Src "$($_.src)" -Dst "$DstParent\$($Settings.Backup.MyDateTime)_P$($_.dst)" | |
| } elseif (Test-Path "$DstParent\$($Settings.Backup.MyDateTime)_C") | |
| { | |
| #C世代ディレクトリが既にある場合 | |
| Backup-Incremental -Src "$($_.src)" -Dst "$DstParent\$($Settings.Backup.MyDateTime)_C$($_.dst)" -Link "$DstParent\$($ParentGen | Select-Object -Last 1)$($_.dst)" | |
| } else | |
| { | |
| #P、Cディレクトリ共に未生成の場合ディレクトリ作成 これらは$BackupDirHash[x].dstparentの設定が変更され、世代グループの状態がちぐはぐになる場合を想定し、毎回計算し直す仕様にしている | |
| #親ディレクトリ下の世代数 | |
| $AllGen = Get-ChildItem -Directory "$DstParent\*" -Name -Exclude $Settings.Backup.ExclPath | |
| #$AllGenの最も新しい世代グループ内の世代(C..P)数を$cntに取得 | |
| $cnt = 0 | |
| foreach ($a in $($AllGen | Sort-Object -Descending)) | |
| { | |
| $cnt++ | |
| if ($a -match "_P") | |
| { | |
| break | |
| } | |
| } | |
| Write-Output "ParentInterval(Previous Gen): $cnt/$($Settings.Backup.ParentInterval)" | |
| #switch文でも良いがネストが深くなり、自動変数$_が上書きされるのでifで書いてる | |
| if (($cnt -eq 0) -Or ($cnt -ge $Settings.Backup.ParentInterval)) | |
| { | |
| #全世代数が0か最新世代グループ内の世代数が$Settings.Backup.ParentInterval = P世代を生成する | |
| Write-Output "New Directory: $DstParent\$($Settings.Backup.MyDateTime)_P" | |
| #現在の世代グループ数と最大世代グループ数設定値を比較 | |
| if ($ParentGen.Count -gt $Settings.Backup.ParentCountMin) | |
| { | |
| #$Settings.Backup.ParentCountMinより大きい場合 = 世代グループ数が満杯なので、最も古いPを削除orリネーム、そのグループのCを削除 | |
| #P世代の扱い | |
| if ($Settings.Backup.IfParentCountOver -eq 'delfull') | |
| { | |
| #古いP世代を削除&フルバックアップの設定 | |
| [array]$Content += "Backup Mode: Parent Generation (Delete Oldest Parent, Child for Full Backup)" | |
| $Content | Select-Object -Last 1 | |
| #新しいディレクトリ | |
| $null = New-Item "$DstParent\$($Settings.Backup.MyDateTime)_P" -itemType Directory | |
| #古いPを削除 | |
| Remove-Item -LiteralPath "$DstParent\$($ParentGen[0])" -Recurse -Force | |
| Write-Output "Delete: $DstParent\$($ParentGen[0])" | |
| } elseif ($Settings.Backup.IfParentCountOver -eq 'rendiff') | |
| { | |
| #古いP世代をリネーム&差分バックアップの設定 | |
| [array]$Content += "Backup Mode: Parent Generation (Rename Oldest Parent, Child for Diff Backup)" | |
| $Content | Select-Object -Last 1 | |
| #古いPをリネーム | |
| Rename-Item -LiteralPath "$DstParent\$($ParentGen[0])" "$DstParent\$($Settings.Backup.MyDateTime)_P" | |
| Write-Output "Rename: $DstParent\$($ParentGen[0])" | |
| } | |
| #古いCを削除 | |
| Write-Output "残すParent世代数が$($Settings.Backup.ParentCountMin)になるように古い世代を削除します" | |
| #(現在のPの数 - Pを残す数)を飛ばして、残った中で最も古いP世代の名前を参照してループを抜ける | |
| $BreakParentName = $ParentGen | Select-Object -Skip ($ParentGen.Count - $Settings.Backup.ParentCountMin) -First 1 | |
| foreach ($a in $($AllGen | Select-Object -Skip 1)) | |
| { | |
| if ($a -match "$BreakParentName") | |
| { | |
| #$BreakParentNameと一致したら消さずに抜ける | |
| break | |
| } | |
| Write-Output "Delete: $DstParent\${a}" | |
| Remove-Item -LiteralPath "$DstParent\$a" -Recurse -Force | |
| } | |
| } elseif ($ParentGen.Count -le $Settings.Backup.ParentCountMin) | |
| { | |
| #$Settings.Backup.ParentCountMin以下の場合 = 世代グループ数を増やせるので、新規Pにフルバックアップ | |
| [array]$Content += "Backup Mode: Parent Generation (Full Backup)" | |
| $Content | Select-Object -Last 1 | |
| #新しいディレクトリ | |
| $null = New-Item "$DstParent\$($Settings.Backup.MyDateTime)_P" -itemType Directory | |
| } | |
| #差分(または実質フル)バックアップ | |
| Backup-Difference -Src "$($_.src)" -Dst "$DstParent\$($Settings.Backup.MyDateTime)_P$($_.dst)" | |
| } else | |
| { | |
| #最新世代グループ内の世代数が1以上$Settings.Backup.ParentInterval未満 = C世代を生成する | |
| Write-Output "New Directory: $DstParent\$($Settings.Backup.MyDateTime)_C" | |
| [array]$Content += "Backup Mode: Child Generation (Incremental Backup)" | |
| $Content | Select-Object -Last 1 | |
| #新しいディレクトリ | |
| $null = New-Item "$DstParent\$($Settings.Backup.MyDateTime)_C" -itemType Directory | |
| #増分バックアップ | |
| Backup-Incremental -Src "$($_.src)" -Dst "$DstParent\$($Settings.Backup.MyDateTime)_C$($_.dst)" -Link "$DstParent\$($ParentGen | Select-Object -Last 1)$($_.dst)" | |
| } | |
| #バックアップディレクトリの世代一覧を取得して文字列に変換 | |
| [array]$Content += '```' | |
| [array]$Content += "Backup Generations:" | |
| [array]$Content += "$(Get-ChildItem "$DstParent\*" -Name | Out-String)" | |
| $Content | Select-Object -Last 1 | |
| [array]$Content += '```' | |
| } | |
| } | |
| [array]$Content += "End: $((Get-Date).ToString("yyyy/MM/dd (ddd) HH:mm:ss"))" | |
| $Content | Select-Object -Last 1 | |
| #====================Post==================== | |
| if ($Settings.Post.TwitterToggle -Or $Settings.Post.DiscordToggle -Or $Settings.Post.BalloonTipToggle) | |
| { | |
| #ストレージの使用状況を取得して文字列に変換 | |
| #@{Name="SizeRemaining(GB)";Expression={"{0:#,0}" -f ($_.SizeRemaining/1GB)}} | |
| $VolumeInfo = Get-Volume | ?{$_.DriveLetter} | Select @{ | |
| Name="Drive"; | |
| Expression= | |
| { | |
| $_.DriveLetter | |
| } | |
| }, | |
| @{ | |
| Name="Enpty(GB)"; | |
| Expression= | |
| { | |
| [math]::round($_.SizeRemaining/1GB,0) | |
| } | |
| }, | |
| @{ | |
| Name="All(GB)"; | |
| Expression= | |
| { | |
| [math]::round($_.Size/1GB,0) | |
| } | |
| }, | |
| @{ | |
| Name="Usage(%)"; | |
| Expression= | |
| { | |
| [int]((($_.Size-$_.SizeRemaining)/$_.Size)*100) | |
| } | |
| } | Out-String | |
| [string]$Content = "$($Content | Out-String)"+'```'+"Storage Usage:`n$VolumeInfo`n"+'```' | |
| } | |
| if ($Settings.Post.TwitterToggle) | |
| { | |
| Write-Output "Twitterに通知します" | |
| $env:ssl_cert_file = $Settings.Post.cert | |
| $env:content = $Content | |
| &"$($Settings.Post.rubyPath)" "$($Settings.Post.ModulePath)" | |
| #Start-Process "${ruby_path}" "${tweet_rb_path}" -WindowStyle Hidden -Wait | |
| } | |
| #Discord | |
| if ($Settings.Post.DiscordToggle) | |
| { | |
| Write-Output "Discordに通知します" | |
| $payload = [PSCustomObject]@{ | |
| content = $Content | |
| } | |
| $payload = ($payload | ConvertTo-Json) | |
| $payload = [System.Text.Encoding]::UTF8.GetBytes($payload) | |
| Invoke-RestMethod -Uri "$($Settings.Post.hookUrl)" -Method Post -Body $payload | |
| } | |
| #BalloonTip | |
| if ($Settings.Post.BalloonTipToggle) | |
| { | |
| Write-Output "BalloonTipに通知します" | |
| #特定のTipIconのみを使用可 | |
| #[System.Windows.Forms.ToolTipIcon] | Get-Member -Static -Type Property | |
| $balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info | |
| #表示するタイトル | |
| $balloon.BalloonTipTitle = "バックアップ終了" | |
| #表示するメッセージ | |
| $balloon.BalloonTipText = $Content | |
| #balloontip_toggle=1なら5000ミリ秒バルーンチップ表示 | |
| $balloon.ShowBalloonTip(5000) | |
| #5秒待って | |
| Start-Sleep -Seconds 5 | |
| } | |
| #タスクトレイアイコン非表示(異常終了時は実行されずトレイに亡霊が残る仕様) | |
| $balloon.Visible = $False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment