Win ssh サーバ設定 @PowerShell

2024/03/28 00:09 OS別::Windowsその他::技術情報
Windows のバージョンごとに設定手順が変更されることがあるため、汎用的に利用できる PowerShell での設定方法を記載します。


確認環境

実際に動作を確認した環境は、以下の通りです。
Version 情報(23H2)
Version 情報(23H2)

ただし、想定する対象としては、Windows Server 2022, Windows Server 2019, Windows 11, Windows 10 (Microsoft 公式情報より)になります。

PowerShell 起動(管理者モード)

システムへの変更を行うため、管理者モードで PowerShell を起動します。

管理者モードで起動

Win キーを押し、そのまま power shell と入力します。

検索結果に Windows PowerShell が表示されたら、「管理者として実行する」を選択します。
PowerShell 起動
PowerShell 起動

このとき、ユーザアカウント制御が表示された場合は「はい」を押して続けます。

起動確認

タイトルバーに「管理者:Windows PowerShell」が表示された画面が起動することを確認します。
PowerShell 管理者モード
PowerShell 管理者モード

sshd インストール

対象バージョン名称確認

インストールする PowerShell のバージョン情報を表示します。
PS C:\WINDOWS\system32> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
OpenSSH バージョン確認
OpenSSH バージョン確認

画像では見辛いですが、以下のように表示されることを確認します。
PS C:\WINDOWS\system32> Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'


Name  : OpenSSH.Client~~~~0.0.1.0
State : Installed

Name  : OpenSSH.Server~~~~0.0.1.0
State : Installed



PS C:\WINDOWS\system32>

インストール

次のコマンドを実行します。
PS C:\WINDOWS\system32> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
インストール画面
しばらく、CUI 上にインストール状況が表示されます。
OpenSSH インストール中
OpenSSH インストール中
インストール結果画面
続けて、OpenSSH がインストールされたことを確認します。
PS C:\WINDOWS\system32> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
OpenSSH インストール結果
OpenSSH インストール結果
画面上に、以下のように Online: True が表示されます。
PS C:\WINDOWS\system32> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0


Path          :
Online        : True
RestartNeeded : False



PS C:\WINDOWS\system32>

サーバ設定

サービス起動

sshd サービスを起動します。
PS C:\WINDOWS\system32> Start-Service sshd

サービス自動起動

sshd サービスを、自動起動するよう設定変更します。
PS C:\WINDOWS\system32> Set-Service -Name sshd -StartupType 'Automatic'

余談(スタートアップの種類を変更)

ちなみに、以下のコマンドでサービスの停止やスタートアップの種類を変更できます。
サービス停止
PS C:\WINDOWS\system32> Stop-Service -Name sshd
※ sshd は、中断と再開をサポートしていないため、中断できないようです。
スタートアップの種類
「自動」の場合
PS C:\WINDOWS\system32> Set-Service -Name sshd -StartupType Automatic
「手動」の場合
PS C:\WINDOWS\system32> Set-Service -Name sshd -StartupType Manual
「無効」の場合
PS C:\WINDOWS\system32> Set-Service -Name sshd -StartupType Disabled

Firewall

必要に応じて、ファイアウォール設定を行います。
# Confirm the Firewall rule is configured. It should be created automatically by setup. Run the following to verify
if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
    Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
    New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
} else {
    Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
}

鍵の生成

鍵を生成するには、以下のコマンドを実行します。
ssh-keygen -t ed25519
※ 記事の作成時点では、rsa より ed25519 が推奨されています。適切に指定してください。

実行例
PS C:\WINDOWS\system32> ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (C:\Users\test/.ssh/id_ed25519):
Created directory 'C:\\Users\\test/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\test/.ssh/id_ed25519
Your public key has been saved in C:\Users\test/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:vNdhiYXL3ci1SDWYKf+pv2SOLiXSdDBWWFCKsNJzlk0 test@Win100
The key's randomart image is:
+--[ED25519 256]--+
|      .   E*++o  |
|     . o =*o+. . |
|    . + =.+=o .  |
|     . = ..Bo* . |
|        So+.O.o. |
|        ..oo..o  |
|        ...o..o  |
|         .. .=   |
|           oo.+. |
+----[SHA256]-----+
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> dir C:\Users\test\.ssh\


    ディレクトリ: C:\Users\test\.ssh


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/03/27     23:29            399 id_ed25519
-a----        2024/03/27     23:29             95 id_ed25519.pub


PS C:\WINDOWS\system32>
公開鍵 id_ed25519.pub を、リモートアクセスしたい相手側サーバに適切に設定すると、鍵を利用した ssh 接続が可能になります。

公開鍵の格納先

Windows でも Linux でも、id_ed25519.pub の内容を、そのまま全部、1行で authorized_keys ファイルに記載してください。
公開鍵は「公開してしまう鍵」なので、ファイルを開いてコピペするなど、多少雑に扱っても問題ありません。
Windows ssh サーバ
sshd サービスが動いている Windows サーバの、ユーザプロファイル直下に .ssh フォルダを作成して配置します。

例として、test ユーザのユーザプロファイル情報を表示します。
PS C:\WINDOWS\system32> echo $env:USERPROFILE\.ssh\
C:\Users\test\.ssh\
PS C:\WINDOWS\system32> dir C:\Users\test\.ssh\authorized_keys


    ディレクトリ: C:\Users\test\.ssh


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/03/27     23:29             95 authorized_keys


