ファストユーザスイッチをより素早く切り替えて快適に

ファストユーザスイッチは、あるユーザーでログイン状態を継続したまま、別のユーザーでもログインする機能といえば良いだろうか。複数のユーザーで同時にログインして、それぞれの作業状態を維持したまま、素早くユーザーを切り替えることが可能だ。(ログイン、ログアウトの読み込みが不要なので)

ところで、OSX 10.4の頃からか*1OS側が用意したゲストアカウントというユーザーが利用出来るようになった。これは、一時的にログインするためのユーザーで、ログアウトするとそのホームフォルダであるGuestフォルダが削除され、それまでの作業内容は綺麗さっぱりクリアされる。(Guestフォルダ以外に保存した書類は維持されるが)そして、再びログインした時には、心機一転、OSが用意したデフォルトの環境が起動するのだ。

自分にとってはこのゲストアカウントの使い勝手はとても便利で、何かのテストで思う存分滅茶苦茶な設定にして試すことができるのだ。でも、ログアウトしてしまえば、それまでの滅茶苦茶は綺麗さっぱり無くなって元通り。他には一切影響を与えずに、気持ち良くテストすることができる。

テスト中は、このゲストアカウントとメインアカウントの間は、頻繁に行ったり来たりすることになる。ファストユーザスイッチによってこの行き来は相当快適になったはずなのだが、それでも頻繁に行き来していると、マウスのクリック、パスワードの入力が煩わしくなってくる。理想はSpacesでデスクトップを切り替えるように、ファストユーザスイッチでも切り替えたいのだ!

ストアカウントへの切替

  • 基本的に上記で紹介されていたAppleScriptをそのまま利用させて頂く。
set thePassword to ""

--このスクリプトのファイル名を取得
set file_name to name of (info for (path to me))

-- 拡張子を含まないファイル名を取得
set AppleScript's text item delimiters to (".") --区切り文字に.を指定
set no_extention_name to first text item of file_name
set AppleScript's text item delimiters to "" --区切り文字をデフォルトに戻す

--ファイル名をログインユーザー名としてユーザーidを取得
set user_id to do shell script "/usr/bin/id -u " & no_extention_name

--ファストユーザースイッチを実行
do shell script "/System/Library/CoreServices/Menu\\ Extras/User.menu/Contents/Resources/CGSession -switchToUserID " & user_id

--ログインパスワードの入力処理(GUIスクリプティングが有効であること)
if thePassword is not "" then
    tell application "System Events"
        tell process "SecurityAgent" to set value of text field 1 of group 1 of window 1 to thePassword
        click button 2 of window 1 of application process "SecurityAgent"
    end tell
end if
      • 上記スクリプトスクリプトエディタにコピーした時、¥(半角 円マーク)を、\(半角 バックスラッシュ)に置き換える必要ありです。(2箇所)
  • ファイル名がログインユーザー名になるので、Guest.scptとして保存すれば、ゲストアカウントへログインできる。
  • これにQuicksilverでショートカットを割り当てれば、キー操作一発でゲストアカウントへ切り替えることができる。

パスワードが必要なアカウントへの切替

  • 上記スクリプトにパスワードを設定すれば、基本的にどんなユーザーでも切り替えることができるのだが、ゲストアカウントから利用する時にはちょっとだけ工夫したくなる。
  • ストアカウントはログアウトするとそのホームフォルダ以下がすべて削除されてしまうので、上記スクリプトの置き場所としては共有フォルダ(/Users/Shared)に保存しておくことになりそう。
  • しかし、誰でも自由にアクセス可能な共有フォルダにログインパスワードまで設定して保存しておくのは、セキュリティ上も問題があり、さすがに心配だ。
  • そこで、propertyを利用して以下のように修正してみた。
property pre_msg : "入力してください。"
property user_name : pre_msg
property user_pass : pre_msg

repeat
    if user_name is pre_msg or user_name is "" then
        display dialog "ユーザー名:" default answer "" with icon note
        set user_name to text returned of result
    else
        exit repeat
    end if
end repeat

repeat
    if user_pass is pre_msg then
        display dialog "パスワード:" default answer "" with icon note
        set user_pass to text returned of result
    else
        exit repeat
    end if
end repeat

--ファイル名をログインユーザー名としてユーザーidを取得
set user_id to do shell script "/usr/bin/id -u " & user_name

--ファストユーザースイッチを実行
do shell script "/System/Library/CoreServices/Menu\\ Extras/User.menu/Contents/Resources/CGSession -switchToUserID " & user_id

--ログインパスワードの入力処理(GUIスクリプティングが有効であること)
delay 0.5
if user_pass is not "" then
    tell application "System Events"
        tell process "SecurityAgent" to set value of text field 1 of group 1 of window 1 to user_pass
        click button 2 of window 1 of application process "SecurityAgent"
    end tell
