/*Google AdSense自動広告*/
ラベル 6.PCとプログラミング の投稿を表示しています。 すべての投稿を表示
ラベル 6.PCとプログラミング の投稿を表示しています。 すべての投稿を表示

2022年5月23日月曜日

LG PCモニタのスタンドを完全撤去する(破壊)

ノートパソコンをスタンド置きにすると、サブディスプレイとの高さ.前後差が気になりました。どんなモニタアーム、スタンドでも、壁際には置けないので、スタンドを自作することに。そうすると問題なのが、既存スタンド。LGのモニタですが、スタンドを外しても可動部が残るため、壁際設置の邪魔になるのです。


アームについている凹みをマイナスドライバーなどで押すと、スタンドを取り外せる


この可動部が残り、写真以上に格納できないので、破壊するしかありませんでした。まぁ、壊れたら買い換えるということで。

バキッと!裏からビスが入っているので、正攻法ではムリ


両脇の抑え部品を外せば、可動部を取り外すことができます。
これで背面がフラットになりますが、ケーブル取り出しのためスタンドに穴が必要です。



VESAマウントに薄板を取付け、窓枠に引っ掛け、足を取り付けます。すると、窓枠にピッタリ寄せることができます。ノートPCも並べて引っ掛ければ、ディスプレイの前後差が無くなります。これ以外にも、フックで壁掛けするのもいいと思います。


2021年9月1日水曜日

GASで気象庁XMLをパースしてLINE公式アカウントでブロードキャスト(全員へ送信)する

 LINE公式アカウントを導入検討している自治体などが喜んで、

ソフトベンダーが泣きそうな記事ですが…


基本的に、掲題のことは完全無料でできます


LINEチャンネルアクセストークンの取得

ここ、まだ完全に理解していないので、後ほど記事更新しますが、

  • チャンネルアクセストークンv2.1⇒セキュリティ高いが実装難しい
  • 長期のチャネルアクセストークン⇒とりあえずこっちでOK

以下URLを参考に、トークン(文字列)をゲットします。

https://developers.line.biz/ja/docs/messaging-api/channel-access-tokens/


GASスクリプト

main.gs


function pullHeadlineAndSend() {
  var url = 'http://www.data.jma.go.jp/developer/xml/feed/extra.xml';
  var xml = UrlFetchApp.fetch(url).getContentText();
  var xmlDoc = XmlService.parse(xml);
  var rootDoc = xmlDoc.getRootElement();
  
  var nsDefault = XmlService.getNamespace("", 'http://www.w3.org/2005/Atom');
   
  var entries = rootDoc.getChildren("entry", nsDefault);
  
  var length = entries.length;
  
  var currentDate = new Date().getTime();
  
  var title, updated, date, author, content;
  var headlines = "";
  // 最長で10分後に更新される
  var past10Min = 10 * 60 * 1000;
  
  // 10分以内に更新された東京都の気象警報のみ取得
  for(var i=0; i < length; i++) {
  
    title = entries[i].getChildText("title", nsDefault);
    author = entries[i].getChild("author", nsDefault).getChildText("name", nsDefault);
    content = entries[i].getChildText("content", nsDefault);

    updated = entries[i].getChildText("updated", nsDefault);
    date = new Date(updated).getTime();
    if(currentDate - date > past10Min) continue;

    if(title.indexOf("気象警報・注意報") != -1 && author === "仙台管区気象台" && content.indexOf("宮城県") != -1 ){
      headlines += Utilities.formatString('[%s]\n%s\n%s\n', title, toLocalDate(updated), content);
    }
   
  }
  
  if(headlines !=="")
  {
    sendPushMessage(headlines);
    Logger.log(headlines);
  }
}

function toLocalDate(dateString)
{
  var date = new Date(dateString);
  var formattedDate = Utilities.formatDate( date, 'Asia/Tokyo', 'yyyy年M月d日 HH時');
  return formattedDate;
}

function testSend()
{
  sendPushMessage('test message');
}


line_functions.gs


const TOKEN = 'got_token_string_ゲットしたトークンの文字列を貼り付け';
 
function sendPushMessage(text) {
  var url = "https://api.line.me/v2/bot/message/broadcast";
  var headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    'Authorization': 'Bearer ' + TOKEN,
  };

  var postData = {
    "messages" : [
      {
        'type':'text',
        'text':text,
      }
    ]
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(url, options);
}


あれ…prettyprintが効かないな…面倒だからこれでいいや!
(たぶんどこかの文字列がひっかかってます。詳しい人教えて…)

これで、function「pullHeadlineAndSend」をGASのタスクで10分毎に実行すればOKです。どんな情報をゲットするかは、条件文で設定します。また、http://www.data.jma.go.jp/developer/xml/feed/eqvol.xml
こちらのURLで地震火山情報をゲットできます。

2021年1月3日日曜日

bashのaliasでexpectを登録→シングルクォーテーションをエスケープし、別セッションでも有効にする方法

LinuxのGUIで複数タブ又は複数ウィンドウ(別セッション)で端末を開きつつ、各画面で臨機応変にサーバーにSSH接続する場合(どんな仕事だ…)、SSH接続をexpectのワンライナーでalias登録すると素早さが増しますが、躓いた部分があったので解説します。




aliasでシングルクォーテーションをエスケープする方法

bashでシングルクォーテーションをエスケープするには「\」=バックスラッシュ(日本語環境では¥マーク)を使用しますが、シングルクォーテーションの中のシングルクォーテーションには使えません。aliasコマンドは、登録するコマンドをシングルクォーテーションで囲む必要がありますが、expectをワンライナーで登録する場合、その内部にシングルクォーテーションを使う場面が出てきます。

この場合、一旦シングルクォーテーションを区切る意味で、「'\'」を使用します。


bad!!

alias 'a1=expect -c \'spawn .....\''


good!!

alias 'a1=expect -c '\''spawn .....'\''' 


.bashrcを更新する方法

aliasコマンドでaliasを登録した場合、別セッション(=GUIでは端末の別タブ・別ウィンドウ)を開く場合、aliasを引き継いでくれません。別セッション立ち上げ時はユーザー・ホームディレクトリにある.bashrcを読み込むので、ここにaliasを記載しておけば事足ります。(OSによっては、.bash_aliasesへの記載が推薦されていることもあります)