PS C:\WINDOWS\system32>
Linux サーバ
ユーザのホームディレクトリ直下に .ssh ディレクトリを作成して配置します。
例として、test ユーザのホームディレクトリ情報を表示します。
$ test@rasp080:~/.ssh $ ls -ld ~/.ssh
drwx------ 2 test test 4096  3月 27 23:41 /home/test/.ssh
test@raspberry:~/.ssh $
test@raspberry:~/.ssh $ ls -l ~/.ssh/authorized_keys
-rw------- 1 test test 0  3月 27 23:41 /home/test/.ssh/authorized_keys
※ Linux サーバは、特に権限情報が重要視されます。 .ssh ディレクトリは 700 かつ authorized_keys は 600 にしてください。

適切に設定すると、以下のように ssh 接続可能です。
PowerShell 画面から Linux へ ssh 実行
PowerShell 画面から Linux へ ssh 実行

sshd アンインストール

インストールした sshd をアンインストールするには、次のコマンドで実行できます。
Remove-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

参考

Win11 SSH サーバ設定 @23H2

2024/03/26 08:19 OS別::Windowsその他::技術情報
Windows 10 での SSH サーバ設定で一度リライトしたのですが、そのバージョンからさらにアップデートすると手順が変更になっていたので、リライトしました。

GUI での説明記事を作成するには、限界を感じてしまいますね。

さて、ssh サーバの説明や接続方法等は別な記事を参照いただくとして、対象のバージョン、手順、起動方法、ログイン確認までを説明範囲とします。

Windows 対象バージョン

設定 選択

スタートメニューを右クリックして「システム」を選択します。
システム
システム

バージョン情報 選択

バージョン情報が表示されます。

表示されているバージョンが今回の記事で利用しているバージョンです。
この場合、Windows11 Pro のバージョンが 23H2 で、OS ビルドが 22631.3296 になります。
バージョン情報
バージョン情報

sshd インストール手順

システム

左ペインから「システム」を選択します。

システム画面が更新されたら、オプション機能を選択します。
「システム」画面
「システム」画面

システム> オプション機能

「オプション機能を追加する」の「機能を表示」を選択します。
「システム > オプション機能」画面
機能を表示

オプション機能を追加する

OpenSSH サーバーを選択して、チェックがついたら「次へ」を選択します。
「オプション機能を追加する」画面
オプション機能を追加する

インストール

追加する機能を確認されるので、OpenSSH サーバーが表示されていることを確認して「インストール」を選択します。
「インストール対象の確認画面
インストール対象確認
OpenSSH サーバーがインストールされるのを待ちます。
インストール中の画面
インストール 待機
インストールされると、インストール済みと表示されます。
もう一度アプリのオプション機能画面を表示して、OpenSSH サーバーがあればインストールされています。
インストールされている機能
インストール確認

sshd 利用

サービス起動手順

OpenSSH サーバーは、サービスとして起動しないと SSH ログインできません。

サービス起動するために、まずスタートメニューを右クリックして「コンピューターの管理」を起動します。

win
コンピューターの管理選択画面
ここから「サービスとアプリケーション」→「サービス」へ移動すると「OpenSSH SSH Server」があります。

サービス選択
サービス選択画面

「OpenSSH SSH Server」をダブルクリックして「OpenSSH Server のプロパティ」を開きます。

まず、サービスが停止していることが分かります。

OpenSSH SSH Server のプロパティ
OpenSSH SSH Server のプロパティ画面
「開始」ボタンをクリックして、サービスを実行しておきます*1

また、Windows を起動したらサービスも起動させたい場合は、「全般」タブの「スタートアップの種類」を「手動」から「自動」に変更して「OK」ボタンをクリックします。

スタートアップの種類選択
スタートアップの種類選択画面

sshd_conf

OpenSSH サーバーとして設定は、以下フォルダの設定ファイルで行います。
%SystemRoot%\System32\OpenSSH
管理者権限でテキストエディタを起動したら sshd_config_default を開いて sshd_config という名前で別名保存します。

コマンドプロンプトを管理者権限で起動すると、簡単にコピーできます。

Win キーを押して cmd を入力し、Ctrl + Shift キーを押しつつ Enter すると、管理者権限でコマンドプロンプトを起動できます。
C:\WINDOWS\system32>cd OpenSSH
C:\Windows\System32\OpenSSH>dir
C:\Windows\System32\OpenSSH>copy sshd_config_default sshd_config
C:\Windows\System32\OpenSSH>notepad sshd_config
C:\Windows\System32\OpenSSH>

アンチウィルスソフト

Norton Internet Security をインストールしていますが、LAN 内の Linux サーバからアクセスする場合、特に何の設定も必要なくアクセスできました。

アクセスできない場合、インストールされているアンチウィルスソフトの設定を確認してみてください。

*1 : プロパティ画面ではなく、サービス選択で「OpenSSH SSH Server」を右クリックして「開始」を選択しても SSH 接続を受け付けるようになります。

ユーザ作成

xxx@hotmail.co.jp のアカウント(いわゆる Microsoft アカウント)では、ssh によるリモートアクセスができません。
ということで、ローカルアカウントの作成が必要です。

ユーザ作成には、システム管理権限のあるユーザが必要です。

Tera Term でアクセスする場合、通常の UNIX / Linux へアクセスするのと手順は同じです。

そのまま localhost:22 へ ssh アクセスすると、通常のログイン処理でアクセス可能です。

Windows11 端末に、管理権限のあるユーザでログインしていることをユーザー作成の前提条件とします。

