目次

よくいるコピペSEだけども、よく使う/便利だったコマンドやスクリプトをまとめて置いておきたいと思いこのブログを作りました。
本来ならqiitaとかでも良いんじゃないかと思うものの、専門的か、とか技術的かどうかとか言われると心苦しいのでとりあえずはここで。
(順番を新しい順にしました)

<掲載済>
【bat】ブロックされるようになったネットワーク上のVBAマクロをbatで実行可能にする(regコマンド、信頼済みサイト) - うまく動けばいいな!

【Powershell】「実行した」くらいのログを取りながら、共有フォルダ内のファイルのセッション切断をする(Start-Transcript、Close-SmbOpenFile) - うまく動けばいいな!

【JavaScript】一定期間の年月(YYYY/MM)の配列を作る([2021/04,2021/05,2021/06]とか。moment.jsを利用) - うまく動けばいいな!

【Powershell】Thunderbirdの「about:config」を簡易的に変更するCUIツールを作る(あるファイルに追記するPowershellスクリプト) - うまく動けばいいな!

【Powershell】(サーバ保守)サービス登録しないでログオン失敗を検知しメール送信する仕組みをつくる - うまく動けばいいな!

【Powershell】(Tips集)PowerShellよく使うコードの紹介 - うまく動けばいいな!

【Powershell】(サーバ保守)毎日定期的に作られるフォルダを週次で古いものを圧縮処理する - うまく動けばいいな!

【Powershell】(サーバ保守)タスクスケジューラの特定のタスクの状態を確認する(Get-ScheduledTask) - うまく動けばいいな!

【bat、Powershell】(PCメンテナンス用)デスクトップにショートカットを作成するスクリプト - うまく動けばいいな!

【PHP】PHPをbatのようにローカルスクリプトとして使う(3)~Curl編(Webアクセス、外部API(HTTP)の利用、JSONデータの活用)~ - うまく動けばいいな!

【PHP】PHPをbatのようにローカルスクリプトとして使う(2)~DBアクセス編~ - うまく動けばいいな!

【bat、PHP】PHPをbatのようにローカルスクリプトとして使う(1)~設定・呼び出し編~ - うまく動けばいいな!

【bat】(ある程度)セキュアなファイル転送を自動で行うbat ~WinSCP公開鍵転送の自動化~ - うまく動けばいいな!

【Powershell】(サーバ保守)PingをPowershellでリスト化した端末へ実行する(Test-Connection) - うまく動けばいいな!

【Powershell】(サーバ保守)フォルダ内ファイル内キーワード検索+圧縮+メール送信 - うまく動けばいいな!

【PowerShell】(サーバ保守)イベントログのログオン履歴抽出②(Get-WinEvent) - うまく動けばいいな!

【bat、Powershell】(サーバ保守)ディスク容量監視、メール送信 - うまく動けばいいな!

【PowerShell】(PCメンテナンス用)メール送信② - うまく動けばいいな!

【PowerShell】(サーバ保守)イベントログのログオン履歴抽出、CSV化(Get-WinEvent) - うまく動けばいいな!

【コマンド(bat)】PSEXECを利用したリモート管理 - うまく動けばいいな!

【PowerShell】(PCメンテナンス用)メール送信 - うまく動けばいいな!

【bat、PowerShell】(PCメンテナンス用)PC設定まとめて取得 - うまく動けばいいな!

【bat】(PCメンテナンス用)ディスククリーンアップ - うまく動けばいいな!

【bat】(PCメンテナンス用)システムファイルチェッカー、DISMCleanup-Image - うまく動けばいいな!

【bat】(個人用ツール)NET DRIVEのbat - うまく動けばいいな!


<予定>
未定(ネタなんかあったっけな)



本ブログに掲載している情報やソースコードの正確性は注意を払っていますが、
情報・ソースコード等により生じるいかなる損失・損害に対しては、一切の責任を負いかねます。

【bat】ブロックされるようになったネットワーク上のExcelのVBAマクロを、batで実行可能にする(regコマンド、信頼済みサイト、Excelファイル)

【ツールの概要】
はてなから見てた、これ対策
togetter.com

・ネットワーク上のOfficeファイルのVBAマクロについて、デフォルトでブロックされるようになりました。(赤い警告が出る)
・各PCの「インターネットオプション」-「信頼済みサイト」に各ネットワークのサーバー(FQDN、アドレス)を入力すればマクロ実行可能になるとのこと。
 (他にも方法はありますが)