しかし、

  • 毎回ログインするサーバーが違う
  • サーバーが不定期にクリーンアップされる

場合、.bashrcを編集するのは不適切です。そこで、aliasで登録した後、aliasの内容を.bashrcにリダイレクトしてやると、それ以降の端末起動時にも読み込ませることができます。


alias >> ~/.bashrc


前回alias登録済みで、重複があった場合、aliasのショートカットが上書きされるだけなので、.bashrcが無限増殖することはありません。


上記2つをまとめてワンライナーで

さらに、サーバー上に設定ファイルが置けない、毎回ログインするサーバーが不定の場合、alias登録から.bashrc更新までワンライナーで記載して、端末へコピペするとその後の作業が楽になります。

例として、複数のサーバーログインショートカットを作成し、.bashrcを更新するワンライナースクリプトを示します。


alias at='expect -c '\''spawn ssh -o UserknownHostsFile=/dev/null -o StrictHostKeyChecking=no username@192.168.0.1; expect "assword"; send "password\r"; interact'\''';alias ax='expect -c '\''spawn ssh -o UserknownHostsFile=/dev/null -o StrictHostKeyChecking=no username@192.168.0.100; expect "assword"; send "password\r"; interact'\''';alias >> ~/.bashrc;


これで、sshでパスワードを打っている隣の同僚を、置いてけぼりにすることができるでしょう!



2020年12月14日月曜日

Windows10で、レジストリを編集してキーの入れ替えを行う

 ノートパソコンのキーボードや、コンパクトタイプのUSBキーボードでは、よく使うキーが、ファンクションキーと同時押しだったり、無かったりして不便なことがあります。

そこで、あまり使わないF11やF12、PageDown等を、InsertやHome等として使用する方法を紹介します。


Microsoft PowerToysを使う

PowerToysは、Microsoft製便利ツールの詰め合わせです。上級者向け・ベータ版のため、GitHubから手動でインストールする必要があります(リンク)。


こちらはWindows PCで、INSを殆ど使わないので、何故か特殊キーとなっているDELを割り当てて使いやすくしています。キーは何個でも割り当て可能です。

他にも、右クリックで画像縮小できるツール(画像のアップロード容量制限があるときにサッと縮小できる)があり、なかなか便利なツールです。


レジストリを編集する

PowerToysのインストールが出来ないが、管理者権限がある場合(そんなことは稀ですが、GitHubへの接続を禁じている等)、レジストリを編集することでキーの入れ替えが可能です。

ただし、表記が見辛くメンテナンスが面倒なため、ベターな方法ではありません。


まず、レジストリの下記ディレクトリを探し、

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

「新規」→「バイナリ値」で新しい値を作成して、名前を「Scancode Map」とします。ここに、バイナリ値を書き込みます。


フォーマットは、


00 00 00 00 00 00 00 00 ←固定

[num] 00 00 00 [after] [before]

[after] [before] ....

00 00 00 00 ←固定


[num]は入れ替えたい組み合わせの数ですが、最後の00 00 00 00も含めるため、

+1の値を記入します。


[after][before]にはキー特有のコードを入力しますが、逆表記とします。

例えば、F12のコードは58ですが、00 58の逆で、58 00となります。


Page Down    E0 51

Insert       E0 52

F12          58

(今回使用したコードです。キーボードタイプによって変わるキーもあるので、Microsoft等のオフィシャルな情報を参考にしてください)


今回は、Shift & Insertで貼り付けを多用し、Page Downキーが無い外付けキーボードにも

対応するため、Page Down -> INS, F12 -> INS へ二つ入れ替えます。


00 00 00 00 00 00 00 00

03 00 00 00 52 E0 51 E0

52 E0 58 00 00 00 00 00


これで、Page Down / F12 が両方ともINSキーとなり、Shiftと組み合わせると貼り付けが可能となります。

Ctrl & V だとコマンドの中止となってしまうLinuxのために、INSが無いキーボードは「注」と大きく表記してほしいものですね。

2020年10月8日木曜日

Selenium+PythonでWeb操作を自動化する→実例:LINEモバイルの複数アカウントの月額料金を自動取得する

今流行のRPA−業務自動化は、在宅ワークと相まって、仕事をパソコンにまかせて酒を呑むことが最終目標となっていることでしょう。

その中でWeb操作の自動化(ウェブスクレイピング)は不安定で動作が遅く、積極的にやるべきものではありませんが、Web上でしか情報を得られない場合はやるしかありません。

今回は、Python + Seleniumで、LINEモバイルの複数アカウントの月額料金を自動取得するプログラムを作りました。

OS : Windows 10
ブラウザ:Chrome

2020年9月14日月曜日

PowerShellでClassを利用する ver.2.0~文字コード指定、ルートタグ追加し、パース可能なxmlファイルを出力するクラス

前回の記事でXMLファイルを作成するPowerShellのClassを紹介しましたが、あれには重大な欠点がありました。


XML宣言は書きましたが、タグを羅列するだけで、ルートタグは特に作成しませんでした。これでも大丈夫かと思っていましたが、PowerShellやPythonのXML Parserでは、ルートタグが無いとエラーを吐いて、読み込んですらしてくれないのです(ただ、キーと値のデータを保存したかっただけなのに…)。


もう一点、文字コードも明確にUTF-8で指定しないと、PowerShellの標準はUTF-16なので、XML宣言と相違が出ることになります。


ルートタグで囲うので、データを保持するハッシュテーブルと、最後にセーブする関数を追加してクラスを再作成します。


仕様

  • PowerShellでタグと値を指定して、XMLファイルを作成する
  • ルートタグを指定して、保存時に全てのタグを囲う ←追加
  • 文字コードをUTF-8にする ←追加


クラス


class xmlFile
{
    $values = @{};
    $override = $false;

    [void]SetOverride($set_boolean){
        $this.override = $set_boolean;
    }
    
    [void]AddVal($key, $val){
        if(!$this.values.Contains($key)){
            $this.values.Add($key, $val);
        }elseif($this.override){
            $this.values.$key = $val;
        }
    
    }

    [String]GetVal($key){
        return $this.values.$key;
    }

