命名って難しい

変数、関数、クラスなどなど実装より命名に毎回悩むタイプの人間による技術についてのメモ。

PowerShellで実行中のPCのActive Directoryのパスワード期限を取得する。

ADのモジュールはADサーバーしかインポートできないみたいですね。
ということで.Netを利用して作りました。

Add-Type -AssemblyName System.DirectoryServices
$adPath = [string]::Format("WinNT://{0}/{1}", [System.Environment]::UserDomainName, [System.Environment]::UserName)
$de = New-Object System.DirectoryServices.DirectoryEntry $adPath

# パスワード期限の取得
$expDt = [System.DateTime]$de.PasswordExpirationDate
echo $expDt

# 差分を取得
$ts = New-TimeSpan (Get-Date) $expDt
echo $ts

タスクスケジューラのタスクの名称変更をするバッチ

概要

タスクスケジューラのタスク名変えられないかゆい所に手が届くと素敵だと思いませんか。

実際はエクスポートして新しい名前でインポートして古い方を削除してます。

実装

ソースコード

@echo off

setlocal
set tempTask=%temp%\tmptask
set oldName=%1
set newName=%2

rem 引数チェック
set result=エラー: 引数不正[空文字]
if "%oldName%" == "" ( goto :EchoResult )
if "%newName%" == "" ( goto :EchoResult )

if %oldName% == %newName% (
  set result=エラー: 引数不正[変更前後が同一名称]
  goto :EchoResult
)

rem クエリによる出力
schtasks /Query /XML /TN %oldName% > %tempTask%
if not %errorlevel% == 0 (
  set result=エラー: タスクのXMLエクスポート失敗
  goto :EchoResult
)

rem 新規タスクのインポート
schtasks /Create /XML %tempTask% /TN %newName%
if not %errorlevel% == 0 (
  set result=エラー: タスクのXMLインポート失敗
  goto :EchoResult
)

rem 命名変更前のタスクの削除
schtasks /Delete /F /TN %oldName%
if not %errorlevel% == 0 (
  set result=エラー: 名称変更前のタスクの削除失敗
  goto :EchoResult
)

set result=タスクの名称変更完了

:EchoResult
echo %result%

endlocal
exit

使い方(RenameTask.batというファイルで作った前提)

RenameTask.bat  *変更対象のタスク名* *変更後のタスク名*
  • 変更対象のタスク名

    • 変更対象のタスク名。
    • タスクスケジューラの直下で作ればそのままの名前。
    • フォルダを作った中のタスクの場合はフォルダ名も含めて指定すること。
    • 例:Automations\すこし自動化するタスク
  • 変更後のタスク名

    • 変更後のタスク名。
    • 変更対象のタスク名と同様、フォルダを考慮した指定をしてください。
    • 例:Automations\すごく自動化するタスク

参考(technet)

タスクをエクスポートする

タスクをインポートする

タスクを削除する

適当感想

こういう作ったバッチのコマンドライン引数とかを説明する時の定石っていうかうまい書き方ってあるのかなぁ。
ちょっとスタイル出来上がってないので既存のベストプラクティスが欲しい。

以上!

デザインテーマ:Naturalのデザインを2カラムにカスタマイズした。

タイトルで全部説明しきってしまった。
自分でブログから記事を見直す時に最近の投稿など、あの部分が右に来ると丁度いいなと思ったのでWeb系最近触れ初めた自分ができるだけのことをしました。

以下、カスタマイズCSSに記述した内容。

#container {
  width: 80%;
  overflow:auto;
}
#wrapper {
  float:left;
  width:70%;
}
#box2 {
  float:left;
  width:10%;
}

なんか右の白いエリアが余分でもうちょっと詰まらないか、とか
幅を狭くしていったら要素が重なっていく!とか

色々足らない部分があるんですが、とりあえず反映。

社内のイントラネットを更新のある時だけ開きたいというバッチ。

イントラネットのトップページに色々更新情報があるんですが、 更新情報が無い時も開いて目視しているのが面倒なので、 更新がある時だけ開くバッチを作りました。

処理の流れ

  1. 以前取得していたページがあればそれを前回取得したページとして名称変更
  2. 現在の対象ページを取得する
  3. 以前取得した対象ページと比較する
  4. 一致してなければそのページを開く

以上。

ソースコード

@echo off
setlocal
pushd %~dp0