・その設定をbatファイルでやってみる!
レジストリをいじるので、慎重に!自己責任で!regedit.exeも確認しながら!
・MSの参考サイトはこちら↓
インターネットからのマクロは、Office で既定でブロックされます - Deploy Office | Microsoft Learn
・その他参考サイトはこちら
IEの信頼済みサイトを一括で登録 | 社内SE3割増し
バッチファイルでIEの信頼済みサイトを登録 ← RootLinks Co., Ltd.
IE11のローカルイントラネットゾーンの設定をするレジストリ - QWERTY.WORK


【環境(使っている環境)】
Windows 10 Pro (ビルド19044.1889)


【ソース(AddTrustedSites.bat)】

@reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1"
@IF %errorlevel%==0 goto exists

@REM 値作成
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1" /v file /t REG_DWORD /d 2 /f
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1" /v :Range /t REG_SZ /d 192.168.0.XX /f

@REM 値作成
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\SERVERXX\\" /v file /t REG_DWORD /d 2 /f

@echo.
@echo 処理が完了しました。

exit /b

:exists
@echo.
@echo エラー!既に信頼済サイトに何か登録があるので、整合性のためGUIで登録をしてください。
pause

【説明】
・1-2行目。すでに値がレジストリに登録されている場合はエラーのほうへ。
 判定も割に合わないので、諦めてGUIでやりましょう!←
・3-5行目。IPアドレスをRangeとして登録します。Excelファイルを実行するためなので、プロトコルはfile:です。
・6-7行目。サーバのFQDNホスト名をDomainsの値として登録します。
・8行目以降。処理結果で画面出力を変更しています。エラーの場合はpauseで残ります。

【総評】
とりあえず場当たり的に作りました。
レジストリの変更なので検証を慎重に行ってくださいね!
これで出来ない場合は、インターネットオプションをいじるようにすればよいかと・・・

【Powershell】「実行した」くらいのログを取りながら、共有フォルダ内のファイルのセッション切断をする(Start-Transcript、Close-SmbOpenFile)

【ツールの概要】
・該当のフォルダ内の「.pdf」の拡張子のセッションを切断する。
・標準出力(かな?エラー出力も出るけど全部かわかりません)をログとして記録する。
 Linuxとかの「tee」コマンドと似たような感じで記録する。

【環境(使っている環境)】
Windows Server 2012 R2
Powershell ver4.0
・実行には管理者権限が必要です

【ソース(closesmb.ps1)】

$Today=(Get-Date).ToString("yyyyMMdd_HHmmss")

Start-Transcript -path "D:\Project\CloseSmbFile\log\transcript-$($Today).txt" -Append

Write-Output "切断対象リスト"
Get-SmbOpenFile | Where-Object -Property Path -Match "E:\pdfホルダー" | Where-Object -Property Path -Match ".pdf"| %{echo $_} | Format-List


Write-Output "切断します"
Get-SmbOpenFile | Where-Object -Property Path -Match "E:\pdfホルダー" | Where-Object -Property Path -Match ".pdf"| Close-SmbOpenFile -force
Write-Output "切断完了しました"


Stop-Transcript

【説明】
・1行目はlogファイル名用の時間取得です。
・2行目、Start-Transcript でその後のコマンドの出力をlogファイルに"も"出力します。-Append パラメータで追記を許可します(秒単位で別のlogファイルにはなりますが)。
・3、5,7行目、Write-Output は標準出力としてlogにも記録されます。Write-Hostでも同様に・・・(のはず)。
・4行目、Get-SmbOpesnFile で「開いているファイル」の一覧が呼べます。パイプで条件を指定し、Format-List で出力します。
・6行目、再度Get-SmbOpesnFile の結果から同じ条件で出力された一覧のそれぞれの要素(ファイル)に、Close-SmbOpenFileを実行します。
・8行目、Stop-Transcript でのlog出力を終了します。
・ちょっと冗長な記述ですが、わかりやすく、ということで。。

【総評】
log専用に関数を作ったりするほどじゃないな、ってときとかに便利ですね、Start-Transcript。
実運用はもっと複雑な条件だったりすると思うので、ここまで小さいスクリプトじゃないと思いますが、
ちょろっと作るけど一応logでも記録したいなって時にはよいですね、実行バージョンとかも出ますし。