    [void]SaveXml($root_tag, $save_filename){
        '<?xml version="1.0" encoding="UTF-8" ?>' | Out-File $save_filename -Encoding utf8;
        "<$root_tag>" | Out-File $save_filename -Append -Encoding utf8;

        $this.values.keys | Sort-Object | ForEach-Object{
            $set_value = $this.values.$_;
            "<$_>$set_value</$_>" | Out-File $save_filename -Append -Encoding utf8;
        }

        "</$root_tag>" | Out-File $save_filename -Append -Encoding utf8;
    }
       
}


関数AddValでハッシュテーブルvaluesにキーと値を追加します。変数overrideの値によって、同名キーがある場合に無視するか、値を更新します。

キーと値はハッシュテーブルに格納し、関数SaveXmlによってXML宣言とルートタグを追加して保存します。いちいち保存しなくていいようにしたかったのですが、ルートタグの追加には必須です。

文字列をそのままパイプでOut-Fileに流してやれば、ファイルに保存できます。オプション -Appendでファイルに追記、-Encodeでエンコードを設定できます。

ハッシュテーブルのkeysを、Sort-Objectを介してForEach-Objectに渡すと、キー名アルファベット昇順で処理できます。


使用例


$xf = New-Object xmlFile;
$xf.AddVal("testKey1", "testVal1");
$xf.AddVal("testKey2", "testVal2");
Write-Output $xf.GetVal("testKey1");
$xf.SetOverride($True);
$xf.AddVal("testKey1", "testVal1-1");
$xf.SaveXml("parent", "C:\myCodes\test.xml");

↓結果

C:\myCodes\test.xml

<?xml version="1.0" encoding="UTF-8" ?>
<parent>
<testKey1>testVal1-1</testKey1>
<testKey2>testVal2</testKey2>
</parent>

このように、指定したルートタグ<parent>の中に、キーと値がタグとして保存されます。

ルートタグ名は何でもいいのですが、前述のとおりこれが無いとPowerShellやPythonでXMLファイルとして認識してくれないのです。

それでは、次回はPowerShellとPythonでXMLファイルを読み込むクラスを・・・



2020年7月11日土曜日

PowerShellでClassを利用する~keyとvalueの単純なxmlファイルを出力するクラス

プログラミングのオブジェクト指向って大仰に聞こえるけど、「クラス」を使うスタイル・流行だと思えば理解しやすいです。語弊がある、と非難されるかもしれないけど、これ以上は宗教の話になるので…。

クラスというのは(また語弊があると言われそうですが…)、
プログラマが楽するために使うものです。例えば、

Car(車)

というクラスを作り、

Car.Speed = 50
Car.Run

とすると、50km/hで車が走ることにする。

Carというクラスの中身については、他の人に作らせるか、作って忘れるかで、
メンテナンスはなるべくやりたくない、それがクラスの肝です。

さて、本題です。PowerShellはスクリプト言語で、クラスと無関係そうですが、オブジェクト指向であり(ここがコマンドプロンプトやbashより進化している部分)、クラスも十分使えます。

今回は、設定ファイルの保存等に使うことを想定した、xmlファイルの作成・キー追加のクラスを作っていきます。

PowerShellコード↓

class xmlFile
{
    $newFile;
    # ->newFileNameにしてしまいそうだが、そこはオブジェクト志向で…
    
    xmlFile($setFileName){
        $this.newFile =New-Item $setFileName -type file -Force;
        Write-Output '<?xml version="1.0" encoding="UTF-8" ?>' | Add-Content $this.newFile -Force
    }
    
    add($key, $val){
        Write-Output "<$key>$val<⁄$key>" | Add-Content $this.newFile -Force
    }

}

$xf = New-Object xmlFile("$PSScriptRoot\test.xml");
$xf.add("testKey1", "testVal1");
$xf.add("testKey2", "testVal2");

↓出力(スクリプトと同じ場所に、test.xml)




※一応xmlのフォーマットに準じているので、他のプログラムのXMLパーサーが使える筈


クラスの宣言

class クラス名で宣言します。同名のメソッドが自動的にコンストラクタになります。ここではファイル名を指定すると、ファイルが新規作成されるようにしました。

メソッド

メソッドはaddのみ。重複キーの処理や、System.Xml.XmlWriterを使った書き込みもいいと思います。でも結構コードが煩雑になります。

クラスの使用

$変数 = New-Object クラス名 でクラスが生成されます。

その他

New-Itemは新たなファイルやディレクトリを作成する際に使います。
Write-Output をパイプで Add-Content に渡すと、ファイルにテキストを追記できます。この際、改行が自動的に入ることは便利ですが、意図しない場合は注意が必要です。



2020年5月24日日曜日

PythonとPowershellでgrep的処理を行う

パイプとかgrepとか、Linuxを使い始めの頃は訳の分からない魔法に見えますが、慣れるとGUIより早く便利で、何よりも流行りのRPA、業務自動化に繋げられます。

システムをWeb化したのはいいが、自動化のためブラウザをSeleniumで動かすなんて、地獄ですからね …「途中で止まるんですけど!」「勝手にid変わってる!」

極力、GUIを自動化するのはやめて、CSVやテキストで出力し、GASでGoogle Siteに出力、というようなスマートな方法を採りたいものです。

今回の記事では、下記のようなファイルから、例としてSendaiServerのアドレス(192.168.120.3)だけを抜き出したい場合…

FukushimaServer,192.168.10.2
SendaiServer,192.168.120.3
TokyoServer,192.168.1.1

この処理を、Linux/Python/Powershellそれぞれ紹介していきます。

Linux grepでファイル内の文字を検索する

grep "SendaiServer" sample_server_list.txt | cut -d , -f2

パイプの後はawkでもsetでも。ワンライナーでシンプル。ただ、可視性とか検索した文字を利用して色々…となると後者のやり方にもメリットが見えてきます。

Python版

myPath = "C:/myApps/python/sample_server_list.txt"
with open(myPath, 'r', encoding='utf-8') as file:
    lines = file.readlines()
    for line in lines:
        if line.startswith("SendaiServer"):
            address = line.strip().split(",")[1]

print(address)

For Eachで回すので、一番汚いコードだと思う…。綺麗なやり方ご存知でしょうか?
withによるファイルオープンではブロックの最後に必ずファイルが閉じられるので、このやり方を推薦します。また、readlinesでは改行コードも入ってしまうので、strip()で抜いた後にsplit()します。

