Powershell 打印自定义每个打印机权限

问题描述 投票:0回答:1

首先,我要感谢大家帮助我解决我的问题。

范围: 我希望编写一个脚本来动态构建每台打印机的全套权限。由于每台打印机都有自己的动态组,并且不允许将所有人组应用于打印机。

示例:

打印机名称:打印机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 方法

设置打印机权限.ps1

爱的安全描述符定义语言(第二部分)

为共享添加多个权限

这些确实让我走上了正确的道路!它让我可以替换打印机上的权限。但它会剥夺所有现有权限,只添加为打印机指定的单个权限。我需要向打印机应用一整套权限,如上所示。我有点超出我的范围,但正在学习如何构建多 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 ?我的想法是验证代码开始部分中的参数,并在其中一个验证失败时退出。不知道是否有更好的方法。

powershell security acl network-printers
1个回答
0
投票

上周左右我经历了与你完全相同的过程。您最终成功获得了“管理文档”功能吗?

© www.soinside.com 2019 - 2024. All rights reserved.