3

I'm attempting to read and eventually write the DACLs for printers shared from my print server. Here's what I have so far, based on scripts found around the internet:

    $pace = DATA {            
ConvertFrom-StringData -StringData @'
983052 = ManagePrinters
983088 = ManageDocuments
131080 = Print 
524288 = TakeOwnership
131072 = ReadPermissions
262144 = ChangePermissions 
'@            
}             
$flags = @(983052, 983088, 131080, 524288, 131072, 262144)

$printers = Get-WmiObject -Class Win32_Printer -ComputerName "NAME"
"Got Printers"

foreach ($printer in $printers)
{
     ""
     "Printer:  $($printer.DeviceID)"

    $sd = $printer.GetSecurityDescriptor()            
    $ssd = $sd.Descriptor.DACL
    foreach ($obj3 in $ssd)
    {
        ""
        "$($obj3.Trustee.Domain) $($obj3.Trustee.Name)"         
        foreach ($flag in $flags)
        {            
            if ($obj3.AccessMask -band $flag)
            {            
                $pace["$($flag)"]
            }
        }            
    }
}

However, I can't make sense of the output. It seems like there are duplicate entries for each domain/name pair except for Creator Owner. However, the duplicates have different access masks than the first. Which ones are the entries I want to look at if I want to confirm the permissions are what I see in the printer's security tab? Writing new permissions shouldn't be a problem once I figure out which access masks to set.

Edit: There also seems to be a problem with the loop to read the bit mask. I got that from another script that's supposed to work.

Edit: Here's some sample output I'm trying to understand:

Got Printers

Printer:  printer

DOMAIN jshier
AccessMask: 983052
ManagePrinters
ManageDocuments
Print
TakeOwnership
ReadPermissions
ChangePermissions

DOMAIN jshier
AccessMask: 983088
ManagePrinters
ManageDocuments
Print
TakeOwnership
ReadPermissions
ChangePermissions

 CREATOR OWNER
AccessMask: 268435456

 Everyone
AccessMask: 131080
ManagePrinters
ManageDocuments
Print
ReadPermissions

 Everyone
AccessMask: 536870912

BUILTIN Administrators
AccessMask: 983052
ManagePrinters
ManageDocuments
Print
TakeOwnership
ReadPermissions
ChangePermissions

BUILTIN Administrators
AccessMask: 268435456

This output doesn't match what I see in the Advanced Security Settings for the printer. For example, the first instance of my user account should have all permissions except "Manage documents". And Everyone should just have a single entry with permissions for "Print" and "Read permissions". Am I missing something in my AccessMask conversion?

BTW, this is Win. Server 2008 R2.

Jon Shier
  • 133
  • 1
  • 5

1 Answers1

4

That sounds like the expected behavior to me. For example, if you examine the printer security using the Printer Management console, you may notice that there is a single ACE entry for a given security principal, with checkboxes for Print, Manage this Printer, and Management Documents.

However, if you click the Advanced security page, there may be two ACE's for that security principal, one for Manage this Printer and a second for Manage Documents, and there is usually an ACE for Everyone for the Print permission.

If you are interested in how the operating system defines and interprets these permissions, here is one possible view. As you can see, Manage Printers includes several other permissions, so that may explain the output.

[Flags]
public enum PrinterRights : int
{
    None = 0,
    Print = (ACCESS_MASK.PRINTER_ACCESS_USE | ACCESS_MASK.READ_CONTROL),
    ManageDocuments = (ACCESS_MASK.JOB_ACCESS_ADMINISTER | ACCESS_MASK.JOB_ACCESS_READ | ACCESS_MASK.DELETE | ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WRITE_DAC | ACCESS_MASK.WRITE_OWNER),
    ManagePrinters = (ACCESS_MASK.PRINTER_ACCESS_ADMINISTER | ACCESS_MASK.PRINTER_ACCESS_USE | ACCESS_MASK.DELETE | ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WRITE_DAC | ACCESS_MASK.WRITE_OWNER),
    ReadPermissions = ACCESS_MASK.READ_CONTROL,
    ChangePermissions = ACCESS_MASK.WRITE_DAC,
    TakeOwnership = ACCESS_MASK.WRITE_OWNER
}

[Flags]
public enum ACCESS_MASK : int
{
    #region Bits 01-15: Specific Rights
    /// <summary>
    /// Authorization to cancel, pause, resume, or restart the job.
    /// </summary>
    JOB_ACCESS_ADMINISTER = 0x00000010,
    /// <summary>
    /// Read rights for the spool file.
    /// </summary>
    JOB_ACCESS_READ = 0x00000020,
    /// <summary>
    /// Access rights for jobs combining STANDARD_RIGHTS_EXECUTE, JOB_ACCESS_ADMINISTER, and PRINTER_ACCESS_USE.
    /// </summary>
    JOB_EXECUTE = (STANDARD_RIGHTS.EXECUTE | JOB_ACCESS_ADMINISTER | PRINTER_ACCESS_USE),
    /// <summary>
    /// Access rights for jobs combining STANDARD_RIGHTS_REQUIRED, JOB_ACCESS_READ, and JOB_ACCESS_ADMINISTER.
    /// </summary>
    JOB_READ = (STANDARD_RIGHTS.REQUIRED | JOB_ACCESS_READ | JOB_ACCESS_ADMINISTER),
    /// <summary>
    /// Access rights for jobs combining STANDARD_RIGHTS_WRITE, JOB_ACCESS_ADMINISTER, and PRINTER_ACCESS_USE.
    /// </summary>
    JOB_WRITE = (STANDARD_RIGHTS.WRITE | JOB_ACCESS_ADMINISTER | PRINTER_ACCESS_USE),


