VBA上でPowerShell使ってパスワード作る(2つの結果をつなげて1行にする)

やること

VBA上でPowerShellを実行し、パスワードを生成することを考えます。

パスワードは最初が英字で、数字は最初に来てはいけない。

このとき、PowerShellを2回実行することとし、1回目は英字から1文字抽出するもので、2つめのスクリプトは英数字から抽出したランダムな文字列とします。(パスワード先頭を英字にしたいから)

そしてこれらの2つの結果をVBA上で連結し、パスワードとして使用します。

VBA上では、パスワードを生成するときはFunctionプロシージャを呼び出して生成することとし、呼び出すことでいつでもパスワードを生成することができるようにします。

 

環境

環境は以下となっています。

VBAバージョン Microsoft Visual Basic for Applications 7.1
PowerShellバージョン 5.1.18362.145

 

PowerShellスクリプト

使用するPowerShellスクリプトは下記で、「Get-Random」と「-join」になります。

Get-Random -input ([char[]](65..90 + 97..122))

このスクリプトを解説。

端的に言うと、このスクリプトは、ASCIIコードの65~90(英大文字)と97~122(英小文字)から一文字をランダムに抽出するものとなっています。

説明すると、Get-Random関数は、0 ~ 2,147,483,647の範囲から、ランダムにピックアップして返す関数です。「-input」パラメータを付けると、指定されたものからランダムにピックアップするようにすることができます。

([char[]](65..90 + 97..122))で、[char]65 ~ [char]90、[char]97 ~ [char]122 をくり返して実行します。[char]65はアスキーコード65番の文字を返すので、「A」が返ってくる。次は「B」「C」「D」というように英字のみを対象にして返し、その英字の中からランダムで一文字返すのが上記のスクリプトです。

-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 7 | % {[char]$_})

このスクリプトは、数字(アスキーコード48~57)と英字をGet-Random関数に渡しています。英数字を渡されたGet-Random関数はその中から7個ピックアップし、%  {[char]$_} に渡し文字列化します。そして最後に -join によって7つの英数字が連結されます。

ASCIIコードを下に記載しておきます。

補足:ASCIIコード表(10進数のみ)

Decimal Symbol
0 NUL
1 SOH
2 STX
3 ETX
4 EOT
5 ENQ
6 ACK
7 BEL
8 BS
9 HT
10 LF
11 VT
12 FF
13 CR
14 SO
15 SI
16 DLE
17 DC1
18 DC2
19 DC3
20 DC4
21 NAK
22 SYN
23 ETB
24 CAN
25 EM
26 SUB
27 ESC
28 FS
29 GS
30 RS
31 US
32
33 !
34
35 #
36 $
37 %
38 &
39
40 (
41 )
42 *
43 +
44 ,
45
46 .
47 /
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9
58 :
59 ;
60 <
61 =
62 >
63 ?
64 @
65 A
66 B
67 C
68 D
69 E
70 F
71 G
72 H
73 I
74 J
75 K
76 L
77 M
78 N
79 O
80 P
81 Q
82 R
83 S
84 T
85 U
86 V
87 W
88 X
89 Y
90 Z
91 [
92 \
93 ]
94 ^
95 _
96 `
97 a
98 b
99 c
100 d
101 e
102 f
103 g
104 h
105 i
106 j
107 k
108 l
109 m
110 n
111 o
112 p
113 q
114 r
115 s
116 t
117 u
118 v
119 w
120 x
121 y
122 z
123 {
124 |
125 }
126 ~
127

 

プログラムコード

コードは以下のようになっています。

宣言

Sleep関数を使うので以下の宣言をします。

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

 

呼び出し元Subプロシージャ

String変数を宣言して、そこにパスワード生成プロシージャ(PasswdCreate)で生成したパスワードを格納し、イミディエイトウィンドウに表示するという、単純なものです。

'======================
'MainのSubプロシージャ
'======================
Sub Main()
    Dim Password As String '生成したパスワードを受け取って格納する変数
    
    Password = PasswdCreate 'パスワード生成プロシージャで作成したパスワードを変数に代入
    
    Debug.Print Password 'イミディエイトウィンドウに表示

End Sub

 

呼び出し先Functionプロシージャ

これが主役のプロシージャです。

'====================================
'パスワード生成Functionプロシージャ
'====================================
Function PasswdCreate() As String
    Dim RandomPW As String
    Dim Cmd As String
    Dim Wsh As Object
    Cmd = "Get-Random -input ([char[]](65..90 + 97..122))"
    Set Wsh = CreateObject("Wscript.shell").Exec("powershell -ExecutionPolicy RemoteSigned -Command " & Cmd)
    Do While Wsh.Status = 0
        Sleep 100
    Loop
    
    RandomPW = Wsh.StdOut.ReadAll
    
    Cmd = "-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 7 | % {[char]$_})"
    Set Wsh = CreateObject("Wscript.shell").Exec("powershell -NoLogo -ExecutionPolicy RemoteSigned -Command " & Cmd)
    
    Do While Wsh.Status = 0
        Sleep 100
    Loop
    
    RandomPW = RandomPW & Wsh.StdOut.ReadAll
    RandomPW = Replace(RandomPW, vbCrLf, "")
    Debug.Print RandomPW
    
    PasswdCreate = RandomPW

End Function

パスワードを格納する変数が「RandomPW」です。

PowerShellのコマンドレットを格納する変数が「Cmd」です。

CreateObject関数でWscript.shellをインスタンス化してExecメソッドでCmd変数に格納したPowerShellコマンドレットを実行します。

1回目の実行では前述した「Get-Random -input ([char[]](65..90 + 97..122))」が実行され、RandomPW変数にランダムな英字1文字が格納されます。

2回目の実行では前述した「-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 7 | % {[char]$_})」が実行され、ランダムな英数字7文字がRandomPW変数の末尾につなげて格納されます。

最後に、「Replace(RandomPW, vbCrLf, “”)」で、RandomPW変数に入っている改行を空白に置き換えて一行のパスワードとします

途中に入っているSleep関数で、100ミリ秒待機させているのは、PowerShellが起動して結果を返すまでに少し時間がかかるので、100ミリ秒待機させる処理をDo~Loopで実装し、結果が帰ってきたら処理を続行するようにしています。

 

実行結果

5回実行した結果をキャプチャで掲載いたします。

 

後書き

ランダムパスワードをVBAで生成する記事は散見されましたが、改行が含まれたString値を1行にすることに多少苦戦しました。

パスワードの最初が数字ではダメというようなときに使用できるTipsだったので、備忘録として記載しました。

最後前お読みいただき、ありがとうございました。