首先,我要感谢大家帮助我解决我的问题。
范围: 我希望编写一个脚本来动态构建每台打印机的全套权限。由于每台打印机都有自己的动态组,并且不允许将所有人组应用于打印机。
示例:
打印机名称:打印机A
打印机广告组: gprt_PrinterA
其他组分配了对打印机的完整(打印/管理文档/管理打印机)权限:本地管理员/本地高级用户/本地打印操作员/网络管理员(域组)
对打印机具有管理文档和打印权限的其他组: 端点(域组)/服务台(域组)/gprt_PrinterA(域组)\
首先什么有效,我在网上看到了很多关于此的示例,但不满足我的要求:
$DefaultPrinterInfo = Get-Printer -Name PrinterA -Full
Set-Printer -Name PrinterB -PermissionSDDL ($DefaultPrinterInfo.PermissionSDDL)
重要: 但这并不能满足所需的规格。原因是gprt_PrinterA组不能存在于PrinterB上。 PrinterB 必须具有 gprt_PrinterB 组。
在一个例子中,我尝试:
Set-Printer -Name PrinterB -PermissionSDDL "G:SYD:(A;;LCSWSDRCWDWO;;;BA)(A;OIIO;RPWPSDRCWDWO;;;BA)"
我什至尝试动态创建所需的默认权限组,如果这有效,那么我很容易再添加 1 个动态分配的组:
(A;;LCSWSDRCWDWO;;;BA)(A;OIIO;RPWPSDRCWDWO;;;BA)
(A;;LCSWSDRCWDWO;;;PU)(A;OIIO;RPWPSDRCWDWO;;;PU)
(A;;LCSWSDRCWDWO;;;PO)(A;OIIO;RPWPSDRCWDWO;;;PO)
(A;;LCSWSDRCWDWO;;;S-1-5-21-51083937-621610274-1850952788-69794)(A;OIIO;RPWPSDRCWDWO;;;S-1-5-21-51083937-621610274-1850952788-69794)
(A;CIIO;RC;;;S-1-5-21-51083937-621610274-1850952788-69792)(A;OIIO;RPWPSDRCWDWO;;;S-1-5-21-51083937-621610274-1850952788-69792)(A;;SWRC;;;S-1-5-21-51083937-621610274-1850952788-69792)
(A;CIIO;RC;;;S-1-5-21-51083937-621610274-1850952788-69791)(A;OIIO;RPWPSDRCWDWO;;;S-1-5-21-51083937-621610274-1850952788-69791)(A;;SWRC;;;S-1-5-21-51083937-621610274-1850952788-69791)
为了便于阅读,我保持了各组的干净,但本质上只是使其成为一条连续的线,开头带有“G:SYD:”。然后替换上面powershell语句中的PermissionSDDL。不管怎样,我不断收到错误:“[Set-Printer:访问特定资源被拒绝]”
我什至尝试做以下事情:
Win32_Printer 类的 SetSecurityDescriptor 方法
这些确实让我走上了正确的道路!它让我可以替换打印机上的权限。但它会剥夺所有现有权限,只添加为打印机指定的单个权限。我需要向打印机应用一整套权限,如上所示。我有点超出我的范围,但正在学习如何构建多 ACL 包以应用于打印机。
如果我可以分配一整套权限,我可以替换所有权限,或者简单地添加和删除现有权限(如果它们存在或不存在)。
我在研究中了解到,权限集需要是:
打印/管理这台打印机
# G:SYD:(A;;LCSWSDRCWDWO;;;$SID)
打印
# G:SYD:(A;;SWRC;;;$SID)
打印/管理此打印机/管理文档/特殊权限
# G:SYD:(A;;LCSWSDRCWDWO;;;$SID)(A;OIIO;RPWPSDRCWDWO;;;$SID)
我希望有人能帮我找出解决方案。
好吧,经过广泛研究后,我越来越接近了。
“Set-PrinterPermission”脚本位于正确的路径上。我必须做的就是从脚本中删除 ACE 函数,将其放入它自己的函数中。
function New-PrinterACE
{
##[CmdletBinding(SupportsShouldProcess)]
Param (
[Parameter(
Mandatory = $true,
HelpMessage = "User/group to grant permissions"
)]
[String]$UserName,
[Parameter(
Mandatory = $true,
HelpMessage = "Permissions to apply"
)]
[ValidateSet('Takeownership', 'ReadPermissions', 'ChangePermissions', 'ManageDocuments', 'ManagePrinters', 'Print + ReadPermissions')]
[String]$Permission,
[Parameter(
Mandatory = $true,
HelpMessage = "Permissions to apply"
)]
[ValidateSet('Allow', 'Deny', 'System Audit')]
[String]$AccessType
)
$Ace = ([WMIClass] "Win32_Ace").CreateInstance()
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()
Write-Verbose "Translating UserName (user or group) to SID"
$SID = (New-Object security.principal.ntaccount $UserName).translate([security.principal.securityidentifier])
Write-Verbose "Get binary form from SID and byte Array"
[byte[]]$SIDArray = , 0 * $SID.BinaryLength
$SID.GetBinaryForm($SIDArray, 0)
Write-Verbose "Fill Trustee object parameters"
$Trustee.Name = $UserName
$Trustee.SID = $SIDArray
Write-Verbose "Translating $Permission to the corresponding Access Mask"
Write-Verbose "Based on https://learn.microsoft.com/en-US/windows/win32/cimwin32prov/setsecuritydescriptor-method-in-class-win32-printer?redirectedfrom=MSDN"
Write-Verbose "https://social.technet.microsoft.com/Forums/Windows/en-US/a67e3ffd-5e41-4e2f-b1b9-c7c2f29a3a12/adding-permissions-to-an-existing-share"
switch ($Permission)
{
'Takeownership'
{
$Ace.AccessMask = "524288"
}
'ReadPermissions'
{
$Ace.AccessMask = "131072"
}
'ChangePermissions'
{
$Ace.AccessMask = "262144"
}
'ManageDocuments'
{
$Ace.AccessMask = "983088"
}
'ManagePrinters'
{
$Ace.AccessMask = "983052"
}
'Print + ReadPermissions'
{
$Ace.AccessMask = "131080"
}
}
Write-Verbose "Translating $AccessType to the corresponding numeric value"
Write-Verbose "Based on https://learn.microsoft.com/en-US/windows/win32/cimwin32prov/setsecuritydescriptor-method-in-class-win32-printer?redirectedfrom=MSDN"
switch ($AccessType)
{
"Allow"
{
$Ace.AceType = 0
$Ace.AceFlags = 0
}
"Deny"
{
$Ace.AceType = 1
$Ace.AceFlags = 1
}
"System Audit"
{
$Ace.AceType = 2
$Ace.AceFlags = 2
}
}
Write-Verbose "Write Win32_Trustee object to Win32_Ace Trustee property"
$Ace.Trustee = $Trustee
Return $ACE
}
$MyPrinterAces = @()
$MyPrinterAces += New-PrinterACE -UserName <DomainUserA> -Permission ManagePrinters -AccessType Allow
$MyPrinterAces += New-PrinterACE -UserName <DomainUserA> -Permission ManageDocuments -AccessType Allow
$MyPrinterAces += New-PrinterACE -UserName "DomainGroupA" -Permission ManageDocuments -AccessType Allow
$MyPrinterAces += New-PrinterACE -UserName "DomainGroupA" -Permission 'Print + ReadPermissions' -AccessType Allow
#https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-security-descriptor-objects#example-checking-who-has-access-to-printers
#https://stackoverflow.com/questions/60261292/explicit-access-array-from-acl-win32-api
对此,对“Set-PrinterPermission”脚本进行了一些其他修饰修改以适应;因此,它现在引用此函数来构建它使用的 ACE,并添加其容纳具有权限类型的多个用户/组的数组的能力。
function Set-PrinterPermission
{
[CmdletBinding(SupportsShouldProcess)]
Param (
[Parameter(
Mandatory = $true,
HelpMessage = "Server or array of servers",
ParameterSetName = 'OnePrinter'
)]
[Parameter(
Mandatory = $true,
HelpMessage = "Server or array of servers",
ParameterSetName = 'AllPrinters'
)]
[string[]]$Servers,
[Parameter(
HelpMessage = "Name of the Printer",
ParameterSetName = 'OnePrinter'
)]
[String]$PrinterName,
$PrinterPermissions =
@(
@('Administrators', 'ManagePrinters','Allow'),
@('Power Users', 'ManagePrinters','Allow'),
@('Print Operators', 'ManagePrinters','Allow'),
@('OHD – Network Support Team', 'ManagePrinters','Allow'),
@("OHD – PC Support Team", 'Print + ReadPermissions','Allow'),
@("OHD - Service Desk Users", 'Print + ReadPermissions','Allow')
)
)
Begin
{
$greenCheck =
@{
Object = [Char]8730
ForegroundColor = 'Green'
NoNewLine = $true
}
ConvertFrom-SddlString -Sddl $printer.PermissionSDDL
#Write-Host "Status check... " -NoNewline
#Start-Sleep -Seconds 1
#Write-Host @greenCheck
#Write-Host " (Done)"
Write-Output "Beginning Treatment ..."
Write-Verbose "creating instances of necessary classes ..."
$SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
$Aces = @()
Foreach ($PrinterPermission in $PrinterPermissions)
{
$Aces += New-PrinterACE -UserName $PrinterPermission[0] -Permission $PrinterPermission[1] -AccessType $PrinterPermission[2]
}
Write-Verbose "Write Win32_Ace and Win32_Trustee objects to SecurityDescriptor object"
$SD.DACL = $Aces
Write-Verbose "Set SE_DACL_PRESENT control flag"
$SD.ControlFlags = 0x0004
}
process
{
try
{
If ($PSCmdlet.ParameterSetName -eq "OnePrinter")
{
ForEach ($Server in $Servers)
{
$Printer = Get-Printer -ComputerName $Server -Name $PrinterName -ErrorAction Stop
$PrinterName = $Printer.name
Write-Output "Beginning treatment of: $PrinterName On: $Server"
Write-Verbose "Get printer object"
<#
It seems that i can't use the Filter parameter using a var
$PrinterWMI = Get-WMIObject -Class WIN32_Printer -Filter "name = $PrinterName"
I've also noticed that I've haven't the same result using Get-CimInstance in particular with
$PrinterCIM.psbase.scope
However I'm sure that using Get-CiMInstance will be better, but i don't know how to proceed
then I'm using the following "Legacy" approach
https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/the-security-descriptor-definition-language-of-love-part-1/ba-p/395202
https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/the-security-descriptor-definition-language-of-love-part-2/ba-p/395258
http://docs.directechservices.com/index.php/category-blog-menu/319-the-security-descriptor-definition-language-of-love
https://learn.microsoft.com/en-us/windows/win32/secauthz/ace-strings?redirectedfrom=MSDN
https://learn.microsoft.com/en-us/windows/win32/secauthz/access-tokens
#>
#$PrinterWMI = (Get-WmiObject -Class WIN32_Printer | Where-Object -FilterScript { $_.Name -like "wilpa0p11" }).GetSecurityDescriptor().Descriptor.dacl
$PrinterWMI = Get-WmiObject -Class WIN32_Printer | Where-Object -FilterScript { $_.Name -like $PrinterName }
Write-Verbose "Enable SeSecurityPrivilege privilegies"
$PrinterWMI.psbase.Scope.Options.EnablePrivileges = $true
Write-Verbose "Invoke SetSecurityDescriptor method and write new ACE to specified"
$PrinterWMI.SetSecurityDescriptor($SD)
Write-Verbose "Treatment of $PrinterName : Completed"
}
} # end if OnePrinter Parameter Set
If ($PSCmdlet.ParameterSetName -eq "AllPrinters")
{
ForEach ($Server in $Servers)
{
$Printers = Get-Printer -ComputerName $Server | Where-Object { $_.Shared -eq $true } -ErrorAction Stop
ForEach ($Printer in $Printers)
{
$PrinterName = $Printer.name
Write-Output "Beginning treatment of : $PrinterName"
Write-Verbose "Get printer object"
<#
It seems that i can't use the Filter parameter using a var
$PrinterWMI = Get-WMIObject -Class WIN32_Printer -Filter "name = $PrinterName"
I've also noticed that I've haven't the same result using Get-CimInstance in particular with
$Printer.psbase.scope
then I'm using the following approach
However I'm sure that using Get-CiMInstance will be better
#>
$PrinterWMI = Get-WmiObject -Class WIN32_Printer | Where-Object -FilterScript { $_.Name -like $PrinterName }
Write-Verbose "Enable SeSecurityPrivilege privilegies"
$PrinterWMI.psbase.Scope.Options.EnablePrivileges = $true
Write-Verbose "Invoke SetSecurityDescriptor method and write new ACE to specified"
$PrinterWMI.SetSecurityDescriptor($SD)
Write-Output "Treatment of $PrinterName : Completed"
}
}
} # end if All Printers Parameter Set
} # End Try
catch
{
Write-Error "Hoops an error occured"
Write-Error $_.Exception.Message
}
}
end
{
Write-Output "All treatments : completed"
}
} # end function
现在效果很好,我可以轻松添加动态组作为参数,并且 ACE 将被分配给打印机的安全描述符。 现在我的问题是我无法向打印机添加“管理文档”权限。如果有人可以帮助我,我将完成我的项目。 仅针对打印和管理打印机正确分配权限。
需要帮助解决的主要问题: 我现在已经非常接近了...将“管理文档”权限应用于打印机 ACL 时我做错了什么? 下图是脚本尝试应用“管理文档”权限的结果。
非常小的美容帮助: 有没有办法验证代码参数部分中的 $PrinterPermissions ?我的想法是验证代码开始部分中的参数,并在其中一个验证失败时退出。不知道是否有更好的方法。
上周左右我经历了与你完全相同的过程。您最终成功获得了“管理文档”功能吗?