param (
[Parameter(Mandatory=$False)]
[Alias('s')]
[string] $ninjaScriptingDir = "C:\ProgramData\NinjaRMMAgent\scripting\",
[Parameter(Mandatory=$False)]
[Alias('f')]
[string] $dbFile = 'ninja.sqlite',
[Parameter(Mandatory=$False)]
[Alias('d')]
[switch]$sDebug = $True # default in production is $False
)
#
# requires: Install-Module -name PSSQLite
Import-Module PSSQLite
#
$Script:testDbDir = Join-Path -Path $ninjaScriptingDir -ChildPath "db"
[System.Collections.ArrayList]$dbPrinterNames = @()
$Script:dbPrinterNames = New-Object System.Collections.ArrayList($null) # ArrayList to hold printer names on system
# this will hold all the 'discovered' printers:
[System.Collections.ArrayList]$foundPrinterNames = @()
$Script:foundPrinterNames = New-Object System.Collections.ArrayList($null)
#
if ($sDebug) { Write-Host "Running with parameters: " }
if ($sDebug) { Write-Host "Ninja Scripting Directory:" $ninjaScriptingDir }
if ($sDebug) { Write-Host "Database File Name:" $dbFile }
if ($sDebug) { Write-Host "Is Debugging Enabled?" $sDebug }
if ($sDebug) { Write-Host "Full Path to Database File:" $testDbDir }
#
###################################################################
#
# functions
#
# DoesNameExist(<string: Name of printer>)
#
Function DoesPrinterNameExist ($printerName=$null) {
if ($sDebug) { Write-Host "in DoesPrinterNameExist with [$printerName]" }
$abcq = "SELECT * FROM main.printers WHERE main.printers.Name = '$printerName'"
$dpneIsInTable = Invoke-SqliteQuery -DataSource $Database -Query $abcq
if ($sDebug) { Write-Host "printerName given: [$printerName]" }
if ($sDebug) { Write-Host "dpneIsInTable table: [$dpneIsInTable]" }
if ($sDebug) { Write-Host "dpneIsMatch.Count: " $dpneIsTable.Count }
if ($sDebug) { Write-Host "Hash: " $_.Hash }
if ($sDebug) { Write-Host "Name: " $_.Name }
if ($dpneIsInTable -eq $null) {
if ($sDebug) { Write-Host "match: $printerName is: false!" }
return $false
} else {
if ($sDebug) { Write-Host "match: $printerName is: true!" }
return $true
}
}
#
# Get-StringHash "string to be hashed" "algorythm"
#
# algorythms include: MD5, RIPEMD160, SHA1, SHA256, SHA384, SHA512
# uses MD5 by default
#
# see: http://jongurgul.com/blog/get-stringhash-get-filehash/
Function Get-StringHash([String] $String,$HashName = "MD5") {
$StringBuilder = New-Object System.Text.StringBuilder
[System.Security.Cryptography.HashAlgorithm]::Create($HashName).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String))|%{
[Void]$StringBuilder.Append($_.ToString("x2"))
}
$StringBuilder.ToString()
}
#
# Get-HashByPrinterName $printerName
#
Function Get-HashByPrinterName([String] $ghbpnPrinterName) {
$ghbpnq = "SELECT * FROM main.printers WHERE main.printers.Name = '$ghbpnPrinterName'"
$ghbpnResult = Invoke-SqliteQuery -DataSource $Database -Query $ghbpnq
$h = $ghbpnResult.Hash
if ($sDebug) { Write-Host "Hash for $ghbpnPrinterName is: " $h }
Return $h
}
#
# GetPrinterNamesDB
#
Function GetPrinterNamesDB() {
[System.Collections.ArrayList]$dbPrinterNamesTemp = @()
# temporary ArrayList to hold printer names on system
$dbPrinterNamesTemp = New-Object System.Collections.ArrayList($null)
$gpndbq = "SELECT Name FROM main.printers"
$gpndbqResult = Invoke-SqliteQuery -DataSource $Database -Query $gpndbq
ForEach ($sName in $gpndbqResult) {
[void]$dbPrinterNamesTemp.Add($sName.Name)
if ($sDebug) { Write-Host "added [$sName] to dbPrinterNames" }
}
Return $dbPrinterNamesTemp
}
#
#########################################################################
#
# program starts here
#
if ($sDebug) { Write-Host "____________________________________________________________" }
#
# Is the right sqlite db directory present?
#
if (Test-Path $testDbDir) {
if ($sDebug) { Write-Host "dir exists" }
$Database = Join-Path $testDbDir $dbFile
} else {
if ($sDebug) { Write-Host "dir does NOT exist" }
# untested on several deep dirs
New-Item -Path $testDbDir -ItemType Directory
}
#
# Is the database file on disk?
#
if (Test-Path $Database) {
# nothing to do
if ($sDebug) { Write-Host "DB at $Database already exists!" }
} else {
if ($sDebug) { Write-Host "DB at $Database doesn't exist: creating!" }
$cqry = "CREATE TABLE printers (
Name VARCHAR(200),
Location TEXT,
PrinterState TEXT,
PrinterStatus TEXT,
ShareName TEXT,
SystemName TEXT,
LastUpdated DATETIME,
Hash TEXT,
PRIMARY KEY(Name)
)"
Invoke-SqliteQuery -Query $cqry -DataSource $Database
} # end of If (Test-Path $Database...
#
#####
#
# Load a list with the configured printers
#
# what is in the db Table 'printers' ($dbPrinterNames)?
$dbPrinterNames = GetPrinterNamesDB
ForEach ($prtName in $dbPrinterNames) {
if ($sDebug) { Write-Host "DB Printer Name: [$prtName]" }
}
#
# Grab all currentprinters, and do somethig with each:
#
Get-WMIObject Win32_Printer -ComputerName $env:COMPUTERNAME |
ForEach-Object {
$pName = $_.Name
if ($sDebug) { Write-Host "Name: " $pName }
$pLocation = $_.Location
if ($sDebug) { Write-Host "Location: " $pLocation }
$pPrinterState = $_.PrinterState
if ($sDebug) { Write-Host "PrinterState: " $pPrinterState }
$pPrinterStatus = $_.PrinterStatus
if ($sDebug) { Write-Host "PrinterStatus: " $pPrinterStatus }
$pShareName = $_.ShareName
if ($sDebug) { Write-Host "ShareName: " $pShareName }
$pSystemName = $_.SystemName
if ($sDebug) { Write-Host "SystemName: " $pSystemName }
#
# this string comprised of all printer attributes is used to detrmine, via hash, if it has changed
#
$pConcatStrings = -join ($pName, $pLocation, $pPrinterState, $pPrinterStatus, $pShareName, $pSystemName)
if ($sDebug) { Write-Host "pConcatStrings: $pConcatStrings" }
#
# $pHash is holding the chksum of the FOUND printer:
#
$pHash = Get-StringHash $pConcatStrings # using default algorythm
if ($sDebug) { Write-Host "pHash: $pHash" }
#
#####
#
# After all found printers, subtract this 'found' printer from the
# 'known' DB Printer ArrayList. This allows us to delete what is
# left in the array from the DB.
#
$foundPrinterNames.Add($pName)
$dbPrinterNames.Remove($pName)
#
# Determine if the printer discovered already exists in the 'printers' table
#
if (DoesPrinterNameExist $pName) {
#
# printer found IS aleady in the 'printers' table
#
if ($sDebug) { Write-Host "Printer already in printers table... " }
if ($pHash -eq (Get-HashByPrinterName $pName)) {
#
# checksum of found and stored printers (by .Name) are a match, so nothing to update
#
if ($sDebug) { Write-Host "Found and stored entries are the same-no update or create needed." }
} else {
#
# checksum of found and stored printers (by .Name) are NOT a match, so we need to update that row (entry)
#
if ($sDebug) { Write-Host "Found and stored entries do NOT match. Need to UPDATE existing row." }
#
$printerUpdateQuery = "UPDATE main.printers SET
Location = @Location,
PrinterState = @PrinterState,
PrinterStatus = @PrinterStatus,
ShareName = @ShareName,
SystemName = @SystemName,
LastUpdated = @InfoDate,
Hash = @Hash
WHERE
main.printers.Name = '$pName'"
if ($sDebug) { Write-Host "updating printer with printerUpdateQuery: " $printerUpdateQuery }
Invoke-SqliteQuery -DataSource $Database -Query $printerUpdateQuery -SqlParameters @{
Location = $pLocation
PrinterState = $pPrinterState
PrinterStatus = $pPrinterStatus
ShareName = $pShareName
SystemName = $pSystemName
LastUpdated = (Get-Date)
Hash = $pHash
} # end Invoke-SqliteQuery
} # end of if ($pHash -eq...
} else {
#
# printer found is NOT aleady in the 'printers' table, need to insert it
#
if ($sDebug) { Write-Host "Printer NOT already in printers table... " }
$iqry = "INSERT INTO printers (Name, Location, PrinterState,
PrinterStatus, ShareName, SystemName, LastUpdated, Hash)
VALUES (@Name, @Location, @PrinterState, @PrinterStatus, @ShareName, @SystemName, @LastUpdated, @Hash)"
if ($sDebug) { Write-Host "creating printer with iqry: " $iqry }
Invoke-SqliteQuery -DataSource $Database -Query $iqry -SqlParameters @{
Name = $pName
Location = $pLocation
PrinterState = $pPrinterState
PrinterStatus = $pPrinterStatus
ShareName = $pShareName
SystemName = $pSystemName
LastUpdated = (Get-Date)
Hash = $pHash
} # end Invoke-SqliteQuery
} # end DoesPrinterNameExist $pName...
} # end For-EachObject
if ($sDebug) { Write-Host "foundPrinterNames:" $foundPrinterNames }
if ($sDebug) { Write-Host "dbPrinterNames:" $dbPrinterNames }
#
# subtract the found from the db, so we can delete the diference in the db:
#
if ($sDebug) { Write-Host "pre-Number dbase printer names to delete:" $dbPrinterNames.Count }
if ($sDebug) { Write-Host "pre-Number found printer names in databs:" $foundPrinterNames.Count }
# $dbPrinterNames should now be either empty, or have rows that need to be deleted.
ForEach ($deleteName in $dbPrinterNames) {
$deleteSql = "DELETE FROM main.printers WHERE main.printers.Name = '$deleteName'"
$r = Invoke-SqliteQuery -DataSource $Database -Query $deleteSql
if ($sDebug) { Write-Host "Deleted $deleteName" }
}
if ($sDebug) { Write-Host "post-Number found printer names in databs:" (GetPrinterNamesDB).Count }