    /// <summary>
    /// Access rights for printers to perform administrative tasks.
    /// </summary>
    PRINTER_ACCESS_ADMINISTER = 0x00000004,
    /// <summary>
    /// Access rights for printers to perform basic printing operations.
    /// </summary>
    PRINTER_ACCESS_USE = 0x00000008,
    /// <summary>
    /// Access rights for printers to perform all administrative tasks and basic printing operations except SYNCHRONIZE. Combines STANDARD_RIGHTS_REQUIRED, PRINTER_ACCESS_ADMINISTER, and PRINTER_ACCESS_USE.
    /// </summary>
    PRINTER_ALL_ACCESS = (STANDARD_RIGHTS.REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE),
    /// <summary>
    /// Access rights for printers combining STANDARD_RIGHTS_EXECUTE and PRINTER_ACCESS_USE.
    /// </summary>
    PRINTER_EXECUTE = (STANDARD_RIGHTS.EXECUTE | PRINTER_ACCESS_USE),
    /// <summary>
    /// Access rights for printers combining STANDARD_RIGHTS_READ and PRINTER_ACCESS_USE.
    /// </summary>
    PRINTER_READ = (STANDARD_RIGHTS.READ | PRINTER_ACCESS_USE),
    /// <summary>
    /// Access rights for printers combining STANDARD_RIGHTS_WRITE and PRINTER_ACCESS_USE.
    /// </summary>
    PRINTER_WRITE = (STANDARD_RIGHTS.WRITE | PRINTER_ACCESS_USE),


    /// <summary>
    /// Access rights to administer print servers.
    /// </summary>
    SERVER_ACCESS_ADMINISTER = 0x00000001,
    /// <summary>
    /// Access rights to enumerate print servers.
    /// </summary>
    SERVER_ACCESS_ENUMERATE = 0x00000002,
    /// <summary>
    /// Access rights for print servers to perform all administrative tasks and basic printing operations except SYNCHRONIZE. Combines STANDARD_RIGHTS_REQUIRED, SERVER_ACCESS_ADMINISTER, and SERVER_ACCESS_ENUMERATE.
    /// </summary>
    SERVER_ALL_ACCESS = (STANDARD_RIGHTS.REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE),
    /// <summary>
    /// Access rights for print servers combining STANDARD_RIGHTS_EXECUTE and SERVER_ACCESS_ENUMERATE. 
    /// </summary>
    SERVER_EXECUTE = (STANDARD_RIGHTS.EXECUTE | SERVER_ACCESS_ENUMERATE),
    /// <summary>
    /// Access rights for print servers combining STANDARD_RIGHTS_READ and SERVER_ACCESS_ENUMERATE.
    /// </summary>
    SERVER_READ = (STANDARD_RIGHTS.READ | SERVER_ACCESS_ENUMERATE),
    /// <summary>
    /// Access rights for print servers combining STANDARD_RIGHTS_WRITE, SERVER_ACCESS_ADMINISTER, and SERVER_ACCESS_ENUMERATE.
    /// </summary>
    SERVER_WRITE = (STANDARD_RIGHTS.WRITE | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE),

    SPECIFIC_RIGHTS_ALL = 0x0000ffff,
    #endregion
    #region Bits 16-23: Standard Rights
    /// <summary>
    /// The right to delete the object.
    /// </summary>
    DELETE = BASE_RIGHTS.DELETE,
    /// <summary>
    /// The right to read the information in the object's security descriptor, not including the information in the SACL.
    /// </summary>
    READ_CONTROL = BASE_RIGHTS.READ_CONTROL,
    /// <summary>
    /// The right to modify the DACL in the object's security descriptor.
    /// </summary>
    WRITE_DAC = BASE_RIGHTS.WRITE_DAC,
    /// <summary>
    /// The right to change the owner in the object's security descriptor.
    /// </summary>
    WRITE_OWNER = BASE_RIGHTS.WRITE_OWNER,
    /// <summary>
    /// The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. Some object types do not support this access right.
    /// </summary>
    SYNCHRONIZE = BASE_RIGHTS.SYNCHRONIZE,

