2023/09/07(木)ジャンクション(NTFS)の更新日時を変更する
ジャンクション(NTFS)の更新日時を変更する
ちょっとジャンクション(NTFS)の更新日時を書き換えようとしたら、すんなりできなくて結構手間取ったのでメモ。
通常の方法ではリンク先の更新日時が変更される
まずはディレクトリとジャンクションをセットで作成。
$directory = New-Item -Path "test_directory" -ItemType Directory $junction = New-Item -Value "test_directory" -Path "test_junction" -ItemType Junction dir Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2023/09/07 3:48 test_directory d----l 2023/09/07 3:48 test_junction
そして、ジャンクションの方に更新日時を設定してみると、ジャンクションではなくリンク先のディレクトリの更新日時が書き換えられてしまいました。
$junction.LastWriteTime = "2000-01-02T03:04:05+09:00" dir Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2000/01/02 3:04 test_directory d----l 2023/09/07 3:48 test_junction
仕様と言えばそうなのかも知れませんが、それだったら表示される更新日時もリンク先のものでないと一貫性が無いような……。
ジャンクションそのものの更新日時を変更する方法
まずは「Junction LastWriteTime」とかで調べてみると、英語圏で同様の疑問が挙がっていましたが手っ取り早い解決策は無さそうでした。(Windows APIを直接使う必要がありそうな感じ。)
更新日時変更をWindows APIを使って行う場合、CreateFile→SetFileTimeという手順になるのでこっちを調べてみたところ、ジャンクション(リパースポイント)をCreateFileで開くときにOPEN_REPARSE_POINTフラグを付けて開くとリンクを辿らずに開いてくれそうです。
FileTimeコピープログラム作成
OPEN_REPARSE_POINTを指定するにはWindows APIで直接指定するしか無さそうなので、自分でプログラムを作ることにしました。
日時を自由に指定できるようにするには日時文字列の解釈が必要になって面倒なので、他のファイル・フォルダの日時をコピーするプログラムです。これなら、GetFileTimeが使えるので楽。
SetFileTimeがcreationTime/lastAccessTime/lastWriteTimeを扱うので全部コピーしています。(コピーしたくなければNULLを渡せば変更されない。)
手抜きなので失敗してもメッセージとかは出ません(^_^;)
- ソースコード
#include <windows.h> #include <tchar.h> int _tmain(int argc, _TCHAR *argv[]) { HANDLE hFrom; HANDLE hTo; FILETIME creationTime, lastAccessTime, lastWriteTime; if (argc < 3) { return 1; } //---------------------------------------- // Get FILETIME from argv[1] //---------------------------------------- hFrom = CreateFile( argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFrom == INVALID_HANDLE_VALUE) { return 1; } if (!GetFileTime(hFrom, &creationTime, &lastAccessTime, &lastWriteTime)) { return 1; } CloseHandle(hFrom); //---------------------------------------- // Set FILETIME to argv[2] //---------------------------------------- hTo = CreateFile( argv[2], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (hTo == INVALID_HANDLE_VALUE) { return 1; } if (!SetFileTime(hTo, &creationTime, &lastAccessTime, &lastWriteTime)) { return 1; } CloseHandle(hTo); return 0; }
- コンパイル
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars32.bat" cl.exe /DUNICODE /D_UNICODE /source-charset:utf-8 CopyFileTime.c
ジャンクションへのFileTimeコピー実験
CopyFileTime.exe test_directory test_junction Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2000/01/02 3:04 test_directory d----l 2000/01/02 3:04 test_junction
ちゃんと日時コピーできてました。
コピー元の方はOPEN_REPARSE_POINTを付けずに開いている(リンク先を辿る)ので、
CopyFileTime.exe test_junction test_junction
としても同じ効果のはず。
2023/04/22(土)[Tampermonkey] fetch responseの割り込み取得
[Tampermonkey] fetch responseの横取り取得
Webページがfetchで動的に取得したJSONデータを観測する手段は無いかなと思って見つけた方法。
ソースコード
// ==UserScript== // @name Test intercept fetch // @description Test intercept fetch // @namespace Test // @version 1.0 // @match https://example.com/* // @run-at document-start // @grant unsafeWindow // ==/UserScript== const proc_fetch_resp = (data, url) => { console.log("proc_fetch_resp:" + url, data); } //===================================================== // Intercept fetch //===================================================== const origFetch = unsafeWindow.fetch; //元のfetchを差し替え unsafeWindow.fetch = async (...args) => { console.log("fetch called with args:", args); const response = await origFetch(...args); //レスポンスをクローンして使う response .clone() .json() .then(body => { proc_fetch_resp(body, response.url); }) .catch(err => console.error(err)) ; //元のレスポンスを返す return response; }
- @match は対象サイトのURLを指定
- @run-at は割り込みたいfetchよりに先にfetch差し替えができるように指定
- unsafeWindow を使わないとfetch差し替えができない
- サンプルなのでレスポンスをJSONとして読み取ってconsole.logに出すだけ。
参考URL
2017/04/08(土)ドライブ空き容量をチェックしてトースト通知する
ドライブ空き容量をチェックしてトースト通知する
PowerShellで空き容量チェックスクリプトを書いてみました。Windows 10 のアクションセンターで通知されます(トースト通知)。
ソースコード
# ドライブごとにしきい値を設定 $min_freespace = @{ "C" = 30GB; "D" = 10GB; "E" = 50GB; } function ShowBalloonTip( [string] $tilte = "件名", [string] $body = "本文" ) { #[Reference] # PowerShell can I use balloons, toasts and notifications? # https://deploywindows.info/2015/12/01/powershell-can-i-use-balloons-toasts-and-notifications/ # Toasts templates # https://msdn.microsoft.com/en-us/library/windows/apps/hh761494.aspx [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null $template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02) # Convert to .NET type for XML manipuration $toastXml = [xml] $template.GetXml() # Customize the toast message $text = $toastXml.GetElementsByTagName("text") $text[0].AppendChild($toastXml.CreateTextNode($tilte)) > $null $text[1].AppendChild($toastXml.CreateTextNode($body)) > $null # Convert back to WinRT type $xml = New-Object Windows.Data.Xml.Dom.XmlDocument $xml.LoadXml($toastXml.OuterXml) $Toast = [Windows.UI.Notifications.ToastNotification]::new($xml) $AppID = 'Microsoft.Explorer.Notification.{3e1c1f24-a023-49cf-98ff-90cdabb9930b}' [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($AppID).Show($Toast) } $msg = "" foreach ($drive_letter in $min_freespace.Keys) { $drive = Get-PSDrive $drive_letter if ( $drive.Free -lt $min_freespace[$drive_letter] ) { $msg += "{0}ドライブ空き容量:{1,0:0.00}GB`n" -f $drive_letter, ($drive.Free/1GB); } } if ( $msg ) { ShowBalloonTip "空き容量警告" $msg }
準備
以下のレジストリを登録しないとトースト通知を履歴に残せないようです。(通知自体はされる。)
- HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.Explorer.Notification.3e1c1f24-a023-49cf-98ff-90cdabb9930b
- 値の名前: ShowInActionCenter
- 値のデータ: 1
- 種類: REG_DWORD
コマンドで追加するなら、
reg add "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.Explorer.Notification.{3e1c1f24-a023-49cf-98ff-90cdabb9930b}" /v ShowInActionCenter /t REG_DWORD /d 1
「Microsoft.Explorer.Notification.3e1c1f24-a023-49cf-98ff-90cdabb9930b」*1のところに特に意味は無く、ソースコード内のIDと一致していれば良いです。
自動実行
タスクスケジューラーに登録すれば、自動実行できます。
- プリグラム/スクリプト: %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
- 引数の追加(オプション): -ExecutionPolicy RemoteSigned -File スクリプトのパス
ただ、普通に登録するだけではどうしてもウィンドウが表示されてしまうようです。検索するとWSH(VBScriptやJScript)経由でPowerShellを呼び出すことでウィンドウを隠す方法が見つかります。PowerShell単体でできるようにして欲しい(-_-;)
更新履歴
- 2017/04/08: 不要な記述が残っていたので削除。
2016/09/11(日)RecentChangesページを考慮したブラウザキャッシュ制御
PukiWiki: RecentChangesページを考慮したブラウザキャッシュ制御
PukiWiki If-Modified-Since(条件付きリクエスト)対応のコメントでやりとりしていた、RecentChangesページを考慮したブラウザキャッシュ制御の機能をbodycache改良版に追加しました。
PukiWiki bodycache改良版のページで公開しています。なお、追加機能を使うには設定が必要です。*1
RecentChangesを考慮したページ更新日時
基本的な方針は、「Wikiページキャッシュ更新日時とRecentChanges更新日時のうち新しい方」をページの更新日時と見なすというものです。
以下の関数がこの新しい方の更新日時を返す関数です。$bodycache_lastmod_whatsnewはpukiwiki.ini.php内の設定で、$bodycache_lastmod_whatsnewがtrueの時のみこの機能は動作します。
- bodycache.php
// Get last-modified time for client side cache control function get_lastmodtime($page) { global $bodycache_lastmod_whatsnew; global $whatsnew; static $lastmodtime = null ; if ($lastmodtime !== null) { return $lastmodtime ; } $cachetime = get_cachetime($page); if ( $cachetime != 0 && $bodycache_lastmod_whatsnew ) { $whatsnewtime = get_filetime($whatsnew); $lastmodtime = ( $cachetime >= $whatsnewtime ) ? $cachetime : $whatsnewtime; } else { $lastmodtime = $cachetime; } return $lastmodtime; }
この関数が返す日時を、ブラウザに返却するLast-Modifiedや、If-modified-sinceの比較に用いることで、RecentChanges更新時にはブラウザキャッシュも更新される動作になります。
追記
get_lastmodtimeは複数回呼ばれるので、処理量を減らすために1回目に呼ばれたときの結果を$lastmodtimeに残して2回目以降は$lastmodtimeを返すだけにしているのですが、今の書き方では引数の$pageを変更して呼ばれると正しく動作しなくなってしまいます。
今のコードでは、$pageを変更してget_lastmodtimeを呼ぶことはないので問題は起こりませんが、get_lastmodtimeの引数を変えてはいけないという制約ができてしまっているのであまり良くないですね。(うっかり忘れて将来事故を起こしそう^^;)そのうち修正するかもしれません。
その他のbodycache改良版の更新
更新のついでに、bodycache.php内の不要な記述の削除とコードインデントのタブへの統一*2も実施しました。
また、bodycache.php内にあった設定用の変数$bodycache_del_depthをpukiwiki.ini.phpに移動しました。
2016/07/30(土)さくらのレンタルサーバーにPHP7を導入
2016年12月14日からPHP7.1が使用できるようになったので、この作業をする必要は無くなりました。→さくらのレンタルサーバ PHP7.1 提供開始のお知らせ | さくらインターネット
さくらのレンタルサーバーにPHP7を導入
さくらのレンタルサーバーがなかなかPHP7に対応しないので自力でインストールしてみました。
注意:この方法でPHP7を導入した後は、自身の責任においてセキュリティーアップデート(最新版の再導入)をしてください。