gologiusの巣

プログラミング、モデリングなどのメモです。誰かの役に立てるとうれしいです。

AWS SAAを受験した話

AWS SAA(ソリューションアーキテクトアソシエイト)の試験を受けてきたので感想を書く。

※試験の内容をバラすのはNGなのでそこには触れない。

試験概要

雑に説明すると、AWSのサービスをつかっていい感じに設計できる能力があるかを測る試験。

試験自体が 「プロフェショナル>アソシエイト>ベーシック 」のランクに分かれている。

今回受けたのは「アソシエイト」

勉強方法と勉強時間

この試験のために 勉強したのは1週間程度。 ただし元々AWSでのVPCやらサーバー構築の知識はあった(作業歴:半年程度)

使ったのは下記二つの教材。

本は家にあった親父のやつを借りパクした。1日かけて読む×2週くらいした。

読んだあとはWEBサイトの過去問※を、通勤中の電車内で解いてた。

※厳密にはAWS試験の過去問は公開されていない・・・はず

試験方法

WEB上で受ける試験なので自宅などでも受けられるらしいが、大阪のテストセンターで受ける方法を選択した。 そもそも自宅で試験受けるのは気分的にもノラないので。

写真付き身分証明書が二つ必要らしく。前日に焦った。 運転免許とパスポートを使ったが、もってない人どうするんですかね・・・

着いたらあとは係の人が色々誘導してくれるので、特に心配しなくていい。

試験中

ここに書いていることなので、ブログに書いても問題ないはず。

WEB試験がSPI以来だったので新鮮だった。

持ち込めるものはほぼないと思っていい。ハンカチくらい。 メモ用紙?のようなものを貸し出ししてくれるので、 そのあたりは心配しなくていい。 ただ、もちろん画面上に直接書き込めないので、そのあたりは普段の筆記試験と勝手が違う。

特徴的な点としては、英語の原文が見れる。 意味不明な日本語訳になってることがあるので、必要であれば英語も見れる。 実際一つ意味不明な問題があったので見た。 コメントもつけれるので意見しておいた。 (コメント投下中は試験時間から除外されるらしい。フィードバックは一切ないが)

時間は2時間くらいあるが、正直1時間くらいで終わる。

結果

合格

試験終了ボタンを押した次のページで即合否が出てきた。

もう少し余韻とかあってもいいんじゃないですかね・・・

正式な連絡は後日メールで来る。昼12時に受けて夜19時くらいには来た。

感想

勉強方法について

基本的なNWやWEB関連の知識があるのであれば、基本方針としては

  • 教科書を一通り読む
  • 実際にAWSで色々触ってみる
  • 空き時間で過去問を解く

で十分だと思う。 一通り触って自分のサイトとか構築していればなお良い。 AWSを触らずにこの試験に合格することも出来るとは思うが、 意味があるのかは正直疑問。

試験対策としては、上記に挙げた教材だけだと少し危なかった。 教材の質が悪いという話ではなく、ただの勉強不足。 深い部分で理解できていないことがいくつかあるなぁと反省した。

あと、情報の鮮度はかなり気にした方がいい。 実際2021年のリリースで変わっている点も多々あった。 その点、上記の過去問サイトはコメント機能がついてて、おかしい部分はツッコミが入っているのでよかった。

試験のレベルについて

個人的にはちょうどよかったと思う。

過去問やっている時には「簡単すぎワロタ」と調子に乗っていたが、 実際受けると1.3倍くらいの難しさに感じた。 調子に乗ってはいけない。

技術営業や発注者レベルであれば、この試験で十分業務に活かせると思う。 が、この試験に受かっただけだといわゆる「完全に理解した」※の状態な気はする。 慢心せずに今後も勉学に励もうとおもった。

※元ネタ

ブラウザからEXEを呼び出す方法調査(プロトコルハンドラー、カスタムURLスキーム、URIハンドラー)

2021/12/13 追記 「URIハンドラー」という用語や参考リンクを追記。

2021/11/20 追記 GitHubのサンプルへのリンクを追加。

2021/11/13 追記 拡張子の関連付けの方法を追記、全体構成を加筆修正。

何がしたいの

ブラウザからクライアントアプリ(EXE)を呼び出したい。

身近な例としては メールアドレスをクリック→メーラーが起動

ってのが一番身近だと思う。