set url=%1
set compare_log_path=%~dp0compare_log.txt
set current_page_path=%~dp0current.html
set previous_page_path=%~dp0previous.html

rem 前回取得したままの現在のファイルを前回のファイル扱いにする。
move  /Y %current_page_path% %previous_page_path%

rem 対象ページを取ってくる
bitsadmin /TRANSFER check_intra %url% %current_page_path%

rem 以前取得したページと比較する
fc %current_page_path% %previous_page_path% > %compare_log_path%

rem 一致しない時は開く
if %errorlevel% == 0 (
  goto end
) else (
  start /d "C:\Program Files\Internet Explorer" IEXPLORE.EXE %url%
)

:end
popd
endlocal

呼び出しているプログラム/参考

bitsadmin

wget的なものが欲しかったので使用。 簡単な使い方しかしてないけれど色々機能あるみたいですね(全部読む気力はない)。 取得先のファイルが既に存在すると上書きしてくれないみたい。

BITSAdmin Tool
BITSAdmin Examples

fc

ファイルの比較で使用。 比較結果は一応ログにしてますけど特に意味は無いです。

FC.exe

使いかた

 [このバッチ] "[url]"

以上

Windowsのバッチのライブラリを作り始めた(ヘルプ出力バッチ&テキストの行数出力バッチ)

なお不定期。

業務で使う特定の処理のバッチを作ってライブラリにしようかなと思って少し書いてみた。 ブログのタイトルにもしてるんですけど、なんでも作る時に命名が難しすぎますね。。。 まだライブラリ未満です。

将来これを拡張して便利なものに~~~とか思ってたんですけど 既にあったりするのかな。 勉強にはなったけれど貢献になるか割と微妙ですね!

面白かったのでとりあえず記事に残しときます。

ヘルプを出力するバッチ

概要

ヘルプの前提は以下です。

  • バッチの中にヘルプ文言を全部書く。
  • ヘルプは引数エラーの時のみ出力する(/h)など未対応

ファイル名称

ShowHelp.bat

ソースコード

@echo off
setlocal enabledelayedexpansion

if "%1"=="" (
  echo 引数が不正です。ヘルプを表示します。
  "%~f0" "::" "%~f0"
  goto :EOF
)

goto TopOfCode

::ShowHelp.bat - 指定のバッチファイルのヘルプを表示します。
::
::使用法
::    ShowHelp [コメントアウト文字列] [ファイルパス] 
::
::詳細
::    指定のバッチファイル内のコメントアウト文字列を使ったヘルプを表示します。
::
::例
::    以下の内容のファイルのヘルプを表示する時
::      対象ファイル    :Test.bat
::      コメントアウト文字列://
::    "ShowHelp.bat" "//" "Test.bat"

:TopOfCode

set annotation=%~1
set filepath=%~f2
for /f "usebackq delims=" %%a in (`findstr /R "^%annotation%" "%filepath%"`) do (
  set cmt=%%a
  set cmt=!cmt:%annotation%=!
  echo.!cmt!
)

endlocal

テキストファイルの行数を出力するコマンド

概要

Windowsバッチにはwcがないのでつくりました。 行数のみをぱっと出力するコマンド。

ファイル名称

CountLine.bat

ソースコード

@echo off
setlocal

REM 引数
set drive=%~d1
set filePath=%~f1

if "%filePath%"=="" (
  echo 引数が不正です。ヘルプを表示します。
  ShowHelp "::" "%~f0"
  goto :EOF
)

if not exist "%filePath%" (
  echo.0
  goto :EOF
)

goto TopOfCode

::CountLine.bat
::
::使用法
::    CountLine [TEXT FILE] 
::詳細
::    パラメータで指定したテキストファイルの行数を取得します。
::

:TopOfCode

pushd %~dp0

REM 指定のファイルパスがUNC形式の場合、参照する場所が違う。
set tokensNumber=3
If "%drive%"=="\\" set tokensNumber=2

for /f "usebackq tokens=%tokensNumber% delims=:" %%a in (`find /v /c "" "%filePath%"`) do (
  set count=%%a
)

echo %count: =%

popd
endlocal

以上!

Outlookの規定の予定表にある各予定表の予定一覧を出力する。

特化しすぎてタイトルが長い!

概要