end if
user_name & " ユーザーへ切替\ncommand-Rで実行可能"
      • 上記スクリプトスクリプトエディタにコピーした時、¥(半角 円マーク)を、\(半角 バックスラッシュ)に置き換える必要ありです。(3箇所)
  • 上記スクリプトを共有フォルダに保存(/Users/Shared/faster_user_switch.scpt)して、command-Iで情報ウィンドウを表示して、ロックを掛けた。


  • ダブルクリックしてスクリプトエディタで起動しておけば、実行ボタンまたはcommand-Rでスクリプトが実行できる。
    • スクリプトエディタで起動後の初回のみ、ユーザー名とパスワードの入力が求められる。
    • 初回のユーザー名とパスワードは保存され、2回目以降の実行からは瞬時に切替が始まる。


  • スクリプトエディタを終了すれば、ユーザー名とパスワードはクリアされる。
    • 通常、プロパティはスクリプトのファイルに保持されるが、スクリプトエディタから実行した場合は保持されなかった。
    • スクリプトエディタでそのスクリプトを開いている間だけ、保持された。
    • 例えスクリプトメニューから起動したとしても、ロックが掛かっているのでユーザー名とパスワードは保持されないのだ。(ロックが解除されていれば、保持される。)
  • 共有フォルダに置いたスクリプト(/Users/Shared/faster_user_switch.scpt)を、複数のユーザーで同時に開いても大丈夫。スクリプトエディタの起動している間だけ、ユーザーごとに利用中のログイン名とパスワードが保持された。

ユーザー切り替えが、すごく快適になった!

ストアカウントのホームフォルダが削除されない時

今回のスクリプトで試行錯誤している時に気付いたのだが、ゲストアカウントのホームフォルダ以下にロックの掛かったファイルが存在すると、ログアウトしてもホームフォルダが削除されずに残った。(おそらく、ロックの掛かったファイルが邪魔をしているようだ。)

  • ストアカウントはログアウトすれば必ず、そのホームフォルダは綺麗さっぱり削除されると思い込んでいたので、この現象には要注意だ。
  • 外部で、ゲストアカウントでログインして作業した後、ログアウト後に本当にホームフォルダが削除されているか確認するべきかもしれない。(もう一度ログインすれば確認できると思う。)

追記

コメントでヒントを頂き、使い勝手の向上を目指しての修正です!

  • スペースを含むユーザー名に対応
  • パスワード入力時にエラーが発生しないように修正
  • 起動直後にdeleteキーを押せば、ユーザー名を変更できるように修正
  • アプリケーションとして実行する方式に変更
    • 以下の設定で保存した
      • ファイルフォーマット:アプリケーション
      • オプション:「実行後、自動的に終了しない」のチェックを入
    • プロパティは利用せず、アプリケーションの起動中のみパスワードを維持する。
      • faster_user_switching.appの起動時は毎回ユーザー名とパスワードを入力する必要あり。
      • faster_user_switching.appを終了しない限り、2回目以降の起動操作では自動入力される。
    • Quicksilver・LaunchBar等でショートカットを割り当てると便利。


global userName
global userPass

on run
set userName to ""
set userPass to ""
main() end run

on reopen
main() end reopen




on main() save_user_name() save_user_pass() fast_user_switch() input_login_password() end main

--ユーザー名の登録(ユーザー名を変更したい時は、このスクリプト起動直後にdeleteキーを押す)
on save_user_name() if userName = "" then
set msg to "ユーザー名を入力してください。"
set icon_name to note
repeat
activate
display dialog msg default answer userName with icon icon_name
set userName to text returned of result
try
user_id() exit repeat
on error
if userName is not "" then
set msg to "このユーザーは登録されていません。\nもう一度、入力してください。"
set icon_name to caution
end if
end try
end repeat
end if
end save_user_name

--パスワードの登録
on save_user_pass() repeat while userPass is ""
activate
display dialog "パスワードを入力してください。" default answer "" with icon note with hidden answer
set userPass to text returned of result
end repeat
end save_user_pass

--ユーザー名からユーザーIDを取得
on user_id() do shell script "/usr/bin/id -u " & quoted form of userName
end user_id

--ファストユーザースイッチを実行
on fast_user_switch() do shell script "/System/Library/CoreServices/Menu\\ Extras/User.menu/Contents/Resources/CGSession -switchToUserID " & user_id() end fast_user_switch

--ログインパスワードの入力処理
on input_login_password() tell application "System Events"
repeat 20 times
delay 0.1
if exists window 1 of application process "SecurityAgent" then exit repeat
end repeat
if userPass is not "" then
tell process "SecurityAgent"
keystroke userPass & return
delay 1
keystroke tab using {command down} end tell
end if
end tell
end input_login_password


2012年の以下の日記に続く...

*1:定かではない。もしかしたら、もっと以前から利用できたのかもしれない。