どんな方法あるの?

ActiveX経由

  • 基本的にIEしか動かない。
  • Chromeだと謎のアプリをインストールする必要がある

IEは今後サポート切れになるので没

NPAPI

→没

JavaApplet

  • Java11から廃止されている
  • 今時JavaAppletは・・・

→没

ファイルを開く

事前にファイルの関連付けを設定しておき※

ファイルをダウンロードする際に「開く」をすれば、任意のプログラムを起動できる。

コマンドプロンプト assoc - [ファイルと拡張子の関連を表示・設定する] とか

edgeの場合↓ f:id:gologius:20211113150505p:plain

この方法なら、ファイルにパラメータを埋め込んでおけば、 ほぼ無制限にパラメータを渡すことができる。

ただし、

  • 毎回「開く」をクリックしないといけない。
  • ダウンロードフォルダにtempファイルが一時的に溜まる
  • 操作をミスるとファイルがDLされてファイルが溜まってしまう

というデメリットが存在する

→ 実現はできるが、ベストではない感じはする。

レジストリに追記する

レジストリを弄ると呼べるようになる。 以下参考文献

windows - ActiveXを使わずにwebブラウザ上でクライアントのexeを実行する方法 - スタック・オーバーフロー

Registering an Application to a URI Scheme (Windows) | Microsoft Docs

→ 今回の本題。以下に詳細を記載

レジストリに追記する」の具体例

サンプルサイトは下記。

クライアント呼び出し

ソース → gologius.github.io/test1.html at master · gologius/gologius.github.io · GitHub

1)自分のPCのレジストリに下記のようなものを登録する

xyz_regist.reg

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\xyz]
"URL Protocol"=""

[HKEY_CLASSES_ROOT\xyz\shell]

[HKEY_CLASSES_ROOT\xyz\shell\open]

[HKEY_CLASSES_ROOT\xyz\shell\open\command]
@="\"C:\\Windows\\System32\\notepad.exe\" \"%1\""

2)html内に <a href="xyz:">ここをクリックするとメモ帳が開きます</a> などと記載しておく

3)リンクをクリックする

するとメモ帳が開く

内部で何してるの?

これはプロトコルハンドラーと呼ばれる技術を使用している。 カスタムURLスキームや、URIハンドラーとも呼ばれるらしい。呼び方を統一してほしい・・・

Edgeの設定だと「アプリケーション リンク」、chromeだと「プロトコル ハンドラ」の設定が該当する。

先のメールアドレスの例だと、下記のような感じのHTMLが埋め込まれているのが一般的になる

<a href="mailto:hogehoge@example.com?subject=件名&amp;body=本文">メールを送信する</a>

コロン ':' の後に文字列をセットすると、その文字列を別アプリに渡すことができる。

別アプリに値を渡す

レジストリキーに %1 が登録されていた場合、パラメータをアプリに引き渡す

(Default) = "C:\Windows\notepad.exe" "%1"

エンコードされた文字列が連携されるため、クライアント側でデコードして処理する必要がある。 よって、文字コードなどにも注意する必要がある。

%1 以外の意味 → Windows レジストリ 解剖記: HKEY_CLASSES_ROOT - Programming Field

<a href="xyz:hogehoge">ここをクリックするとメモ帳が開きます</a>

の場合だと

C:\レジストリに登録した.exe xyz:hogehoge

のような感じでOS側でコールされる模様

サンプルサイト

下記サイトで伝送できるバイト値を変えて遊べるようにした。

クライアント呼び出し

ソース → gologius.github.io/test2.html at master · gologius/gologius.github.io · GitHub

サンプルレジストリバッチを起動しているなら

[HKEY_CLASSES_ROOT\xyz\shell\open\command]
@="\"C:\\Windows\\System32\\notepad.exe\" \"%1\""

になってるはずなので、メモ帳が開く先のファイルパスにランダム文字列を指定することになる。

使い方は単純で、バイト数入力→反映ボタンを押すとそのバイト数に応じたURLを生成→リンククリックでメモ帳が開く

※ただしファイルパスですらないのでエラーは出る。

こんな感じのリンクが裏では作られている↓

<a id="exetarget_ex" href="xyz:5nBGDkabx9tz4eCrl4xsEjMZbzle9v">サンプルアプリxyz呼び出し バイト数指定</a>

下記はChromeの例

