Windows PowerShellユーザー プロビジョニングを自動化する (第 3 部)

Don Jones

目次

サンプル環境
フォルダを作成する
アクセス許可を割り当てる

今月の Windows PowerShell コラムでは、先月のコラムの続きから、Active Directory 環境で新しいユーザーのプロビジョニングを行うのに役立つスクリプトを作成する方法を紹介します。先月のコラムをまだお読みでない場合は、今月のコラムの前に、先月のコラムをお読みになることをお勧めします。

現時点では、4 つのサブ関数を含むプロビジョニングのメイン関数が完了しています。そのメイン関数は次のような状態です。

Function Provision {
  PROCESS {
    CreateUser $_
    CreateHomeFolder $_
    AddToGroups $_
    UpdateAttributes $_
  }
}

CreateUser 関数については、既にさまざまなバージョンを作成しました。今月のコラムでは、CreateHomeFolder 関数について説明します。この関数を使用してユーザーのホーム フォルダを作成し、適切なアクセス制御リスト (ACL) のエントリを適用します。

Windows PowerShell に関する Q&A

Q Windows PowerShell では、文字列を囲むのに使用した単一引用符と二重引用符は区別されますか。

A はい、区別されます。ただし、1 つの例外を除き、単一引用符と二重引用符はまったく同じように動作します。たとえば、以下のコマンドでは、どちらも Microsoft という文字列が $var 変数に代入されます。

$var = 'Microsoft'
$var = "Microsoft"

ただし、二重引用符で囲まれている場合のみ、シェルによってドル記号 ($) が検索されます。ドル記号が見つかった場合、シェルによってドル記号の後に続く文字は変数名であると見なされ、文字列に含まれる変数は、変数の内容に置き換えられます。

$var1 = 'Windows'
$var2 = "Microsoft $var1"

この 2 つのコマンドを実行すると、($var1 変数は変数の内容に置き換えられるので) $var2 変数には Microsoft Windows という文字列が格納されます。この変数の置換機能が必要な場合以外は、単一引用符を使用することをお勧めします。

サンプル環境

CreateHomeFolder 関数では、Provision 関数によって呼び出されるすべてのサブ関数と同様に、入力引数としてハッシュテーブルを受け取ります。ユーザーのログオン名がわかればホーム フォルダを作成できるので、['samAccountName'] ハッシュテーブル キーを使用できます。新しい Active Directory ユーザー アカウントを作成するときには samAccountName 属性が必要になるので、先月のコラムでも、このキーを使用しました。

また、ホーム フォルダを作成する場所も把握しておく必要があり、その場所へのネットワーク アクセスが必要です。このサンプル環境では、すべてのユーザーのホーム フォルダが、ユーザーのログオン名に基づいて、特定のサーバーに格納されることを前提としています。たとえば、ログオン名が A ~ D で始まるユーザーのホーム フォルダは HomeFolders1 サーバーに格納され、E ~ H で始まる場合は HomeFolders2 サーバーに格納されます。サンプル環境で使用している構造は、拡張して、ご使用の環境内で機能する構造を実現できます。ここでは、ログオン名が I ~ Z で始まるユーザーは対象としていません。このパターンは簡単に理解することができるので、サンプル環境をシンプルなものにすることで、スペースを節約しています。

サンプル環境の各サーバーには $Homes という管理用共有が存在し、ここには、すべてのユーザーのホーム フォルダが格納されます。ここでは、管理者が新しいフォルダを作成できることと、スクリプトが管理者によって実行されることを前提としています。また、関連するすべてのサーバーが、同じドメインまたは信頼する側のドメインに参加しており、スクリプトの実行に使用される管理者アカウントがサーバーによって信頼されることを前提としています。

フォルダを作成する

フォルダの作成は比較的簡単な作業です。まず、次のように、フォルダを作成するサーバーを決める必要があります。