【JavaScript】一定期間の年月(YYYY/MM)の配列を作る([2021/04,2021/05,2021/06]とか。moment.jsを利用)

【ツールの概要】
・['YYYY/MM', 'YYYY/MM', ...]な感じで月単位の配列を作る。
・moment.jsを活用する。
・今回は自分の都合上、3年前の最初(1月)から当月までの年月文字列配列を作ります。

【環境(使っている環境)】
・moment.js(2.29.1)

【ソース(関数部分)】

let arr = [];

let i = 0;
let start = moment().add(-3, 'years').startOf('year');  // addせず、moment(なにか)で開始日を指定するのもいいですね
let end = moment().startOf('month'); // 今月までなのでmoment()です
let diffmonthes = end.diff(start, 'months'); // 201801-202105なら40がとれます

for(; i <= diffmonthes; i++) {
     arr.push(start.clone().add(i, 'months').startOf('month').format('YYYY/MM'));
}

console.log(arr);

【説明】
・moment.jsを読み込んだ状態で実行します。
・momentオブジェクト?(Dateオブジェクトをラッパした感じのもの)はかなり多機能で、javascriptで日付を扱うならmoment.jsをぜひ利用したいもの。
・4、5行目で3年前の1月月初と当月月初のmomentオブジェクトを取得します。
 startとendについて、いずれも月初(startOf)としています。
 その理由は差分を取る時に同じ日付としてないと差分月数が正確に取れなさそうなためです。
 6行目でdiff( , 'month')で差分の月数を取ります。(2021/4/1~2021/5/1なら1になります。日付がずれてて且つ引数3つ目にtrueを指定すると小数までdiffがでます)

Month and year diffs
moment#diff has some special handling for month and year diffs. It is optimized to ensure that two months with the same date are always a whole number apart.
~~
出典:Moment.js Documentation

・あとはfor文で一月ずつcloneしてformatで指定した形式の文字列を配列にaddします。
 add(0, 'month')で当月いけるっぽいです
 ここのstartOfは不要だと思いますがなんとなく。。
 clone()はmoment()でもよさげですね
 iをあくまでイテレータとして1ずつstartそのものを加算しても良いですね

【総評】
意外と記事がなかったのでまとめました。
標準のDateオブジェクトだとなかなか遠回りになりそうなので、moment.jsの便利さが際立ちます。

【参考】
JavaScript|Moment.jsで日付操作(比較, 差分, フォーマット) - わくわくBank

Moment.js | Docs

【Powershell】Thunderbirdの「about:config」を簡易的に変更するCUIツールを作る(あるファイルに追記するPowershellスクリプト)

【ツールの概要】
Thunderbirdというメーラー(フリー版あり)の「オプション」からいじれる「about:config」という設定を変更する。
・「about:config」は以下のような「prefs.js」というJavascriptファイルになっているので、追記する。
おそらく推奨ではないので、自己責任で実行してください!(あくまでPowershellのお勉強としてお願いします)
Thunderbird起動中の編集は無意味。また、編集後、起動時に読み取られ、設定がダブった場合は最後の行のみ反映される(順序が整理される)。さらに、デフォルト値の場合、削除される。
・ログインしてるユーザのプロファイル中の「about:config(prefs.js)」をいじる。全部いじる。

f:id:hagure_m:20201102143614p:plain
Thunderbird の about:config 画面。これをツールで設定したい。
f:id:hagure_m:20201102144104p:plain
prefs.jsファイル。about:configの設定はここから起動時に行われ、終了時にこのファイルは上書きされる。(なのでThunderbird起動中にこのファイルを編集しても意味がない)

【環境(使っている環境)】
・Windows10
Powershell ver5.1
Thunderbird v78.4.0

【ソース(CallPS1.bat、呼び出し用bat)】

@echo off
cd /d %~dp0

SET PSFile=ChangeThunderBirdPrefs.ps1
SET ThunderbirdApplicationName="thunderbird.exe"

echo 処理を開始します。
echo.

REM Thunderbird 実行確認。実行してたら終了。
tasklist | find %ThunderbirdApplicationName%
if %ERRORLEVEL% == 0 (
    echo Thunderbird が実行中です。Thunderbird を終了し、再度実行してください。
    echo.
    exit /b
)