ローカルアカウント追加

ユーザー作成ですが、開いているタスクマネージャーのメニューからユーザーを選択して、そのままユーザーアカウントの管理をクリックします。
ユーザアカウントの管理

ユーザーアカウントの画面がでたら、別のアカウントの管理を選択します。
別のアカウントの管理

「PC 設定で新しいユーザーを追加」をクリックします。
PC 設定で新しいユーザーを追加

「アカウントの追加」をクリックします。
アカウントの追加

Microsoft アカウント画面が表示されたら「このユーザーのサインイン情報がありません」を選択します。
Microsoft アカウント 1

続いて「Microsoft アカウントを持たないユーザーを追加する」を選択します。
Microsoft アカウント 2

やっとローカルアカウントを作成する画面が表示されるので、必要事項を入力します。
Microsoft アカウント 3

ここでは、サンプルとして test ユーザーを作成します。
まず、ユーザー名とパスワードを入力します。
Microsoft アカウント 情報入力 1

下へスクロールして、パスワードを忘れた場合の質問に回答します。
ここでは、すぐに削除するので x で埋めていますが、忘れた際に必要になります。
Microsoft アカウント 情報入力 2

すべて入力して「次へ」をクリックすると、以下の「ほかのユーザー」画面に戻りますので、ユーザーが作られたことを確認します。

ここで作られたユーザーの「アカウントの種類」は「標準ユーザー」です。
アカウント確認画面

リモートアクセスするユーザーに管理者権限が必要な場合は、別途管理者権限を付与してください。

レビュービルド26052以降であれば、Linux の sudo コマンドと同じコマンドが実装されるとのこと。

Windows11 へ SSH アクセス

Tera Term で Windows 11 に対してアクセスし、先ほど設定したユーザー名およびパスワードを入力すると、Windows 11 のターミナル(ここではデフォルトの cmd.exe を利用)にログインできます。
Tera Term から SSH ログイン
ここでは Raspberry Pi からアクセスしていますが、ローカル (localhost)でもアクセス可能です。


SSHd が動作していれば、Windows 端末の「標準ユーザー」で Tera Term から SSH アクセスが可能です。

Windows SSH サーバ設定

2024/03/28 00:08 OS別::Windowsその他::技術情報
Windows 11 での SSH サーバ設定ですが、Windows 10 と合わせて、ビルド番号ごとにまとめておきます。

Windows 10

以下、Windows 10 での sshd サーバ設定に関する設定手順になります。

Ver.1803

OS ビルド 17134.829 での設定方法です。

Windows 11

以下、Windows 11 での sshd サーバ設定に関する設定手順になります。

Ver.22H2

OS ビルド 22621.1848 での設定方法です。

Ver.23H2

OS ビルド 22631.3296 での設定方法です。

PowerShell

管理者モード

PowerShell を利用した設定方法です。軽く、公開鍵の設定方法も記載しています。

Win11 SSH サーバ設定 @22H2

2024/03/23 09:12 OS別::Windowsその他::技術情報
Windows 10 での SSH サーバ設定は、かなりの方に参照いただいているようで、感謝いたします。
基本的には Windows 11 でも同じような設定を行うのですが、手順としては微妙に変わるので、リライトしました。

ssh サーバの説明や接続方法等は Win10 SSH サーバ設定 を参照いただくとして、対象のバージョン、手順、起動方法までを説明範囲とします。

Windows 対象バージョン

設定 選択

スタートメニューを右クリックして「設定」を選択します。
設定
スタートメニューから設定選択

バージョン情報 選択

表示された設定画面をスクロールして、バージョン情報を選択します。
win11 バージョン情報
バージョン情報 選択
バージョン情報が表示されます。

表示されているバージョンが今回の記事で利用しているバージョンです。
この場合、Windows11 Pro のバージョンが 22H2 で、OS ビルドが 22621.1848 になります。
win11 Version
Windows バージョン情報
続けて ssh をインストールするため、この画面のメニューからアプリを選択します。

sshd インストール手順

アプリ

アプリ画面に移動したら、オプション機能を選択します。
オプション機能
オプション機能

アプリ > オプション機能

「オプション機能を追加する」の「機能を表示」を選択します。
機能を表示
機能を表示

オプション機能を追加する

OpenSSH サーバーを選択して、チェックがついたら「次へ」を選択します。
オプション機能を追加する
オプション機能を追加する

インストール

追加する機能を確認されるので、OpenSSH サーバーが表示されていることを確認して「インストール」を選択します。
インストール対象確認
インストール対象確認
OpenSSH サーバーがインストールされるのを待ちます。
win11 OpenSSH サーバー インストール待機
インストール 待機
インストールされると、インストール済みと表示されます。
もしくは、もう一度アプリのオプション機能画面を表示して、OpenSSH サーバーがあればインストールされています。
インストール済み
インストール確認
インストール確認

sshd 利用

サービス起動手順

OpenSSH サーバーは、サービスとして起動しないと SSH ログインできません。

サービス起動するために、まずスタートメニューを右クリックして「コンピューターの管理」を起動します。

win
コンピューターの管理選択画面
ここから「サービスとアプリケーション」→「サービス」へ移動すると「OpenSSH SSH Server」があります。

サービス選択
サービス選択画面

「OpenSSH SSH Server」をダブルクリックして「OpenSSH Server のプロパティ」を開きます。

まず、サービスが停止していることが分かります。