Outlookの予定表を複数用意して、定時タスクを登録している。 複数の予定表から特定の日付のタスクを全部リストアップしたい。

ソースコード

以下のソースで適当にvbs作って呼ぶだけ。
必要に応じてテキストにリダイレクトでもすればいい。

cscript //nologo [VBSファイル名] [取得したい日付] [取得したい予定表の名前(N個)] 
' 引数チェック!
if WScript.Arguments.Count < 2 Then
  WScript.Echo "引数が少なすぎます。 [日付] [予定表名(任意の数)]"
  WScript.Quit
End if
Set args = WScript.Arguments
Set objOutlook = CreateObject("Outlook.Application")
Set objNamespace = objOutlook.GetNamespace("MAPI")
Set defFolder = objNamespace.GetDefaultFolder(9)

' 指定の日付(第一引数)
dt = CDate(args(0))
' それ以降の対象の予定表名をループ
For i = 1 to args.Count - 1
    calName = CStr(args(i))
    Set calFolder = defFolder.Folders(calName)
    Call EchoEvents(calFolder, dt)
Next

' 指定のカレンダーの指定の日付のイベントを出力
Sub EchoEvents(calFolder, dt)
    Set colItems = calFolder.Items
    calName = calFolder.Name
    ' 普通のイベント
    For Each objItem In colItems
        If GetDateOnly(objItem.Start) = GetDateOnly(dt) Then
            ' CSV形式で [予定表名],[予定名],[開始時刻] で出力
            WScript.Echo calName & "," & objItem.Subject & "," & Hour(objItem.Start) & ":" & Minute(objItem.Start)
        End If
    Next
    
    ' 定期イベント
    Set colFilteredItems = colItems.Restrict("[IsRecurring] = TRUE")
    For Each objItem In colFilteredItems
        ' DayOfWeekMaskの各曜日の値はWeekDayで取得できる数値から1引いて2乗した値になる。
        maskValue = 2^(Weekday(dt) - 1)
        Set objPattern = objItem.GetRecurrencePattern
        ' ANDで一致すればOK
        If objPattern.DayOfWeekMask AND maskValue = maskValue Then
            ' CSV形式で [予定表名],[予定名],[開始時刻] で出力
            WScript.Echo calName & "," & objItem.Subject & "," & Right("00" & Hour(objItem.Start), 2) & ":" & Right("00" & Minute(objItem.Start), 2)
        End If
    Next
End Sub

' 日付のみ取得。DateTimeをシンプルなDateに変える。
Function GetDateOnly(dt)
  GetDateOnly = CDate(Year(dt) & "/" & Month(dt) & "/" & Day(dt))
End Function

(技術メモ)(SQL Server 2000/2012)ログインの追加→DBへのユーザーの追加→ユーザーのロール設定までの流れ

概要

ちょっとしたDBリプレースで必要になったのでメモ。
これをうまいことコードで管理して同一構成のサーバーをすぐにセットアップできるようにしたい。

SQL Server 2000

t-sql

-- masterでログインを追加
use master;
EXECUTE sp_addlogin 'NEW_LOGIN', 'NEW_LOGIN_PASS', 'NEW_DB';

-- 指定のDBでそのログインに合わせたユーザーを追加
use NEW_DB;
EXECUTE sp_adduser 'NEW_LOGIN', 'NEW_USER';

-- 読み書き自由自在のユーザーにしたい
EXECUTE sp_addrolemember db_datareader, 'NEW_USER';
EXECUTE sp_addrolemember db_datawriter, 'NEW_USER';

参考URL

sp_addlogin (Transact-SQL)

sp_adduser (Transact-SQL)

sp_addrolemember (Transact-SQL)

SQL Server 2012

t-sql

-- masterでログインを追加
use master;
CREATE LOGIN NEW_LOGIN WITH PASSWORD = 'NEW_LOGIN_PASS', DEFAULT_DATABASE =NEW_DB;

-- 指定のDBでそのログインに合わせたユーザーを追加
use NEW_DB;
CREATE USER NEW_USER FROM LOGIN NEW_LOGIN;
-- 読み書き自由自在のユーザーにしたい
EXECUTE sp_addrolemember db_datareader, 'NEW_USER';
EXECUTE sp_addrolemember db_datawriter, 'NEW_USER';

参考URL

CREATE LOGIN (Transact-SQL)

CREATE USER (Transact-SQL)