Access PDQ Info with Powershell

Access PDQ Info with Powershell

You read that right, access PDQ information with PowerShell. You will need the PS SQL Lite module first. This module will allow you to access the SQL lite server. The second thing you will need is a Powershell script on the server accessing the module information. Then finally you will need to be able to access that script remotely. Let’s install the PSSQLite first. Do this on the PDQ server as the script that will be interacting with the SQLite database is on that server.

Install-Module -Name PSSQLite -RequiredVersion 1.0.3

Now we ill build a script on the PDQ server. The folder should be accessible by anyone you want to run this script. Let’s look at the starting points.

First we will import the module using the Import-Module command.

Import-Module PSSQLite

Next we need to declare the database. By default the database is located under the C > ProgramData > Admin Arsenal > PDQ Inventory > Database.db if it is not, you will need to declare it here.

$Database = "C:\ProgramData\Admin Arsenal\PDQ Inventory\database.db"

Before we continue, this script is designed to grab just a single computer’s information. If you choose to grab more than one computer, this can cause PDQ to crash and even the server to crash. So, play itself and don’t be too greedy. With that said, Let’s grab the computers with the computer name. from the server. This is our first SQL query of the script. It’s also the most important as it gives us the Computer ID. Without it, nothing else will work.

$Computer = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Computers WHERE Name LIKE '$ComputerName'"

The Command to grav the SQL lite database information is Invoke-SQLiteQuery. Watch out because I made the mistake of adding an additional L while typing it. We select the data base as the data source. And the rest is very much like SQL commands. Inside our Query we select everything from the computers table where the name is like the computer name we provide. This gives us a lot of useful data that can be used else where. Once again, the ComputerID is the most important part of this data.

We will repeat this process but instead of looking for the name, we will be looking for the computerID inside our SQL Query from each table.

Apps = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Applications WHERE ComputerID LIKE '$($Computer.ComputerID)'"

Here we are selecting everything from the Application table where the ComputerID is like $($Computer.ComputerID). Without the first command the second command would not run. From here you can do each table like this until you create a list of data you want. You can place the data inside the [pscustomobject] and pump that out for use else where. Here is a full list of items I grab.

[pscustomobject]@{
    Computer = $Computer
    CPU = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM CPUs WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    CustomInfo = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM CustomComputerValues WHERE ComputerID LIKE '%$($Computer.ComputerId)%'"                 
    Apps = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Applications WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    PDQDeployments = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM PDQDeployments WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    DiskDrives = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM DiskDrives WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Displays = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Displays WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    EnvironmentVariables = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM EnvironmentVariables WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    HardwareDevices = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM HardwareDevices WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    HotFixes = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM HotFixes WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    LocalUsers = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM LocalUsers WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    LocalGroups = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM LocalGroups WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    LocalGroupMembers = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM LocalGroupMembers WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    MemoryModules = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM MemoryModules WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    NetworkAdapters = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM NetworkAdapters WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    LocalPrinters = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Printers WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    ProductKeys = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM ProductKeys WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Profiles = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM PowerShellScanner_4aa0b92dc0524234a90075fa296d3f84_View WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Scanns = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM ScanProfileComputers WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Services = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Services WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Shares = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Shares WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    SharesPermission = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM SharePermissions WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    WindowsFeatures = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM WindowsFeatures WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    WindowsTaskSchedules = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM WindowsTaskSchedules WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    DesktopShortcuts = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM Files WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Activation = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM PowerShellScanner_6162ffd7f94249d6a4964b5c08fad9b3_View WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    Bitlocker = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM PowerShellScanner_f609ba7492b54dbeaf1d7d72b05d50e4_View WHERE ComputerID LIKE '$($Computer.ComputerID)'"
    GPO = Invoke-SqliteQuery -DataSource $Database -Query "SELECT * FROM WMIScanner_31_View WHERE ComputerID LIKE '$($Computer.ComputerID)'"
}

I want to point out the Profiles object. This is the PowerShell scanner name for the profile size scanner. To grab the table names I suggest using the SQLite browser. You can download it here: Link.

Notice the bottom right hand side there is text. This text is the commands. You can browse around and find good information.