OpenSSH SSH Server のプロパティ
OpenSSH SSH Server のプロパティ画面
「開始」ボタンをクリックして、サービスを実行しておきます*1

また、Windows を起動したらサービスも起動させたい場合は、「全般」タブの「スタートアップの種類」を「手動」から「自動」に変更して「OK」ボタンをクリックします。

スタートアップの種類選択
スタートアップの種類選択画面

ユーザ

普段、私は Windows に xxx@hotmail.co.jp のアカウント(いわゆる Microsoft アカウント)を利用してログインしています。
このアカウントでは、ssh によるリモートアクセスができませんでした。

ということで、ローカルアカウントの作成が必要です。

スタートメニューを右クリックしたときにでる「コンピューターの管理」は、すでに起動しているものと思います。
「コンピューターの管理(ローカル)」→「システムツール」→「ローカル ユーザーとグループ」→「ユーザー」と開いていくと、sshd ユーザが自動で作られているのが確認できました。

この「ユーザー」か、「ユーザー」を選択して出てきた右ペインを右クリックすると「新しいユーザー」が出てくるので、これをクリックして ssh 接続するための新しいユーザーを追加します。

RDP だと、Administrators グループまたはリモートデスクトップユーザーグループに追加しなければなりません。
ここで作成したアカウントは Administrators グループに入れてしまいましたが、OpenSSH でのアクセスの場合はユーザー登録だけで良いようです(未確認)。

sshd_conf

OpenSSH サーバーとして設定は、以下フォルダの設定ファイルで行います。
%SystemRoot%\System32\OpenSSH
管理者権限でテキストエディタを起動したら sshd_config_default を開いて sshd_config という名前で別名保存します。

コマンドプロンプトを管理者権限で起動すると、簡単にコピーできます。

Win キーを押して cmd を入力し、Ctrl + Shift キーを押しつつ Enter すると、管理者権限でコマンドプロンプトを起動できます。
C:\WINDOWS\system32>cd OpenSSH
C:\Windows\System32\OpenSSH>dir
C:\Windows\System32\OpenSSH>copy sshd_config_default sshd_config
C:\Windows\System32\OpenSSH>notepad sshd_config
C:\Windows\System32\OpenSSH>

アンチウィルスソフト

Norton Internet Security をインストールしていますが、LAN 内の Linux サーバからアクセスする場合、特に何の設定も必要なくアクセスできました。

アクセスできない場合、インストールされているアンチウィルスソフトの設定を確認してみてください。

*1 : プロパティ画面ではなく、サービス選択で「OpenSSH SSH Server」を右クリックして「開始」を選択しても SSH 接続を受け付けるようになります。

Windows 11 への SSH 接続

Tera Term でアクセスする場合、通常の UNIX / Linux へアクセスするのと手順は同じです。

そのまま localhost:22 へ ssh アクセスすると、通常のログイン処理でアクセス可能です。

詳細については、Win10 SSH サーバ設定 の SSH 接続方法を参照してみてください

以降、2024.3.2 追記。

質問があり、現時点のバージョンでローカルアカウントを作って、Tera Term でアクセスできることを確認しましたので、簡単に追記します。

[追記] Tera Term ログイン

Windows11 端末に、管理権限のあるユーザでログインしていることをユーザー作成の前提条件とします。

バージョン情報

記事に投稿当時より Windows のバージョンが上がっているので、現時点のバージョン情報を記載します。
Win11 Version

sshd サービス確認

Ctrl + Shift + Esc 等でタスクマネージャーを起動し、サービスを選択します。
sshd サービス起動
ここで、状態が「停止」であれば、右クリックして開始をクリックし、実行中にさせます。

上記画像の通り、sshd の「状態」欄が「実行中」になっていれば大丈夫です。

ローカルアカウント追加

ユーザー作成ですが、開いているタスクマネージャーのメニューからユーザーを選択して、そのままユーザーアカウントの管理をクリックします。
ユーザアカウントの管理

ユーザーアカウントの画面がでたら、別のアカウントの管理を選択します。
別のアカウントの管理

「PC 設定で新しいユーザーを追加」をクリックします。
PC 設定で新しいユーザーを追加

「アカウントの追加」をクリックします。
アカウントの追加

Microsoft アカウント画面が表示されたら「このユーザーのサインイン情報がありません」を選択します。
Microsoft アカウント 1

続いて「Microsoft アカウントを持たないユーザーを追加する」を選択します。
Microsoft アカウント 2

やっとローカルアカウントを作成する画面が表示されるので、必要事項を入力します。
Microsoft アカウント 3

ここでは、サンプルとして test ユーザーを作成します。
まず、ユーザー名とパスワードを入力します。
Microsoft アカウント 情報入力 1

下へスクロールして、パスワードを忘れた場合の質問に回答します。
ここでは、すぐに削除するので x で埋めていますが、忘れた際に必要になります。
Microsoft アカウント 情報入力 2

すべて入力して「次へ」をクリックすると、以下の「ほかのユーザー」画面に戻りますので、ユーザーが作られたことを確認します。

ここで作られたユーザーの「アカウントの種類」は「標準ユーザー」です。
アカウント確認画面

リモートアクセスするユーザーに管理者権限が必要な場合は、別途管理者権限を付与してください。

レビュービルド26052以降であれば、Linux の sudo コマンドと同じコマンドが実装されるとのこと。

Windows11 へ SSH アクセス

