Forum Discussion

timjeens's avatar
timjeens
Copper Contributor
May 12, 2025

Automated import of Hardware Hashes into Intune

Hi everyone,

So, here is the script I used to pre-seed the hardware hashes into my Intune environment.

Please check it over before just running it..

You'll need to create a csv called: computernamelist.csv

In this file, you'll need a list of all your computer names like this:

"ComputerName"
"SID-1234"
"SID-4345"

You can use a the Get-ADComputer command to gather all your computers and output to a CSV.

Features:

  • It will run through 10 computers at a time.
  • It will remove computers that it has confirmed as being updated in Intune.
  • Pings a computer first to speed it up.
  • Only for devices on your network or on the VPN.

You can schedule it to run, or I just re-ran it a bunch of times over a few weeks.

 

# Path to the CSV file
$csvPath = "C:\scripts\computernamelist.csv"

# Import the CSV file
$computers = Import-Csv -Path $csvPath

# Number of concurrent jobs (adjust as needed)
$maxConcurrentJobs = 10

# Array to store the job references
$jobs = @()

# Ensure the required settings and script are set up
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned -Force
Install-Script -Name Get-WindowsAutopilotInfo -Force

# Authenticate with Microsoft Graph (Office 365 / Azure AD)
Connect-MGGraph

# Function to remove a computer from the CSV after successful import
function Remove-ComputerFromCSV {
    param (
        [string]$computerName,
        [string]$csvPath
    )
    $computers = Import-Csv -Path $csvPath
    $computers = $computers | Where-Object { $_.ComputerName -ne $computerName }
    $computers | Export-Csv -Path $csvPath -NoTypeInformation
    Write-Host "Removed $computerName from CSV."
}

# Loop through each computer in the CSV
foreach ($computer in $computers) {
    $computerName = $computer.ComputerName

    # Start a new background job for each computer
    $job = Start-Job -ScriptBlock {
        param($computerName, $csvPath)

        # Check if the computer is reachable (ping check)
        if (Test-Connection -ComputerName $computerName -Count 1 -Quiet) {
            Write-Host "$computerName is online. Retrieving Autopilot info..."

            # Ensure TLS 1.2 is used and execution policy is set for the job
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned -Force

            # Run the Autopilot info command and capture the output
            $output = Get-WindowsAutopilotInfo -Online -Name $computerName

            # Check if the output contains the success or error messages
            if ($output -like "*devices imported successfully*") {
                Write-Host "Success: $computerName - Autopilot info imported successfully."

                # Remove the computer from the CSV after successful import
                Remove-ComputerFromCSV -computerName $computerName -csvPath $csvPath
            } elseif ($output -like "*error 806 ZtdDeviceAlreadyAssigned*") {
                Write-Host "Error: $computerName - Device already assigned."
            } else {
                Write-Host "Error: $computerName - Unknown issue during import."
            }
        } else {
            Write-Host "$computerName is offline. Skipping."
        }
    } -ArgumentList $computerName, $csvPath

    # Add the job to the list
    $jobs += $job

    # Monitor job status
    Write-Host "Started job for $computerName with Job ID $($job.Id)."

    # If the number of jobs reaches the limit, wait for them to complete
    if ($jobs.Count -ge $maxConcurrentJobs) {
        # Wait for all current jobs to complete before starting new ones
        $jobs | ForEach-Object {
            Write-Host "Waiting for Job ID $($_.Id) ($($_.State)) to complete..."
            $_ | Wait-Job
            Write-Host "Job ID $($_.Id) has completed."
        }

        # Check job output and clean up completed jobs
        $jobs | ForEach-Object {
            if ($_.State -eq 'Completed') {
                $output = Receive-Job -Job $_
                Write-Host "Output for Job ID $($_.Id): $output"
                Remove-Job $_
            } elseif ($_.State -eq 'Failed') {
                Write-Host "Job ID $($_.Id) failed."
            }
        }

        # Reset the jobs array
        $jobs = @()
    }
}

# Wait for any remaining jobs to complete
$jobs | ForEach-Object {
    Write-Host "Waiting for Job ID $($_.Id) ($($_.State)) to complete..."
    $_ | Wait-Job
    Write-Host "Job ID $($_.Id) has completed."
}

# Check job output for remaining jobs
$jobs | ForEach-Object {
    if ($_.State -eq 'Completed') {
        $output = Receive-Job -Job $_
        Write-Host "Output for Job ID $($_.Id): $output"
        Remove-Job $_
    } elseif ($_.State -eq 'Failed') {
        Write-Host "Job ID $($_.Id) failed."
    }
}

 

This is all derived from: https://learn.microsoft.com/en-us/autopilot/add-devices

"Get-WindowsAutopilotInfo" is from this link.

Hope this helps someone.

Thanks,

Tim Jeens

Resources