f:id:gologius:20210704152643p:plain f:id:gologius:20210704153753p:plain f:id:gologius:20210704153812p:plain

判明している不具合

大量のデータを伝送できない模様。 特に日本語をbase64エンコードしようものなら、バイト量が増えてアプリが開かなくなるパターンを見つけた。

ちなみに、ブラウザによって限界値が違う模様。

  • chrome → 1000バイトまではメモ帳起動する。3000バイトは起動すらしない
  • firefox → 10000バイトまではメモ帳起動する。100000バイトは起動すらしない

※厳密に何バイトまでいけるかという実験ではないのでご了承下さい。

原因考察

二つある気がしている

  • ブラウザ側の伝送制限(そうでないと、ChromeFirefoxとの挙動差の説明がつかない)
  • OS側の制限 ※1

※ 文字数制限がある。8191文字が最大っぽい。が上記の結果とつじつまが合わない・・・

コマンド プロンプト行の文字列の制限 - Windows Client | Microsoft Docs

余談

C#でつくったWindowsFormアプリに値を飛ばしてみた。 ここでもブラウザの違いが見られた。 パラメータに全角文字をそのままぶちこんで飛ばすと、

された。

Chromef:id:gologius:20210704224518p:plain

Firefoxf:id:gologius:20210704224528p:plain

作ったもの github.com

所感

まぁ便利なんですが、下記のようにセキュリティ的なデメリットもあります。

カスタムURLスキームの乗っ取りとその対策 - Akaki I/O

パラメータにOSコマンド入れたりすれば、OSへの攻撃もできそうですよね。

レジストリを弄ってないと開かないとはいえ、注意したほうがいいと思いました。

というか、ブラウザからOSの機能にアクセスできるってのが個人的には怖いですね。

AWS ELB +EC2で構築しているWEBサイトにて、iPhoneのSafariだけHTTP通信になる不具合

iPhoneSafariだけ挙動がおかしい。

AWSELBでHTTPSへリダイレクトしているはずなのに、HTTP通信が発生して「安全ではありません」と出る。

初回アクセスはHTTPSでアクセスするのだが、戻るボタン→再度リンクからアクセスするとHTTPになる。

キーワードだけで調べると「ELBでHTTP/2通信を無効化すればよい」的な情報にヒットしたが、 下記リンクの対象はApacheのようで、なんかひっかかるので少し調べることにした。

https://salumarine.com/only-safari-cannot-load-a-webpage/

切り分け

  • 同じドメインの別ページでは発生していない。
  • 別の開発環境でも発生していない。
  • 単体環境でも発生していない。

なので

  • 呼び出し元がおかしい
  • AWSのなにかが悪い

の二択まで絞れた

同等のサーバーを構築する

本番環境と同等の構成を作る。AWSなら証明書含めてさっさと作れるので楽。

下記のように構築した。なおELBでHTTP→HTTPSリダイレクトしている。

構築方法は別サイトや本に死ぬほどあるのでここには記載しない。

f:id:gologius:20210821124731p:plain

開発者ツールでデータを見てみる

実際に構築してみると、リダイレクトが二回発生しているのである。

f:id:gologius:20210821130104p:plain

動きとしては

  1. HTTPSの末尾スラッシュなしページをリクエス
  2. (なぜか)HTTPで末尾スラッシュありのページへリダイレクト
  3. ELBの機能で、HTTPSのスラありページへリダイレクト

呼び出しているURLを確認すると確かに、

  • 末尾スラッシュなし
  • ファイル指定が明示的にされていない

のである

/hogehoge?param1=1

他URLで確認してみる

他の指定方法で調べてみるとリダイレクトは発生しない f:id:gologius:20210821131324p:plain

/hogehoge/?param1=1
/hogehoge/index.html?param1=1

原因(推察)と対策

通信関連の推測

だいたいのサーバーは末尾にスラッシュ(トレイリングスラッシュというらしい)がないと自動リダイレクトするらしい。

URLの最後に付ける「トレイリング スラッシュ」ありなしの違いはSEOに影響するのか? | 海外SEO情報ブログ

で、APサーバー側の挙動にもよるが、おそらく下記のような感じの通信になっている模様。

リダイレクトする担当がそれぞれ違う。 f:id:gologius:20210821220746p:plain