The call

Now you must create a function to call the script. This part is the easy part. We will be using the Invoke-command to trigger the script in question.

$Test = Invoke-Command -ComputerName $ServerName -ScriptBlock { c:\PSScripts\PDQ-Calls\Get-PDQComputerData.ps1 -ComputerName $args[0] } -ArgumentList $Computer

Now test will provide a large number of information for you. You can sort this information however you like. It will look something like this:

if ($Quick) {
        [PSCustomObject]@{
            Computername      = $test.computer.Name
            IPAddress         = $Test.Computer.IPAddress
            MacAddress        = $test.Computer.MacAddress
            CurrentUser       = $Test.Computer.CurrentUser
            BootTime          = $test.computer.BootTime
            Manufacturer      = $test.computer.Manufacturer
            Model             = $test.computer.model 
            SystemFamily      = $test.Computer.SystemFamily
            Chassis           = $test.Computer.Chassis
            SerialNumber      = $test.Computer.SerialNumber
            CPU               = $test.CPU.name
            Memory            = "$($Test.Computer.Memory /1gb)/gb"
            DiskDriveSize     = "$($Test.DiskDrives.Size /1gb)/gb"
            OSname            = $Test.Computer.OSName
            PhysicalDiskType  = $Test.DiskDrives.PhysicalDiskType
            bitlocker         = $test.bitlocker.ProtectionStatus
            WindowsActivation = $test.Activation.StatusReason
            WebrootVersion    = ($test.apps | where-object { $_.name -like "*webroot*" }).Version
            TeamViewerVersion = ($test.apps | where-object { $_.name -like "*TeamViewer*" }).Version
        }
    }

The above code is part of a script that will give me quick information. As you see, it should be treated as an XML because the data is loaded like an XML.

One of the things I have done is used this inside my universal dashboard to allow quick information that is formatted nicely.

Watch out

  • Here are some gotyas. If the database is busy, sqlite will break down on you.
  • If the disk is busy, the SQL lite will break down on you.
  • Don’t make to many requests as it slows everything down.

PDQ Auto Deploy

PDQ Auto Deploy

We use PDQ where I work, and I am lazy. So, I have made a way to set up devices into Different OUs. This way when I am gone, it’s as easy as putting a computer into an OU and walks away. When I image, The image will load the OS and put the computer into the OU for me, which makes it even sweeter. Then PDQ will hit that OU, check the file, and bam, off to the races with the most up to date software. Makes a great hybrid solution.

Here are a few things you will need before we get started.

  • A Licensed version of PDQ.
  • A laptop Deployment Package
  • A general knowledge of how the conditions work in package deployments.

We first make a new package deployment. This package deployment will have the Laptop package deployment nested inside of it. We will place a special condition on this deployment package. On your new package deployment, select properties and then conditions. Under File we will select “Does Not Exist” and put a directory of your choice and a filename of your choice.

Initial Install – Laptop Base

Your first step is the laptop base install. I name my deployments with a CTP if it is complete. The second step is the “Done” step which creates the condition file. This way it will not redeploy, but you can force it by deleting the file.

Now you have the initial install package built, it’s time to build the scheduling.

  • Right click on the deployment package
  • Select New Schedule
  • Under Targets tab, click choose targets
  • Select Active Directory
  • Select Containers
  • Select the OU you want.
  • Under Triggers select the Interval button
    • Here you change the Time ranges. we do an hour as it takes 30 minutes for the laptop deployment to go through.
  • Select the Package tab
  • Confirm your package is located there.
  • Under Options
    • Here you can tell it to stop redeploying if the deployment was successful. We don’t want to do that because we have a condition and we don’t want it to stay in that OU. This is a good way to create a reminder for yourself by having the Notification send you emails.
  • You’re done.

A quick way to add a computer to the OU while setting it up is the Add-Computer Command.

Add-Computer -DomainName <Your Domain> -OUPath <OU Path for the Initial Install> -NewName <New Computer Name> -Credential (Get-Credential) -restart 

This command will add the computer to the OU that you want and restart it. Make sure you have a group policy set to the OU to turn off or Open the ports on the firewall.

Thank you for reading.