Script Repository


Export logon-enabled users with photos

February 24, 2021
1349

The script creates a PDF report on all enabled and not expired user accounts, including their photos.

Note: The script relies on the MigraDoc module .NET library to generate PDF files. Before using the script, do the following:
  1. Download MiraDoc Foundation Libraries.
  2. Copy files located in the GDI+ folder of the downloaded ZIP archive to a certain folder on the computer where Adaxes Service is installed.

To schedule the report, create a scheduled task configured for the Domain-DNS object type that runs the script and assign it over any of your AD domains. To add the script to a scheduled task, use the Run a program or PowerShell script action.

Parameters:

  • $migraDocDllPath - Specifies a path to the folder where files from the MiraDoc GDI+ library are located.
  • $pdfFilePath - Specifies a path to the PDF file that will be created by the script.
  • $header - Specifies the document header.
  • $landscapeOrientation - Specifies document page orientation. Set the parameter to $True if you want landscape orientation or to $False to use portrait orientation.
  • $fontSize - Specifies the font size in points.
  • $fontName - Specifies the font face name.
  • $columnMap - Specifies a map of column names and the corresponding properties of the user accounts. The properties must be specified by their LDAP display names. If you want a column to contain values from more than one property, specify a list of the properties you need separated by commas and enclosing each property in double quotes, for example: "Web Pages" = "wWWHomePage", "url".
  • $columnOrder - Specifies the order in which the columns will appear in the document (left to right). Columns must be specified by their names as defined in $columnMap.
Edit Remove
PowerShell
$migraDocDllPath = "C:\Scripts\MigraDoc" # TODO: modify me

# PDF File Settings
$pdfFilePath = "\\server\share\UserReport.pdf" # TODO: modify me
$header = "User List" # TODO: modify me
$landscapeOrientation = $True # TODO: modify me
$fontSize = 12 # TODO: modify me
$fontName = "Calibri" # TODO: modify me

$columnMap = @{
    "Photo" = "thumbnailPhoto"
    "First Name" = "givenName"
    "Last Name" = "sn"
    "Full Name" = "cn"
    "Company" = "company"
    "Address" = "streetAddress"
    "Phone Numbers" = "telephoneNumber", "mobile", "otherHomePhone", "otherMobile"
} # TODO: modify me
$columnOrder = "Photo", "Full Name", "First Name", "Last Name", "Company", "Address", "Phone Numbers" # TODO: modify me

function GetObjectDisplayName($objectDN)
{
    $objectPath = New-Object -TypeName "Softerra.Adaxes.Adsi.AdsPath" -ArgumentList @($null, $objectDN)
    return [Softerra.Adaxes.Utils.ObjectNameHelper]::GetObjectName($objectPath, "IncludeParentPath")
}

function FindObjects($searhFilter, $propertiesToExport)
{
    # Set search parameters
    $searcher = $Context.BindToObject("Adaxes://rootDSE")
    $searcher.SearchFilter = $searhFilter
    $searcher.PageSize = 500
    $searcher.SearchScope = "ADS_SCOPE_SUBTREE"
    $searcher.SetPropertiesToLoad($propertiesToExport)
    $searcher.VirtualRoot = $True
    
    try
    {
        $searchResultIterator = $searcher.ExecuteSearch()
        $searchResults = $searchResultIterator.FetchAll()
        
        return ,$searchResults
    }
    finally
    {
        # Release resources used by the search
        $searchResultIterator.Dispose()
    }
}

function TooWide($string, $maxWidth)
{
    $width = $xGraphics.MeasureString($string, $xfont).Width
    return $width -gt $maxWidth.Point
}

# Build filter: enabled and not expired users
$currentDate = (Get-Date).ToFileTime()
$filter = "(&(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(accountExpires=>$currentDate)(accountExpires=0)(accountExpires=9223372036854775807)))"

# Get properties to export
$propertiesToExport = @()
$columnMap.Values | %%{$propertiesToExport += $_}

# Find objects and fetch properties
$searchResults = FindObjects $filter $propertiesToExport

if ($searchResults.Length -eq 0)
{
    $Context.LogMessage("No users found", "Information")
    return # Exit script
}

# Import MigraDoc DLLs
$files = Get-ChildItem -Path $migraDocDllPath
$files | %%{Import-Module $_.FullName}

# Create PDF Document
$document = New-Object MigraDoc.DocumentObjectModel.Document
$pageSize = [PdfSharp.PageSizeConverter]::ToSize([PdfSharp.PageSize]::A4)
if ($landscapeOrientation)
{
    $document.DefaultPageSetup.Orientation = [MigraDoc.DocumentObjectModel.Orientation]::Landscape
    $pageWidth = [MigraDoc.DocumentObjectModel.Unit]::FromPoint($pageSize.Height)
}
else
{
    $document.DefaultPageSetup.Orientation = [MigraDoc.DocumentObjectModel.Orientation]::Portrait
    $pageWidth = [MigraDoc.DocumentObjectModel.Unit]::FromPoint($pageSize.Width)
}

# Add empty section
$section = $document.AddSection()
$section.PageSetup.LeftMargin = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter(1)
$section.PageSetup.RightMargin = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter(1)

# Add paragraph and insert the header
$paragraph = $section.AddParagraph()
$paragraph.AddText($header)
$paragraph.Format.Font.Bold = $true
$paragraph.Format.Font.Size = 20
$paragraph = $section.AddParagraph()

# Add table
$table = $section.AddTable()
$table.Borders.Visible = $true
$table.Borders.Width = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter(0.01)
$point = [MigraDoc.DocumentObjectModel.Unit]::FromPoint($fontSize)
$font = New-Object MigraDoc.DocumentObjectModel.Font $fontName, $point
$table.Format.Font = $font