PowerShell版

$finder = Select-String -Path $PSScriptRoot\sample_server_list.txt -Pattern "SendaiServer";
$address = $finder.line.Split(",")[1];
Write-Output $address;

Select-Stringはgrepと同じような動作をしますが、帰ってくるのはオブジェクト(MatchInfo Class)なので、その中のlineを抜き出して、Splitする必要があります。
普通に$finder.ToStringを出力すると、「ファイル名:行:見つかった行」とコロン区切りで色々な情報が入ってくるので、これをコロン区切りのSplitで分割して…というのは初心者の陥る罠です。でも、うん、分かります…Select-Stringって言ってますからね!



2020年5月22日金曜日

RLoginを使用し、ワンクリックでサーバー接続→SSH認証を行う

RLoginというのは、TeraTermやPutty、Poderosaの上位互換ターミナルソフトです(私感)。

RLogin本家 紹介&ダウンロードページ

普通に使っても便利なソフトですが、私は面倒くさがりなので、起動したら特定のサーバーにSSH接続までしてもらうようなスクリプトを作りました。

Server Entryの登録

先ずは、接続するサーバーを登録します。新規ボタンで色々な設定タブが開きますが、「サーバー」タブで殆ど事足ります。「プロトコル」子タブからポートフォワードの設定も可能です。ここで登録したEntry名を覚えておきましょう。

次に、「スクリプト」タブで下記スクリプトを指定します。


スクリプトの作成

上で作成したサーバーに、SSH接続を自動化するスクリプトを登録します。

編集 > サーバー > スクリプト
エントリースクリプト
(サーバーエントリー接続時に実行するスクリプト・ファイルを指定します)

スクリプトファイルの拡張子は何でも構いません。

Document.Open();
wait(CONNECT);
sopen(OPEN_LOOK);
swait(3,">");
sputs("ssh SSH_Server_Name\n")
swait(3,":");
sputs("myPassword\n");
swait(3,"Do you access this server(yes/no):");
sputs("yes\n");
sclose();

【解説】
前後はオマジナイのようなもので、以下2つの関数が重要です。

  • swait(3,">") : プロンプト文字列「>」が出るのを3秒待ちます。
  • sputs("ssh SSH_Server_Name\n") : swaitでプロンプトが出るのを待った後、文字列を入力します。sshコマンドや、ユーザー名、パスワード等。最後に改行コードを入れると、エンターキーを押す挙動になります。

RLoginをEntryで自動接続するスクリプトの作成(VBS/PowerShell)

特定のEntryしか使わない場合は、RLogin起動後に「ファイル - サーバーに接続」から指定するのも煩わしく感じるでしょう。

これは、起動時のオプションで指定可能です。

VBSの場合


Dim myShell
Set myShell = CreateObject("WScript.Shell")
myShell.Run "C:\Tool\RLogin.exe /entry Entry_Name" , 1, true

PowerShellの場合


& C:\Tool\RLogin.exe /entry Entry_Name

スクリプトのEntry_Name部分に、最初に登録したEntry名を記載します。このスクリプトを実行すれば、RLoginの起動→SSH接続・認証まで自動で進めることが出来ます。

究極の面倒くさがりのために…






2020年5月21日木曜日

Powershellでフォルダ内のdocファイルを開き、CustomPropertiesを取得する

あまり需要が無さそうな記事ですが…
(↓そんなことやるなら最初からWordで出力するな、という話)

フォルダ内にあるWordファイルから、詳細プロパティを取得するPowerShellプログラムです。詳細プロパティは、ファイルメニューからプロパティー詳細プロパティで見ることができます。





ここに使いたい情報があるけど、全てのファイルを開いて見るのは面倒だ、自動でテキストファイル出力等がしたい時にこのプログラムが使えます。

コード


$getProperties = @('myId', 'myNetwork');
$binding = "System.Reflection.BindingFlags" -as [type];

$word = New-Object -ComObject word.Application;
$word.Visible = $False;

$targetFolder = '\\QNAP\myData';
$docs = Get-ChildItem $targetFolder -Filter *.doc;

foreach($doc in $docs){
    $Document = $word.Documents.Open($doc.FullName, $False, $True); #fileFullName, Convert Dialog, Read-Only
    $customProperties = $Document.CustomDocumentProperties;
    $getValues = @{};
    
    foreach($prop in $getProperties){
        $myProp = [System.__ComObject].InvokeMember('Item', $binding::GetProperty, $null, $customProperties, $prop);
        $myVal = [System.__ComObject].InvokeMember('Value', $binding::GetProperty, $null, $myProp, $null);
        $getValues.Add($prop, $myVal);
    }

    $Document.Close(0); #0:Don't save, -2:Prompt, -1:Save

    $outputString = $doc.FullName + ">" + $getValues['myId'] + ">" +  $getValues['myNetwork'];

    Write-Output $outputString;
}

$word.Quit();
$null = [System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$word);
[gc]::Collect();
[gc]::WaitForPendingFinalizers();
Remove-Variable word;


解説

  • $getProperties … 取得したいCustomProperty名を指定する
  • $Document = $word.Documents.Open($doc.FullName, $False, $True)→Excelの場合はfileを指定すればいいのですが、何故かWordはFullName指定
  • $getValues … foeachで回して、CustomProperty名を取得し、値を取得(見つからない場合などエラー処理を必要に応じて追加してください)
  • $Document.Close(0) … 変数に入れたので、Wordファイルは閉じてOK。0は保存しない
  • $getValues[プロパティ名] … これで値が利用できます




フォルダ内にこのようなファイルがあり、詳細プロパティ「myId」「myNetwork」があれば、以下のようにPowerShellコンソールに出力されます↓
\\QNAP\myData\a1.doc>500604>10.56.135.12
\\QNAP\myData\a2.doc>500607>10.56.145.12
\\QNAP\myData\a3.doc>500609>10.72.136.11


2020年5月17日日曜日

SSH login without inputting password : expect oneliner ワンライナーでexpectを使ってsshログインする

Linux/bashでsshログインを自動化するには、

  • 公開鍵を使う
  • sshpassを使う