REM ps1ファイル存在確認。存在してなかったら終了。
if not exist %PSFile% (
    echo ChangeThunderBirdPrefs.ps1をこのファイルと同じ階層に置いて再度実行してください。
    echo.
    exit /b
)

REM ps1ファイル実行。
powershell -ExecutionPolicy RemoteSigned .\%PSFile%
if %ERRORLEVEL% == 1 (
    echo 処理に失敗しました。
    echo.
    exit /b
)

echo 処理が正常終了しました。
echo.

pause

【ソース(ChangeThunderBirdPrefs.ps1、特定ファイルへの追記処理他もろもろ)】

$ErrorActionPreference = "Stop"

# prefs.jsは既定通りインストールしていれば下記のような場所にあります。「~default」フォルダは複数ある可能性もあり。
# $env:APPDATA + "\Thunderbird\Profiles\XXXXXXX.default\prefs.js";

# ということでProfilesフォルダをまず取得
$ProfilesFoldersPath=$env:APPDATA + "\Thunderbird\Profiles";

# Profilesフォルダ内のフォルダコレクションを取得したいので、Get-ChildItem。
try{
    [System.IO.DirectoryInfo[]] $dirs = Get-ChildItem $ProfilesFoldersPath -Directory;
} 
catch [Exception] {
    Write-Output ("実行アカウントの既定のフォルダにThunderbirdプロファイルフォルダがありませんでした。");
    throw; # code 1 return. 
}