# Add columns
$columnIndex = @{}
$columnWidth = ($pageWidth.Centimeter - 2) / $columnMap.Count

for ($i = 0; $i -lt $columnOrder.Length; $i++)
{
    $column = $table.AddColumn()
    $column.Width = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter($columnWidth)
    $columnName = $columnOrder[$i]
    $columnIndex.Add($columnName, $i)
}

# Add table header
$tableHeader = $table.AddRow()
foreach ($columnName in $columnIndex.Keys)
{
    $index = $columnIndex[$columnName]
    $cell = $tableHeader.Cells[$index]
    $cell.Format.Font.Bold = $True
    [void]$cell.AddParagraph($columnName)
}

$tempFilesToRemove = @() # Temporary files with user pictures

try
{
    # Create XGraphics object
    $pdfDocument = New-Object PdfSharp.Pdf.PdfDocument
    $page = $pdfDocument.AddPage()
    $xGraphics = [PdfSharp.Drawing.XGraphics]::FromPdfPage($page)
    
    # Create font object
    $xfont = New-Object PdfSharp.Drawing.XFont $fontName, $fontSize
    
    # Set cell parameters
    $cellBordersWidth = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter(0.01)
    $cellRightIndent = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter(0.2)
    $cellLeftIndent = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter(0.2)
    $availableWidth = [MigraDoc.DocumentObjectModel.Unit]::FromCentimeter($columnWidth - 
        $table.Borders.Width.Centimeter - $cellBordersWidth.Centimeter - 
        $cellRightIndent.Centimeter - $cellLeftIndent.Centimeter)
    
    # Add user information to the table
    foreach ($searchResult in $searchResults)
    {
        # Create row
        $row = $table.AddRow()

        foreach ($columnName in $columnMap.Keys)
        {
            # Get cell
            $index = $columnIndex[$columnName]
            $cell = $row.Cells[$index]
            
            # Set cell settings
            $cell.Borders.Width = $cellBordersWidth
            $cell.Format.LeftIndent = $cellLeftIndent
            $cell.Format.RightIndent = $cellRightIndent
    
            # Get property values
            $propertyName = $columnMap[$columnName]
            $value = $NULL

            if ($propertyName -is [System.Array])
            {
                $allValues = @()
                foreach ($name in $propertyName)
                {
                    $propertyValues = $searchResult.Properties[$propertyName].Values
                    if ($propertyValues -eq $NULL)
                    {
                        continue
                    }
                    
                    $allValues += $propertyValues
                }
                
                if ($allValues.Length -ne 0)
                {
                    $value = [System.String]::Join("; ", $allValues)
                }
            }
            else
            {
                $values = $searchResult.Properties[$propertyName].Values
                if ($propertyName -eq "thumbnailPhoto" -and $values -ne $NULL)
                {
                    # Create temporary file
                    $tmpFilePath = [System.IO.Path]::GetTempFileName()

                    function ResizePhoto ($thumbnailPhotoBytes, $tmpFilePath)
                    {
                        $original = [System.Drawing.Image]$thumbnailPhotoBytes

                        if (($original.Height -lt 80) -and ($original.Width -lt 80))
                        {
                            # Write photo to file
                            [System.IO.File]::WriteAllBytes($tmpFilePath, $thumbnailPhotoBytes)
                            return
                        }
                        
                        # Calculate the new size, preserve ratio
                        $ratioX = 80 / $original.Width
                        $ratioY = 80 / $original.Height
                        $ratio = $ratioY

                        if ($ratioX -le $ratioY)
                        {
                            $ratio = $ratioX
                        }
                        
                        # Resize the photo to fit in the cell
                        [int]$newWidth = $original.Width * $ratio
                        [int]$newHeight = $original.Height * $ratio
                        
                        $picture = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
                        $graph = [System.Drawing.Graphics]::FromImage($picture)
                        
                        $graph.Clear([System.Drawing.Color]::White)
                        $graph.DrawImage($original, 0, 0, $newWidth, $newHeight)
                        
                        # Write photo to file
                        $picture.Save($tmpFilePath)
                    }

                    ResizePhoto $values[0] $tmpFilePath

                    # Add photo to PDF cell
                    $image = $cell.AddImage($tmpFilePath)
                    $tempFilesToRemove += $tmpFilePath
                    
                    continue
                }
                elseif ($values -ne $NULL)
                {
                    $value = [System.String]::Join("; ", $values)
                }
            }
            
            # Check value length
            if (($value -ne $NULL) -and (TooWide $value $availableWidth))
            {
                # Split the value to fit within column width
                $formatedString = New-Object "System.Text.StringBuilder"
                $current = [System.String]::Empty

                foreach ($char in $value.ToCharArray())
                {
                    $newString = $current + $char
                    if (TooWide $newString $availableWidth)
                    {
                        [void]$formatedString.Append($current)
                        [void]$formatedString.Append([MigraDoc.DocumentObjectModel.Chars]::CR)
                        $current = $char.ToString()
                    }
                    else
                    {
                        $current += $char
                    }
                }

                [void]$formatedString.Append($current)
                $value = $formatedString.ToString()
            }
            
            # Add value to cell
            $cell.AddParagraph($value)
        }
    }
    
    # Render the document
    $renderer = New-Object MigraDoc.Rendering.PdfDocumentRenderer
    $renderer.Document = $document
    $renderer.RenderDocument()
    
    # Write to file
    $renderer.PdfDocument.Save($pdfFilePath)
    
    # Remove temporary files
    foreach ($path in $tempFilesToRemove)
    {
        Remove-Item -Path $path -Force -ErrorAction SilentlyContinue
    }
}
finally
{
    # Release resources
    $pdfDocument.Dispose()
    $xGraphics.Dispose()
}


Comments ( 0 )
No results found.
Leave a comment