方法がありますが、どちらもサーバー側の対応が必要になります。
「接続先が客先(またはコミュニケーションのとれない部署)なのでサーバーはいじれない」場合は、expectを使う方法があります。

expectはbashのパスワードやyes/no入力を自動化する機能で、sshの他にkinit等の認証にも利用できます。

また、サーバーにスクリプトを保存することもできない場合は、ワンライナーのスクリプトをローカルマシンからコピペすることで対応できます。

数秒の業務効率化ですが、毎回のパスワード入力にウンザリしている人はお試しあれ。

【条件】ssh, expectがインストールされていること

【スクリプト】
expect -c 'spawn ssh userName@serverName; expect "assword:"; send "myPassword\r"; interact'

【解説】
  • -c:スクリプトとして以下の分を実行する
  • spawn:コマンドを実行、今回はssh
  • expect:名前が紛らわしいのですが、これで入力待ち。次の分が正規表現で見つかるまでまつ。"assword:"だと、Password:とpassword:両方に対応。サーバーによってこの文字が違うかもしれないので注意
  • send:キー入力、今回はパスワード
  • interact:シェルに戻る
  • シングルクォーテーションとエスケープ:今回は、シングルクォーテーションで全体を囲み、文字列をダブルクォーテーションで囲みましたが、ダブルクォーテーションで始めると、スクリプト中の文字列はエスケープして「\"」を使う必要あり。見辛いので前者をオススメ。




2020年5月2日土曜日

Excel VBA ~ ClassをDictionaryに格納するコツ Dictionaryの癖…オブジェクトは参照渡しになってしまう、Watch式に入れるとEmpty Itemができてしまう…

VBAでクラスを使用する人は少ないと思われます(ライブラリとして共用したり、継承したりできないので、そこまでやりたい人は別の言語を使っているのでは…)。
私は結構使っています、シートを設定したら項目でアクセスするものや、作業ログを最後にテキストファイルで吐き出すもの等。
実行速度やオブジェクト指向とか、そういう難しい話でなく、ブラックボックス化して頭を整理するため、というのが本心。

さて、そこで作成したクラスをDictionaryに格納しようとしたところ、おかしな挙動が…。
例えばループで次々にクラスを宣言、格納しても、全て最後に格納したクラスを参照してしまうのです。
どうやら、Dictionaryにクラスなどのオブジェクトを格納する際は、参照渡ししかできないようです。
エッ!!バグですか?仕様ですかそうですか。

通常はオブジェクトと言っても別セルを格納したりすることが多いので、普通に使っている分には問題ないでしょう。
しかしちゃんと新たに宣言したクラスがですよ、VBAにはさっき使ったものと同じに見えるのですよ!
エッ!!バグですか?仕様ですかそうですか。

ということで諦めて配列を使う…にはまだ早い!どうしてもKeyでアクセスしたい場合は、クラスをたくさん作っておけばいいのです。
setArrayを自作クラスとしてmaxNum個作成しておいて、インクリメントしながらDictionary(ここではdics)に格納していく。
配列を使わずに、都度Dimで宣言したりNewで作成した場合、どのKeyでも最後に格納したクラスしか参照できなくなります。
エッ!!バグですか?仕様ですかそうですか。


Dim setArray, dics As New Dictionary, c As Integer

ReDim setArray(maxNum - 1)

Do While Not IsEmpty(setSheet.Cells(r, 1))

    Set setArray(c) = New myClass
    dics.add setSheet.Cells(r, 1).Value, setArray(c) 
    c = c + 1
    r = r + 1
    
Loop

これで、Keyで自作クラスにアクセスできるようになります。Keyを配列の添字に変換するクラスを作ってもいいと思います。

それと、クラスに関係ない話ですが、どうもVBAはオブジェクトを流用(メモリから消えない?)するようで、ループで回す際に、
Dictionaryの前データが邪魔する場合があります。その場合は、新たに宣言したDictionaryでもRemoveAllを入れておくと解決します。

Set units = New Dictionary
units.RemoveAll

また、ウォッチ式が邪魔することがあります。Excelのバージョンによっては、ウォッチ式にDictionaryを入れるとEmptyデータが格納され、ItemのCount=1となってしまうようです。これは実行途中で止めたときにウォッチ式に追加すると回避できます。

まとめ VBAでDictionaryを使う際のTips
  • DictionaryにObjectを格納すると、強制的に参照渡しとなる Object in the Dictionary forces to be reference
  • よって、同名・単一クラスをDictionaryに格納することはできない Therefore, the same name / single class cannot be stored in Dictionary
  • 同名オブジェクトを流用する際は、値が残る場合があるので、RemoveAll等で強制クリアする When diverting an object with the same name, the value may remain, so forcibly clear it with RemoveAll etc.
  • ウォッチ式にDictionaryを入れるとEmptyデータができてしまうので注意する A dictionary to the watch expression, empty data will be created.

2020年1月26日日曜日

Ubuntu 19.10 日本語 Remixを外付けHDDにインストールする手順(18.04 + Universal-USB-Installerで失敗した後)

Windows PCにて、なるべく環境に影響を与えずにUbuntuで遊びたい場合、
外部USB HDD or SSD or メモリにインストールして、差した時だけ
Ubuntuが起動する形がいいと思います。

パーテーション切ったりは怖いですからね。
シェルのみであれば、Windows10上で、WSL+Ubuntuでもイケます。

【SPEC】
  • PC : NEC Lavie LL850/S
  • HDD : Buffalo MiniStation 500GB
  • Live USB作成ツール : Rufus-3.8
  • Ubuntu本体ISO : ubuntu-ja-19.10-desktop-amd64.iso


【手順】

(1) Live USBメモリの作成

※これはお試し用で、データや設定の保存はできません!!

最初にUbuntu 18.04とUniversal-USB-Installerで試しましたが、

Mounting /cow on root failed: Invalid argument overlay mount failed

のエラーが出て起動できませんでした。明確な理由は不明ですが、
18.04 + Rufus(Universal-USB-Installerも?)ではバグのために失敗することがある、との情報が…。

解決策は、
  • 19.10を使う→リンク
  • Rufusで作成する際、Persistent partition Sizeを適当(半分くらい)な値にする
これでうまくいきました。


(2) 内蔵ストレージの取り外し

※これを行わないと、内蔵ストレージにUbuntuがインストールされてしまいます!!

