Determining Disk Type with Get-PhysicalDisk

2 CommentsPowerShell

After today, you are going to know that determining disk type with Get-PhysicalDisk is super easy.

If you recently watched our PDQ & A webcast, you may have seen that we were unable to answer a question about how to determine if a disk is a solid state drive (SSD) or not.

Fast forward to now and we have that answer by utilizing Get-PhysicalDisk cmdlet.

Thanks PowerShell!

Gathering Physical Disk Information with Get-PhysicalDisk

If you’re using Windows 8 or later, you can get all the information you could ever want to know about your physical disk but were afraid to ask by running this (very) simple command:

Get-PhysicalDisk | Select *

Blog - SSD or not - Get-PhysicalDisk example with all properties

Determining Disk Type with Get-PhysicalDisk

Armed with this new knowledge, of how to use Get-PhysicalDisk, let’s find out which (if any) of my physical disks are SSD.

Get-PhysicalDisk | Select FriendlyName, MediaType

Blog - SSD or not - Get-PhysicalDisk example

Ta da!  Like magic, you can now determine your disk types!  That is, only if you’re using Windows 8 or higher. Should you happen to be stuck on older versions of windows, then you’ll just have to pretend to follow and/or sing along.

By default, just running Get-PhysicalDisk will not get you the MediaType, so be sure to select it specifically.

That’s it. We’re done. You can go home now and show off your new and powerful knowledge to your friends and neighbors.

There’s nothing more to see here. That is, unless you want to learn more! *gasp!*

Slightly Deeper Dive

Since it’s not a true deep dive, perhaps we should call this the casual saunter into the the shallow end of the pool of knowledge. If you’re still reading this far, we’ll show you the class that Get-PhysicalDisk appears to be using to gather those fancy properties.

In addition to the Get-PhysicalDisk cmdlet, we found that the MSFT_PhysicalDisk appears to provide exactly what we’re looking for (link about the class). Knowing the class, here is how you would query that information with PowerShell:

Get-WmiObject -Class MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage  | Select FriendlyName, MediaType

Blog - SSD or not - MSFT_PhysicalDisk example

Unsurprisingly, this looks very similar to the result we got with Get-PhysicalDisk. Now, we just need to know what the media types 3 and 4 actually mean.

Based on this page about the MSFT_PhysicalDisk class (link here – Look for MediaType section), we can see which media types are available and what their values mean.

3 = HDD
4 = SSD

Since we know what these values now mean, we can modify our PowerShell above to use some calculated properties (fancy!) and include a simple switch statement to display friendlier results. Joy!

