私のアプリケーションはいくつかのスクリプトを実行する必要があり、それらを実行しているユーザーが管理者であることを確認する必要があります... C#を使用してこれを行う最良の方法は何ですか?
8 に答える
using System.Security.Principal;
public static bool IsAdministrator()
{
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
{
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
return new WindowsPrincipal(WindowsIdentity.GetCurrent())
.IsInRole(WindowsBuiltInRole.Administrator);
これを行うためにWindowsAPIを呼び出すこともできます。
[DllImport("shell32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsUserAnAdmin();
これは、より一般的に、ユーザーが昇格された権限で実行されているかどうかを示します。
IsInRoleに関する上記の回答は、実際には正しいものです。現在のユーザーが管理者権限を持っているかどうかを確認します。でも、
Windows Vista以降、ユーザーアカウント制御(UAC)がユーザーの特権を決定します。組み込みのAdministratorsグループのメンバーである場合は、標準のユーザーアクセストークンと管理者アクセストークンの2つのランタイムアクセストークンが割り当てられます。デフォルトでは、標準のユーザーロールになっています。
(MSDNから、たとえばhttps://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogpermission(v=vs.110).aspx)
したがって、IsInRoleはデフォルトでユーザー特権を考慮し、したがってメソッドはfalseを返します。ソフトウェアが管理者として明示的に実行されている場合にのみ当てはまります。
https://ayende.com/blog/158401/are-you-an-administratorでADをチェックするもう1つの方法は、ユーザー名が管理者グループにあるかどうかをチェックします。
したがって、両方を組み合わせる私の完全な方法は次のとおりです。
public static bool IsCurrentUserAdmin(bool checkCurrentRole = true)
{
bool isElevated = false;
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
{
if (checkCurrentRole)
{
// Even if the user is defined in the Admin group, UAC defines 2 roles: one user and one admin.
// IsInRole consider the current default role as user, thus will return false!
// Will consider the admin role only if the app is explicitly run as admin!
WindowsPrincipal principal = new WindowsPrincipal(identity);
isElevated = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
else
{
// read all roles for the current identity name, asking ActiveDirectory
isElevated = IsAdministratorNoCache(identity.Name);
}
}
return isElevated;
}
/// <summary>
/// Determines whether the specified user is an administrator.
/// </summary>
/// <param name="username">The user name.</param>
/// <returns>
/// <c>true</c> if the specified user is an administrator; otherwise, <c>false</c>.
/// </returns>
/// <seealso href="https://ayende.com/blog/158401/are-you-an-administrator"/>
private static bool IsAdministratorNoCache(string username)
{
PrincipalContext ctx;
try
{
Domain.GetComputerDomain();
try
{
ctx = new PrincipalContext(ContextType.Domain);
}
catch (PrincipalServerDownException)
{
// can't access domain, check local machine instead
ctx = new PrincipalContext(ContextType.Machine);
}
}
catch (ActiveDirectoryObjectNotFoundException)
{
// not in a domain
ctx = new PrincipalContext(ContextType.Machine);
}
var up = UserPrincipal.FindByIdentity(ctx, username);
if (up != null)
{
PrincipalSearchResult<Principal> authGroups = up.GetAuthorizationGroups();
return authGroups.Any(principal =>
principal.Sid.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid) ||
principal.Sid.IsWellKnown(WellKnownSidType.AccountDomainAdminsSid) ||
principal.Sid.IsWellKnown(WellKnownSidType.AccountAdministratorSid) ||
principal.Sid.IsWellKnown(WellKnownSidType.AccountEnterpriseAdminsSid));
}
return false;
}
昇格された特権(UACが有効)のない管理者グループのユーザーの場合、このメソッドIsCurrentUserAdmin()は!checkCurrentRoleを返します:checkCurrentRole == falseの場合はtrue、checkCurrentRole==trueの場合はfalse
管理者権限が必要なコードを実行する場合は、checkCurrentRole==trueを検討してください。そうしないと、それまでにセキュリティ例外が発生します。したがって、正しいIsInRoleロジックです。
別の解決策を追加すると思っただけです。常に機能するとIsInRole
は限りません。
- ユーザーが現在のセッションで指定されたWindowsユーザーグループのメンバーではない場合。
- 管理者がグループポリシー設定を変更しました
- ロールパラメータは「大文字と小文字を区別する」メソッドとして扱われます。
- また、XPマシンに.NET Frameworkバージョンがインストールされていない場合、それは機能しません。
古いシステムをサポートする必要がある場合は、ニーズに応じて。または、クライアントがシステムを物理的にどのように管理しているかわからない。これは私が実装したソリューションです。柔軟性と変更のため。
class Elevated_Rights
{
// Token Bool:
private bool _level = false;
#region Constructor:
protected Elevated_Rights()
{
// Invoke Method On Creation:
Elevate();
}
#endregion
public void Elevate()
{
// Get Identity:
WindowsIdentity user = WindowsIdentity.GetCurrent();
// Set Principal
WindowsPrincipal role = new WindowsPrincipal(user);
#region Test Operating System for UAC:
if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)
{
// False:
_level = false;
// Todo: Exception/ Exception Log
}
#endregion
else
{
#region Test Identity Not Null:
if (user == null)
{
// False:
_level = false;
// Todo: "Exception Log / Exception"
}
#endregion
else
{
#region Ensure Security Role:
if (!(role.IsInRole(WindowsBuiltInRole.Administrator)))
{
// False:
_level = false;
// Todo: "Exception Log / Exception"
}
else
{
// True:
_level = true;
}
#endregion
} // Nested Else 'Close'
} // Initial Else 'Close'
} // End of Class.
したがって、上記のコードにはいくつかの構成があります。ユーザーがVista以降を使用しているかどうかを実際にテストします。そうすれば、顧客が数年前のフレームワークまたはベータフレームワークなしでXPを使用している場合、やりたいことを変更することができます。
次に、アカウントのnull値を回避するために物理的にテストします。
そして最後に、ユーザーが実際に適切な役割を果たしていることを確認するためのチェックを提供します。
私は質問が答えられたことを知っています。しかし、私の解決策は、Stackを検索している他の人にとってはページへの素晴らしい追加になると思いました。保護されたコンストラクターの背後にある私の推論により、このクラスを派生クラスとして使用して、クラスがインスタンス化されるときの状態を制御できるようになります。
ここにある他の人と同様に、私のプログラムは昇格して実行されていないため、false
UACが有効になっている場合、このコードは返されます。
private bool IsCurrentUserAnAdmin()
{
var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
@EricBDevの答えは、私のプログラムが昇格して実行されておらず、ユーザーが管理者である場合にIsAdministratorNoCache
返されます。true
しかし、ブログの作者が言うように、それは非常に遅いです。
これが私の解決策です。エミュレートしIsAdministratorNoCache
ますが高速です:
private bool IsCurrentUserInAdminGroup()
{
// https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows
// S-1-5-32-544
// A built-in group. After the initial installation of the operating system,
// the only member of the group is the Administrator account.
// When a computer joins a domain, the Domain Admins group is added to
// the Administrators group. When a server becomes a domain controller,
// the Enterprise Admins group also is added to the Administrators group.
var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
var claims = principal.Claims;
return (claims.FirstOrDefault(c => c.Value == "S-1-5-32-544") != null);
}
それらを実行しているユーザーが管理者であることを確認する必要があります
アプリケーションを管理者権限で実行する必要がある場合は、マニフェストを更新するのが適切です。
に設定requestedExecutionlevel
しrequireAdminstrator
ます。
これが私が最終的に行う方法です...私は自分のアプリを管理者モードとして実行するように強制しています。これをする
1-ファイルに追加<ApplicationManifest>app.manifest</ApplicationManifest>
しますcsproj
。
MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
</Project>
2-以下のapp.manifest
ファイルをプロジェクトに追加します。
app.manifest
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>