証明書をユーザ権限によって振り分けて証明書ストアに登録するバッチ


#証明書をユーザ権限によって振り分けて証明書ストアに登録するバッチ

## 要件
- 証明書をバッチでWindowsマシンにインストールしたい
- 証明書は2件あり、それぞれ「信頼されたルート証明機関」「中間証明機関」にインストールしたい
- バッチを実行したユーザの権限によって処理を分けたい
    - 管理者権限を持つ場合
        - コマンドプロンプトを管理者権限で実行した場合には、ローカルコンピュータの証明書ストアにインストール
        - コマンドプロンプトを管理者権限なしに実行した場合には、管理者権限を持つコマンドプロンプトを起動して、ローカルコンピュータの証明書ストアにインストール
    - 管理者権限を持たない場合
        - 既にローカルコンピュータの証明書ストアに証明書がある場合には、インストール処理をスキップ
        - ローカルコンピュータ、カレントユーザの証明書ストアの両方に証明書がない場合は、カレントユーザにインストール処理を実行する
- バッチを実行したログを残したい

##実行環境
Windows7, 8.1, 10
（UACは有効無効どちらも対応）

## 難しかったところ
### 管理者権限ありユーザの挙動
- バッチを叩いて実行した場合、管理者権限として実行されるか、権限実行なしで実行されるか分からない（確実に管理者権限で実行する方法をご存知の方、ご教授ください…）
- 上記理由により、管理者ユーザが管理者権限なしコマンドプロンプトでバッチを実行してしまった場合に備えて、参考記事のコマンドプロンプトの昇格処理を追加した。
- ただし、管理者権限なしユーザで上記バッチをそのまま実行すると昇格無限ループに陥ってしまうため、管理者権限での実行タイミングで引数を設定し、その引数付でバッチが起動されたら、カレントユーザ用処理に移行するようにした。

参考)
バッチファイル(*.bat) を管理者として実行するための バッチファイル
http://qiita.com/jTakasuRyuji/items/e7bd576ed57969b2d06e

### 管理者権限なしユーザの挙動
- カレントユーザにCA証明書をインストールしようとすると、登録確認ダイアログが出てくる。
- 既に同じPCにおいて管理者権限ユーザでバッチを実行し、ローカルコンピュータに証明書が入っている場合、カレントユーザに証明書がなくても、状態としてはインストール不要
- カレントユーザからローカルコンピュータに指定証明書があるかのチェックを入れて、入ってたら、処理スキップ。なかったら仕方ないのでカレントユーザに証明書インストール


## 証明書インストール起動バッチ
（ユーザにはこちらのバッチを実行してもらう）

```bat:certexecute.bat

@echo off

rem -- カレントディレクトリを基準とする
cd /d %~dp0

rem -- バッチの実行結果をログとして出力する
cmd.exe /c certinstall.bat >> result.log 2>&1

```


## 証明書インストールバッチ
（これ単体でも起動可能）

