其他缓解措施
Credential Guard 提供针对派生凭据的攻击的缓解措施,防止在其他地方使用被盗的凭据。 但是,即使派生的凭据受 Credential Guard 保护,设备仍可能容易受到某些攻击。 这些攻击可能包括滥用特权,直接从受攻击的设备使用派生凭据,在启用 Credential Guard 之前重复使用被盗的凭据,以及滥用管理工具和弱应用程序配置。 因此,还必须部署其他缓解措施,使域环境更加可靠。
其他安全资格
满足硬件、固件和软件基线保护的所有设备都可以使用 Credential Guard。
满足更多资格的设备可以提供额外的保护,以进一步减少攻击面。
下表列出了提高安全性的资格。 建议满足其他资格,以增强 Credential Guard 可以提供的安全级别。
保护 | 要求 | 安全优势 |
---|---|---|
安全启动配置和管理 | - 必须支持 BIOS 密码或更强的身份验证 - 在 BIOS 配置中,必须设置 BIOS 身份验证 - 必须支持受保护的 BIOS 选项来配置允许的启动设备列表 (例如, 仅从内部硬盘驱动器 启动) 和启动设备顺序,覆盖 BOOTORDER 操作系统所做的修改 |
- 阻止其他操作系统启动 -阻止对 BIOS 设置的更改 |
硬件根信任平台安全启动 | - 必须支持启动完整性 (平台安全启动) 。 请参阅 System.Fundamentals.Firmware.CS.UEFISecureBoot.ConnectedStandby - 硬件安全测试接口 (必须实现 HSTI) 下的 Windows 硬件兼容性计划要求。 请参阅 硬件安全可测试性规范 |
- 开机的启动完整性(平台安全启动)可防范现实存在的攻击者,并深度防御恶意软件。
- HSTI 为正确安全的芯片和平台提供安全保障 |
通过 Windows 更新进行固件更新 | - 固件必须通过 Windows 更新和 UEFI 封装更新支持字段更新 | 有助于确保快速、安全且可靠地执行固件更新。 |
保护启动配置和管理 | - 所需的 BIOS 功能:OEM 能够在制造时 在安全启动 DB 中添加 ISV、OEM 或企业证书 - 所需的配置:必须从安全启动 DB 中删除Microsoft UEFI CA。 允许支持第三方 UEFI 模块,但应对特定的 UEFI 软件使用 ISV 提供的证书或 OEM 证书 |
- 企业可以选择允许专有 EFI 驱动程序/应用程序运行 - 从安全启动 DB 中删除Microsoft UEFI CA 使企业能够完全控制操作系统启动前运行的软件 |
为 UEFI 运行时服务启用 VBS No-Execute (NX) 保护 | - VBS 对 UEFI 运行时服务代码和数据内存区域启用 NX 保护。 UEFI 运行时服务代码必须支持只读页面保护,并且 UEFI 运行时服务数据不得是可执行的。 UEFI 运行时服务必须满足以下要求: - 实现 UEFI 2.6 EFI_MEMORY_ATTRIBUTES_TABLE 。 此表 必须描述所有 UEFI 运行时服务内存 (代码和数据) - PE 部分必须在内存中对齐, (非易失性存储) 不需要。 - 内存属性表需要正确标记代码和数据,以便 RO/NX 由 OS 配置 - 所有条目都必须包括属性 EFI_MEMORY_RO 和 EFI_MEMORY_XP /或属性。
- 不能留下任何带有上述两个属性的条目,这表示内存既可执行又可写。 内存必须是可读且可执行的或可写且不可执行的 , (在此表) 之后查看重要信息 |
- 阻止 UEFI 运行时中的漏洞(如果有)破坏 VBS (,例如 UpdateCapsule 和 SetVariable) 等函数中的漏洞 - 将攻击面减少到来自系统固件的 VBS。 |
SMM 保护的固件支持 | - Windows SMM 安全缓解表 (WSMT) 规范 包含 ACPI 表的详细信息,该表是为支持基于 Windows 虚拟化的功能的 Windows 操作系统而创建的。 | - 防止 UEFI 运行时服务中的潜在漏洞(如果有)会阻止其破坏 VBS (,例如在 UpdateCapsule 和 SetVariable 等函数中) - 从系统固件将攻击面减少到 VBS - 阻止针对 SMM 的其他安全攻击 |
重要提示
关于 为 UEFI 运行时服务启用 NX 保护的 VBS:
- 它仅适用于 UEFI 运行时服务内存,不适用于 UEFI 启动服务内存
- 保护由 VBS 对 OS 页表应用
- 不要使用可写和可执行的节
- 不要尝试直接修改可执行系统内存
- 不要使用动态代码
将域用户限制为加入特定域的设备
凭据盗窃攻击使攻击者能够盗取一台设备的密码,并在另一台设备上使用这些密码。 如果用户可以登录多台设备,那么可使用任何设备盗窃凭据。 如何确保用户仅使用启用了 Credential Guard 的设备登录? 部署身份验证策略,以将其限制为已使用 Credential Guard 配置的特定已加入域的设备。 若要使域控制器知道用户正在通过哪台设备登录,必须使用 Kerberos 保护。
Kerberos 保护
Kerberos 保护是 RFC 6113 的一部分。 当设备支持 Kerberos 保护时,其 TGT 用于保护用户的所有权证明,这可以缓解脱机字典攻击。 Kerberos 保护还提供已签名 KDC 错误的其他优势,这可缓解导致降级攻击等操作的纂改。
若要启用 Kerberos 保护以将域用户限制为特定的已加入域的设备,请执行以下操作:
- 用户需要位于运行 Windows Server 2012 R2 或更高版本的域中
- 必须配置这些域中的所有域控制器,才能支持 Kerberos 保护。 将 声明、复合身份验证和 Kerberos 保护组策略设置的 KDC 支持 设置为 “受支持 ”或 “始终提供声明”
- 必须将用户限制为的具有 Credential Guard 的所有设备配置为支持 Kerberos 防护。 在计算机配置>管理模板>系统>Kerberos 下启用对声明、复合身份验证和 Kerberos 保护组策略设置的 Kerberos 客户端支持。
保护已加入域的设备机密
由于已加入域的设备还将共享密钥用于身份验证,因此攻击者也可以盗窃这些密钥。 通过使用 Credential Guard 部署设备证书,可以保护私钥。 然后,身份验证策略可能要求用户登录到使用这些证书进行身份验证的设备。 这会阻止配合使用设备上的被盗共享密码与被盗用户凭据以用户身份登录。
已加入域的设备证书身份验证具有以下要求:
- 设备的帐户位于 Windows Server 2012 域功能级别或更高级别的域中。
- 这些域中的所有域控制器都具有满足严格的 KDC 验证证书要求的 KDC 证书:
- 存在 KDC EKU
- DNS 域名与 SubjectAltName (SAN) 扩展名的 DNSName 字段相匹配
- Windows 设备在企业存储中具有颁发域控制器证书的 CA。
- 已建立一个过程来确保设备的标识和可信度,其方法类似于你在向用户颁发智能卡之前建立用户的标识和可信度。
部署已加入域的设备证书
若要确保仅将具有所需颁发策略的证书安装在这些用户必须使用的设备上,则必须在每台设备上手动部署它们。 用于向用户颁发智能卡的相同安全过程应适用于设备证书。
例如,假设你想要仅在这些设备上使用高确定性策略。 使用 Windows Server 企业证书颁发机构,将创建新的模板。
创建新的证书模板
- 在证书管理器控制台中,右键单击“证书模板>管理”
- 右键单击“工作站身份验证>重复模板”
- 右键单击新模板,然后选择“ 属性”
- 在“扩展”选项卡上,选择“应用程序策略>编辑”
- 选择“客户端身份验证”,然后选择“删除”
- 添加 ID-PKInit-KPClientAuth EKU。 选择“添加新”>,然后指定以下值:
- 名称:Kerberos 客户端身份验证
- 对象标识符:1.3.6.1.5.2.3.4
- 在“扩展”选项卡上,选择“颁发策略>编辑”
- 在“颁发策略”下,选择“高保证”
- 在“ 使用者名称 ”选项卡上,清除“ DNS 名称 ”复选框,然后选中“ 用户主体名称 (UPN) ”复选框
然后在运行 Credential Guard 的设备上,使用创建的证书注册设备。
在证书中注册设备
运行以下命令:
CertReq -EnrollCredGuardCert MachineAuthentication
注意
你必须在注册计算机身份验证证书后重新启动设备。
证书颁发策略如何用于访问控制
从 Windows Server 2008 R2 域功能级别开始,对身份验证机制保证的域控制器支持提供了一种将证书颁发策略 OID 映射到通用安全组的方法。 使用声明支持的 Windows Server 2012 域控制器可以将它们映射到声明。 若要了解有关身份验证机制保证的详细信息,请参阅 TechNet 上的 Windows Server 2008 R2 中的 AD DS 身份验证机制保证分步指南。
查看可用的颁发策略
-
get-IssuancePolicy.ps1 显示所有适用于证书颁发机构的颁发策略。
在 Windows PowerShell 命令提示符下,运行以下命令:
.\get-IssuancePolicy.ps1 -LinkedToGroup:All
将颁发策略链接到通用安全组
-
set-IssuancePolicyToGroupLink.ps1 创建通用安全组、创建组织单位并将颁发策略链接到该通用安全组。
在 Windows PowerShell 命令提示符下,运行以下命令:
.\set-IssuancePolicyToGroupLink.ps1 -IssuancePolicyName:"<name of issuance policy>" -groupOU:"<Name of OU to create>" -groupName:"<name of Universal security group to create>"
限制用户登录
因此我们现在完成了以下操作:
- 创建了一种特殊证书颁发策略,可标识满足用户登录所需的部署条件的设备
- 已将该策略链接到通用安全组或声明
- 为域控制器提供了一种使用 Kerberos 保护在用户登录期间获取设备授权数据的方法。 现在只需在域控制器上配置访问权限检查。 这是使用身份验证策略完成的
身份验证策略具有以下要求:
- 用户帐户位于 Windows Server 2012 域功能级别或更高版本的域中
创建将用户限制为特定通用安全组的身份验证策略
- 打开 Active Directory 管理中心
- 选择 “身份验证 > ”“新建 > 身份验证策略”
- 在 “显示名称 ”框中,输入此身份验证策略的名称
- 在 “帐户” 标题下,选择“ 添加”
- 在 “选择用户、计算机或服务帐户 ”对话框中,键入要限制的用户帐户的名称,然后选择“ 确定”
- 在“ 用户登录” 标题下,选择“ 编辑” 按钮
- 选择 “添加条件”
- 在“编辑访问控制条件”框中,确保读取每个>值的用户组>>成员,然后选择“添加项”
- 在 “选择用户、计算机或服务帐户 ”对话框中,键入使用 set-IssuancePolicyToGroupLink 脚本创建的通用安全组的名称,然后选择“ 确定”
- 选择 “确定” 以关闭 “编辑访问控制条件 ”框
- 选择 “确定” 以创建身份验证策略
- 选择“Active Directory 管理中心”
注意
当身份验证策略强制执行策略限制时,用户不能使用没有部署相应颁发策略的证书的设备登录。 这适用于本地和远程登录方案。 因此,强烈建议首先仅审核策略限制,确保你没有意外失败。
发现由于身份验证策略而导致的身份验证失败
若要更轻松地跟踪由于身份验证策略导致的身份验证失败,可使用包含这些事件的运行日志。 若要在域控制器上启用日志,请在事件查看器中导航到 “应用程序和服务日志\Microsoft\Windows\身份验证”,右键单击“AuthenticationPolicyFailures-DomainController”,然后选择“ 启用日志”。
若要了解有关身份验证策略事件的详细信息,请参阅身份验证策略和身份验证策略接收器。
附录:脚本
下面是本文中提到的脚本列表。
获取证书颁发机构的相关可用颁发策略
将此脚本文件另存为 get-IssuancePolicy.ps1。
#######################################
## Parameters to be defined ##
## by the user ##
#######################################
Param (
$Identity,
$LinkedToGroup
)
#######################################
## Strings definitions ##
#######################################
Data getIP_strings {
# culture="en-US"
ConvertFrom-StringData -stringdata @'
help1 = This command can be used to retrieve all available Issuance Policies in a forest. The forest of the currently logged on user is targeted.
help2 = Usage:
help3 = The following parameter is mandatory:
help4 = -LinkedToGroup:<yes|no|all>
help5 = "yes" will return only Issuance Policies that are linked to groups. Checks that the linked Issuance Policies are linked to valid groups.
help6 = "no" will return only Issuance Policies that are not currently linked to any group.
help7 = "all" will return all Issuance Policies defined in the forest. Checks that the linked Issuance policies are linked to valid groups.
help8 = The following parameter is optional:
help9 = -Identity:<Name, Distinguished Name or Display Name of the Issuance Policy that you want to retrieve>. If you specify an identity, the option specified in the "-LinkedToGroup" parameter is ignored.
help10 = Output: This script returns the Issuance Policy objects meeting the criteria defined by the above parameters.
help11 = Examples:
errorIPNotFound = Error: no Issuance Policy could be found with Identity "{0}"
ErrorNotSecurity = Error: Issuance Policy "{0}" is linked to group "{1}" which is not of type "Security".
ErrorNotUniversal = Error: Issuance Policy "{0}" is linked to group "{1}" whose scope is not "Universal".
ErrorHasMembers = Error: Issuance Policy "{0}" is linked to group "{1}" which has a non-empty membership. The group has the following members:
LinkedIPs = The following Issuance Policies are linked to groups:
displayName = displayName : {0}
Name = Name : {0}
dn = distinguishedName : {0}
InfoName = Linked Group Name: {0}
InfoDN = Linked Group DN: {0}
NonLinkedIPs = The following Issuance Policies are NOT linked to groups:
'@
}
##Import-LocalizedData getIP_strings
import-module ActiveDirectory
#######################################
## Help ##
#######################################
function Display-Help {
""
$getIP_strings.help1
""
$getIP_strings.help2
""
$getIP_strings.help3
" " + $getIP_strings.help4
" " + $getIP_strings.help5
" " + $getIP_strings.help6
" " + $getIP_strings.help7
""
$getIP_strings.help8
" " + $getIP_strings.help9
""
$getIP_strings.help10
""
""
$getIP_strings.help11
" " + '$' + "myIPs = .\get-IssuancePolicy.ps1 -LinkedToGroup:All"
" " + '$' + "myLinkedIPs = .\get-IssuancePolicy.ps1 -LinkedToGroup:yes"
" " + '$' + "myIP = .\get-IssuancePolicy.ps1 -Identity:""Medium Assurance"""
""
}
$root = get-adrootdse
$domain = get-addomain -current loggedonuser
$configNCDN = [String]$root.configurationNamingContext
if ( !($Identity) -and !($LinkedToGroup) ) {
display-Help
break
}
if ($Identity) {
$OIDs = get-adobject -Filter {(objectclass -eq "msPKI-Enterprise-Oid") -and ((name -eq $Identity) -or (displayname -eq $Identity) -or (distinguishedName -like $Identity)) } -searchBase $configNCDN -properties *
if ($OIDs -eq $null) {
$errormsg = $getIP_strings.ErrorIPNotFound -f $Identity
write-host $errormsg -ForegroundColor Red
}
foreach ($OID in $OIDs) {
if ($OID."msDS-OIDToGroupLink") {
# In case the Issuance Policy is linked to a group, it is good to check whether there is any problem with the mapping.
$groupDN = $OID."msDS-OIDToGroupLink"
$group = get-adgroup -Identity $groupDN
$groupName = $group.Name
# Analyze the group
if ($group.groupCategory -ne "Security") {
$errormsg = $getIP_strings.ErrorNotSecurity -f $Identity, $groupName
write-host $errormsg -ForegroundColor Red
}
if ($group.groupScope -ne "Universal") {
$errormsg = $getIP_strings.ErrorNotUniversal -f $Identity, $groupName
write-host $errormsg -ForegroundColor Red
}
$members = Get-ADGroupMember -Identity $group
if ($members) {
$errormsg = $getIP_strings.ErrorHasMembers -f $Identity, $groupName
write-host $errormsg -ForegroundColor Red
foreach ($member in $members) {
write-host " " $member -ForeGroundColor Red
}
}
}
}
return $OIDs
break
}
if (($LinkedToGroup -eq "yes") -or ($LinkedToGroup -eq "all")) {
$LDAPFilter = "(&(objectClass=msPKI-Enterprise-Oid)(msDS-OIDToGroupLink=*)(flags=2))"
$LinkedOIDs = get-adobject -searchBase $configNCDN -LDAPFilter $LDAPFilter -properties *
write-host ""
write-host "*****************************************************"
write-host $getIP_strings.LinkedIPs
write-host "*****************************************************"
write-host ""
if ($LinkedOIDs -ne $null){
foreach ($OID in $LinkedOIDs) {
# Display basic information about the Issuance Policies
""
$getIP_strings.displayName -f $OID.displayName
$getIP_strings.Name -f $OID.Name
$getIP_strings.dn -f $OID.distinguishedName
# Get the linked group.
$groupDN = $OID."msDS-OIDToGroupLink"
$group = get-adgroup -Identity $groupDN
$getIP_strings.InfoName -f $group.Name
$getIP_strings.InfoDN -f $groupDN
# Analyze the group
$OIDName = $OID.displayName
$groupName = $group.Name
if ($group.groupCategory -ne "Security") {
$errormsg = $getIP_strings.ErrorNotSecurity -f $OIDName, $groupName
write-host $errormsg -ForegroundColor Red
}
if ($group.groupScope -ne "Universal") {
$errormsg = $getIP_strings.ErrorNotUniversal -f $OIDName, $groupName
write-host $errormsg -ForegroundColor Red
}
$members = Get-ADGroupMember -Identity $group
if ($members) {
$errormsg = $getIP_strings.ErrorHasMembers -f $OIDName, $groupName
write-host $errormsg -ForegroundColor Red
foreach ($member in $members) {
write-host " " $member -ForeGroundColor Red
}
}
write-host ""
}
}else{
write-host "There are no issuance policies that are mapped to a group"
}
if ($LinkedToGroup -eq "yes") {
return $LinkedOIDs
break
}
}
if (($LinkedToGroup -eq "no") -or ($LinkedToGroup -eq "all")) {
$LDAPFilter = "(&(objectClass=msPKI-Enterprise-Oid)(!(msDS-OIDToGroupLink=*))(flags=2))"
$NonLinkedOIDs = get-adobject -searchBase $configNCDN -LDAPFilter $LDAPFilter -properties *
write-host ""
write-host "*********************************************************"
write-host $getIP_strings.NonLinkedIPs
write-host "*********************************************************"
write-host ""
if ($NonLinkedOIDs -ne $null) {
foreach ($OID in $NonLinkedOIDs) {
# Display basic information about the Issuance Policies
write-host ""
$getIP_strings.displayName -f $OID.displayName
$getIP_strings.Name -f $OID.Name
$getIP_strings.dn -f $OID.distinguishedName
write-host ""
}
}else{
write-host "There are no issuance policies which are not mapped to groups"
}
if ($LinkedToGroup -eq "no") {
return $NonLinkedOIDs
break
}
}
注意
如果在运行此脚本时遇到困难,请尝试替换 ConvertFrom-StringData 参数后的单引号。
将颁发策略链接到组
将脚本文件另存为 set-IssuancePolicyToGroupLink.ps1。
#######################################
## Parameters to be defined ##
## by the user ##
#######################################
Param (
$IssuancePolicyName,
$groupOU,
$groupName
)
#######################################
## Strings definitions ##
#######################################
Data ErrorMsg {
# culture="en-US"
ConvertFrom-StringData -stringdata @'
help1 = This command can be used to set the link between a certificate issuance policy and a universal security group.
help2 = Usage:
help3 = The following parameters are required:
help4 = -IssuancePolicyName:<name or display name of the issuance policy that you want to link to a group>
help5 = -groupName:<name of the group you want to link the issuance policy to>. If no name is specified, any existing link to a group is removed from the Issuance Policy.
help6 = The following parameter is optional:
help7 = -groupOU:<Name of the Organizational Unit dedicated to the groups which are linked to issuance policies>. If this parameter is not specified, the group is looked for or created in the Users container.
help8 = Examples:
help9 = This command will link the issuance policy whose display name is "High Assurance" to the group "HighAssuranceGroup" in the Organizational Unit "OU_FOR_IPol_linked_groups". If the group or the Organizational Unit do not exist, you will be prompted to create them.
help10 = This command will unlink the issuance policy whose name is "402.164959C40F4A5C12C6302E31D5476062" from any group.
MultipleIPs = Error: Multiple Issuance Policies with name or display name "{0}" were found in the subtree of "{1}"
NoIP = Error: no issuance policy with name or display name "{0}" could be found in the subtree of "{1}".
IPFound = An Issuance Policy with name or display name "{0}" was successfully found: {1}
MultipleOUs = Error: more than 1 Organizational Unit with name "{0}" could be found in the subtree of "{1}".
confirmOUcreation = Warning: The Organizational Unit that you specified does not exist. Do you want to create it?
OUCreationSuccess = Organizational Unit "{0}" successfully created.
OUcreationError = Error: Organizational Unit "{0}" could not be created.
OUFoundSuccess = Organizational Unit "{0}" was successfully found.
multipleGroups = Error: More than one group with name "{0}" was found in Organizational Unit "{1}".
confirmGroupCreation = Warning: The group that you specified does not exist. Do you want to create it?
groupCreationSuccess = Univeral Security group "{0}" successfully created.
groupCreationError = Error: Univeral Security group "{0}" could not be created.
GroupFound = Group "{0}" was successfully found.
confirmLinkDeletion = Warning: The Issuance Policy "{0}" is currently linked to group "{1}". Do you really want to remove the link?
UnlinkSuccess = Certificate issuance policy successfully unlinked from any group.
UnlinkError = Removing the link failed.
UnlinkExit = Exiting without removing the link from the issuance policy to the group.
IPNotLinked = The Certificate issuance policy is not currently linked to any group. If you want to link it to a group, you should specify the -groupName option when starting this script.
ErrorNotSecurity = Error: You cannot link issuance Policy "{0}" to group "{1}" because this group is not of type "Security".
ErrorNotUniversal = Error: You cannot link issuance Policy "{0}" to group "{1}" because the scope of this group is not "Universal".
ErrorHasMembers = Error: You cannot link issuance Policy "{0}" to group "{1}" because it has a non-empty membership. The group has the following members:
ConfirmLinkReplacement = Warning: The Issuance Policy "{0}" is currently linked to group "{1}". Do you really want to update the link to point to group "{2}"?
LinkSuccess = The certificate issuance policy was successfully linked to the specified group.
LinkError = The certificate issuance policy could not be linked to the specified group.
ExitNoLinkReplacement = Exiting without setting the new link.
'@
}
# import-localizeddata ErrorMsg
function Display-Help {
""
write-host $ErrorMsg.help1
""
write-host $ErrorMsg.help2
""
write-host $ErrorMsg.help3
write-host "`t" $ErrorMsg.help4
write-host "`t" $ErrorMsg.help5
""
write-host $ErrorMsg.help6
write-host "`t" $ErrorMsg.help7
""
""
write-host $ErrorMsg.help8
""
write-host $ErrorMsg.help9
".\Set-IssuancePolicyToGroupMapping.ps1 -IssuancePolicyName ""High Assurance"" -groupOU ""OU_FOR_IPol_linked_groups"" -groupName ""HighAssuranceGroup"" "
""
write-host $ErrorMsg.help10
'.\Set-IssuancePolicyToGroupMapping.ps1 -IssuancePolicyName "402.164959C40F4A5C12C6302E31D5476062" -groupName $null '
""
}
# Assumption: The group to which the Issuance Policy is going
# to be linked is (or is going to be created) in
# the domain the user running this script is a member of.
import-module ActiveDirectory
$root = get-adrootdse
$domain = get-addomain -current loggedonuser
if ( !($IssuancePolicyName) ) {
display-Help
break
}
#######################################
## Find the OID object ##
## (aka Issuance Policy) ##
#######################################
$searchBase = [String]$root.configurationnamingcontext
$OID = get-adobject -searchBase $searchBase -Filter { ((displayname -eq $IssuancePolicyName) -or (name -eq $IssuancePolicyName)) -and (objectClass -eq "msPKI-Enterprise-Oid")} -properties *
if ($OID -eq $null) {
$tmp = $ErrorMsg.NoIP -f $IssuancePolicyName, $searchBase
write-host $tmp -ForeGroundColor Red
break;
}
elseif ($OID.GetType().IsArray) {
$tmp = $ErrorMsg.MultipleIPs -f $IssuancePolicyName, $searchBase
write-host $tmp -ForeGroundColor Red
break;
}
else {
$tmp = $ErrorMsg.IPFound -f $IssuancePolicyName, $OID.distinguishedName
write-host $tmp -ForeGroundColor Green
}
#######################################
## Find the container of the group ##
#######################################
if ($groupOU -eq $null) {
# default to the Users container
$groupContainer = $domain.UsersContainer
}
else {
$searchBase = [string]$domain.DistinguishedName
$groupContainer = get-adobject -searchBase $searchBase -Filter { (Name -eq $groupOU) -and (objectClass -eq "organizationalUnit")}
if ($groupContainer.count -gt 1) {
$tmp = $ErrorMsg.MultipleOUs -f $groupOU, $searchBase
write-host $tmp -ForegroundColor Red
break;
}
elseif ($groupContainer -eq $null) {
$tmp = $ErrorMsg.confirmOUcreation
write-host $tmp " ( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
new-adobject -Name $groupOU -displayName $groupOU -Type "organizationalUnit" -ProtectedFromAccidentalDeletion $true -path $domain.distinguishedName
if ($?){
$tmp = $ErrorMsg.OUCreationSuccess -f $groupOU
write-host $tmp -ForegroundColor Green
}
else{
$tmp = $ErrorMsg.OUCreationError -f $groupOU
write-host $tmp -ForeGroundColor Red
break;
}
$groupContainer = get-adobject -searchBase $searchBase -Filter { (Name -eq $groupOU) -and (objectClass -eq "organizationalUnit")}
}
else {
break;
}
}
else {
$tmp = $ErrorMsg.OUFoundSuccess -f $groupContainer.name
write-host $tmp -ForegroundColor Green
}
}
#######################################
## Find the group ##
#######################################
if (($groupName -ne $null) -and ($groupName -ne "")){
##$searchBase = [String]$groupContainer.DistinguishedName
$searchBase = $groupContainer
$group = get-adgroup -Filter { (Name -eq $groupName) -and (objectClass -eq "group") } -searchBase $searchBase
if ($group -ne $null -and $group.gettype().isarray) {
$tmp = $ErrorMsg.multipleGroups -f $groupName, $searchBase
write-host $tmp -ForeGroundColor Red
break;
}
elseif ($group -eq $null) {
$tmp = $ErrorMsg.confirmGroupCreation
write-host $tmp " ( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
new-adgroup -samAccountName $groupName -path $groupContainer.distinguishedName -GroupScope "Universal" -GroupCategory "Security"
if ($?){
$tmp = $ErrorMsg.GroupCreationSuccess -f $groupName
write-host $tmp -ForegroundColor Green
}else{
$tmp = $ErrorMsg.groupCreationError -f $groupName
write-host $tmp -ForeGroundColor Red
break
}
$group = get-adgroup -Filter { (Name -eq $groupName) -and (objectClass -eq "group") } -searchBase $searchBase
}
else {
break;
}
}
else {
$tmp = $ErrorMsg.GroupFound -f $group.Name
write-host $tmp -ForegroundColor Green
}
}
else {
#####
## If the group is not specified, we should remove the link if any exists
#####
if ($OID."msDS-OIDToGroupLink" -ne $null) {
$tmp = $ErrorMsg.confirmLinkDeletion -f $IssuancePolicyName, $OID."msDS-OIDToGroupLink"
write-host $tmp " ( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
set-adobject -Identity $OID -Clear "msDS-OIDToGroupLink"
if ($?) {
$tmp = $ErrorMsg.UnlinkSuccess
write-host $tmp -ForeGroundColor Green
}else{
$tmp = $ErrorMsg.UnlinkError
write-host $tmp -ForeGroundColor Red
}
}
else {
$tmp = $ErrorMsg.UnlinkExit
write-host $tmp
break
}
}
else {
$tmp = $ErrorMsg.IPNotLinked
write-host $tmp -ForeGroundColor Yellow
}
break;
}
#######################################
## Verify that the group is ##
## Universal, Security, and ##
## has no members ##
#######################################
if ($group.GroupScope -ne "Universal") {
$tmp = $ErrorMsg.ErrorNotUniversal -f $IssuancePolicyName, $groupName
write-host $tmp -ForeGroundColor Red
break;
}
if ($group.GroupCategory -ne "Security") {
$tmp = $ErrorMsg.ErrorNotSecurity -f $IssuancePolicyName, $groupName
write-host $tmp -ForeGroundColor Red
break;
}
$members = Get-ADGroupMember -Identity $group
if ($members -ne $null) {
$tmp = $ErrorMsg.ErrorHasMembers -f $IssuancePolicyName, $groupName
write-host $tmp -ForeGroundColor Red
foreach ($member in $members) {write-host " $member.name" -ForeGroundColor Red}
break;
}
#######################################
## We have verified everything. We ##
## can create the link from the ##
## Issuance Policy to the group. ##
#######################################
if ($OID."msDS-OIDToGroupLink" -ne $null) {
$tmp = $ErrorMsg.ConfirmLinkReplacement -f $IssuancePolicyName, $OID."msDS-OIDToGroupLink", $group.distinguishedName
write-host $tmp "( (y)es / (n)o )" -ForegroundColor Yellow -nonewline
$userChoice = read-host
if ( ($userChoice -eq "y") -or ($userChoice -eq "yes") ) {
$tmp = @{'msDS-OIDToGroupLink'= $group.DistinguishedName}
set-adobject -Identity $OID -Replace $tmp
if ($?) {
$tmp = $Errormsg.LinkSuccess
write-host $tmp -Foreground Green
}else{
$tmp = $ErrorMsg.LinkError
write-host $tmp -Foreground Red
}
} else {
$tmp = $Errormsg.ExitNoLinkReplacement
write-host $tmp
break
}
}
else {
$tmp = @{'msDS-OIDToGroupLink'= $group.DistinguishedName}
set-adobject -Identity $OID -Add $tmp
if ($?) {
$tmp = $Errormsg.LinkSuccess
write-host $tmp -Foreground Green
}else{
$tmp = $ErrorMsg.LinkError
write-host $tmp -Foreground Red
}
}
注意
如果在运行此脚本时遇到困难,请尝试替换 ConvertFrom-StringData 参数后的单引号。