Function CreateHomeFolder {
  Param($userinfo)
  $server1 = 'a','b','c','d'
  $server2 = 'e','f','g','h'
  Switch ($userinfo['samAccountName'].    substring(0,1).tolower()) {
    { $server1 –contains $_ } 
      { $homeserver = '\\homeserver1\'; break; }
    { $server2 –contains $_ } 
      { $homeserver = '\\homeserver2\'; break; }
  }
}

このコードでは、具体的には次のような処理を行っています。

  • まず、各ホーム フォルダ サーバーでサポートされる文字の配列を作成しています。このサンプル環境では、$server1 および $server2 という 2 つの配列を作成し、各配列でホストする文字を代入しています。この方法を使用すると、将来文字の割り当てを変更したり、必要に応じてサーバーを追加したりする作業を簡単に行えるようになります。
  • 次に、Switch コンストラクトを使用して、考えられる一連の条件を評価しています。ここでは、ユーザーの samAccountName 属性値の最初の文字を小文字に変換してから、その文字を評価しています。
  • ホーム サーバーごとに、Switch コンストラクトに条件を追加しています。この条件では、ユーザーの samAccountName 属性値の最初の文字 (この時点では、特殊な $_ 変数に含まれています) が、サーバーの文字の配列内に存在するかどうかを確認します。配列内に存在する場合、該当するサーバーの汎用名前付け規則 (UNC) パスの先頭部分が $homeserver 変数に格納されます。break キーワードによって、適切なサーバーが見つかったら、それ以上条件が評価されないようになっています。先ほど説明したように、このサンプルは、ログオン名が I ~ Z で始まるユーザーについては機能しないことに注意してください。運用環境で使用する際には、この文字範囲に対応する条件を追加する必要があります。

次は、Windows PowerShell によってフォルダが作成されるようにするので、関数は次のような状態になります。

Function CreateHomeFolder {
  Param($userinfo)
  $server1 = 'a','b','c','d'
  $server2 = 'e','f','g','h'
  Switch ($userinfo['samAccountName'].
    substring(0,1).tolower()) {
    { $server1 –contains $_ } 
      { $homeserver = '\\homeserver1\'; break; }
    { $server2 –contains $_ } 
      { $homeserver = '\\homeserver2\'; break; }
  }
  Mkdir ($homeserver + '\$Homes\' + $userinfo['samAccountName'])
}

MkDir コマンドが UNC パスを受け取ります (このコマンドの実体は、New-Item コマンドレットを使用する組み込み関数です)。そのため、適切なホーム フォルダ サーバー名と、$Homes 管理用共有およびユーザーの samAccountName 属性値を組み合わせています。ユーザーの samAccountName 属性値が DonJ である場合、MkDir コマンドによって \\server1\$Homes\DonJ という UNC パスが作成されます。

アクセス許可を割り当てる

既定では、新しいフォルダは親フォルダのアクセス許可を継承します。そのため、このサンプルでは、すべての新しいユーザーのホーム フォルダに割り当てる適切な基本アクセス許可が、親フォルダに割り当てられていることを前提としています。たとえば、親フォルダに設定されているアクセス許可によって、組み込みの SYSTEM アカウント、および Domain Admins グループまたはローカルの Administrators グループにフル コントロールが割り当てられることがありますが、その他のユーザーにフル コントロールのアクセス許可が割り当てられることは、おそらくありません。そのため、ここでは、作成したホーム ディレクトリのアクセス許可が、新しいユーザー アカウントに割り当てられていることを確認するだけにとどめました。

気を悪くしないでいただきたいのですが、現時点では、Windows PowerShell は、この作業を実行するのに適していないということをお伝えしなければいけません。本当に申し訳ありません。適していない理由は、Windows のファイル アクセス許可が、非常に複雑で厄介だからです。アクセス制御リスト (ACL) があり、その中にはアクセス制御エントリ (ACE) が含まれています。各 ACE では、許可または拒否のフラグ、アクセス許可 (読み取り、書き込みなど)、およびセキュリティ プリンシパルの GUID (ユーザー、グループなど) が組み合わされます。この大量の情報は、組み合わせた状態で使用する必要があります。

シェルでは Get-ACL コマンドレットと Set-ACL コマンドレットが提供されますが、ACL を変更するには、ACL を取得し、Microsoft .NET Framework オブジェクトを使用して ACL を変更し、変更した ACL をファイルやフォルダに適用し直す必要があります。この方法は専門性のレベルが若干低いので、私の嗜好に合いません。代わりに Windows Management Instrumentation (WMI) を使用することは可能ですが、このツールはほぼ同様に機能します。

さいわいなことに、マイクロソフトは、このような膨大な複雑な処理を、便利で使いやすい Cacls.exe というツールにまとめました。Cacls.exe は公開されてから随分時間がたっているので、なじみがあると思います。Cacls.exe を使用すると、余計な労力を使わずに済むだけでなく、Windows PowerShell が外部コマンド ライン ツール (Cacls、Ping、Ipconfig など) と何の問題もなく連動することが実証されます。こうしたツールのいずれかの使用方法を習得している場合は、今後も、そのツールを Windows PowerShell でご利用ください。Windows PowerShell に関する最も重要な概念の 1 つは、最初からすべて学習し直す必要がないということです。

(ちなみに、Cacls.exe が非推奨のツールだということは知っていますが、代替ツールの ICacls.exe よりも構文が若干単純なので使用しているだけです。必要に応じて、以下のコードを調整して ICacls.exe を使用できます。)

Cacls.exe のヘルプ ファイルによると、次のようなコマンドが必要です。

cacls \\server1\homes\DonJ /e /g DOMAIN\DonJ:R
cacls \\server1\homes\DonJ /e /g DOMAIN\DonJ:W

このコマンドによって、新しいユーザーに読み取りと書き込みのアクセス許可が割り当てられます。その際、フォルダに既に割り当てられている他のアクセス許可が上書きされることはありません。

ただし、このコマンドでは、静的な値ではなく変数を使用したいという問題があります。外部コマンドにシェル変数を指定すると、厄介になることがあります。さまざまな方法がありますが、シェル変数でコマンド文字列全体を作成し、cmd.exe を使用して作成した文字列を実行することをお勧めします。以下にそのコードを示します。

$cacls1 = "cacls "+$homeserver+"$Homes\"
  +$userinfo['samAccountName']+" /E /G "
  +$user+":W"
$cacls2 = "cacls "+$homeserver+"$Homes\"
  +$userinfo['samAccountName']+" /E /G "
  +$user+":W"
cmd /c $cacls1
cmd /c $cacls2

確かにこれは最もすばらしい方法とは言えないかもしれませんが、必要な作業は行われます。また、シェル変数を使用して外部コマンド ライン ツールにパラメータを渡すことがどれほど複雑なのかを示すといった私の隠れた動機も達成されます。上記の 4 行のコードを関数の MkDir コマンドの直後に挿入すれば、関数は完成です。

後は、AddToGroups と UpdateAttributes という 2 つの関数を作成すれば、Provision メイン関数は完成です。その方法については、次回の Windows PowerShell コラムで説明します。

Don Jones は、Concentrated Technology (ConcentratedTech.com) の共同創設者です。彼は、このサイトで、Windows PowerShell、SQL Server、App-V などのトピックに関するブログを毎週更新しています。Don に対するお問い合わせについては、彼の Web サイトを参照してください。