Automating Software Installs for Imaged Computers

Today we’ll look at automating software installs for imaged computers, all while saving yourself some storage space and more importantly…time.

Before you get started here, you’ll want to have an Active Directory security group and OU for imaged machines set.

Automating Software Installs for Imaged Computers

PowerShell Code

The PowerShell code is really pretty straightforward. It looks to the OU you created where machines will be dropped after they are added to Active Directory by the imaging process. You can set the frequency to whatever fits best with your environment.

New additions to this OU will be assigned to the security group you create, and once they are deployed and moved out of the Imaging OU and into the OU where they will serve their life sentence, the script removes them from the security group. This all syncs up with the dynamic collection you will create in PDQ Inventory!

It’s pretty slick in once you have an image created, and machines in the OU, the PowerShell script works with PDQ Deploy and PDQ Inventory to deploy your baseline applications to the machines. The script will also generate email notifications, alerting you to any changes that it has made to the security group.

#######################################################
# END USER DEFINED VARS #
#######################################################
#Array for computers that will be removed
$removed = @()
#Array of hostnames stripped from $search
$sanitized = @()
#Array of hostnames stripped from $members
$memsanitized = @()
#########################################################
# CONTAINERS FOR CHANGED HOSTS #
#########################################################
#table for hosts added to the Baseline group
$addedtable = New-Object System.Data.DataTable "Added Hosts"
$addedcolumn = New-Object System.Data.DataColumn Name, ([string])
$addedtable.Columns.Add($addedcolumn)
#table for hosts removed from the baseline group
$removedtable = New-Object System.Data.DataTable "Removed Hosts"
$removedcolumn = New-Object System.Data.DataColumn Name, ([string])
$removedtable.Columns.Add($removedcolumn)
####################################
# ADD TO GROUP #
####################################
Foreach ($s in $search){
$sanitized += $s.SamAccountName
}
#If exists in group, skip, else add.
Foreach ($san in $sanitized){
If (Get-ADGroupMember "TUSC Baseline" | Where { $_.SamAccountName -eq $san}){
 Out-Null
 }
Else {
 Add-ADPrincipalGroupMembership -Identity $san -MemberOf "$securitygroup" 
 #actually add data to added table.
 $addedrow = $addedtable.NewRow()
 $addedrow.Name = $san
 $addedtable.Rows.Add($addedrow)
 
 }
}
########################################
# REMOVE FROM GROUP #
########################################
#Trim group members down to a new array of just hostnames
Foreach ($mem in $members){
 $memsanitized += $mem.SamAccountName
}
 
#Do some logic that compares the array and dumps differences to a new array. This array will contain members that need the group stripped away. 
Foreach ($ms in $memsanitized){
 If ($sanitized -contains $ms){
 Out-Null
 
 }
 Else {
 $removed += $ms
 }
}
#If there is actually something in the $removed array, take action and removed that machine from the group.
If ($removed -ge 1) {
 Foreach ($rem in $removed){
 Remove-ADPrincipalGroupMembership -Identity $rem -MemberOf "$securitygroup" -Confirm:$False
 #add data to removed table
 $removedrow = $removedtable.NewRow()
 $removedrow.Name = $rem
 $removedtable.Rows.Add($removedrow)
  }
}
#Counts on the datatables to determine if email will be sent.
$acount = $addedtable.Rows.Count
$rcount = $removedtable.Rows.Count
If ($acount -and $rcount -eq 0) {
Out-Null
}
Else {
###########################################################
# CONVERSION TO HTML TABLE FOR EMAIL #
###########################################################
#This builds the table for machines added to TUSC Baseline
$ahtml = "<br><table><tr><td>Hostnames Added to TUSC Baseline</td></tr><br>"
foreach ($arow in $addedtable.Rows){
 $ahtml += "<tr><td>" + $arow.Name + "</td></tr>"
}
$ahtml += "</table> <br>"
#This builds the table for machines removed from TUSC Baseline
$rhtml = "<br><table><tr><td>Hostnames Removed from TUSC Baseline</td></tr><br><br>"
foreach($rrow in $removedtable.Rows) {
$rhtml += "<tr><td>" + $rrow.Name + "</td></tr>"
}
$rhtml += "</table>"
########################################################
# SEND EMAIL REPORT #
########################################################
#Send the message
#Send-MailMessage -SmtpServer $smtpserver -From $from -to $to -Subject $subject -Body $body -BodyAsHtml
}
$addedtable.Dispose()
$removedtable.Dispose()
Exit

Run this script as a scheduled task. You will want to create the task to run as an account that has been delegated access to manage group memberships in Active Directory. I recommend setting up the scheduled task as a Service Account that has been delegated access to change group memberships in Active Directory.

Also, the Start A Program line you will want to use for the executable is the path for Powershell (Typically C:\windows\WindowsPowershell\v1.0\powershell.exe) and in the Arguments field use:

-noprofile "ExecutionPolicy Bypass "File <path to .ps1 script>

Setting Up Automated Software Deployments

Create a new dynamic collection in PDQ Inventory using the filters as show below. Change the value to match the name of your security group in Active Directory.

dynamic powershell collection

Next in PDQ Deploy, you’ll create a new schedule. (Either select Deploy > New Schedule or go to File > New Schedule.) Set the trigger to Heartbeat (requires a Pro or higher license). Under the Targets tab, select Link to and select the PDQ Inventory collection you created in the last step. Click OK.

link to collection automating software installs for imaged computers

 

Now that you have your schedule saved, you may attach packages to it for deployment. When the Heartbeat trigger detects a new machine in the PDQ Inventory Collection you have linked to, these packages will be deployed to those target machines.

 

attach package to schedule

 

That’s all there is to it! Now when you image a machine, and it goes into the OU, PowerShell will add it to the appropriate groups, PDQ Inventory will add it to your collection, and PDQ Deploy will push your selected applications to it. When you move the machine out of your Imaging OU, the PowerShell script will detect the change and remove that machine from the Security group, which will update your Dynamic Collection.

Try PDQ Deploy

5 responses

  • Great Instructions! How would I get the PowerShell script to connect to AD that is installed on another server? like a remote deployment/connection to the AD to make the changes?

    Thanks

    • For the script to work properly you either need 1) the Active Directory module installed locally, or the ability to use Powershell Remoting to connect to machine with the module installed on it (It is installed by default with the RSAT tools for Windows).

      I’m going to assume that you are working on a server that is in the same active directory domain, but does not have the tools installed locally. In order to query active directory you will need to have powershell remote access to the machine with RSAT installed, and then use the Invoke-Command cmdlet inside of the ps1 script to execute the query:

      Invoke-Command -ComputerName -Credential -ScriptBlock {Put the call to Get-ADGroupMember etc etc in here}

  • Is there a way to do this same thing but with a twist? All of our computers get a standard build and then, depending on where they’re located or who’s using them, we’ve got different baselines for different OU’s. For example, all computers get packages X, Y and Z but one lab might also need packages A, B, and C installed while a second lab would additionally need packages A, F, and Q. I’m also wondering how to sustain this software if a computer in said lab fails and is re-imaged – it would need those packages re-deployed once it’s back up and running.

  • Are the ‘User Defined Variables’ of this script available somewhere? It seems like they’re missing on this page.

Respond to Matt Cancel response

Your email address will not be published.

Your Name