```bat:certinstall.bat
@echo off

echo **** 証明書インストール処理: %date% %time%

SETLOCAL enabledelayedexpansion

rem -- SAMPLE1証明書のファイル名
set SAMPLE1_CERT_NAME=<sample1.cer>

rem -- SAMPLE2証明書のファイル名
set SAMPLE2_CERT_NAME=<sample2.cer>

rem -- SAMPLE1証明書のシリアル番号, サブジェクト
set SAMPLE1_CERT_SERIAL=<aaaaaaa>
set SAMPLE1_CERT_SERIAL_SUBJECT="OU=<aa>, OU=<aaa>, O=<aaaaa>"

rem -- SAMPLE2証明書のシリアル番号, サブジェクト
set SAMPLE2_CERT_SERIAL=<bbbbbbb>
set SAMPLE2_CERT_SUBJECT="CN=<bb>, OU=<bbb>, OU=<bbbb>, O=<bbbbb>"

rem -- カレントディレクトリを基準とする
cd /d %~dp0

:checkMandatoryLevel
rem --- ▼管理者として実行されているか確認 START
for /f "tokens=1 delims=," %%i in ('whoami /groups /FO CSV /NH') do (
    if "%%~i"=="BUILTIN\Administrators" set ADMIN=yes
    if "%%~i"=="Mandatory Label\High Mandatory Level" set ELEVATED=yes
)


echo ADMIN=%ADMIN%
echo ELEVATED=%ELEVATED%

if "%ADMIN%" neq "yes" (
    rem -- Administratorsグループでない（ローカルユーザの場合）
    echo カレントユーザにのみ証明書をインストールします。
    
    rem --- 証明書コピーSAMPLE1確認処理
    CALL :checkUserCertificationSAMPLE1

    goto exit1
)
if "%ELEVATED%" neq "yes" (
    rem -- (プロセスが昇格されていない) Admin権限ありユーザが通常実行した場合
    echo このファイルは管理者権限での実行が必要です
    echo 昇格を行いますので、しばらくお待ちください
    
    goto runas
)
rem --- ▲管理者として実行されているか確認 END

:admins
    rem --- ▼管理者として実行したいコマンド START

    rem --- 証明書コピー処理
    echo ローカルコンピュータに証明書をインストールします。
    CALL :copyCertification

    rem --- ▲管理者として実行したいコマンド END
    goto exit1

:runas

    if "%1" == "" (
        rem --- 引数なしのため、★管理者として再実行
        @powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process %~f0 REPEATED -Verb runas"
    ) else (
        rem --- 引数ありのため、すでに自身を再実行している。
        rem --- カレントユーザにのみインストール
        echo 管理者への昇格に失敗しました。カレントユーザにのみ証明書をインストールします。
        
        rem --- 証明書コピーSAMPLE1確認処理
        CALL :checkUserCertificationSAMPLE1
    )


goto exit1

rem --- ローカルコンピュータ用コピー処理サブルーチン
:copyCertification

    ECHO コピー処理実施: SAMPLE1証明書

    rem -- SAMPLE1証明書を強制上書きインストールする
    rem -- ローカル コンピューター:信頼されたルート証明機関
    certutil -addstore -f ROOT %SAMPLE1_CERT_NAME%

    ECHO コピー処理実施: SAMPLE2証明書

    rem -- SAMPLE2証明書を強制上書きインストールする
    rem -- ローカル コンピューター:中間証明機関
    certutil -addstore -f CA %SAMPLE2_CERT_NAME%


    exit /B


rem --- カレントユーザ用コピーSAMPLE1確認処理サブルーチン
:checkUserCertificationSAMPLE1

    rem --- ローカルマシンに既にSAMPLE1証明書が入っているか
    verify >nul
    certutil -verifystore ROOT %SAMPLE1_CERT_SERIAL% | findstr %SAMPLE1_CERT_SERIAL_SUBJECT%

    rem -- 見つからなかった(エラー)の場合、コピー
    IF '%ERRORLEVEL%'=='1' goto copyUserCertificationSAMPLE1
    rem -- 見つかった(正常)の場合、スキップ
    IF '%ERRORLEVEL%'=='0' goto skipUserCertificationSAMPLE1

    exit /B


rem --- カレントユーザ用SAMPLE1証明書スキップサブルーチン
:skipUserCertificationSAMPLE1


    ECHO SAMPLE1証明書：ローカルコンピュータに証明書ありの為、処理スキップ
    
    rem -- SAMPLE2証明書チェック
    CALL :checkUserCertificationSAMPLE2
    
    exit /B
    
rem --- カレントユーザ用SAMPLE1証明書コピーサブルーチン
:copyUserCertificationSAMPLE1
    

    ECHO コピー処理実施: SAMPLE1証明書

    rem -- SAMPLE1証明書をインストールする
    rem -- カレントユーザ:信頼されたルート証明機関
    certutil -user -addstore -f ROOT %SAMPLE1_CERT_NAME%
    
    rem -- SAMPLE2証明書チェック
    CALL :checkUserCertificationSAMPLE2
    
    exit /B



rem --- カレントユーザ用コピーSAMPLE2証明書確認処理サブルーチン
:checkUserCertificationSAMPLE2

    rem --- ローカルマシンに既にSAMPLE2明書が入っているか
    verify >nul
    certutil -verifystore CA %SAMPLE2_CERT_SERIAL% | findstr %SAMPLE2_CERT_SUBJECT%
    
    rem -- 見つからなかった(エラー)の場合、コピー
    IF '%ERRORLEVEL%'=='1' goto copyUserCertificationSAMPLE2
    rem -- 見つかった(正常)の場合、スキップ
    IF '%ERRORLEVEL%'=='0' goto skipUserCertificationSAMPLE2

    exit /B

rem --- カレントユーザ用SAMPLE2証明書スキップサブルーチン
:skipUserCertificationSAMPLE2


    ECHO SAMPLE2証明書：ローカルコンピュータに証明書ありの為、処理スキップ
    
    exit /B
    
rem --- カレントユーザ用SAMPLE2証明書コピーサブルーチン
:copyUserCertificationSAMPLE2
        
    ECHO コピー処理実施: SAMPLE2証明書

    rem -- SAMPLE2証明書をインストールする
    rem -- カレントユーザ:中間証明機関
    certutil -user -addstore -f CA %SAMPLE2_CERT_NAME%
    
    exit /B


:exit1
    
    exit



```