Get-WmiObject -Class MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage | 
     Select FriendlyName,
             switch ($_.MediaType) { 
                 3 {"HDD"}
                 4 {"SSD"} 

Blog - SSD or not - MSFT_PhysicalDisk example with calculated propertie

Running the code above will show each physical disk and the associated media type. Amazing!

Alternatively, you could break this into multiple commands instead of the single command. But, that would have robbed me of the opportunity to use calculated properties.

Wrapping up

Like I mentioned before, I recommend that you use the first example since it’s much easier to remember and use:

Get-PhysicalDisk | Select FriendlyName, MediaType

As Always, go forth and PowerShell!


Managing Domain Memberships with PowerShell

2 CommentsDeployment Examples, PDQ Deploy

Let’s go through some steps that may prove helpful in speeding up your processes in joining machines to a domain, or helping you to migrate machines to a new domain at scale. We will utilize some pretty simple PowerShell to accomplish this task. So without further ado, grab a drink, sit back, and let’s do this!

Checking Domain Membership

We need some logic to see if the machine is currently a member of a domain. That’s pretty simple with PowerShell. The code looks like this (and will return a true/false value):

(Get-WMIObject win32_computersystem).partofdomain

Removing a Machine from a Domain

This also is going to return to us a true/false value. Given that we want to put the machine on a new domain, let’s use some logic to automate removing the machine from its current domain membership.

If ( (Get-WMIObject win32_computersystem).partofdomain "eq $true ){

Pretty simple right? The machine is now off the domain! However, you may need to restart the computer for the changes to apply. You can add a -restart parameter to your script if desired. Keep in mind that this will only tell the local computer to switch to using a workgroup. It doesn’t clean anything up in Active Directory. It will only disable the associated computer object in Active Directory.

Some additional parameters to consider:


This is for specifying a user account that has permission to remove computers from their current domain. This is a required parameter if you’re trying to use Remove-Computer with a remote computer.


This parameter is for specifying a user account with permission to connect to the computer

Putting a Machine on a New Domain

The question then becomes “Well, how do I put it on the new domain?” I’m so glad you asked! Let’s look at that:
A couple of prerequisites are needed. To add a computer to the domain, we must supply credentials to the command that have been delegated rights to add machines to the domain. There are a few ways to do this, and I will provide the simplest method in this post, though I would recommend reading Kris’ excellent post on using more secure credentials here. Let’s go ahead and get our account setup in PowerShell.

$User = "DOMAIN\DelegatedUser"
$Password = ConvertTo-SecureString "somepassword" "AsPlainText "Force
$Credentials = New-Object System.Management.Automation.PSCredential $user,$password

Now we can pass that set of credentials to the next cmdlet we need to utilize:

Add-Computer "Domainname "YourDomainName" -Credential $Credentials

Restart Options

The computer will need a reboot after the task is complete. You have some options here. You can use a Restart-Computer cmdlet in your script right after Add-Computer, or if deploying your script with PDQ Deploy you can add a Reboot Step to your deployment package. The Reboot step is my preferred method, as that will let PDQ Deploy control deployment state, and return a successful result when the computer checks back in after the reboot is complete. Otherwise, if you choose to add Restart-Computer cmdlet directly into your script, you have no way of receiving any feedback from the script being run. It will simply timeout (though the target machine will be rebooted).

A simple way to put this together would be to make a PowerShell function that joins the machine to the domain. This makes it easy.

Let’s put that all together so you have a clear picture of what the complete script would look like:

$User = "DOMAIN\DelegatedUser"
$Password = ConvertTo-SecureString "somepassword" "AsPlainText "Force
$Credentials = New-Object System.Management.Automation.PSCredential $User,$Password

Function Join-Domain {
    Add-Computer "Domainname "" -Credential $Credentials

If ( (Get-WMIObject win32_computersystem).partofdomain "eq $true ) {
} Else {

Deploying Your PowerShell Script

One option for deploying your script is to use PDQ Deploy. Save this script as a ps1 file somewhere on your network, such as your PDQ Repository.

  1. Create a new package, give it a name, and add a PowerShell step to the package.Powershell Step Window.
  2. Give the step a title, and then select Insert PowerShell Script at the bottom of the command window on the details tab.Powershell Step Insert Script managing domain memberships
  3. Browse to and select your PowerShell script you created from the code above. Set your conditions and options as you see fit for your environment.
  4. Deploy to your target machines with a Local Administrator account. (We don’t want any hiccups once the machine is off the domain.)Change Deploy Credentials

Enforcing Execution of Browser Extensions Explicitly

Leave a commentUncategorized

Part the First: Chrome

Given last month’s Cisco WebEx Browser Extension Vulnerability, and the resultant hours of near-terror that ensued, you might be wondering how you can better manage browser extensions for your users.

Many of you asked, “Does PDQ manage extensions?” The short answer is no, we don’t manage browser extension easily. Like most things, using the right tools will often result in more expedient, easily managed solutions. Group Policy (GPO) is that tool.

The included instructions are for Google Chrome. Like Internet Explorer, Chrome is an enterprise browser. We’ll tackle handling add-ons for IE in a (near) future blog post.

Extension Management for Chrome

If you don’t already have them, get the ADM* files for Chrome, which can be downloaded here. Import the ADMX and ADML files into your GPO schema (I use the central store for all Administrative Templates).

Assuming you’ve imported the ADMX/ADML files properly and opened the GPMC again, you’ll see Computer Configuration > Policies > Administrative Templates > Google > Google Chrome. This is where the magic happens. Navigate to Extensions and you’ll see something like this:

Here is where we make a decision between whether we want to blacklist or whitelist Chrome extensions. My preference is to whitelist since there are far more extensions I don’t want to allow than those I do. It’s a lot easier to stay on top of what extensions are needed than to filter what could be harmful, hurt compliance, end Western Civilization as we know it, or cause other unintended difficulties.

Before we whitelist, we need to get the Chrome extension ID. The easiest way to do this is to go to the Google Chrome Web Store and search for the extensions you want to allow.

For this example, I’m going to whitelist the following extensions:

  • uBlock Origin
  • Privacy Badger
  • Office Online
  • Google Hangouts

To get the extension ID, search for the extension, select the extension from the results and the ID will appear in the address bar:


In this case, my extension IDs are as follows:

uBlock Origin = cjpalhdlnbpafiamejdnhcphjbkeiagm
Privacy Badger = pkehgijcmpdhfbdbbnkijodmdjhbjlgp
Office Online = ndjpnladcallmjemlbaebfadecfhkepb
Google Hangouts = nckgahadagoaajjgafhacjanaoiihapd

The next step, and by far the easiest and most fun, is to blacklist everything. In your GPO, navigate to Computer Configuration > Policies > Administrative Templates > Google > Google Chrome > Extensions and open Configure extension installation blacklist. Enable the policy, click “Show” in the Options section, and use the * (wildcard) as the value:

At this point, all extensions are now blacklisted. If you were to apply this GPO to the domain, site, or OU, all impacted Chrome instances would no longer have any available extensions, even if previously installed by the user. Likewise, the user would be unable to install any extensions.

To avoid the angry, pitchfork wielding mob of users storming through your office gate, create a whitelist of extensions to appease the Great Unwashed. We’ll whitelist the following: uBlock Origin, Privacy Badger, Office Online, and Google Hangouts in Computer Configuration > Policies > Administrative Templates > Google > Google Chrome > Extensions and open Configure extension installation whitelist.

The process is the same for configuring the blacklist. Enable the policy, then configure the extension IDs to exempt from the blacklist.

When viewing the policy settings, you should now see the wildcard blacklist and all of the whitelisted extensions IDs like:

Now, prior to applying the GPO, let’s go back to our user. If we have a look at Nigel’s Chrome extensions, we see:

As a test, apply the GPO, and do it with some force, using the Remote Command tool from PDQ Inventory:

In remote command, simply run gpupdate or gpupdate /force.

After we’ve confirmed the test is successful, update all your machines (prior to the GPO actually taking effect), by deploying a GPUpdate package:

Manage Google Chrome Browser Extensions

On the target machine (Nigel’s), we left Chrome open. No reason to close it down, as the GPO will apply the appropriate settings while the process runs. This is the result:

And what happens when a user tries to install an extension that’s not whitelisted?

But really, we don’t even want users to go to the extension store at all. So, we go back to our GPO and edit the Computer Configuration > Policies > Administrative Templates > Google > Google Chrome > Extensions, and open the Configure the list of force-installed apps and extensions policy. Enable the policy and choose the whitelisted extension IDs and update URL.

Typically, the install/update URL is going to be You can check the Update URL by going to:

Data\Default\Extensions\[Extension ID]\[Extension Version]\manifest.json

Check for the following line (in this example, the URL is

"update_url": ""

The entry in the GPO follows this:

[Extension ID];[URL] (no spaces and don’t forget the semicolon)

For example:


Now update the GPO on your target machines by testing with PDQ Inventory (if desired) and then deploying with PDQ Deploy.


In testing this process, a restart of Chrome was necessary for some extension installations. In others, it required a reboot of the machine.


Unlike certain user-initiated extension installations, this does not store the extension information in the registry. Instead, the information is stored in:

Data\Default\Extensions\[Extension ID]


If you use the Configure the list of force-installed apps and extensions setting, you don’t need to whitelist those extensions. It’s a good idea, but the force-installed extensions overrides blacklists and whitelists. That means you can force-install some extensions, but have others that are optional the user can choose to install if needed via the Google Web Store.

PPPPS: Can’t get enough? Check out Part II of this series where we discuss Internet Explorer.

Deploy Monthly Windows Updates

4 CommentsPDQ Deploy, PDQ Inventory

Need to deploy monthly Windows updates to PCs on your network? Good news, we are now offering the Monthly Windows updates for Windows 7, 8.1 and 10 in the PDQ Deploy Package Library!

Take a knee, team. Microsoft recently modified the way that OS updates are delivered. Windows 7 and Windows 8.1 updates now behave a little more like their Windows 10 cousins. Basically, there are two sets of patches that are offered each month for the OS. (We aren’t talking about .NET or IE updates, just the OS). Anyway, Microsoft is no longer offering individual patches for security and bug fixes. Rather they are offering all patches in two different patch sets for Windows 7 and 8.1. They still only offer one OS patch set for Windows 10.

Windows Updates for Windows 7 and 8.1

Security Monthly Quality Rollup

These packages will be called Win 7 – Monthly Rollup and Win 8.1 – Monthly Rollup. These KB updates will, according to Microsoft, contain “all the new security fixes for that month…as well as fixes from all previous monthly rollups”. If you deploy this patch you do not need to deploy the Security-only update listed below.

Security Only Quality Update

These packages are called Win 7 – Security-only Update and Win 8.1 Security-only Update. This patch set isn’t cumulative. It only contains the security fixes for that month. If you deploy the Monthly Rollup package you do NOT need to deploy the security-only packages.

Windows 10 Cumulative Updates

These packages are broken up based on the Release ID of Windows 10. At this writing there are three different releases. There is the initial release, 1511 and 1607.

deploy monthly Windows updates-PackageLibrary-WindowsUpdates

All the packages will have the version listed as [Month][Year]. In the event that more than one patch set comes out in a month the subsequent package versions will be called [Month][Day][Year].

Track Updates using PDQ Inventory

You can use the Collection Library to see up-to-date status of machines and their compliance with the Windows Updates. You can deploy monthly Windows updates to, for example, the Win 7 Monthly Rollup (Old) collection in PDQ Inventory from PDQ Deploy.

Keep an eye out for videos where we demonstrate Auto Deployments of your Windows updates.

At this point we are only making packages for workstations. We are not including Servers in the packages.


Disabling Web Bluetooth API in Google Chrome

Leave a commentPowerShell

Disabling Web Bluetooth API in Google Chrome seems to be on the mind of many administrators in recent days. Google Chrome 56 recently came out (update notes here), it included the fancy new Web Bluetooth API. This allows developers to easily create web applications that can communicate with Bluetooth devices.

While there are many fun and creative things that could be done with this, you may have some privacy red flags popping up in your brain. Because, security.

Assuming that you stumbled upon this blog because you wish to disable it, here is how you would do just that.

Disabling Web Bluetooth API in Google Chrome

Disabling Web Bluetooth API in Google Chrome is pretty straightforward. In fact, Google Chrome policies can be enabled and disabled very easily. They are documented in the Chromium Administrators policy list. Here’s a link directly to the policy we’re going to use when disabling Web Bluetooth API. By default, this setting is not disabled.

There are couple of different ways to change Google Chrome policy settings:

  • Group Policy and Active Directory administrative templates (get them here)
  • Registry modification

Ideally, you’ve downloaded the Google Chrome Active Directory policy templates. With these, you should easily be able to set up a Group Policy Object (GPO) to get this setting deployed throughout your domain.

Seriously, folks. Use Group Policy to apply these settings and live the dream.

That being said, however, I also ♥ PowerShell and want to show you how you could tackle this with PowerShell.

Setting up via GPO

After grabbing those Google Chrome administrative templates, you’ll need to create a Group Policy Object that enables the following:

  • Location – Computer Configuration > Administrative Templates > Google > Google Chrome > Content Settings
  • Setting – Control use of the Web Bluetooth API
  • Value – “Do not allow any site to request access to Bluetooth devices via the Web Bluetooth API”

In addition to the instructions above, here are some pretty screenshots to show the process.

Disabling Web Bluetooth API - Web Bluetooth API - GPO Editor

Web Bluetooth API - GPO Setting

Setting up via Registry Key

In order to disable the Web Bluetooth API manually, you’ll want to create the following in your registry:

  • Location –  HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\
  • Setting –  DefaultWebBluetoothGuardSetting (DWORD)
  • Value –  2

Web Bluetooth API - Registry Example

While you could easily add this to the registry manually like an animal, you could also choose to flex your PowerShell muscles and whip this problem out like a proper champ:

$Path = "HKLM:\\SOFTWARE\Policies\Google\Chrome"
$Type = "DWORD"
$Name = "DefaultWebBluetoothGuardSetting"
$Value = "2" # 2 = Disabled; 3 = Allow requests

# Create $Path if it doesn't exist
IF ( -Not (Test-Path -Path $Path) ) {
    New-Item -Path $Path -Force | Out-Null

# Create new DWORD with $Name and $Value
New-ItemProperty -Path $Path -PropertyType $Type -Name $Name -Value $Value -Force | Out-Null

Voila! Disabling Web Bluetooth API in Google Chrome was no problem thanks to Group Policy and PowerShell!

As a result, you should go grab yourself a delicious cookie and enjoy it.

Seems like you earned it.

PS: While it is awesome to use PowerShell, please please please use Group Policy where you can!

Create a Hipster Playlist Using PowerShell

Leave a commentPowerShell

Hipster playlist in Powershell

Hipster cred! I have it, you want it. No way to build it up faster than to be into something before it becomes popular. You may have been wondering how you might be able to pull a random list of fifteen infrequently listened to bands and document the fact that you knew of them before it became all about the money. Well lucky for you we have what you need.

Note: if you see a band in this list and object to their placement, you are functioning at a higher hipster level than this blog accounts for and can add that feather to your fedora.

Setting Up the Spotify API

Before this script will be able to run at all we will need to set up an API(Application Program Interface) at This will give us the client ID and let us set a redirect URI(Uniform Resource Identifier) for after we authenticate. Seen below is what this screen looks like after I use cutting edge blurring technology to hide my actual IDs.

hipster playlist uri spotify

With this created, you can now generate an access request. The request has to contain the following:

  • Client ID – Identification number generated by Spotify
  • Redirect URI – URI that the browser will go to after you authenticate.
  • Response Type – How you want the Spotify servers to respond to the request
  • Scope – Permissions you are requesting

Opening Your Spotify Hipster Playlist

Here is how our URI request looks. $clientID should be replaced with your client ID after you register your application with Spotify

$clientid = <Your Client ID Here>
$AuthUri = "" +
           "client_id=$clientid" +                                                                                     #Put the client ID from your web application here here
           "&redirect_uri=//" +         #Thanks to Jonathan Lindgren ( for use of that awesome gif
           "&scope=playlist-modify-public playlist-modify-private playlist-read-private playlist-read-collaborative" +

If you copy the above URL into a web browser it will respond with your access token inside the address bar. We could manually copy that over like we are animals, or we can use PowerShell to build our own browser on the fly that will have the token we need in an object. Let’s check in with Kris to see how he might perform such a task.

Add-Type -AssemblyName System.Windows.Forms
$FormProperties = @{
    Size = New-Object System.Drawing.Size(850, 675)
    StartPosition = "CenterScreen"
$Form = New-Object System.Windows.Forms.Form -Property $FormProperties
$BrowserProperties = @{
    Dock = "Fill"
$Browser = New-Object System.Windows.Forms.WebBrowser -Property $BrowserProperties

Compelling stuff Kris, thanks for stopping by.

Running this will bring you to a login screen for Spotify. Once your credentials are in it will take you to some fantastic artwork by Jonathan Lindgren.

Feel free to bask in its glory, but to move forward with the script you will eventually have to close this browser.

Once you close that browser, your access token will be in $Browser.Url.Fragment. It will take a little work to clean up that data to make it usable. First, you need to use regular expressions to strip everything but the token value. Then, you need to specify the token type and create a header variable.

If ($Browser.url.Fragment -match "access_token=(.*)&token") {$AccessToken = $Matches[1]}

$BearerToken = "Bearer $AccessToken"
$HeaderValue = @{Authorization = $BearerToken}

Now the we have the token the rest of the script is just the same command over and over. Invoke-RestMethod is the PowerShell cmdlet that lets you send HTTPS requests against a web service.

Each time you run the command you specify where you are making the request (URI), what you are doing (method), what you are sending over (body), and your access token (header).

That is it. Just use different variations of that command and it will let you grab your account, build a playlist, grab every genre, and get the three least listened to bands for each one.

Now that we have all the steps lets take a look at the completed script.

### Create uri for generating access request ###

$AuthUri = "" +
            "client_id=$clientid" +                                                                                     #Put the client ID from your web application here here
            "&redirect_uri=//" +         #Thanks to Jonathan Lindgren ( for use of that awesome gif
            "&scope=playlist-modify-public playlist-modify-private playlist-read-private playlist-read-collaborative" +

### Build Browser and request authentication ###

Add-Type -AssemblyName System.Windows.Forms
$FormProperties = @{
    Size = New-Object System.Drawing.Size(850, 675)
    StartPosition = "CenterScreen"

$Form = New-Object System.Windows.Forms.Form -Property $FormProperties
$BrowserProperties = @{
    Dock = "Fill"

$Browser = New-Object System.Windows.Forms.WebBrowser -Property $BrowserProperties


### Create access token variable and grab your user account information ###

If ($Browser.url.Fragment -match "access_token=(.*)&token") {$AccessToken = $Matches[1]}

$UserUri = ""
$BearerToken = "Bearer $AccessToken"
$HeaderValue = @{Authorization = $BearerToken}
$UserAccount = (Invoke-RestMethod -Uri $UserUri -Method Get -ContentType application\json -Headers $HeaderValue).href

### Build Playlist and get ID ###

$PlaylistUri = $UserAccount + "/playlists"
$NewPlaylist = @{
    name = "Before they are Popular"
    public = "true"
} | ConvertTo-Json

$PlaylistID = Invoke-RestMethod -Uri $PlaylistUri -Method Post -ContentType application/json -Headers $HeaderValue -Body $NewplayList

### Grab all genres seeds and select 5 random ones that have more than 10 bands associated with it ####

$GenreSeedUri = ""
$Genres = Invoke-RestMethod -Uri $GenreSeedUri -Headers $HeaderValue | Select-Object -ExpandProperty genres
$GenreList = @()
foreach($Genre in $Genres){
    $GenreUri = "$Genre&type=artist&limit=5&market=us"
    $BandCount = (Invoke-RestMethod -Uri $GenreUri -ContentType Application/json -Headers $HeaderValue)
    if($BandCount -gt 10){
        $GenreList += $Genre
    Write-Output "Generating list for: $Genre"
    Start-Sleep -Milliseconds 100

$FinalList = Get-Random -InputObject $GenreList -Count 5

### Grab 3 least popular band per genre ###

$Bands = @()
foreach($Item in $FinalList){
    $BandUri = "$($Item)&type=artist&type=artist&limit=5&market=us"
    $BandCount = [System.Math]::Round(((Invoke-RestMethod -Uri $BandUri -ContentType Application/json) - 3), 0)
    $OffsetUri = "$($Item)&type=artist&offset=$($BandCount)&limit=3&market=us"
    $LastThreeBands = (Invoke-RestMethod -Uri $OffsetUri -ContentType Application/json).artists.items | Select-Object name, id
    $Bands += $LastThreeBands

### Add top track from bands to playlist ###

Foreach($Band in $Bands){
    $TopTrackUri = "$($"
    $TopTrack = (Invoke-RestMethod -Uri $TopTrackUri -ContentType Application/json).tracks | Select-Object uri
    if($TopTrack -ne $null){
         $CombinedTopTrack = $TopTrack.uri -join ','
         $AddTrackUri = $UserAccount + "/playlists/" + $ + "/tracks?position=0&uris=$CombinedTopTrack"
         Invoke-RestMethod -Uri $AddTrackUri -Method Post -ContentType application/json -Headers $HeaderValue

### List the 5 Genres used ###

Write-Host "You have created a playlist from the following genres: $FinalList"

Final note, should you want to do something useful with these commands the format would be the same. Just know that I used these commands before they were cool.

Managing Changes to PDQ Deploy or Inventory with Git

4 CommentsPDQ Deploy, PDQ Inventory

Write-Host “Hello world!”

Hi there. I’m Colby Bouma, a shiny new employee at on the QA team. I used PDQ extensively at my previous job and I did some crazy things with it. Today I would like to share one of those crazy things with you. It’s important to know I tend to go a little over the top occasionally 😀

Have you ever wanted a detailed history of the changes you’ve made to PDQ Deploy and Inventory? You can accomplish this with the built in Export feature and your own git repository. The Export feature creates XML files which are fairly readable and work very well with git. If you follow my workflow of exporting and committing after every change you get some handy benefits:

  • Quickly find when a change was made
  • See exactly what changed
  • Keep notes on why you made a change
  • Create a sort of undo button by importing a snippet of XML

Setting Up Gitlab and Preparing Your Workstation

  1. Install and configure Gitlab.
    1. Create a virtual machine with at least 2GB RAM, 20GB HDD, and 1 CPU core. You can use your favorite Linux distro, but I chose Ubuntu 16.04 for this demo. I followed these instructions to install Gitlab.
      sudo apt-get install curl openssh-server ca-certificates postfix
      curl -sS | sudo bash
      sudo apt-get install gitlab-ce
    2. Follow this guide to configure email. This is required for creating accounts in Gitlab. Once you are done, run:
      sudo gitlab-ctl reconfigure
    3. You should now be able to log into your Gitlab webpage and change the root password.
    4. Create a user account for yourself. It’s never a good idea to run as root.
      gitlab admin area
      gitlab new user
  2. Create a repository.
    gitlab new project
  3. Install Git on your workstation. The defaults are fine.
  4. Clone the repository to your workstation.
    git clone http://lnxDEMO/colby/PDQ_Settings.git

    clone git repository
    clone repository black

  5. Create the initial export. In PDQ Deploy, go to File > Preferences > Export All.
    preferences export all
    xml preferences export
  6. Commit the initial export with the comment “Initial commit”.
    git add .\Deploy_Settings.xml
    git commit -m “Initial commit”

    initial commit

  7. Push the initial commit to Gitlab.
    git push -u origin master

    git credentials
    git push black
    repository pdq settings git

Workflow for Managing Changes to PDQ Deploy or Inventory

Perform an export after making any change. If you need to make multiple changes, do them one at a time and export after each change. This makes it much easier to look through and encourages detailed notes instead of “Huh, looks like I changed some stuff”.

  1. Perform an export and save over the previous file.
    export deploy settings
    confirm replace file git
  2. Commit all changed files:
    git commit -a

    git commit
    git commit 2

  3. Press “i” to enter INSERT mode.
    git editor press i
  4. Write a comment such as “Increase ‘Backups to Keep’ to 200”. I also like to make a note of the path to the item I have changed, such as “Database –> Backups to Keep”. The first line is a brief note to summarize the commit; everything below that can be as detailed as you want. Make sure to put a blank line after the first line if you are going to write detailed notes.
    Keep 200
  5. To save and close the comment hit the ESC key, type “:x”, and hit ENTER.
    Keep 200 x
  6. Synchronize with Gitlab:
    git push origin master

    (If you make multiple changes you can wait to do this step until you’re done.)
    git push origin
    backups to keep changes to pdq deploy

Undo Button

  1. Find the snippet of code you want to restore.
    restore code pdq deploy
  2. Copy and paste it into a text editor. In this example I had to rearrange it a little bit due to how the diff was formatted. For packages you want everything between <Package> and </Package>.
    Package code snip
  3. Save it as an XML file.
    activation status save
  4. Import it.
    import to pdq deploy
    import rebuilt package
    rebuilt package was successfully imported

PDQ Inventory 12 is Now Available

Leave a commentPDQ Inventory

PDQ Inventory 12 is now available to download. To upgrade the version, click the notice A new version is available in the status bar of the console. Here are all the new and exciting features that await you.

Custom Fields Import Wizard*

Are you currently using Inventory but have to maintain a separate spreadsheet to track those little items that Inventory does not gather? Perhaps you have to keep track of Asset Tag numbers, Employee numbers, or even the colors used on that one guy’s cool mechanical keyboard. Whatever the data, your days of separate tracking are about to come to an end. We bring to you the Custom Fields Import Wizard. This very handy tool allows you to import a large amount of custom data all at once from a CSV (comma-separated values) file.

To launch the Import Wizard, click File > Preferences > Custom Fields, then click Import Wizard (or on the Custom Fields page of the Computer window, click Import Wizard).

Select your CSV file and map the fields in the CSV file to any existing Custom Fields in PDQ Inventory or create brand new fields within the wizard. You can also import and overwrite data whenever you update the CSV file.

Tool Details in the Tools Library

The Tools Library now includes a Tool Details sidebar that displays the description, any applicable keyboard shortcuts, required software, and category. This is available to all license types; however, Enterprise mode is required to import tools.

Heartbeat Trigger for Scan Profiles*

We’ve added the ability for PDQ Inventory to start a scan whenever a computer goes from offline to online status so you can always have the most recent data. If the computer registers as offline and online within the Heartbeat interval (default 300 seconds), the computer will not register as offline by the Heartbeat and a scan will not be initiated. This is set up on the Triggers tab of the Scan Profile window found in File > Preferences > Scan Profiles. Open an existing Scan Profile or click New to create a new profile.

New actions available for Files and Registry pages*

The Files and Registry pages of the Computer window have more flexibility than before. Have you ever scanned for file or registry entries and had the results return far too many line items? Or have you changed a scan profile, but the results are still showing? You can now delete individual entries without having to repeat the process of editing your scan profile and scanning the computer again.

Additionally, opening File Explorer to the exact location of a file is now just a right-click away using the context menu.

More data collected during a scan

  • Current User (User UPN Name), Display Name (AD User Display Names), and Deep Freeze Status* have all been added to the Computer page of the Computer window as well as Collections and Reports.
  • Added From, Deep Freeze Product Code*, and Deep Freeze Version* have all been added to Collections and Reports.
  • SMART Status* has been added to the Disk Drives page of the Computer window as well as Collections and Reports.

Other smaller (but no less important) additions

  • The Computer window of a selected computer can be opened directly from within the Remote Command window using the context menu.
  • The Main Console Toolbar is now arranged more conveniently by task.

*Requires Pro or Enterprise mode

How to Disable Flash on Your Network

Leave a commentDeployment Examples, PDQ Deploy

In this post, we’ll go over how to disable Flash on IE, Firefox, and Chrome. The video below is the complete recorded webcast in which we cover each browser. In each section, a link is provided that will go to that portion of the webcast or you can watch the webcast in its entirety below.

Is Flash all that bad? Maybe, maybe not. Adobe Flash is a necessary evil for some organizations…a lot of schools often need Flash to run certain educational programs. The objective is to minimize your possible security risks (AKA minimizing your attack surface). If you don’t need Adobe Flash in your environment, disable it. If you need it, get it and make sure you keep it up to date. For your consideration, what would happen in a month without Adobe Flash?

How to Uninstall Flash in Firefox

In the Package Library, there is a deployment package available that will uninstall Adobe Flash (requires an Enterprise license). It will only uninstall the Flash as made available by Adobe. It will not uninstall or disable Flash built into IE (for Windows 8 and higher) or the embedded PPAPI Flash in Chrome. Watch how to uninstall Adobe Flash for Firefox.

Disable Flash in Google Chrome

There are two steps to disabling Flash in Chrome. First there is the embedded Pepper Flash (PPAPI). Straight up, the best and surefire way to make sure the embedded Flash is disabled in Chrome is through a GPO. In order to use this method you need to import the Google ADMX files into your Group Policy environment. You can download the latest ADMX files here. In a new or existing GPO you can configure the new policy. With the example below we have a dedicated GPO called Component Update Disabled.

GPO how to disable flash in chrome

In Settings > Administrative Templates > Google/Google Chrome you’ll be able to see what policies you have enabled or disabled. Right-click on your GPO (on the left pane) and select Edit. With the ADMX template loaded, you’ll have the option to go to Computer Configurations > Policies > Administrative Templates > Google > Google Chrome. From there you can find the setting called Enables component updates in Google Chrome. Which you can then set to disabled. If you do not explicitly set this policy to Disabled then any computers that can access the internet will automatically have the latest embedded Pepper Flash installed.

If you are using Chrome make sure you don’t have the Adobe Flash Player PPAPI installed. This is important because even if you disable the Enables Component Updates in Google Chrome setting Chrome will use the installed Adobe Flash Player PPAPI if it is installed. You can deploy the Uninstall Adobe Flash Player package from PDQ Deploy’s Package Library to uninstall this application.
edit gpo flash google chrome

If you would prefer to not use a GPO to disable the embedded Flash for Chrome you can use PDQ Deploy to push out a specific registry value to your target computers. Below is a download for a package you can use in PDQ Deploy to deploy this policy’s registry changes. Also below is an accompanying Collection you can import into PDQ Inventory to help you track computers with Flash disabled.

Package – Disable Flash in Chrome

Collections – Flash Disabled

Watch the video on how to disable Flash in Chrome here.

Disable Flash in IE

Every KB that comes out from Microsoft for Flash has a workaround for disabling Flash. Again, GPO is probably the best way to accomplish this, check out this blog post on how to disable Flash in IE using GPO.

We also have a deployment package you can push out here. Make things easy on yourself and deploy to the right computers and use the Collections provided here to track computers that have Flash disabled.

Why disable Flash? Shouldn’t uninstalling it do the same thing?

In some cases you will want to uninstall it. Other situations, however, uninstalling really isn’t an option so you are left with disabling it. Below is a chart showing which OS/browser combinations you can uninstall vs. disable. If uninstalling is an option, you can use the deployment package available that will uninstall Adobe Flash available in PDQ Deploy.

OS Browser Disable/Uninstall
Windows XP to Windows 7 IE Uninstall
Windows 8.1-10 IE Disable
All Firefox Uninstall
All Chrome Disable AND Uninstall
All Opera Uninstall

Deploy Adobe Creative Cloud Using Setup.exe

Leave a commentDeployment Examples, PDQ Deploy

You’re looking to deploy Adobe Creative Cloud using setup.exe, rather than the MSI. For instructions on using the MSI, check out this blog post. This post will show you how to configure the Creative Cloud Packager and then successfully install the selected Adobe CC products. Be sure to check out the tips for troubleshooting silent installations of Creative Cloud at the bottom of this post.

Configuring the Creative Cloud Packager

1. Download the Creative Cloud Packager by logging in to and selecting the appropriate management link. In the management window, select Deployment Tools then select the Download Win > package.

2. This will download the CCPLauncher.exe. Launch the executable.
3. Click on Create Package.

4. Give the package a name, a location where the package should be saved, the architecture (32 or 64-bit) of the applications, the license type, and any special configuration options (mostly update preferences).


5. Click Next.
6. Select the applications and/or updates you wish to build into your installer.

NOTE: As indicated in the image above, for multilingual offices you can also select the Match OS Language, which will install the applications based on OS locale. This negates needing to create multiple packages in specific languages.adobe creative cloud packages

7. Once you’ve made the appropriate application and/or update selections, click Build. And wait. And wait some more. Go to lunch. Wait. Deploy some other things. Wait. Inventory the satellite office in Boca Raton with their 3,478 USB printers. Wait.

You should now have a directory containing an MSI installer and a setup.exe for the Creative Cloud products in the ..\DownloadDirectory\Build\.

setup.exe for adobe creative cloud
Deploy Adobe Creative Cloud Using Setup.exe

In the following example, we are only deploying the 64-bit version, but it is possible to create a 32 and a 64-bit installation. For information on how to do this, see the original KB.

1. In PDQ Deploy, click New Package or Ctrl+N from the toolbar or click on File > New Package or right-click the Packages folder in the navigation tree and select New Package.
2. Name the package something reasonable, and choose the appropriate Copy Mode (see Considerations below) if not already set globally (Pull Copy Mode should be default in your global settings if you have followed the recommendations at the bottom of this article).

Deploy Adobe Creative Cloud Using Setup
3. Click on New Step > Install, and give the step a title. For the Install File, navigate to the directory containing the setup.exe you created above.


  • The setup.exe has a silent parameter, –silent. This must be used when deploying the setup.exe. The full usage statement for setup executable is:
setup [--silent] [--ADOBEINSTALLDIR=<TargetInstallDirPath>] [--INSTALLLANGUAGE=<ProductInstallLanguage>] [{-h, -help, --help}]
  • Make sure to check Include Entire Directory. If this is not checked, the deployment will fail.

silent install parameter for adobe creative cloud
4. Click on the Conditions tab and select the O/S Version. Since Adobe Creative Cloud products will only run on Windows 7 and above, exclude XP and Vista. Exclude servers unless required. Since this package is installing the 64-bit Creative Cloud applications, select 64-bit from Architecture.

architecture type for adobe cc
5. Save the package.
6. Deploy and enjoy.

IMPORTANT: While we make every effort to test on multiple platforms and architectures, it is highly recommended you test the deployment before a general release into production. Given the possibility of the package being substantially sized, testing will provide important information on bandwidth limitations and deployment times. In our tests, an install consisting of Adobe Acrobat, Photoshop, and Dreamweaver took anywhere from 6 – 20 minutes to deploy.


  • In order to download the Creative Cloud Packager from Adobe, you will need to be an administrator of an Adobe Creative Cloud account.
  • You cannot deploy using Creative Cloud for Individuals (requires Team, Enterprise, or Education Creative Cloud plans).
  • While the deployment method outlined in this article can be accomplished using PDQ Deploy in free mode, changes will need to be made to create separate deployments based, for example, on OS architecture


  • The guidance in this article is focused on Creative Cloud for Teams. The steps for Creative Cloud for Enterprise and Education vary, but should be intuitive enough to allow successful deployment given the general instruction expressed in this article.
  • Since the size of a Creative Cloud package can be significant, it is recommended you use the Pull copy mode instead of the default Push copy mode (File > Preferences > Performance). This will also require placing the Repository on an accessible file share. For more information, see: PDQ Deploy: Understanding Push and Pull Deployments
  • For the greatest level of performance where multiple file servers exist and the deployment audience is greater than 30 machines, the use of Distributed File System Replication (DFSR) is highly recommended. For more information, see: PDQ Deploy and Microsoft DFS.
  • If users do not have local admin access on their respective machines and therefore do not have access to the Creative Cloud App Panel, the Creative Cloud Package can also be used to push out updates to machines with installed Creative Cloud products.

Troubleshooting Your Deployment

If the package deployment fails and/or you receive a 1603 error, please try the following.

  • Machines should be fully patched and not in need of a reboot.
  • Check to ensure sufficient space is available on the drive where Adobe CC will be installed. Some Creative Cloud deployments can be several gigabytes in size, which includes the files copied to the target and the installed size.
  • Clear out %WINDIR%\Temp directory.
  • Review the troubleshooting steps in This Article.

Error: “Setup.exe returned error code N”:
Adobe has a great Creative Cloud Troubleshooting Guide. There should be a log file on the target machine called PDApp.log, usually in C:\Windows\Temp. At the end of the log or near the end, there should be an error code. That error code can then be used to diagnose the particular issue. For example, PDQ Deploy reports, “setup.exe returned error code 4”. Reviewing the log file shows, “The Bootstrapper Process return code is (82).Stopping the installation process.” Reviewing the Troubleshooting Guide, error 82 is caused by AAM running and can be solved by closing all Adobe processes and/or renaming the PDApp folder.

Error: “Setup.exe returned error code 6”:
Usually the programs will have installed, but the error will still be thrown and the deployment will show as failed. There can be a few causes for the error code 6, which are outlined here as well as in the Troubleshooting Guide. This can also be caused by insufficient disk space or any number of other environmental conditions.