try{
    foreach($dir in $dirs){
        # 処理するProfilesフォルダ内のフォルダ名をコンソールに表示
        Write-Output ('対象フォルダ :' + $dir.FullName);
        $targetJSFile=$dir.FullName + "\prefs.js";
        Write-Output ("対象ファイル :" + $targetJSFile);
        
        # prefs.jsの存在チェック
        if((Test-Path $targetJSFile) -eq $false){
            Write-Output ("変更用ファイルが存在しませんでした。thunderbirdを起動し、手動で設定してください。 `r`n" + $targetJSFile);
            continue;
        }
        Write-Output ("ファイルが存在しました。処理を続行します。");
        
        # 追記処理。最後の行だけ設定として生きるよ、thunderbird起動時にきれいになるよ、ということを説明。
        # if any same keys exists, only last row parameter is enable.(when thunderbird application executed.)
        # and... new line , line feed not exiting is no probrem.(thunderbird application is formating the file, after read.) 
        Write-Output ("user_pref(`"security.tls.version.min`", 1);") | Add-Content -Encoding utf8 $targetJSFile;
    }
}
catch [Exception] {
    Write-Output ("設定ファイルの書込み時に何らかのエラーが発生しました。thunderbirdを起動し、手動で設定してください。");
    throw; # code 1 return. 
}

Write-Output ("設定追記処理終了しました。");

return 0;

【説明】
・追記している「"user_pref(`"security.tls.version.min`", 1);"」という文字列は、TLSの下限バージョンを1.1まで引き下げるというものです。
 (デフォルトでは1.3-1.2までしか使えない)
・batを実行します。batはps1ファイルをRemoteSignedで実行させます。
・batではThunderbirdが実行中かについてプロセスを見て判断します。あったら終了。
 あとはps1ファイルが無かったりエラーだったらその旨表示して終了。
・ps1の方では、Profilesフォルダの中に複数のプロファイルがある可能性があるので、全部に処理するためforeach(雑)
・test-pathでチェックしてるので、try-catchでcatchに行くときは書き込めなかったとき等なので、その場合は処理自体中断し終了。
 (1行目でErrorActionPreferenceをStopに設定しているため、このようなエラー時には継続しません。)

【総評】
それぞれの行でやってることが明確に判るよう意識しています。
Thunderbirdがベキ等性を保証してくれるので(絶対そのためじゃないけど)、
何度実行して延々とprefs.jsに追記しても、たぶん、Thunderbirdが実行時に1行にしてくれます!(そのうち仕様が変わる可能性あり)
結構即席で作ったので、try-catchの当たりなどは工夫し甲斐が残ったりしてそうですね。

【Powershell】(サーバ保守)サービス登録しないでログオン失敗を検知しメール送信する仕組みをつくる

【ツールの概要】
・タスクスケジューラ上に特定のWindowsイベントログをトリガーとしたタスクを作る。
Powershellで、フィルターされた直近数分間のイベントログのデータをメールで送る。

【環境(使っている環境)】
Windows Server2016(+ Windows10)
Powershell ver5.1

【ソース(AlertLoginError.ps1、メイン処理)】

# クラスファイルを読み込む
using module .\class\Class_CommonFunction.psm1
using module .\class\Class_GetEvents.psm1
using module .\class\Class_Sendmail.psm1

# 各変数をセットアップする、ログの命名などにも使用
$DocRoot = Split-Path (Split-Path $MyInvocation.MyCommand.Path -Parent) -Parent
$YMD = Get-Date -Format "yyyyMMdd"
$yMdHms = Get-Date -Format "yyyyMMddHHmmss"

# xmlにメールの設定を格納しておく
$mailcfgpath = $DocRoot + '\etc\mailcfg.xml'

# クラス[CommonFunction]のインスタンスを作成、ログ実行(ログ用、logfileにWrite-Outputをするメソッドをもつクラス(省略))
$CF = [CommonFunction]::new()
$CF.logfile = $DocRoot + '\log\AlertLoginError_' + $YMD + '.log';
$CF.logwrite("INF", "AlertLoginError process start.")

# クラス[GetEventLog]のインスタンスを作成、メソッド実行(イベントログ取得用)
$GE = [GetEventLog]::new()
$str = $GE.GetEvents()

# 返り値(文字列)のLengthが0じゃなかったらメール送信
if ($str.Length -ne 0) {
    $SM = [SendMail]::new()
    $SM.ConfigMailProperty($str, $mailcfgpath, $logfile)
    $CF.logwrite("INF", "Alert mail sended.")
}

$CF.logwrite("INF", "AlertLoginError process Finished.")

【ソース(class\Class_GetEvents.psm1、イベントログ抽出処理)】

class GetEventLog {
# Get-WinEventで得られるオブジェクトを変数に格納
    [string] GetEvents() {
        $MESSAGES = Get-WinEvent  `
            -logname security  `
            -FilterXPath  `
            "Event [ `
            System [ `
                Provider [@Name='Microsoft-Windows-Security-Auditing'] `
                and ( `
                    EventID='4625'
                ) `
                and ( `
                    TimeCreated[timediff(@SystemTime) <= 300000] `
                ) `
            ] `
        ]"
# オブジェクトの必要な要素のみJsonとして文字列にする(流用しやすいデータにしたいため)
        $str = $MESSAGES | ForEach-Object {
            if ( $_.id -eq "4625" ) {
                $_ | Select-Object `
                @{Name = "TimeCreated"; Expression = { $_.TimeCreated.ToString("yyyy-M-d HH:mm:ss") } }, `
                Id, `
                @{Name = "TargetLogonId"; Expression = { $_.properties[5].value } }, `
                @{Name = "TargetDomainName"; Expression = { $_.properties[6].value } }, `
                @{Name = "TargetUserSid"; Expression = { $_.properties[4].value } }, `
                @{Name = "IpAddress"; Expression = { $_.properties[19].value } }, `
                @{Name = "Message"; Expression = { $_.Message.Substring(0, 18) } }        
            }
        } | ConvertTo-Json
        return $str
    }
}

【ソース(class\Class_Sendmail.psm1、メール送信処理)】

class SendMail{
    [string]ConfigMailProperty($str, $mailcfgpath, $logfile) {
        $Body = "Windows events LoginError catched. `r`n`r`n EventData : `r`n`r`n " + $str

        $Result = $this.SendmailbyPS($Body, $mailcfgpath, $logfile)
        return $Result
    }

    [string]SendmailbyPS($Body, $mailcfgpath, $logfile) {
        $Mailconf_info = [xml](Get-Content $mailcfgpath)
        foreach ($data in $Mailconf_info.config.data) { }
        foreach ($data2 in $Mailconf_info.config.data) { }
        $MailSv = $data.MailSv
        $Port = $data.Port
        $Encode = $data.Encode
        $uid = $data.uid
        $pwd = $data.pwd
        $From = $data.from
        $To = $data.To
        $Cc = $data.Cc
        $Subject = $data.Subject

        #Credential
        $pwd = $pwd | ConvertTo-SecureString -AsPlainText -Force
        $cred = New-Object System.Management.Automation.PSCredential $uid, $pwd

        #Send Mail
        try {
            Send-MailMessage `
                -To $To `
                -Cc $Cc `
                -From $From `
                -SmtpServer $MailSv `
                -Credential $cred `
                -UseSsl `
                -Encoding $Encode `
                -Port $Port `
                -Subject $Subject `
                -Body $Body
            $result = 'OK'
        }
        catch {
            $ErrorMessage = $_.Exception_Message
            $result = $ErrorMessage + $LASTEXITCODE
            Write-Output $LASTEXITCODE | Out-File -Append $logfile -encoding Default
        }

        if ($result -ne 'OK') {
            $MailSv = $data2.MailSv
            $Port = $data2.Port
            $Encode = $data2.Encode
            $uid = $data2.uid
            $pwd = $data2.pwd
            $From = $data.from 
            $pwd = $pwd | ConvertTo-SecureString -AsPlainText -Force
            $cred = New-Object System.Management.Automation.PSCredential $uid, $pwd
            try {
                Send-MailMessage `
                    -To $To `
                    -Cc $Cc `
                    -From $From `
                    -SmtpServer $MailSv `
                    -Credential $cred `
                    -UseSsl `
                    -Encoding $Encode `
                    -Port $Port `
                    -Subject $Subject `
                    -Body $Body
                $result = 'OK'
            }
            catch {
                $ErrorMessage = $_.Exception_Message
                $result = $ErrorMessage + $LASTEXITCODE
                Write-Output $LASTEXITCODE | Out-File -Append $logfile -encoding Default
            }
        }
        return $result
    }
}

f:id:hagure_m:20191217130708p:plain
イベントログトリガ設定


【説明】
・タスクスケジューラでイベントIDで発火するように、上記のようなトリガ設定でPowershellスクリプトを実行します。
PowershellスクリプトではイベントログをFilterXPathでフィルターし、ConvertTo-Jsonでイベントログオブジェクトを文字列にしてメールします。
・イベントログの仕様上、一回のログイン失敗に見えても、数回 ID4625のイベントログが記録されることがあります。

【総評】
Classで分けることである程度わかりやすいスクリプトが書けるようになっていると思います。
FilertXPathやForEach-Objectのところで条件を変えれば、いろんな要件も満たせそうですね。
まあでも、業務用途の場合ちゃんとした商用監査ソフトを使うのが一番でしょうね・・・

【参考文献】
Get-wineventで抽出したログから、IDによって参照するフィールドを分けて表示させる方法

【Powershell】(Tips集)PowerShellよく使うコードの紹介

今回はPowerShellスクリプト作成時に、自分がよく使うコードをTipsとして紹介します。


1.実行場所(カレントディレクトリ)をスクリプトのフォルダに指定

Set-Location -Path (Split-Path -Parent $MyInvocation.MyCommand.Path);


2.XML読込

$ConfigXmlPath = "D:\hoge\etc\ConfigHoge.xml";
$XMLConfig = [xml](Get-Content $ConfigXmlPath);
foreach ($LogConfig in $XMLConfig.config.LogConfig) { }
foreach ($HogeServiceConfig in $XMLConfig.config.HogeService) { }
# 参照方法は $LogConfig.LogFol のように。下記なら"yyyyMMdd_Query.log"の文字列が生成される。
$TodayLogFileName = [string]::Join("", (Get-Date).ToString("yyyyMMdd"), $LogConfig.LogFileName);
xmlファイル(ConfigHoge.xml)
<?xml version="1.0"?>
<config>
  <LogConfig>
    <LogFol>D:\</LogFol>
    <LogFileName>_Query.log</LogFileName>
  </LogConfig>
  <HogeService>
    <PhpExePath>D:\app\php\php.exe</PhpExePath>
    <HogeProductFol>D:\hoge\laravelsite\</HogeProductFol>
  </HogeService>
</config>


3.連想配列(string, string)定義、追加、抽出

$ArrString = @{ };
$ArrString.Add( "Mysql", $MysqlMessage );
$ArrString.GetEnumerator() | Where-Object { $_.Value -eq "だめぽよ" } | ForEach-Object { $Message = "今夜は" + $_.Key + "が、" + $_.Value + "<br />"  }


4.簡単なクラスの扱い方

.("./class/Class_Yomikomare.ps1");   # スクリプト冒頭で読込

$Yomikomare = New-Object YomikomareClass($ValueForConstructor); #インスタンス化、コンストラクタへ変数渡す
$ResultValue = $Yomikomare.StartHoge();  # クラスメソッド実行


5.ファイルコピー等

if ((Test-Path $this.FilePath) -eq $false) {  # ファイルパスにファイルが存在しないなら
      New-Item $this.FilePath;     # ファイル作成
      icacls $this.FilePath /grant Everyone:F;   # Everyone権限付与
}


6.Y秒間ごとにX回繰り返し

$maxrepeat = 30    # X回
 do {
    $Status = $this.IsMentananceMode_Larvel()     # クラスメソッドなど判定を行える変数を返せるメソッド等
    $maxrepeat--                                         # 繰り返しを進める
    Start-Sleep -Milliseconds 1000                 # Y秒間sleepする
} until ($Status -eq $false -or $maxRepeat -eq 0)   # 変数の状態と回数をチェックし、どちらかの条件にtrueになるまで続ける


6.Webリクエスト定型(Getのみ最小限)

try {
    $Response = Invoke-WebRequest -Uri $WebURL -Method Get
    $StatusCode = $Response.StatusCode
}
catch {
    $StatusCode = $error[0].Exception.Response.StatusCode.value__
}


7.タスクスケジューラ起動

$TaskName = "Honyararatask";
if (((Get-ScheduledTask -TaskName $TaskName).State) -ne "Running") {
    try {
         Get-ScheduledTask -TaskName $TaskName | Start-ScheduledTask 
    }
    catch {
        return $_.Exception
    }
}


とりまこんなところで!

【Powershell】(サーバ保守)毎日定期的に作られるフォルダを週次で古いものを圧縮処理する

【ツールの概要】
Powershellで、日別で作られるログフォルダ、データフォルダなどを週次で基準より古いものを圧縮するPowershellスクリプト

【環境(使っている環境)】
Windows Server2016
Powershell ver5.1

【ソース(PS_LogArchiver.ps1)】

# ログfunction
function logwrite($MSG, $INFO, $outputfile) {
    $NOW = Get-Date -Format G
    Write-Output "[ $NOW ][ $MSG ] $INFO" | Out-File -Append $outputfile -encoding Default
}

# ここではlogフォルダの中に、日次でフォルダが新規で作られている想定。それとこのスクリプトのログ(月別)
$targetFolder = 'D:\log\';
$logfile = 'D:\PCompressLog\log\CompressLog_GetJson_' + (Get-Date -Format "yyyyMM") + '.log';

# 対象のlogフォルダの一覧を作成日でソート(降順)
$List = Get-ChildItem $targetFolder | Sort-Object -Descending { $_.CreationTime }

# ログに処理数書くため
$i = 0;

# logフォルダの中のアイテムについて、「フォルダかどうか」そして「21日前より前」かどうかで処理分岐
foreach ($item in $List) {
    if ($item.PSIsContainer -And ($item.CreationTime -lt (Get-Date).AddDays(-21))) {
        # セミコロン使うか使わないか統一しろっての(自戒)
        $zipfullpath = "$($item.FullName).zip";

        # CompressArchiveこけるとエラるのでtrycatch。成功したらログ+オリジナル削除。失敗はログしてログの中身を書き出し。
        try {
            compress-archive -Path $item.FullName -DestinationPath $zipfullpath
            logwrite "INF" "Files-compressed. itemname : $($item.FullName)" $logfile
            Remove-Item -Path $item.FullName -Recurse -Force
            $i++
        }
        catch {
            logwrite "ERR" "Error. Files-compress Failed. itemname : $($item.FullName)" $logfile
            $errstring = $error[0] | Out-String
            logwrite "ERR" "$errstring" $logfile
        }
    }
}

logwrite "INF" "Compressed Files Count : $($i)" $logfile


【使用方法】
・対象フォルダの中の更にフォルダのみを対象としています。
・$targetFolder、$logfile をそれぞれ環境に沿って設定します。
powershellで実行します。

【説明】
・非常に基本的な記述のみを使っていると思います。
・ログ出力やtrycatchにこだわらなければ、ソートの行のところで、一行でも終われるかもしれません。

【総評】
Windowsでは、powershellはbatに比べ非常に記述しやすいかと思います。
VBSと比べてナウい(?)感じがしますね!