Tera Term で Windows 11 に対してアクセスし、先ほど設定したユーザー名およびパスワードを入力すると、Windows 11 のターミナル(ここではデフォルトの cmd.exe を利用)にログインできます。
Tera Term から SSH ログイン
ここでは Raspberry Pi からアクセスしていますが、ローカル (localhost)でもアクセス可能です。


流れを見てもらえれば分かる通り、SSHd が動作していれば、Windows 端末の「標準ユーザー」で Tera Term から SSH アクセスが可能です。

祝日を返すマクロ [Excel VBA]

2024/03/26 05:56 OS別::Windowsその他::技術情報
Excel VBA で、毎年祝祭日リストを更新しなくても祝日を自動計算して返すマクロができないか見ていたら、なんとできそうでした。

使うためには、fnWeekday 関数(Public 関数)を Excel のセルに記述して利用してください。
少なくとも、2023年~2025年は問題なさそうです。
(2023.6.25 2025年の「敬老の日」が祝日にならない問題を修正)
(2024.3.2 Date 関数の戻り値が日付型と判定できない問題を修正)

最終的に挙動を確認した Excel バージョンは、次の通りです。
Microsoft® Excel® for Microsoft 365 MSO (バージョン 2401 ビルド 16.0.17231.20236) 64 ビット

仕様

モジュール

モジュール内の関数を Excel のセルで利用します。
主に利用する関数は fnWeekday です。

セルには =fnWeekday(シリアル値) を指定することで戻り値を得ることができます。

fnWeekday 実行サンプル
fnWeekday 実行サンプル

また、=fnWeekday(シリアル値, 1) のように第2引数に 1 を指定すると、平日と休日、祝日の名称のいずれかを得ることができます。
これが 2 の場合は「祝日の趣旨」(画像における D 列)を得ます。

fnWeekday オプションを指定時の実行サンプル
fnWeekday オプションを指定時の実行サンプル

出力利用例
セル内の記述例出力例備考
=fnWeekday(DATE(2024,5,5))8祝日を示す 8 を表示する
=fnWeekday(DATE(2024,5,5),1)こどもの日平日/休日/(祝日の名称)の、いずれかを表示する
=fnWeekday(DATE(2024,5,5),2)こどもの人格を重んじ、こどもの幸福をはかるとともに、母に感謝する。祝日の趣旨を表示する
fnWeekday 以外の関数は、内部で細かい計算をするために使われます。
(もちろん、セル内で利用することも可能です)

戻り値

戻り値は、第2引数の指定で変化します。
上述したように、デフォルトで weekday 関数とほぼ同じ*1ですが、追加で 8=祝日としています。

以下、第2引数を明記した場合の挙動を記載します。
0の場合:数値(デフォルト)
第2引数に 0 を指定した(もしくは指定しない)場合に出力される番号です。
デフォルト
番号内部変数意味備考
1vbSunday日曜日
2vbMonday月曜日
3vbTuesday火曜日
4vbWednesday水曜日
5vbThursday木曜日
6vbFriday金曜日
7vbSaturday土曜日
8-祝日
1 の場合:名称
第2引数に 1 を指定した場合に出力される文字列です。
名称を返す
文字列意味備考
休日土日どちらか
平日土日祝以外の平日(実際は月~金曜日)
(各祝日名)祝日
祝日の名称は、国民の祝日に関する法律に準拠しています。
2 の場合:趣旨
第2引数に 2 を指定した場合に出力される文字列です。
趣旨を返す
趣旨意味備考
(Nothing)平日/休日であり、祝日ではない日
(各祝日の趣旨)法律などで定義される趣旨
(Nothing) については、表示しないように(Null 表示に)するかもしれません。

*1 : weekday 関数のデフォルトの戻り値は 1=日, 2=月, 3=火, 4=水, 5=木, 6=金, 7=土になっています。

関数

作成したモジュールは、つぎの五つの関数から成り立っています。

fnWeekday(Serial, [Switch])

このモジュールの本丸で、公式の weekday 関数のように使います。
戻り値として曜日(vbMonday から vbSaturday)だけでなく、追加で Holiday を意味する 8 も返します。

オプションには、シリアル値が必要です。
戻り値の内容を変えるために、Switch 番号も指定可能です。

第2引数を指定した際に、セルに表示される内容は、次の通りです。
Switch意味備考
0曜日と祝日を意味する 1~8 の数字を返すSwitch を省略した場合のデフォルト
1平日/休日/祝日の名称を返す
2祝日の趣旨を返す

fnDate(Year, Month, Day)

Excel 関数 date コマンドを模したものです。
オプションには、年・月・日の、三つが必要です。

Excel VBA の場合、DateValue コマンドを使えばいいのですが、年月日を文字列で指定しなければならないため、コードがかなり読みにくくなっていました。
可読性を目的に関数化しています。

fnHappyMonday(Year, Month, Weeks)

ハッピーマンデー制度でシリアル値を取得するのに必要な、x年x月の第x月曜日、という指定でシリアル値を取得するための関数です。
オプションには、年・月・第x週の、三つが必要です。

考え方としては、月の1日が何曜日なのかを見て、そこから月曜日が何日なのかを割り出します。
あとは、7日に第x週のx-1 を掛けたものを足してあげれば、シリアル値を取得できます。

fnVernalEquinox(Year)

春分の日を割り出し、シリアル値を取得するための関数です。
オプションには、年の指定が必要です。

1行しかない、かなり短いコードですが関数化しています。
計算で出力した日付ではない場合、ここで出力情報を調整する予定です。

fnAutumnalEquinox(Year)

