今回もWindows ServerベースのNASの話です。NASを小規模なワークグループ環境で運用する場合、NASにローカルユーザーを作成して、ユーザー名/パスワードの認証で共有フォルダへのアクセスを提供することになると思いますが、そのパスワードを誰が、どう管理するのかということで悩んだことはないでしょうか。実際に導入してみないと気が付かない“落とし穴”があったりします(本稿は、とあるオンラインセミナーでも少し触れたものです)。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Windows ServerベースのファイルサーバやNAS(ネットワーク接続型記憶域)専用機をワークグループ環境、つまりActive Directoryドメインに参加しない環境で利用する場合、ファイルサーバやNAS(以下、サーバ)のWindows Serverにローカルユーザーとグループを作成し、共有フォルダへのアクセス許可を設定することになると思います。
共有フォルダにアクセスするユーザーは、共有フォルダに接続する際にファイルサーバやNASに登録されているユーザーのユーザー名/パスワードを入力して認証を受けます。
サーバ側でローカルユーザーを作成するには、一般的に「コンピューターの管理」(Compmgmt.msc)や「ローカルユーザーとグループ」(Lusrmgr.msc)スナップインを使用します(他にも、コマンドラインや「Windows Admin Center」などを使う方法があります)。その際、「パスワードを無期限にする」オプションをチェック(有効化)しないと、既定では最後にパスワードを設定(例えば、ユーザー作成時)してから「42日後」にパスワードの有効期限が切れてしまいます。
パスワードの有効期限は、「ローカルグループポリシーエディター」(Gpedit.msc)スナップインで「ローカルコンピューターポリシー」を開くと、以下の場所に設定されています(Active Directoryの場合はドメインの「Default Domain Policy」)。ユーザーごとに「パスワードを無期限にする」オプションをチェックする代わりに、以下のポリシーを「0日」に設定することで、パスワードの有効期限を無期限にすることができます。
パスワードの有効期限が切れてしまった場合、「ユーザーは次回ログオン時にパスワードの変更が必要」オプションをチェックしたときと同様に、パスワードを変更するまでログオンまたはネットワーク経由で認証をパスすることはできなくなります(画面1)。
ユーザーがサーバのローカルコンソール(サーバに接続されたディスプレイ、キーボード、マウス)に物理的にアクセスできる場合は、「ユーザーは次回ログオン時にパスワードの変更が必要」オプションが有効な場合でも、パスワードの有効期限が切れていても、ローカルログオンしたときにパスワードの変更が可能です。
また、ログオン後は[Ctrl]+[Alt]+[Del]キーで「セキュリティオプション」に切り替え、「パスワードの変更」から自分のパスワードを変更できます。しかし、NAS専用機の場合、通常、ローカルコンソールは接続されていません。
古くからWindows Serverを、それもワークグループ環境で利用してきたサーバ管理者やユーザーであれば、ネットワーク上の別のWindows PCで[Ctrl]+[Alt]+[Del]キーを押し、「パスワードの変更」画面で「サーバ名\ユーザー名」を指定して、古いパスワードと新しいパスワードを入力すれば、有効期限が切れている/切れていないに関係なく、パスワードを変更できることをご存じかもしれません。この後説明することも、既知の情報かもしれません。
しかし、普通にできると思っていたことが実は簡単にはできないと分かると、慌ててしまうと思います。例えば、「Windows Server 2019」ベースのファイルサーバで手元のWindows PCから、サーバのローカルユーザーのパスワードをリモートから変更しようとすると、「アクセスが拒否されました」のメッセージが表示され、失敗するでしょう(画面2)。少なくとも、Windows Server 2019の既定のセキュリティ設定ではそうなります。
「ユーザーは次回ログオン時にパスワードの変更が必要」オプションをチェックして多数のユーザーを準備し、運用を始めようとしたとき、あるいは「42日」というパスワードの有効期限を知らずに運用を始めていた場合、有効期限が切れたところで、ネットワーク経由で変更できず、他に変更する方法が見当たらないことに気が付くことになります。
「リモートデスクトップ接続でできるじゃないか」(リモートデスクトップ接続の場合は[Ctrl]+[Alt]+[End]キー)という声が聞こえてきそうですが、一般ユーザーにリモートデスクトップ接続を許可するには、「リモートデスクトップサービス(RDS)」環境の構築と「RDS CAL(クライアントアクセスライセンス)」が必要です。
ワークグループ環境で可能な限り、RDSはコストをかけたくないという企業や組織には向きません。もし、RDSを利用するにしても、有効期限が切れたパスワードの変更は「ネットワークレベル認証(NLA)」の接続ではできなくなりました(その代わりというわけではありませんが、RDSのRD Webアクセスポータルにパスワードの変更機能があります)。
そもそも、「Windows Server IoT 2019 for Storage」や「Windows Storage Server 2016」のNASを利用している場合は、ライセンス上、RDSを有効化して利用することは許可されていません。ローカルログオンしようにも、NASには常時ディスプレイやマウス、キーボードが接続されているわけではありません。
実は筆者自身、Windows Server 2019の既定のセキュリティ設定ではサーバのローカルユーザーのパスワードをリモートから変更できないことに、つい先日気が付きました。
最初、「アクセス拒否」でパスワード変更が失敗するのは、2016年に提供された「MS16-101」および11月の「MS16-137」のセキュリティ更新の影響と想像しましたが、そうではないようです。確かに「MS16-101」のセキュリティ更新で一時的に失敗するようになったようですが、その後の「MS16-137」のセキュリティ更新で別のアプローチに変更され、既知の問題の多くは解消されたようなのです。
Windows Serverの以前のバージョンはどうなのか、さかのぼって挙動を確認してみました。最初は、前述したセキュリティ更新が原因と考えていたので、セキュリティ更新が提供された時点で既にサポートが終了していた「Windows Server 2003 R2」のサーバと「Windows 8」のクライアントで試してみました。Windows 8からサーバのローカルユーザーのパスワード変更は期待通りにうまく動きました。
「Windows Server 2016」(最新のセキュリティ更新適用済み、以下同)のローカルユーザーのパスワード変更は、Windows Server 2019と同じく「アクセスが拒否されました」で失敗しました。「Windows Server 2012 R2」のローカルユーザーのパスワード変更は、リモートから何の問題もなく変更できました。「Windows Server 2003 R2/2008/2008 R2/2012」のローカルユーザーのパスワード変更は、「アクセスが拒否されました」で失敗しました。いずれも、クライアントは最新バージョンの「Windows 10」で確認しました。
どうやら、Windows Serverのバージョンごとに異なる既定のセキュリティ設定と、クライアントのWindowsバージョンの組み合わせの両方が、リモートからのパスワード変更操作の拒否にさまざまに影響しているようです。「MS16-101」のときのようにセキュリティ更新で一時的に変更できなくなることもありましたが、現在その問題は解消されています。
ユーザーフォーラムやあるメーカーのNAS製品のマニュアルなどを参考に、以下の設定をサーバ側で行い、再起動することで、Windows Server 2016やWindows Server 2019のローカルアカウントの、Windows 8.1/10クライアントからのリモートからのパスワード変更が可能になりました。
ちなみに、Windows Server 2008/2008 R2/2012は、SAMR(Security Account Manager Remote)の設定と再起動だけで可能になりました。なお、ファイアウォールで「ファイルとプリンターの共有」の規則が許可されていることも必要です。ファイルサーバとして利用できているのなら、許可されているはずです。
「ローカルグループポリシーエディター」(Gpedit.msc)や「レジストリエディター」(Regedit.exe)を使用して上記設定を行う代わりに、コマンドプロンプトで以下の3行のコマンドラインを実行して再起動することでも必要な設定を行えます(画面3、画面4)。なお、「ネットワーク アクセス:リモートからアクセスできる名前付きパイプ」に他の値が設定されている場合は、以下のコマンドラインではなく、「ローカルグループポリシーエディター」で「SAMR」を改行で区切って既存のデータに追加してください。
REG ADD HKLM\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters /v NullSessionPipes /t REG_MULTI_SZ /d SAMR /f REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Lsa /v RestrictRemoteSamAuditOnlyMode /t REG_DWORD /d 1 /f shutdown /r /t 0
パスワードの変更元が、Microsoftアカウントでサインインして使用しているWindows 8.1やWindows 10の場合、セキュリティオプションに「パスワードの変更」は表示されません。そこで、ユーザー自身がネットワーク経由でサーバのローカルアカウントのパスワードを変更する別の方法を考えてみました。1フロアに全従業員がいるような、ごく小規模な環境で使えるかもしれないアイデアです。
Microsoftが無償で提供している「Windows Sysinternals」には、ネットワーク経由でローカルアカウントやドメインアカウントの変更が可能な「PsPasswd」というツールが用意されています。PsPasswdは、対象のサーバやドメインに管理者権限(ドメインの場合は「Domain Admins」または「Account Operators」のメンバー)でアクセスできるユーザーが使用することを想定した“管理者のため”のツールですが、今回はローカルアカウントのパスワード変更をネットワーク経由でできることに着目しました(前述のポリシーとレジストリの設定は不要です)。
ローカルアカウントのパスワードを変更する場合は、次のようなパラメーターを指定して実行します。管理者のパスワードとユーザーの新しいパスワードが画面に表示されてしまうことが難点です。「-p <管理者のパスワード>」パラメーターを省略すると「Password:」プロンプトが表示され、入力したパスワードが画面に表示されることはありませんが、「<新しいパスワード>」パラメーターを省略すると空のパスワードを設定しようとするため、やはり表示されてしまいます(画面5)。
PsPasswd \\<コンピュータ名> -u <管理者のユーザー名> [-p <管理者のパスワード>] <パスワードを変更したいユーザー名> <新しいパスワード>
このパスワードの画面表示を回避するために、簡単なPowerShellスクリプト「changepwd.ps1」とバッチファイル「changepwd.cmd」を作成しました。「changepwd.cmd」は、「changepwd.ps1」を呼び出すだけのものです。
# SecureStringを平文に変換 function SecureStringToPlain($SecureString){ $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) $str = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) return $str } # PsPasswd が存在しない場合はダウンロード if (!(Test-Path ".\pspasswd.exe")) { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 wget -uri https://live.sysinternals.com/pspasswd.exe -o .\pspasswd.exe } # 管理者アカウントのユーザー名 $AdminName = "Administrator" Write-Host "----------------------------------------------------------" Write-Host "サーバに登録されているユーザーのパスワードを変更します。" Write-Host "パスワードの変更には管理者による承認が必要です。" Write-Host "管理者をここに連れてきてください。" Write-Host "----------------------------------------------------------" $TargetUserName = Read-Host -Prompt "あなたのユーザー名" $SecureString = Read-Host -Prompt "新しいパスワード" -AsSecureString $UserNewPwd = SecureStringToPlain($SecureString) Write-Host "" Write-Host "----------------------------------------------------------" Write-Host "ここから管理者に変わってください。" Write-Host "----------------------------------------------------------" $TargetComputer = Read-Host -Prompt "サーバのコンピュータ名" $SecureString = Read-Host -Prompt "管理者のパスワード" -AsSecureString $AdminPwd = SecureStringToPlain($SecureString) Write-Host "" Write-Host "----------------------------------------------------------" Write-Host "実行結果" Write-Host "----------------------------------------------------------" $RunCmd = ".\pspasswd.exe" $RunCmdArg = "-accepteula -nobanner \\" + $targetComputer + " -u " + $AdminName + " -p " + $AdminPwd + " " + $TargetUserName + " " + $UserNewPwd Start-Process -FilePath $RunCmd -ArgumentList $RunCmdArg -NoNewWindow -Wait └───────────────────────────────────┘
@echo off powershell.exe -nologo -ExecutionPolicy RemoteSigned -File .\changepwd.ps1 pause
クライアントPCにこれらのファイルをコピーして「changepwd.ps1」をダブルクリックすると、PsPasswdがなければダウンロードし、PsPasswdのパラメーターに「必要なユーザー名」「新しいパスワード」「サーバ名」「管理者のパスワード」を対話的に聞いてきます。前半はユーザーが入力し、後半は管理者が入力することで、管理者とユーザーが互いのパスワードを知ることなく、ユーザーのパスワードを変更できます(画面6)。
なお、サーバに対するSMB(Server Message Block)接続の資格情報が残っている場合、PsPasswdコマンドは指定した管理者ではなく、残っている資格情報でアクセスしようとするらしく、パスワード変更は「アクセスが拒否されました」で失敗します。「NET USE」コマンドで確認し、「NET USE 共有名 /DELETE」を実行して削除してから再実行してみてください。
管理者がユーザーの所に出向く必要があるのが難点ですが、ごく小規模な環境では使えるのではないでしょうか。Windows 8.1/10の「リモートアシスタンス」やWindows 10の「クイックアシスト」と組み合わせて、管理者がリモートで対応することも可能です。
ただし、弱点もあります。ユーザーがスクリプトを少し改変すれば、サーバの管理者パスワードを取得できてしまいます。それには、PowerShellスクリプトに署名して改変不能にする(「Set-AuthenticodeSignature」コマンドレットを使用)、あるいは管理者がUSBメモリなどでスクリプトを持ち歩くなどの方法で回避できるでしょう。
岩手県花巻市在住。Microsoft MVP:Cloud and Datacenter Management(2020-2021)。SIer、IT出版社、中堅企業のシステム管理者を経て、フリーのテクニカルライターに。Microsoft製品、テクノロジーを中心に、IT雑誌、Webサイトへの記事の寄稿、ドキュメント作成、事例取材などを手掛ける。個人ブログは『山市良のえぬなんとかわーるど』。近著は『Windows版Docker&Windowsコンテナーテクノロジ入門』(日経BP社)、『ITプロフェッショナル向けWindowsトラブル解決 コマンド&テクニック集』(日経BP社)。
Copyright © ITmedia, Inc. All Rights Reserved.