Public/Connect-PdqInventoryScanner.ps1

<#
.SYNOPSIS
Connects Scanners to a Scan Profile by reading the contents of the clipboard.
 
.DESCRIPTION
When this function executes, it will clear your clipboard and give you a couple of prompts.
It retrieves IDs from the data you copied to your clipboard, then accesses your database.
The Scanner IDs and Scan Profile ID will be inserted into the ScanProfileScanner table.
 
.INPUTS
None.
 
.OUTPUTS
None.
 
.EXAMPLE
Connect-PdqInventoryScanner
Displays a couple of prompts, then inserts some data into your database.
#>

function Connect-PdqInventoryScanner {

    [CmdletBinding()]
    param (
    )

    # https://www.reddit.com/r/pdq/comments/iyfsku/experimental_scanners_can_be_tied_to_multiple/
    Assert-PdqMinimumVersion -Product 'Inventory' -MinimumVersion '19.2.68.0'

    Write-Host ''
    Write-Host 'Open a Scan Profile and copy the Scanner(s) you would like to connect to a different Scan Profile.'
    Write-Host 'You can copy Scan Profiles instead, if you would like to select ALL of their Scanners.'

    $ScannerId = New-Object System.Collections.Generic.List[String]
    $Skipped = $false

    switch ( Wait-PdqClipboardData -Format 'Scanner', 'ScanProfile' ) {
        'Scanner' {
            $Scanner = Get-PdqClipboardData -Format 'Scanner'

            Write-Host ''
            Write-Host 'These the Scanner(s) you selected:'

            foreach ( $ScannerIterator in $Scanner ) {

                Write-Verbose $ScannerIterator.SourceScannerId
                
                if ( $ScannerIterator.TypeName -in 'Files', 'Registry', 'PowerShell', 'WMI' ) {

                    $ScannerId.Add($ScannerIterator.SourceScannerId)

                    if ( $ScannerIterator.TypeName -in 'PowerShell', 'WMI' ) {
                    
                        Write-Host "$($ScannerIterator.TypeName) - $($ScannerIterator.Name)"

                    } else {

                        Write-Host "$($ScannerIterator.TypeName) - ID: $($ScannerIterator.SourceScannerId)"

                    }

                } else {

                    Write-Warning "Skipped: $($ScannerIterator.TypeName)"
                    $Skipped = $true

                }

            }

            Write-Host ''
        }
        'ScanProfile' {
            $ScanProfile = Get-PdqClipboardData -Format 'ScanProfile'

            Write-Host ''
            Write-Host 'These are the Scan Profile(s) you selected and the Scanners they contain:'

            foreach ( $ScanProfileIterator in $ScanProfile.'AdminArsenal.Export'.ScanProfile ) {

                Write-Host $ScanProfileIterator.Name
                
                foreach ( $ScannerIterator in $ScanProfileIterator.Scanners.Scanner ) {

                    Write-Verbose $ScannerIterator.SourceScannerId.value
                
                    if ( $ScannerIterator.TypeName -in 'Files', 'Registry', 'PowerShell', 'WMI' ) {

                        $ScannerId.Add($ScannerIterator.SourceScannerId.value)

                        if ( $ScannerIterator.TypeName -in 'PowerShell', 'WMI' ) {
                    
                            Write-Host " $($ScannerIterator.TypeName) - $($ScannerIterator.Name)"

                        } else {

                            Write-Host " $($ScannerIterator.TypeName) - ID: $($ScannerIterator.SourceScannerId.value)"

                        }

                    } else {

                        Write-Warning "Skipped: $($ScannerIterator.TypeName)"
                        $Skipped = $true

                    }

                }

            }

            Write-Host ''
        }
    }

    if ( $ScannerId.Count -eq 0 ) {

        if ( $Skipped ) {

            throw 'Every scanner was skipped. Please select one or more configurable scanners.'

        } else {
        
            throw 'Unable to retrieve any Scanner IDs from the clipboard.'

        }

    }

    

    Write-Host 'Copy the Scan Profile you would like to connect the selected Scanner(s) to.'
    Wait-PdqClipboardData -Format 'ScanProfile'

    $ScanProfile = Get-PdqClipboardData -Format 'ScanProfile'

    if ( $ScanProfile.'AdminArsenal.Export'.ScanProfile.Count -gt 1 ) {

        throw 'You cannot select more than 1 Scan Profile at this step.'

    }

    $ScanProfileId = $ScanProfile.'AdminArsenal.Export'.ScanProfile.ScanProfileId.value
    $ScanProfileName = $ScanProfile.'AdminArsenal.Export'.ScanProfile.Name

    if ( -not $ScanProfileId ) {

        throw 'Unable to retrieve the Scan Profile ID from the clipboard.'

    }

    Write-Verbose "Scan Profile ID: $ScanProfileId"
    Write-Host "You selected: $ScanProfileName"



    try {

        $CloseConnection = Open-PdqSqlConnection -Product 'Inventory'

        foreach ( $ScannerIdIterator in $ScannerId ) {
            
            $CurrentScanProfilesQuery = "SELECT ScanProfileId FROM ScanProfileScanner WHERE ScannerId = $ScannerIdIterator;"
            $CurrentScanProfiles = (Invoke-SqlQuery -Query $CurrentScanProfilesQuery -ConnectionName 'Inventory').ScanProfileId
            Write-Verbose "Scanner ID $ScannerIdIterator is currently in these Scan Profiles: $($CurrentScanProfiles -join ', ')"
            if ( $ScanProfileId -in $CurrentScanProfiles ) {

                Write-Warning "Scan Profile '$ScanProfileName' already contains ScannerId $ScannerIdIterator."
                continue

            }

            $ScanProfileScannerQuery = "INSERT INTO ScanProfileScanner (ScanProfileId, ScannerId) VALUES ($ScanProfileId, $ScannerIdIterator)"
            $null = Invoke-SqlUpdate -Query $ScanProfileScannerQuery -ConnectionName 'Inventory'

        }

        Write-Host ''
        Write-Host 'Success! Please refresh the PDQ Inventory console.'

    } finally {

        Close-PdqSqlConnection -Product 'Inventory' -CloseConnection $CloseConnection

    }

}