(3)の本番インストールの際、内蔵ストレージが存在すると、外部USBドライブを指定できません。物理的に取り外す必要があります。繋いだドライブを全て選択できたらよかったのにな…。


(3) Live USBとインストール用HDDを接続し、起動

パソコンの起動時にF2キー(NECノートPCの場合)を押し続け、BIOS設定画面を開きます。Boot関係のタブにて、USB MemoryとUSB Strageの順位を内蔵HDDより上位に設定します。これでUSBに起動可能ドライブを差している時は、そちらを優先して起動するようになります。


(4) Ubuntuをインストール


デスクトップに「Ubuntuをインストール」アイコンがあるので、そこからインストールします。昔と比べて分かりやすいGUIでインストールできます。

日本語設定をしたにもかかわらず、半角/全角キーで日本語切り替えができない場合、キーボードレイアウトが英語になっている可能性があります。

端末から、下記コマンドで日本語レイアウトに変更できます。

setxkbmap -layout jp



2019年12月15日日曜日

Alteryxでフォルダ作成 mkdir するのに R tool を使う

Alteryxを業務で使っていると、どうにもファイル入出力が貧弱で萎えますよね?

「フォルダを作る」こんなことも、バッチかPowerShellを作って、コマンドを叩くしか方法がないらしい(AlteryxCommunityより)。

いや、もうボクの作業フォルダはyxwzとps1と出力ファイルでゴチャゴチャなんですけど…

ということで、R Toolを使ってAlteryx内でDynamicにフォルダ作成する方法を紹介します。

Alteryxワークフロー






フォルダ指定とディレクトリツール

フォルダ指定のダイアログを出して、結果をディレクトリツールに渡し、フォルダ内の*.csvファイルを開きます

Block Untilツール

Rでフォルダを作るのを先に完了させるため、実行順を強制的にしていします。Alteryxは並列処理するので、場合によっては「フォルダが無いよ!」エラーが出てしまうので。

フォルダ作成、フィールド付加 Append Field

Rツールでフォルダを作成し(コードは後述)、そのフォルダ名をFieldとして付加、それと元のファイル名で保存パスを作成します。

最後のOutputでは、ファイル名をダミーにしておいて、


フルパスを変更 Change FullPath を選ぶことで、保存フォルダとファイル名を自由に設定できます。元のファイル名を使ったり、日付を入れたり、Excelファイルの場合はファイル名+「|||シート名」でシート名を指定したり。



Rコード


df<-read.Alteryx("#1", mode="data.frame")
mkdir<-paste(df[1,1], "output", sep="")
dir.create(mkdir)
names(mkdir)<-c("outputFolder")
write.Alteryx(mkdir, 1)

df[1,1]は1行目1列目のデータ、この場合はグループ化した選択フォルダとなります。作りたいフォルダとして、今回はそのフォルダに"output"を付加しました。Rの文字列結合はpasteを使いますが、sep=""を指定しないとスペースが入るので注意します。

dir.create()でフォルダを作成します。元々存在する場合は警告がでるかも。

names()<-c("itemname")で項目名を指定します。指定しないと、長々とした自動項目名となり、テーブルによって変わってしまうので不便です。これをwrite.Alteryxで出力し、前述したOutput Fileのパスとして利用します。


まとめ

ここまでくるとハッと思いつきますね、「これならRで全部やればいいんじゃない?」
その通りだと思います。ちなみに、Alteryxはcommand実行ライセンスが別売りなので、自動実行したい時は別料金。

高額なライセンス料と見合う売り上げが見込めないなら、R勉強した方がいいんじゃない?コミュニティも英語ばかりだし、コードや英語にアレルギーがある人には無理なツールです。導入は慎重に!



2019年11月30日土曜日

Excel VBAでグラフの範囲をグラフタイトル+複数列(配列)で設定する

