バックグラウンドで(潜在的に)長時間実行され、システムの再起動時に自動的に再開されるユーティリティに取り組んでいます。このユーティリティを実行するには昇格した特権 (つまり、「管理者として実行」) が必要です。そのため、レジストリの「実行」セクション ( HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
) はデフォルトの特権でしかプロセスを起動しないため、信頼できません。
そのため、TaskScheduler API を使用した「ログオン」トリガーと、昇格された権限でアプリを起動する「TASK_RUNLEVEL_HIGHEST」の実行レベルでスケジュールされたタスクを使用しています (必要な UAC はありません)。ここまでは順調ですね。
問題は、このアプリケーションが Credential Manager にも資格情報を保存し、再起動後に再読み込みすることです (たとえば、上記のスケジュールされたタスクがトリガーされたとき)。これは、advapi32.dll の CredRead()/CredWrite() 関数を使用して行われます。何らかの理由で、タスクが RUNLEVEL_HIGHEST で起動されると、CredRead() 関数は false を返し、GetLastError() は 1168 (「要素が見つかりません」) を返します。
ドキュメントによると、CredWrite() によって保存された資格情報は、現在のユーザー トークンのログオン セッションに関連付けられています。「LOCAL_MACHINE」の永続タイプで資格情報を保存しました。つまり、現在のセッションを超えて永続する必要があります。実際、タスクが読み取りに失敗した場合でも、資格情報マネージャーに表示されます。
そのため、最高の権限で起動されたタスクが原因で、ユーティリティが最初に起動されたときに作成された資格情報を表示できなくなっているようです。資格情報を保存します)。
FWIW、問題は、「管理者として実行」コマンドプロンプトから実行されることによる昇格と、「最高の特権で実行」のタスクとして起動されることによる昇格が、どういうわけか異なる「レベル」になることだと思います標高。スケジュールされたタスクの作成方法、または CredWrite/CredRead のいずれかで何かが足りないように感じます。どんな助けでも大歓迎です!
更新: コメントでの CodyGray の提案に従って、アプリ マニフェストで requiredExecutionLevel を設定しようとしました。これは、元の問題に関して動作を変更しませんでした。
また、現在の WindowsIdentity ( ) のトークン、ユーザー SID、さまざまな "IsAuthenticated" などのプロパティも確認しましたが、WindowsIdentity.GetCurrent()
機能しているケースと機能していないケースですべて同じです。
また、「false」を返し、エラー コードを 1168 に設定する CredEnumerate() の呼び出しも追加しました (上記の CredRead() と同じ「見つかりません」)。したがって、これは、プロセスが、特にアプリの資格情報だけでなく、そのユーザーの保存された資格情報をまったく見つけられないことを示しています。
最後に、タスク スケジューラからタスクを手動で実行すると、期待どおりに動作し、保存されている資格情報が見つかります。この問題は、ログイン時にタスクがトリガーされた場合にのみ発生するようです。
更新 #2
以前はできなかった開発マシンで問題を (簡単に) 再現することができました。この問題は、ユーザーが 2 つのグループ (「ユーザー」と「管理者」など) のメンバーである場合にのみ発生するようです。デフォルトの開発ボックス ログインは、「管理者」のメンバーのみです。両方のグループのメンバーである新しいユーザーを作成すると、問題が再現されました。ただし、ユーザーのみ/管理者のみ/両方の間でユーザーをある程度切り替えた後、そのユーザーで問題を再現できなくなりました (両方のグループに戻ったとしても)。
クレデンシャルを別の場所に保存するという回避策を見つけました(現時点では許容できますが、長期的には理想的ではありませんが、最終的にはこれらはとにかく機密性の高いクレデンシャルではありません)。ただし、ここで何が起こっているのかを理解したいと思います。時間があるので実験を続けますが、それまでの間の洞察に感謝します!