    /// <summary>
    /// Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access
    /// </summary>
    STANDARD_REQUIRED = STANDARD_RIGHTS.REQUIRED,
    /// <summary>
    /// Currently defined to equal READ_CONTROL
    /// </summary>
    STANDARD_READ = STANDARD_RIGHTS.READ,
    /// <summary>
    /// Currently defined to equal READ_CONTROL
    /// </summary>
    STANDARD_WRITE = STANDARD_RIGHTS.WRITE,
    /// <summary>
    /// Currently defined to equal READ_CONTROL
    /// </summary>
    STANDARD_EXECUTE = STANDARD_RIGHTS.EXECUTE,
    /// <summary>
    /// Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and SYNCHRONIZE access
    /// </summary>
    STANDARD_ALL = STANDARD_RIGHTS.ALL,
    #endregion
    #region Bit  24...: Access System Security
    /// <summary>
    /// Access system security (ACCESS_SYSTEM_SECURITY). It is used to indicate access to a system access control list (SACL). This type of access requires the calling process to have the SE_SECURITY_NAME (Manage auditing and security log) privilege. If this flag is set in the access mask of an audit access ACE (successful or unsuccessful access), the SACL access will be audited.
    /// </summary>
    ACCESS_SYSTEM_SECURITY = 0x01000000,
    #endregion
    #region Bit  25...: Maximum allowed
    /// <summary>
    /// Maximum allowed (MAXIMUM_ALLOWED).
    /// </summary>
    MAXIMUM_ALLOWED = 0x02000000,
    #endregion
    #region Bits 26-27: Reserved
    #endregion
    #region Bits 28-31: Generic Rights
    /// <summary>
    /// Generic all 
    /// </summary>
    GENERIC_ALL = 0x10000000,
    /// <summary>
    /// Generic execute 
    /// </summary>
    GENERIC_EXECUTE = 0x20000000,
    /// <summary>
    /// Generic write 
    /// </summary>
    GENERIC_WRITE = 0x40000000,
    /// <summary>
    /// Generic read 
    /// </summary>
    //GENERIC_READ = 0x80000000
    #endregion
}

/// <summary>
/// Standard Access Rights
/// </summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa379607(VS.85).aspx"/>
[Flags]
public enum BASE_RIGHTS : int
{
    /// <summary>
    /// The right to delete the object.
    /// </summary>
    DELETE = 0x00010000,
    /// <summary>
    /// The right to read the information in the object's security descriptor, not including the information in the SACL.
    /// </summary>
    READ_CONTROL = 0x00020000,
    /// <summary>
    /// The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. Some object types do not support this access right.
    /// </summary>
    SYNCHRONIZE = 0x00100000,
    /// <summary>
    /// The right to modify the DACL in the object's security descriptor.
    /// </summary>
    WRITE_DAC = 0x00040000,
    /// <summary>
    /// The right to change the owner in the object's security descriptor.
    /// </summary>
    WRITE_OWNER = 0x00080000
}

/// <summary>
/// Standard Access Rights
/// </summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa379607(VS.85).aspx"/>
[Flags]
public enum STANDARD_RIGHTS : int
{
    /// <summary>
    /// Currently defined to equal READ_CONTROL
    /// </summary>
    READ = BASE_RIGHTS.READ_CONTROL,
    /// <summary>
    /// Currently defined to equal READ_CONTROL
    /// </summary>
    WRITE = BASE_RIGHTS.READ_CONTROL,
    /// <summary>
    /// Currently defined to equal READ_CONTROL
    /// </summary>
    EXECUTE = BASE_RIGHTS.READ_CONTROL,
    /// <summary>
    /// Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access
    /// </summary>
    REQUIRED = (BASE_RIGHTS.DELETE | BASE_RIGHTS.READ_CONTROL | BASE_RIGHTS.WRITE_DAC | BASE_RIGHTS.WRITE_OWNER),
    /// <summary>
    /// Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and SYNCHRONIZE access
    /// </summary>
    ALL = (BASE_RIGHTS.DELETE | BASE_RIGHTS.READ_CONTROL | BASE_RIGHTS.SYNCHRONIZE | BASE_RIGHTS.WRITE_DAC | BASE_RIGHTS.WRITE_OWNER)
}
Greg Askew
  • 34,339
  • 3
  • 52
  • 81
  • Added some example output if you want to take a look. – Jon Shier Apr 09 '13 at 20:59
  • Ok, so clearly a given security principal (jshier) with two ACE's does have one for Manage this Printer (983052) and Manage Documents (983088). As expected. Why the PowerShell command $pace["$($flag)"] outputs all that other text - it may be due to the Manage this Printer implies the other permissions. I will update the answer so that you can see what the printer permissions mean in its full glory. – Greg Askew Apr 09 '13 at 21:14
  • Thanks. I'll take another look and see if I can get some saner output. – Jon Shier Apr 09 '13 at 23:46
  • I've been able to integrate your enums into my script but the results still aren't making sense. I just added two groups through the printer's security dialog and they have the same AccessMask despite one of them not having the "Manage Documents" permission checked. They are both 983052. – Jon Shier Apr 10 '13 at 13:03
  • Nevermind, that just means they both have the "Manage Printers" attribute. – Jon Shier Apr 10 '13 at 13:25