The script creates and emails 2 lists: a list of computers where Bitlocker is installed and a list of computers where it is not installed.
To generate such a report on demand, create a custom command configured for the Domain-DNS object type. To generate it on a regular basis, create a scheduled task and include any of your AD domains in the Activity Scope.
Script 1: Report in Excel
The script creates and emails an Excel report with 2 lists: a list of computers where Bitlocker is installed, and a list of computers where it is not installed.
Parameters:
- $xlFilePath - Specifies a path to the Excel file that will be created by the script.
- $removeXlFile - Specifies whether to remove the Excel file after sending.
- $to - Specifies a recipient of the report.
- $subject - Specifies the email message subject.
- $from - Specifies the email address from which the notification will be sent.
- $smtpServer - Specifies the SMTP server to use for sending the report.
$xlFilePath = "C:\scripts\BitlockerReport.xlsx" # TODO: modify me
$removeXlFile = $True # TODO: modify me
# E-mail settings
$to = "recipient@domain.com" # TODO: modify me
$subject = "Bitlocker Report" # TODO: modify me
$from = "noreply@domain.com" # TODO: modify me
$smtpServer = "mail.domain.com" # TODO: modify me
function SearchObjects($filter, $properties)
{
$searcher = $Context.BindToObject("Adaxes://rootDSE")
$searcher.SearchFilter = $filter
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500
$searcher.ReferralChasing = "ADS_CHASE_REFERRALS_NEVER"
$searcher.SetPropertiesToLoad($properties)
$searcher.VirtualRoot = $True
try
{
$searchResultIterator = $searcher.ExecuteSearch()
$searchResults = $searchResultIterator.FetchAll()
return ,$searchResults
}
finally
{
# Release resources
if ($searchResultIterator){ $searchResultIterator.Dispose() }
}
}
function ReleaseComObjects($objArray)
{
foreach ($object in $objArray)
{
[System.Runtime.Interopservices.Marshal]::FinalReleaseComObject($object)
}
}
# Get all BitLoker objects
$bitlockerSearchResults = SearchObjects "(objectClass=msFVE-RecoveryInformation)" @("distinguishedName")
$computersWithBitlocker = New-Object "System.Collections.Generic.HashSet[System.String]"
foreach ($searchResult in $bitlockerSearchResults)
{
$dn = New-Object "Softerra.Adaxes.Ldap.DN" $searchResult.Properties["distinguishedName"].Value
[void]$computersWithBitlocker.Add($dn.Parent)
}
# Search all computers
$computers = SearchObjects "(objectCategory=computer)" @("distinguishedName", "description", "operatingSystem")
try
{
# Create Excel COM object
try
{
$objExcel = New-Object -ComObject Excel.Application
}
catch
{
$errorMessage = "Cannot create an Excel object." + $_.Exception.Message
Write-Error $errorMessage
return
}
$objExcel.Visible = $false
$objExcel.DisplayAlerts = $false
$objExcel.AskToUpdateLinks = $false
$objExcel.AlertBeforeOverwriting = $false
$workbook = $objExcel.Workbooks.Add()
$list = $workbook.Worksheets.Item(1)
$list.Name = $subject
$cells = $list.Cells
$computersWithBitlockerRecords = New-Object "System.Collections.ArrayList"
$computersWithoutBitlockerRecords = New-Object "System.Collections.ArrayList"
foreach ($searchResult in $computers)
{
# Get computer info
$computerName = $Context.GetDisplayNameFromAdsPath($searchResult.AdsPath)
$description = $searchResult.Properties["description"].Value
$operatingSystem = $searchResult.Properties["operatingSystem"].Value
# Build record
$record = New-Object "System.Collections.ArrayList"
[void]$record.Add($computerName)
[void]$record.Add($description)
[void]$record.Add($operatingSystem)
$dn = $searchResult.Properties["distinguishedName"].Value
if ($computersWithBitlocker.Contains($dn))
{
$computersWithBitlockerRecords.Add($record)
}
else
{
$computersWithoutBitlockerRecords.Add($record)
}
}
if ($computersWithBitlockerRecords.Count -ne 0)
{
# Create an array for computer with BitLocker records
$rows = New-Object "object[,]" $computersWithBitlockerRecords.Count, 3
for ($i = 0; $i -lt $computersWithBitlockerRecords.Count; $i++)
{
$record = $computersWithBitlockerRecords[$i]
for($j = 0; $j -lt $record.Count; $j++)
{
$rows[$i,$j] = $record[$j]
}
}
# Add records to the Excel file
$cells.Item(1, 1) = "Computers with BitLocker"
$cells.Item(2, 1) = "Name"
$cells.Item(2, 2) = "Description"
$cells.Item(2, 3) = "Operating System"
$cells.Item(1, 1).Font.Bold = $True
$cells.Item(2, 1).Font.Bold = $True
$cells.Item(2, 2).Font.Bold = $True
$cells.Item(2, 3).Font.Bold = $True
$list.Range($cells.Item(3, 1), $cells.Item($computersWithBitlockerRecords.Count + 2, 3)).Value2 = $rows
}
if ($computersWithoutBitlockerRecords.Count -ne 0)
{
if ($computersWithBitlockerRecords.Count -ne 0)
{
$startRecord = $computersWithBitlockerRecords.Count + 6
}
else
{
$startRecord = 3
}
# Create an array for computer without BitLocker records
$rows = New-Object "object[,]" $computersWithoutBitlockerRecords.Count, 3
for ($i = 0; $i -lt $computersWithoutBitlockerRecords.Count; $i++)
{
$record = $computersWithoutBitlockerRecords[$i]
for($j = 0; $j -lt $record.Count; $j++)
{
$rows[$i,$j] = $record[$j]
}
}
# Add records to Excel file
$cells.Item($startRecord - 2, 1) = "Computers without BitLocker"
$cells.Item($startRecord - 1, 1) = "Name"
$cells.Item($startRecord - 1, 2) = "Description"
$cells.Item($startRecord - 1, 3) = "Operating System"
$cells.Item($startRecord - 2, 1).Font.Bold = $True
$cells.Item($startRecord - 1, 1).Font.Bold = $True
$cells.Item($startRecord - 1, 2).Font.Bold = $True
$cells.Item($startRecord - 1, 3).Font.Bold = $True
$list.Range($cells.Item($startRecord, 1), $cells.Item($computersWithoutBitlockerRecords.Count + 1, 3)).Value2 = $rows
}
$usedRange = $list.UsedRange
[void]$usedRange.EntireColumn.AutoFit()
$workbook.SaveCopyAs($xlFilePath)
# Send mail
Send-MailMessage -To $to -from $from -SmtpServer $smtpServer -Subject $subject -Body "BitLocker report" -Attachments $xlFilePath
if ($removeXlFile)
{
# Remove the file
Remove-Item -Path $xlFilePath -Force
}
}
finally
{
# Quit Excel application
ReleaseComObjects @($cells, $usedRange, $list)
$workbook.Close($False)
ReleaseComObjects @($workbook)
$objExcel.Quit()
ReleaseComObjects @($objExcel)
}
Script 2: Report in CSV
The script creates and emails 2 CSV files: one with a list of computers where Bitlocker is installed, and another with a list of computers where it is not installed.
Parameters:
- $computersWithBitlockerCsvFilePath - Specifies a path to the CSV file that will contain computers with Bitlocker installed.
- $computersWithoutBitlockerCsvFilePath - Specifies a path to the CSV file that will contain computers with not Bitlocker installed.
- $removeCSVFile - Specifies whether to remove the CSV files after sending.
- $to - Specifies a recipient of the report.
- $subject - Specifies the email message subject.
- $from - Specifies the email address from which the notification will be sent.
- $smtpServer - Specifies the SMTP server to use for sending the report.
# CSV file settings
$computersWithBitlockerCsvFilePath = "C:\scripts\ComputersWithBitlocker.csv" # TODO: modify me
$computersWithoutBitlockerCsvFilePath = "C:\scripts\ComputersWithoutBitlocker.csv" # TODO: modify me
$removeCSVFile = $True # TODO: modify me
# Mail settings
$to = "recipient@domain.com" # TODO: modify me
$subject = "Bitlocker Report" # TODO: modify me
$from = "noreply@domain.com" # TODO: modify me
$smtpServer = "mail.domain.com" # TODO: modify me
function SearchObjects($criteria, $properties)
{
$searcher = $Context.TargetObject
$searcher.Criteria = $criteria
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500
$searcher.ReferralChasing = "ADS_CHASE_REFERRALS_NEVER"
$searcher.SetPropertiesToLoad($properties)
$searcher.VirtualRoot = $True
try
{
# Execute search
$searchResultIterator = $searcher.ExecuteSearch()
$searchResults = $searchResultIterator.FetchAll()
return ,$searchResults
}
finally
{
# Release resources
if ($searchResultIterator){ $searchResultIterator.Dispose() }
}
}
# Get all BitLoker objects
$criteria = New-AdmCriteria "msFVE-RecoveryInformation"
$computersWithBitlocker = New-Object "System.Collections.Generic.HashSet[System.String]"
foreach ($searchResult in $bitlockerSearchResults)
{
$dn = New-Object "Softerra.Adaxes.Ldap.DN" $searchResult.Properties["distinguishedName"].Value
[void]$computersWithBitlocker.Add($dn.Parent)
}
# Search all computers
$computersCriteria = New-AdmCriteria "computer"
$computersSearchResult = SearchObjects $computersCriteria @("distinguishedName", "description", "operatingSystem")
$computersWithBitlockerRecords = New-Object "System.Collections.ArrayList"
$computersWithoutBitlockerRecords = New-Object "System.Collections.ArrayList"
foreach ($searchResult in $computersSearchResult)
{
# Get computer info
$computerName = $Context.GetDisplayNameFromAdsPath($searchResult.AdsPath)
$description = $searchResult.Properties["description"].Value
$operatingSystem = $searchResult.Properties["operatingSystem"].Value
# Build record
$recordProperties = [ordered]@{
"Name" = $computerName;
"Description" = $description;
"Operating System" = $operatingSystem
}
$record = New-Object PSObject -Property $recordProperties
$dn = $searchResult.Properties["distinguishedName"].Value
if ($computersWithBitlocker.Contains($dn))
{
$computersWithBitlockerRecords.Add($record)
}
else
{
$computersWithoutBitlockerRecords.Add($record)
}
}
$computersWithBitlockerRecords | Export-csv -NoTypeInformation -Path $computersWithBitlockerCsvFilePath
$computersWithoutBitlockerRecords | Export-csv -NoTypeInformation -Path $computersWithoutBitlockerCsvFilePath
# Send mail
Send-MailMessage -To $to -from $from -SmtpServer $smtpServer -Subject $subject -Body "BitLocker report" -Attachments @($computersWithBitlockerCsvFilePath, $computersWithoutBitlockerCsvFilePath)
if ($removeCSVFile)
{
# Remove the file
Remove-Item -Path $computersWithBitlockerCsvFilePath -Force
Remove-Item -Path $computersWithoutBitlockerCsvFilePath -Force
}
Hello Mark,
As per our check, the script works fine with Adaxes 2019.2. Most probably, the issue is related to Excel and not Adaxes or the script itself. We will add a version of the script that will create 2 CSV files for computers with Bitlocker installed/not installed.