秋分の日を割り出し、シリアル値を取得するための関数です。
オプションには、年の指定が必要です。

1行しかない、かなり短いコードですが関数化しています。
計算で出力した日付ではない場合、ここで出力情報を調整する予定です。

ソースコード

Option Explicit

Public Function fnWeekday(Serial As Date, Optional Switch As Byte = 0)
' #########################################################################
' #
' # 呼び出されると、引数の Serial から曜日/祝日情報を返すマクロ
' # デフォルトの戻り値は、以下の通り
' #
' # 戻り値の定義
' #  0 = 平日(月曜~金曜)
' #  1 = 日曜日(vbSunday)
' #  2 = 曜日月(vbMonday)
' #  3 = 火曜日(vbTuesday)
' #  4 = 水曜日(vbWednesday)
' #  5 = 木曜日(vbThursday)
' #  6 = 金曜日(vbFriday)
' #  7 = 土曜日(vbSaturday)
' #  8 = 祝日
' #
' #########################################################################

' ### 変数定義 #########################

Dim DEFpDayName     As String
Dim DEFpDayMeaning  As String
Dim pDayName        As String
Dim pDayMeaning     As String
Dim pRV             As Byte
Dim pYYYY           As Integer
Dim fSubstitute     As Boolean

' ### 変数設定 #########################

DEFpDayName = "平日"
DEFpDayMeaning = "(Nothing)"

pDayName = DEFpDayName
pDayMeaning = DEFpDayMeaning

pYYYY = Year(Serial)

' ### メイン処理 #######################

' serial に指定された年月日と、該当する年の祝日に相当するシリアル値を比較する。
' 該当の祝日であれば、第2引数通りに変数を設定する。
' もし該当の祝日名があれば、戻り値 8 を指定する。

Select Case Serial
    ' 日付が固定されているもの
    Case fnDate(pYYYY, 1, 1)
        pDayName = "元旦"
        pDayMeaning = "年のはじめを祝う。"
    Case fnDate(pYYYY, 1, 15)
        If pYYYY <= 1999 Then
            pDayName = "成人の日"
            pDayMeaning = "おとなになったことを自覚し、みずから生き抜こうとする青年を祝い、励ます。"
        End If
    Case fnDate(pYYYY, 2, 11)
        pDayName = "建国記念の日"
        pDayMeaning = "建国をしのび、国を愛する心を養う。"
    Case fnDate(pYYYY, 2, 23)
        If 2019 < pYYYY Then
            pDayName = "天皇誕生日"
            pDayMeaning = "天皇の誕生日を祝う。"
        End If
    Case fnDate(pYYYY, 4, 29)
        If 2007 <= pYYYY Then
            pDayName = "昭和の日"
            pDayMeaning = "激動の日々を経て、復興を遂げた昭和の時代を顧み、国の将来に思いをいたす。"
        ElseIf 1989 <= pYYYY Then
            pDayName = "みどりの日"
            pDayMeaning = "自然の恩恵に感謝する"
        ElseIf 1948 <= pYYYY Then
            pDayName = "天皇誕生日"
            pDayMeaning = "天皇の誕生を祝う(昭和天皇)"
        ElseIf 1927 <= pYYYY Then
            pDayName = "天長節"
            pDayMeaning = "天地が永久であるように天皇の治世も続くように"
        End If
    Case fnDate(pYYYY, 5, 3)
        pDayName = "憲法記念日"
        pDayMeaning = "日本国憲法の施行を記念し、国の成長を期する。"
    Case fnDate(pYYYY, 5, 4)
        If 2007 <= pYYYY Then
            pDayName = "みどりの日"
            pDayMeaning = "自然に親しむとともにその恩恵に感謝し、豊かな心をはぐくむ。"
        End If
    Case fnDate(pYYYY, 5, 5)
        pDayName = "こどもの日"
        pDayMeaning = "こどもの人格を重んじ、こどもの幸福をはかるとともに、母に感謝する。"
    Case fnDate(pYYYY, 7, 20)
        If pYYYY <= 2002 Then
            pDayName = "海の日"
            pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。"
        End If
    Case fnDate(pYYYY, 8, 11)
        ' 2014年制定、2016年より施工
        If 2016 <= pYYYY Then
            pDayName = "山の日"
            pDayMeaning = "山に親しむ機会を得て、山の恩恵に感謝する。"
        End If
    Case fnDate(pYYYY, 9, 15)
        If pYYYY <= 2002 Then
            pDayName = "敬老の日"
            pDayMeaning = "多年にわたり社会につくしてきた老人を敬愛し、長寿を祝う。"
        End If
    Case fnDate(pYYYY, 11, 3)
        pDayName = "文化の日"
        pDayMeaning = "自由と平和を愛し、文化をすすめる。"
    Case fnDate(pYYYY, 11, 23)
        pDayName = "勤労感謝の日"
        pDayMeaning = "勤労をたっとび、生産を祝い、国民たがいに感謝しあう。"
    Case fnDate(pYYYY, 12, 23)
        If pYYYY < 2019 Then
            ' 以降、上皇陛下
            pDayName = "天皇誕生日"
            pDayMeaning = "天皇の誕生日を祝う。"
        End If
End Select