以前Excel VBAでグラフをタイトルで操作するコードを書きました(→記事

今回は、バラバラに並んだ項目名から、そのグラフに必要な列を検索し、グラフの範囲指定を自動化します。

実務では、Alteryxでビッグデータから作った表の項目が、毎回違う場合でも、同じフォーマットに出力するために作りました。やっぱりまだExcelのグラフの方がフレキシブルで綺麗なので。

こんな表から、



定型フォーマットのグラフ一覧へ、データをセットするコードです。



ユーザー定義クラス graphInSheet



Public graphSet As Dictionary
Private targetSheet As Worksheet
 
Public Function setSheet(mySheet As Worksheet)
 
    Set targetSheet = mySheet
 
    With targetSheet
 
        Set graphSet = New Dictionary
 
        Dim chart
        For Each chart In targetSheet.ChartObjects
            graphSet.Add chart.chart.ChartTitle.Text, chart.Name
        Next
    
    End With
 
End Function
  
Public Function setSourceData(GraphTitle, setRange As Range)
 
    With targetSheet
 
        Dim currentChart As chart
        Set currentChart = .ChartObjects(graphSet(GraphTitle)).chart
               
        currentChart.setSourceData Source:=setRange
 
    End With
 
End Function
 
 
Public Function setCategoryMinMax(GraphTitle, MinScale, MaxScale)
 
    With targetSheet
 
        Dim currentChart As chart
        Set currentChart = .ChartObjects(graphSet(GraphTitle)).chart
        currentChart.Axes(xlCategory).MinimumScale = MinScale
        currentChart.Axes(xlCategory).MaximumScale = MaxScale
       
    End With
 
End Function

メインコード「RangeをUnionする」



Public Sub setDataToGraph()
       
    Dim payment, payments
    payments = Array("現金", "カード", "PayPay")
    
    '今回はグラフとデータを別にしましたが、同じシートでも可
    Dim graphs As New graphInSheet
    graphs.setSheet ThisWorkbook.Worksheets("graph")

    Dim dataSheet As Worksheet
    Set dataSheet = ThisWorkbook.Worksheets("data")
         
    Dim region
    For Each region In graphs.graphSet
                                
        Dim dataColumns As New Dictionary
        Dim setRange As Range, lastRow
                                
        With dataSheet
                                
            '横軸(項目に対して固定)を設定
            lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
            Set setRange = .Range(.Cells(1, 1), .Cells(lastRow, 1))
                                
            '各グラフに必要な項目の列を収集
            dataColumns.RemoveAll
            For Each payment In payments
                dataColumns.Add .Rows(1).Find(region & "_" & payment).Column, Null
            Next
                              
            '列からRangeの集合を作成し、グラフにセット
            Dim setColumn
            For Each setColumn In dataColumns
                
                Set setRange = Union(setRange, .Range(.Cells(1, setColumn), _
                                                                   .Cells(lastRow, setColumn)))
            Next
        End With
        
        graphs.setSourceData region, setRange
    
    Next
       
End Sub


一番左の横軸となる列を範囲指定し、そのRangeへUnionで必要な列を追加していきます。できあがったRangeをChartObjectにsetSourceDataで入れればいいのですが、グラフのタイトルでなく、「Chart12」などとExcelで決められたオブジェクト名で指定するのが不便なため、ユーザー定義クラスでシート中の全グラフを保持しておきます。

ただし、グラフタイトルが被るとうまく動作しませんので、別の方法を考えなければいけません(結局Chart番号??)。


2019年11月24日日曜日

AmazonのブラックフライデーでSSDを購入してHDDから換装→爆速でビックリ

SSDが良い、オススメとの声をよく聞きますが、我が家のノートパソコンは多少重いけれど不便というほどでもない現状に、ブラックフライデーで「黒い」SSDがセールとなって現れます。

爆速で届いて、ちょっとクローンに躓きましたが、半日で換装完了。これはオススメ…というか、今までハードディスクがボトルネックだったのね!

【PC】 NEC LaVie LL850/S
【HDD】 HGST SATA 6Gb/s 5400rpm 1.5TB
 ↓
【SSD】 シリコンパワー SSD 512GB 3D NAND採用 SATA3 6Gb/s


シリコンパワー SSD 512GB 3D NAND採用 SATA3 6Gb/s 2.5インチ 7mm PS4動作確認済 3年保証 A55シリーズ SP512GBSS3A55S25



→これが、ブラックフライデーで 5,870円まで下がっていました。

必要なものは他に、スペーサーとUSB-SATA変換ケーブルだけです。ソフトは無料のもので十分。



KAUMO 2.5インチ SSD/HDD用スペーサー 7mmを9.5mm厚に変換 耐熱シール付き KM-296




SATA-USB 3.0 変換ケーブル YOKELLMUX 2.5インチ SSD/HDD用



マシンやSSDによって換装のコツは色々あるようですが、私の場合は

 GPTでフォーマット → クローン

でうまくいきました。ソフトはEaseUS Todo Backup(無料版)です。
(有料版もありますが、クローンは無料版でできます)

クローン作製時、ハードディスク全体と、ドライブそれぞれのチェックが可能ですが、最初にC(Windows)ドライブのみのクローンを行うと、交換後にBIOS画面から進まずに失敗。「システムリカバリ」など無駄と思われる領域があっても、全体のクローンを作るべし(詳しい方は選択して適切なパーティションを切ってください)。

全体のクローンは1時間ほどかかりました。そのまま寝てしまったので半日かかったことになりますが、実際は準備も含め2時間ほどでしょう。

クローンが出来たら、HDDからSSDに換装して起動するだけです。スペーサーはロゴマーク側、隠れて見えなくなる方です。



交換後は、今までのモッサリは何だったのだろう?という軽さ。そしてハードディスクが無くなって気付く静かさ。耐久性はこれから見ていきますが、これだけ快適なら次もSSDでしょう。もうカリカリ音には戻れません。NAS用も普及価格に落ちてきてくれないかな…。



2019年10月25日金曜日

PowershellからAccess VBAのサブプロシージャを実行する(ついでに最適化を行う)方法

Powershellから、マクロを含んだExcelやAccessのサブプロシージャを実行することが出来ます。

Hiddenな動作、例えばExcelで別名ファイルを生成したり、AccessでCSV読み込みとテーブル作成クエリを実行したい場合、元ファイルを開くことなく、Powershellの実行だけで完了するので、自動化の目途が立ちます。

今回はAccessの例を紹介しますが、Excelの場合も殆ど同じですので、試してみてください。


2019年9月21日土曜日

光コラボ乗り換え~AsahiNet光から楽天ひかりへ

親が格安SIMを検討中ということで、色々調べるうち、「WIMAX安いなぁ」「光コラボは…あれ、2019年7月以降は簡単に乗り換えできるようになってる」ことを知りました。

 今までの自宅のネット回線は、

①フレッツ光+Biglobe(プロバイダが遅い)
②フレッツ光+Asahiネット(高い)
③Asahiネット光(障害多い)

といった経歴で、光コラボは事業者変更時にフレッツ光解約を伴うため、手数料や手間がかかることがあり、③を我慢して使っていました。しかし2019年7月から、光コラボの事業者変更が工事無しで簡単にできるようになったと知り、すぐに次の業者を探しました。



光コラボ業者の選定


値段的にはSo-netか楽天。ただしSo-netは最初だけ安い遣り口です。楽天は特典が楽天ポイントなので、楽天市場を良く利用する人には良。ということで楽天ひかりに決めました。

3年縛りのキャンペーン特典↓

  • Archer C6プレゼント
  • 楽天ポイント 7000ptプレゼント
  • 工事費無料

乗り換え手数料は軽く吹き飛びます。デメリットは、プロバイダが原因でネットが遅すぎる場合に、違約金を払わなければ辞められないことですが、使えないくらい遅ければクレーマーとなって戦えばいいと思います。

月額料金は、

  • 4,800円(税込5,184円)
  • 特典200ポイント+楽天カード払い1%=48ポイント

つまり、実質4,936円。AsahiNet光は5,486円(長期割引100円含む)なので、月550円安くなることに。選ばない手はありません。

楽天ひかりを契約する場合は、楽天会員かつ楽天カードを持っている方がお得です。






光コラボの事業者変更~申し込み方法



事業者変更手続きは、スマホのMNPに似ています。まず、変更元のAsahiNet光から、「事業者変更承諾番号」を貰います(会員ページから)。取得は無料ですが、変更が完了すると手数料2,000円が発生します。

日中に手続きを行えば、その日のうちに番号がメールで届きます。それを変更先の楽天ひかり申込みホームページで入力するのです。 

楽天ひかりのホームページから、「他社の光コラボから乗り換え」を選択、戸建てかマンションを選びます。事業者変更承諾番号は変更元からメールで届く、Fで始まる番号です。番号の有効期限は15日なので、すぐに手続きしましょう。西日本の方はCAF番号も必要なようです。

迷うのは、近隣の電話番号を使った仮番号の入力。フレッツ光の収容先の目安にするのでしょう。近くのお店の電話番号でいいのですが、県や市区町村境をまたがないように。間違ったとしても多少手続きが遅れるくらいだと思いますが。




光コラボの事業者変更~設定方法



申し込み翌日に電話があり、本人確認の後、


  • 約2週間後の開通
  • 工事は発生しない
  • 夕方には開通するので、そのタイミングで機器設定して下さい


と説明を受けました。フレッツ光回線をそのまま使うので、収容先を変えるだけで事業者変更ができるのです。その後、アカウントのお知らせが郵送されてきます。






切り替えの次の日、まだAsahiNet光のアカウントで繋がっています。ルーターの設定画面で、楽天ひかりのアカウント設定をします。恐らく設定後に、旧プロバイダには繋がらなくなると思われます。インターネット接続タイプは「PPPoE」になっていると思いますので、そのままで。ユーザー名とパスワードを新しいものに書き換えます。早速スピードテスト↓






早い!!!早朝でしたが、AsahiNet光はどの時間帯も3桁に達したことはなかったので。




楽天ブロードバンドメンバーステーションでポイントキャンペーンなど設定




楽天ブロードバンドメンバーステーションから、


  • 楽天スーパーポイント口座情報変更
  • 楽天スーパーポイント口座番号の表示手続き(楽天会員アカウントで)


これで、楽天ブロードバンドと楽天会員アカウントが紐づきます。
(というか、最初から紐づけてくれたらいいのに…)

これを行わないと、楽天ポイントが貰えないので注意!


ネットは爆速になり、月額料金は安くなる。簡単手続きで乗り換えできるので、今の光コラボに満足していない方は切り替えをおすすめします。ただし、手数料や解約金が大きくなることもあるので、何度も切り替えることのないよう、ご注意あれ。




2019年8月9日金曜日

Alteryx : R Toolでテーブルを横展開する(reshape wide)~Cross Tabツールを不便に思ったら~

コードフリーのAlteryxで結局コードを書くシリーズ【第2弾】

縦に並んだテーブルを、ある項目をキーとして横方向に展開するには、Cross Tabツールを使います。

しかし、このツールには制限があり、展開する列は1つのみで、列名を自動付与することができません。そのため、2つ以上の列を横展開するには、Cross Tabを複数個用意してからSelectツールで列名を変更してから結合するという、バカらしくも面倒なフローが必要となります。そこで、それらの処理をR Tool一発でできるようなコードを書きました。

困ったときはR Tool、R言語を覚えつつ、最終的にAlteryxはイラナイ!となるのが、コスト・スキル的にベストだと思います。

処理の概要とワークフロー

例として、店舗名と商品ID、Key Performance Indicatorがいくつかまとまった表をソースとして、グラフの描画に使うため、日付ごとに全て横並びにしたい場合。



 ↓




下図ワークフローの、Cross Tabを使う流れの場合、ShopとItemIdを文字列結合してキーとし、Group byにDateId、ヘッダーにShopItemId、値にKPI_1を指定します。値に指定できるのはひとつだけなので、KPI_2はもう一つのCross Tabで処理し、Joinしなければなりません。









しかも、Cross Tab後のデータはKPI_1かKPI_2か項目名では分からなくなるので、それぞれ項目名をリネームする必要があります。私が担当を任された表では、これが10以上あったので、超絶面倒になって、R言語を勉強した方がマシ!と思った次第です。

そもそもAlteryxのグラフツールが、項目を抽出して項目名を付けてくれるとか、横軸のインターバル(間引きして見やすく)とかが柔軟にできていたら、この横展開も必要なかったのに…。結局Excelのグラフを使い、参照するテーブルを更新する形にしました。





R Toolの処理解説

R Toolの中身は↓

--------------------------------------------------------------------------------------

df <- read.Alteryx("#1", mode="data.frame")
sidf <- subset(df, select=c(Shop, ItemId))
ShopItemId <- apply(sidf, 1, paste, collapse = "_")
df <- cbind(df, ShopItemId)
df <- df[ , colnames(df)!="Shop"]
df <- df[ , colnames(df)!="ItemId"]
df <- reshape(df, timevar="ShopItemId", idvar="DateId", direction="wide")
write.Alteryx(df, 1)

--------------------------------------------------------------------------------------

上から説明します。

--------------------------------------------------------------------------------------


df <- read.Alteryx("#1", mode="data.frame")

Alteryxのワークフローからテーブルをデータフレームとして読み込みます。勿論、Text Inputの他、Input DataもDynamic Inputも使えます。




sidf <- subset(df, select=c(Shop, ItemId))
ShopItemId <- apply(sidf, 1, paste, collapse = "_")
df <- cbind(df, ShopItemId)

項目Shop, ItemIdのみのテーブルを作り、applyで行毎に文字列を結合、キー値として最初のテーブルに追加します。




df <- df[ , colnames(df)!="Shop"]
df <- df[ , colnames(df)!="ItemId"]

項目Shop, ItemIdが残っていると、横展開で出てきてしまうので、列削除します。一行で複数列を削除することもできるようですが、暗号みたいな文字列に蕁麻疹が出る人なので…。




df <- reshape(df, timevar="ShopItemId", idvar="DateId", direction="wide")

reshape関数で変換したデータフレームを、元のデータフレームに代入します。別のデータフレームにして、途中経過を出力してもいいでしょう。timevarは横に展開するキーとなる項目、idvarはグルーピングする項目で、その他の項目は全て名前が自動付与されて(例→KPI_1.Sendai-2、間の「.」ドットは変更できないようです)、横に並びます。directionは横展開がwide、縦展開はlongを指定します。




write.Alteryx(df, 1)

データフレームdfを、R Toolの出力足1番に出力します。R Toolには5つ足が付いていますので、処理途中を2番など、デバッグにも使えます。基本的に1入力1出力で使うのが分かりやすいと思います。