EC2(IIS)側としてはELBに対してレスポンスを返すのだが、ELB⇔EC2間はHTTP通信になっているはず(EC2に証明書入れてないので)

よって、IISが返却するLocation属性はhttpのURLが記載されるが、結局ELBでhttpはhttpsにリダイレクトされる。

根本原因は?

正直分からないが、iPhoneSafariで「二回リダイレクトしているが、リダイレクト途中の状態のページがキャッシュされてる?」 みたいな動きになってるんじゃないでしょうか。 iPhoneの開発環境がないので推察しかできない。

対策としては明示的にスラッシュとファイル名を記載しましょう、ということになる。

/hogehoge/index.html?param1=1

明示的にというのは大事ですね。 f:id:gologius:20210821131620j:plain

AWS EC2にリモートデスクトップできない(認証エラーが発生しました(コード:0x800706be)

下記のエラーが出てEC2にリモートできない。

f:id:gologius:20201213192313p:plain

認証画面(ID、PW入力画面)は出てきて、入力した後にこのエラーが表示される。

よって、IPが違う(無効化されている)やポートがふさがっているなどではなさそうだが・・・

まず基本的なところの確認

結局、公式が一番詳しい。

Windows インスタンスへの接続に関するトラブルシューティング - Amazon Elastic Compute Cloud

ACL、セキュリティグループ、パブリックIPが割り当てられているか・・・などを確認。

全部確認後

ポートとか全部空いてるしなぁ・・・と思ってクライアント側のエラーを疑う。

別のノートPCだと普通にリモートできる。

エラーコードでググると下記URLがヒット。

リモートデスクトップ接続エラー 0x800706be - マイクロソフト コミュニティ

下記のファイルを適当なファイル名に変更(無効化)すると解決すると記載あり。

"C:\Program Files\CSR\CSR Harmony Wireless Software Stack\BLEtokenCredentialProvider.dll"

ウソだろ・・・と思いつつ修正してみると、リモートできた。

AWSのせいにしてたけどクライアント側の問題でしたとさ。

BLEtokenCredentialProvider.dll って何なの?

名前の通りBluetooth製品のドライバをインストールする際に勝手についてくるらしい。

CSR Harmony Wireless Software Stack” でググると色々出てくる。

Win7時代からRDPの問題があったらしい。

Bluetooth使ってないので私は上記に記載の通りリネームしました。

【バッチ】powershell で複数ファイルをPW付圧縮するバッチを作る話

業務で自動化したかったので作った(業務自体を潰したほうがいいのでは

何がやりたいの?

もらったファイルをリネームして、PW付ZIP圧縮する。

作ったバッチ

※7ZIPのインストールなどをして、7z.exeを叩ける状態にする必要がある

圧縮・解凍ソフト 7-Zip

gist.github.com

使い方

別途下記のようなbatを用意して、D&Dで実行させる。

cd %~dp0
powershell -NoProfile -ExecutionPolicy Unrestricted .\process.ps1 %1 %2 %3 %4 %5 %6 %7 %8 %9
pause

こんな感じ↓ f:id:gologius:20201108162247g:plain

補足感想など

ファイル名の置換

バッチ(DOS)でやろうとしたが、ごり押しバッチしか出てこなかった。 replace() 的な関数使ってスマートにやりたいよね、ということでpowershellを採用した。

PW付圧縮ファイルについて

社内で使えるソフトのほうがいいよねという個人的理由で7zipを採用。

公式に

C:\Program Files\7-Zip\7z.exe" a -pPassWord data.zip data.xlsx

と書いているせいで -pPassWord がオプション指定用と勘違いした。よく考えたらすぐ分かるのだが。 (-p → オプション指定文字列 | PassWord → 任意のパスワード文字列)

コマンドでZIPや7zにパスワードを付ける | 7-Zip

7zipの実行

直接下記のように指定したら、$password が変数展開してくれず、 「$password 」という文字列がパスワードとして設定されてしまった。

&$sevenzip_path a .\$result_file_name .\$work_dir_name  -p$password 

スペースを挟まないと変数展開してくれない模様。とりあえず別変数を用意して対応した。

感想

powershell気持ち悪いし永遠に慣れる気がしない

POSTパラメータがなぜか固定文字列 "on" になってしまう

事象

POSTパラメータやGETパラメータに、セットした覚えのない固定文字列 "on" がセットされてしまう

f:id:gologius:20200715123207p:plain
理想

f:id:gologius:20200715123222p:plain
現実

原因

input type="radio"

かつ

input タグに全角スペースが混じっている

と発生する模様

再現コード

<?php
if (isset($_POST) ) {
    print("<pre>");
    var_dump($_POST);
    print("</pre>");    
}
?>

<form method="post" action="./test_post.php">

    <input type="text" name="group1" value="fugafuga">

        NG<input type="radio" name="group2" value="hogehoge1">
        NG<input type="radio" name="group2" value="hogehoge2">
        NG<input type="radio" name="group2" value="hogehoge3">
        OK<input type="radio" name="group2" value="hogehoge4">

    <button type="submit">検索</button>
</form>

hogehoge1,2,3 のタグには、全角スペースが混じっています。

hogehoge4 は半角スペースで正しく区切られています。

補足

<input type="text" name="group1" value="fugafuga1">

のように、type=text に全角スペースが入っていると、value値は空になる模様。

f:id:gologius:20200715124114p:plain
type=text の全角スペース混じり

なんでや工藤・・・

Vueっぽく階層式プルダウンを作ったが、もっとスマートに書きたいという話

※Vue始めて3か月くらいです。

とりあえず作ったものを下記リンクに置いておく。

Vueでプルダウンテスト

ソースは下記に置いておく。JSなら動くのでgithubio便利。

gologius.github.io/test/PULLDOWN_SAMPLE at master · gologius/gologius.github.io · GitHub

リンク先を見るのが面倒な人向けにGIFも貼っておく

f:id:gologius:20200606152036g:plain
プルダウンのGIF

なぜ作ったのか

  • 3階層、4階層以降に対応したサンプルがなかった(気がする)
  • 超適当に調べたが、微妙にやりたいこととずれたものだった(気がする)
  • こんなんサイトちゃんと見なくても自力実装できるわwwwww(所感)

感想

1

HTMLはそこそこ綺麗かなと思いました

<div id="pulldown">
    <div v-for="(choices,layer) in selectable_items">

        <div v-bind:id="'layer' + layer" v-show="choices.length >= 1">    
            <h2>第{{layer+1}}階層</h2>
            <select v-bind:id="'pd-'+ layer" v-model="selected_stack[layer]">
                <option v-for="item in choices" v-bind:value="item.id">
                    {{item.name}}
                </option>
            </select>
        </div>

    </div>
</div>

<script src="pulldown.js"></script>

2

現状の選択に紐づく選択肢をJSでフィルターして渡してるんだけど、 HTML側のフィルターで頑張るべきなのか、JS側で頑張るべきなのか、ライブラリの思想としてどっちがいいのかがよくわからない

//現状のユーザー選択(selected_stack)に対して、表示すべき選択肢を取得
selectable_items: function () {
    
    var results = [];
    var layer = 0;
    for (layer = 0; layer <= this.selected_stack.length; layer++) {
        
        //上位層の選択結果を取得
        before_selected_id  = ''
        if (layer >= 1 ) {
            before_selected_id = this.selected_stack[layer-1];
        }

        //該当層かつ、上位層の選択肢に合致するもののみ抽出
        layer_result = MENU_M.filter(function (value) {
            return value.layer === layer && value.before_id === before_selected_id;
        });

        results.push(layer_result);
    }
    return results;
},

3

JS側が汚い。初期化処理とかキモイ。watch使っているんだけど謎ラッパーかまさないとListの検知ができない

computed: {
    //watch関数をまともに動作させるためのラッパー
    //参考:https://qiita.com/haruyanagi17/items/d74c0b9546719ff88c63
    watch_selected_stack: function () {
        return Object.assign({}, this.selected_stack); // ディープコピーしたものを返す
    },
},
watch: {
    //選択肢が入力された際の動作定義
    watch_selected_stack: function (newval, oldval) {
        
        //変更箇所を検知
        var update_flag = false;
        var layer = 0;
        for(layer=0; layer < this.selected_stack.length; layer++){
            
            //変更箇所より後の選択肢は初期化する
            if(update_flag) {
                this.selected_stack[layer] = '';
            }

            //変更されている箇所があれば、フラグを立てる
            if (newval[layer] !== oldval[layer]) {
                update_flag = true;
            }
        }
    },      
}

今後

もうちょいきれいに書く方法探しますわ