Select Case Serial
    ' ハッピーマンデー
    Case fnHappyMonday(pYYYY, 1, 2)
        ' 2000 年より適用
        If 2000 <= pYYYY Then
            pDayName = "成人の日"
            pDayMeaning = "おとなになったことを自覚し、みずから生き抜こうとする青年を祝いはげます。"
        End If
    Case fnHappyMonday(pYYYY, 7, 3)
        If 2003 <= pYYYY Then
            ' 2003 年より適用
            pDayName = "海の日"
            pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。"
        End If
    Case fnHappyMonday(pYYYY, 9, 3)
        If 2003 <= pYYYY Then
            pDayName = "敬老の日"
            pDayMeaning = "多年にわたり社会につくしてきた老人を敬愛し、長寿を祝う。"
        End If
    Case fnHappyMonday(pYYYY, 10, 2)
        ' 2000 年より適用。2020 年より名称変更
        If 2020 <= pYYYY Then
            pDayName = "スポーツの日"
            pDayMeaning = "スポーツを楽しみ、他者を尊重する精神を培うとともに、健康で活力ある社会の実現を願う。"
        ElseIf 2000 <= pYYYY Then
            pDayName = "体育の日"
            pDayMeaning = "スポーツにしたしみ、健康な心身をつちかう日"
        End If

    ' 春分/秋分の日
    Case fnVernalEquinox(pYYYY)
        pDayName = "春分の日"
        pDayMeaning = "自然をたたえ、生物をいつくしむ。"
    Case fnAutumnalEquinox(pYYYY)
        pDayName = "秋分の日"
        pDayMeaning = "祖先をうやまい、なくなった人々をしのぶ。"
End Select

' 天皇の即位の日及び即位礼正殿の儀の行われる日を休日とする法律
Select Case Serial
    Case fnDate(2019, 5, 1)
        pDayName = "天皇の即位の日"
    Case fnDate(2019, 5, 2)
        pDayName = "国民の休日"
    Case fnDate(2019, 10, 22)
        pDayName = "即位礼正殿の儀の行われる日"
End Select

' 振替休日
Select Case Serial
    Case fnDate(pYYYY, 1, 1) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnDate(pYYYY, 2, 11) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnDate(pYYYY, 2, 23) + 1
        If 2019 < pYYYY Then
            If Weekday(Serial) = vbMonday Then fSubstitute = True
        End If
    Case fnDate(pYYYY, 4, 29) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnDate(pYYYY, 5, 5) + 1
        ' 5月5日が日曜~火曜日だったら、5/6 が振替休日
        If vbSunday <= Weekday(fnDate(pYYYY, 5, 5)) And Weekday(fnDate(pYYYY, 5, 5)) <= vbTuesday Then
            fSubstitute = True
        End If
    Case fnDate(pYYYY, 8, 11) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnDate(pYYYY, 11, 3) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnDate(pYYYY, 11, 23) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnDate(pYYYY, 12, 23) + 1
        If pYYYY < 2019 Then
            ' 以降、上皇陛下
            If Weekday(Serial) = vbMonday Then fSubstitute = True
        End If
        
    ' ハッピーマンデー
    Case fnHappyMonday(pYYYY, 1, 2) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnHappyMonday(pYYYY, 7, 3) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnHappyMonday(pYYYY, 9, 3) + 1
        ' シルバーウィーク対応
        ' もし、敬老の日の2日後が秋分の日なら、国民の休日にする。
        If fnHappyMonday(pYYYY, 9, 3) + 2 = fnAutumnalEquinox(pYYYY) Then
            pDayName = "国民の休日"
        ElseIf Weekday(Serial) = vbMonday Then
            fSubstitute = True
        End If
        
    Case fnHappyMonday(pYYYY, 10, 2) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True

    ' 春分/秋分の日
    Case fnVernalEquinox(pYYYY) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    Case fnAutumnalEquinox(pYYYY) + 1
        If Weekday(Serial) = vbMonday Then fSubstitute = True
    'Case DateValue("2020/9/22")
    '    DayName = "秋分の日"

End Select

If fSubstitute = True Then pDayName = "振替休日"

' -----------------------------------------------------------
' 令和 2 年(2020年)及び令和 3 年(2021年)に限り、
' 東京オリンピック・パラリンピック競技大会の開催にあわせ、
' 「海の日」、「スポーツの日」及び「山の日」が移動している。
' -----------------------------------------------------------

' 令和2年 (2020) & 令和3年 (2021)
Select Case Serial
    ' 海の日
    Case fnHappyMonday(2020, 7, 3), fnHappyMonday(2021, 7, 3)
        pDayName = DEFpDayName
        pDayMeaning = DEFpDayMeaning
    Case fnDate(2020, 7, 23)
        pDayName = "海の日"
        pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。"
    Case fnDate(2021, 7, 22)
        pDayName = "海の日"
        pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。"

    ' スポーツの日
    Case fnHappyMonday(2020, 10, 2), fnHappyMonday(2021, 10, 2)
        pDayName = DEFpDayName
        pDayMeaning = DEFpDayMeaning
    Case fnDate(2020, 7, 24)
        pDayName = "スポーツの日"
        pDayMeaning = "スポーツを楽しみ、他者を尊重する精神を培うとともに、健康で活力ある社会の実現を願う。"
    Case fnDate(2021, 7, 23)
        pDayName = "スポーツの日"
        pDayMeaning = "スポーツを楽しみ、他者を尊重する精神を培うとともに、健康で活力ある社会の実現を願う。"

    ' 山の日
    Case fnDate(2020, 8, 11), fnDate(2021, 8, 11)
        pDayName = DEFpDayName
        pDayMeaning = DEFpDayMeaning
    Case fnDate(2020, 8, 10)
        pDayName = "山の日"
        pDayMeaning = "山に親しむ機会を得て、山の恩恵に感謝する。"
    Case fnDate(2021, 8, 8)
        pDayName = "山の日"
        pDayMeaning = "山に親しむ機会を得て、山の恩恵に感謝する。"
End Select

' 祝日値判定
If pDayName = DEFpDayName Then
    ' 平日/休日であれば、戻り値を 1~7 で指定する。
    ' ## 曜日選択 #####
    If IsDate(Serial) Then
        Select Case Weekday(Serial)
            Case vbSunday
                pRV = vbSunday
                pDayName = "休日"
            Case vbMonday
                pRV = vbMonday
            Case vbTuesday
                pRV = vbTuesday
            Case vbWednesday
                pRV = vbWednesday
            Case vbThursday
                pRV = vbThursday
            Case vbFriday
                pRV = vbFriday
            Case vbSaturday
                pRV = vbSaturday
                pDayName = "休日"
        End Select
    Else
        ' IsDate の判定内容にエラーがある場合
        fnWeekday = "祝日値判定エラー"
        Exit Function
    End If
Else
    ' 平日でなければ、戻り値を 8 で指定する。
    pRV = 8
End If

' ### 終了処理 #########################

' オプションの内容で、戻り値を変更する。
Select Case Switch
    Case 0
        fnWeekday = pRV
    Case 1
        fnWeekday = pDayName
    Case 2
        fnWeekday = pDayMeaning
End Select

' ######################################

End Function

Public Function fnDate(Year, Month, Day)
' #########################################################################
' #
' # VBA の date 関数は、Excel sheet の date 関数と異なり、文字列を指定する。
' # この関数は、セルで利用する date 関数と同じ使い勝手を実現するもの。
' #
' #########################################################################

fnDate = DateValue(Year & "/" & Month & "/" & Day)

End Function

Public Function fnHappyMonday(Year, Month, Weeks)
' #########################################################################
' #
' # ハッピーマンデー用のシリアル値を返す。
' # 指定された、Year 年 Month 月の第 Weeks 週の月曜日(シリアル値)を返す。
' #
' # 参考資料
' # http://www.relief.jp/itnote/archives/003241.php
' #########################################################################

Dim pMondayDate     As Byte
Dim pFirstMonDay    As Date

' ## 第1週目の月曜日を求める。

' 先に指定月の1日が何曜日なのかを見て、次の月曜日が何日なのかを指定する。
Select Case Weekday(fnDate(Year, Month, 1))
    Case vbSunday       ' 1
        ' x月1日が日曜日なら、月曜日は翌日の 2 日
        pMondayDate = 2
    Case vbMonday       ' 2
        ' x月1日が月曜日なので、そのまま 1 日
        pMondayDate = 1
    Case vbTuesday      ' 3
        ' x月1日が火曜日なので、月曜日は 6 日後の 7 日
        pMondayDate = 7
    Case vbWednesday    ' 4
        ' x月1日が水曜日なので、月曜日は 5 日後の 6 日
        pMondayDate = 6
    Case vbThursday     ' 5
        pMondayDate = 5
    Case vbFriday       ' 6
        pMondayDate = 4
    Case vbSaturday     ' 7
        pMondayDate = 3
End Select

' 第1週目の月曜日から何週間後なのか、必要な日数を足してシリアル値を返す。
fnHappyMonday = fnDate(Year, Month, pMondayDate) + (7 * (Weeks - 1))

End Function

Public Function fnVernalEquinox(Year)
' #########################################################################
' #
' # 呼び出されると、引数の Year から算出した 春分の日 情報を返すマクロ
' #
' # 参考 URL http://www.wanichan.com/pc/excel/2010/5/page07.html
' #########################################################################
fnVernalEquinox = fnDate(Year, 3, Int(20.8431 + 0.242194 * (Year - 1980) - Int((Year - 1980) / 4)))

End Function

Public Function fnAutumnalEquinox(Year)
' #########################################################################
' #
' # 呼び出されると、引数の Year から算出した 秋分の日 情報を返すマクロ
' #
' # 参考 URL http://www.wanichan.com/pc/excel/2010/5/page07.html
' #########################################################################
fnAutumnalEquinox = fnDate(Year, 9, Int(23.2488 + 0.242194 * (Year - 1980) - Int((Year - 1980) / 4)))

End Function

その他

zip ファイル

コピペより、インポート可能なファイルが良いという方向け。
現在バージョン
過去バージョン

更新履歴

  • 2023.3.5 細かい表現と、マクロの微修正を行った。
  • 2023.6.25 敬老の日に関するご指摘をいただき、ハッピーマンデーの扱いを修正*2 した。
  • 2024.3.2 オプションに Date を指定した場合 0 が返ってくる現象についてご指摘をいただき、IsDate 関数で判断する値を CVDate 関数で日付型へ事前に変換*3するようにした。
  • 2024.3.2 IsDate 関数で判断する Serial について、fnWeekday 関数にオプションとして入力する時点で Date 型であることを強制した。

*2 : シリアル値で祝日を判断するフローで、固定されていた敬老の日(2002年以前)を分岐させたあとにハッピーマンデーの分岐が来ており、ハッピーマンデー対象である敬老の日が分岐済みの扱いになってチェックされない流れになっていた。

*3 : VBA の IsDate 関数が、Date 関数で取得した値そのままだと、数値を日付と判断できない。

参考サイト様