WannaCry ransomware – are you protected?

2 CommentsPDQ Deploy, PDQ Inventory

WannaCry? More like wanna pull your hair out from all the confusing information out there? Yeah. We hear you. With the recent news about the WannaCry/WannaCrypt ransomware, people are scrambling to find out if their machines are patched and protected.

Worry not, this blog will show you how to find out if you’re protected or not. Additionally, if you use PDQ Deploy and PDQ Inventory, we have pre-built packages and collections to keep all your machines safe and protected.


  • PDQ Inventory – We now have a collection in our Collection Library for determining which machines are vulnerable to WannaCry.
    • We even detail how to create your own collection if you don’t use the Collection Library (Link here).
  • PDQ Deploy – We have packages in our Package Library for the cumulative/rollup updates for Windows 7, 8.1, and Windows 10.
  • PDQ Deploy – As a bonus, we’ve recently released a package with the out-of-band patches for Windows XP, Windows 8, and Server 2003. (Microsoft link about those).

WannaCry – am I protected?

As Professor Farnsworth would say, “good news, everybody!”


Finally! Connect multiple PDQ Deploy consoles to a Central PDQ Server

11 CommentsUncategorized

So let it be written, so let it be done.” All due respect to the fellow bald-headed Yul Brynner, but I wish the writers of The Ten Commandments would have had someone (Charlton, perhaps?) retort, “Hey, Russian Ramses, that’s easier said than done”. Many of you have, most assuredly, noticed that PDQ Deploy version 12 is a little long in the tooth. It was released on December 7th, 2016. That date is, of course, infamous for being Tom Waits’ 67th birthday.

Anyway, the long wait is over as we have finally completed one of the most requested features for PDQ Deploy: A centralized server in PDQ Deploy 13. To update your console, click the “A new version is available” notice in the status bar of your console. If the update link is not visible, go to File > Preferences > Alerts to enable update notices.

TL;DR – Enterprise customers with multiple licenses can now connect multiple PDQ Deploy consoles concurrently (based on the number of licenses held) to a single “PDQ Deploy server” and thus centrally maintain packages, deployment history, schedules, etc. The Central Server is not required and is an optional feature.

PDQ Deploy was built to be a standalone deployment solution. The console and server resided on the same computer. While this is still the default way to run Deploy (in fact it is probable that most of our customers will continue running PDQ Deploy in this fashion) the fact remains that quite a few of our customers wanted something a little more centralized to accommodate multiple administrators. Enter Central Server.

Central Server Modes

Central Server isn’t a component, instead it’s a mode of operation. It works in one of three modes. A computer can only be in one mode at a time and all components installed on that computer (console, CLI, and background service) operate in that same mode. The modes are as follow:

WannaCrypt Ransomware Attack Patch

Leave a commentUncategorized

Ransomware Attack Patch

Important Note: Due to the critical nature of the WannaCrypt ransomware attack, we have made the Windows Update patches temporarily available to Pro customers as well as Enterprise customers until May 31, 2017. After May 31 these patches will  be exclusive to Enterprise customers.

On Friday May 12, one of the largest ransomware attacks in history was detected in several European countries and has since spread to over 150 countries world-wide. The WannaCrypt (also called WannaCry) ransomware attack exploits a vulnerability in older versions of the Microsoft Windows operating system, encrypts your data, and holds that data hostage until a ransom is paid. There is, however, a ransomware attack patch available. PDQ Inventory will help you identify which computers need to be patched and PDQ Deploy can deploy the patches.

Identify Vulnerable Computers With PDQ Inventory

On March 14, Microsoft issued a security update to patch this operating system vulnerability. Use the collection created in the PDQ Inventory Collection Library to identify which computers on your network require the patch.

Deploy The Patch With PDQ Deploy

Once you have identified the computers that require the patch, use PDQ Deploy to deploy the patch and update your systems. The patches in the PDQ Deploy Collection Library installs the WannaCrypt patches for unsupported operating systems (XP, 2003x, 2008, Win8). Patches are also available for supported OS versions.

See how to manage this threat in this video:

More detailed instructions can be found in this KB article.

Important Links:

WannaCrypt Out Of Band Patches (Old OS) 1.0

Microsoft Security Bulletin MS17-010 – Critical


PowerShell and DevOps Global Summit 2017

Leave a commentPowerShell

Seems like so long ago, but I recently had the chance to attend the PowerShell and DevOps Global Summit 2017. In addition to enjoying some tasty food (haha), it was an amazing opportunity to learn, interact, and network with the top experts in the world of PowerShell. 

Would I repeat? You betcha!

What is the PowerShell and DevOps Global Summit?

The Summit is a chance for people (such as myself) to network and spend time with the top experts in the world of PowerShell, listen to presentations, and meet the PowerShell team. It is centered around PowerShell and DevOps and the problems/solutions that many of us face.


Happy Star Wars Day

2 CommentsPowerShell

It’s the age-old* question people have been asking since at least 2006. Which is nerdier, Star Wars or PowerShell? While the debate rages on, we’ve taken on a different task. How can we join the two together for the ultimate mashup of fandom meets technical prowess?

While it may be an unconventional use of PDQ Deploy (running a non-silent pun intended interactive windowed deployment), it’s still a fun experiment.

Behind the Scenes

Here is an excerpt of the trumpet part. Copy it into your PowerShell ISE and give it a run.

$sw = [Diagnostics.Stopwatch]::StartNew()
$host.ui.RawUI.BackgroundColor = "Blue"
$host.ui.RawUI.ForegroundColor = "White"

function Pause-Console
 param([int]$p = 0,[int]$n = 0)
 $playhead = $p
 $next = $n
 $savedColor = $host.ui.RawUI.BackgroundColor

 $elapsed = $sw.elapsedMilliseconds
 $pelapsed = $elapsed - $playhead
 $dur = $next-$playhead

 if($pelapsed -lt 0) {
  $pos = [math]::abs($pelapsed) + $dur
  if($pos -gt 200) {
   $host.ui.RawUI.BackgroundColor = "Black"
  Write-Output "Start-Sleep -m $pos"
  Start-Sleep -m $pos
  if($pos -gt 200) {
   $host.ui.RawUI.BackgroundColor = $savedColor
  $dif = $dur - $pelapsed
  if($dif -gt 0) {
   if($dif -gt 200) {
    $host.ui.RawUI.BackgroundColor = "Black"
   Write-Output "Start-Sleep -m $dif"
   Start-Sleep -m $dif
   if($dif -gt 200) {
    $host.ui.RawUI.BackgroundColor = $savedColor

function Console-Beep
  param( [int]$h = 0,
    [int]$p = 0,
     [int]$n = 0)
  $hertz = $h
  $playhead = $p
  $next = $n
  $elapsed = $sw.elapsedMilliseconds
  $pelapsed = $elapsed - $playhead
  $dur = $next-$playhead

 if($pelapsed -lt 0) {
  $pos = [math]::abs($pelapsed)
  $dur = $dur+$pos
  Write-Output "[console]::beep($hertz,$dur)" 
  $dif = $dur - $pelapsed
  if($dif -gt 0) {
   Write-Output "[console]::beep($hertz,$dif)" 

Console-Beep -h 880 -p 566 -n 778
Pause-Console -p 778 -n 1132
Console-Beep -h 880 -p 1132 -n 1344
Pause-Console -p 1344 -n 1698
Console-Beep -h 880 -p 1698 -n 1910
Pause-Console -p 1910 -n 4867
Console-Beep -h 466 -p 4867 -n 4909
Pause-Console -p 4909 -n 4926
Console-Beep -h 466 -p 4926 -n 4968
Pause-Console -p 4968 -n 4989
Console-Beep -h 466 -p 4989 -n 5029
Pause-Console -p 5029 -n 5051
Console-Beep -h 466 -p 5051 -n 5107
Pause-Console -p 5107 -n 5119
Console-Beep -h 466 -p 5119 -n 5197
Pause-Console -p 5197 -n 5281
Console-Beep -h 349 -p 5281 -n 5338
Pause-Console -p 5338 -n 5449
Console-Beep -h 622 -p 5449 -n 5515
Pause-Console -p 5515 -n 5664
Console-Beep -h 698 -p 5664 -n 5742
Pause-Console -p 5742 -n 5864
Console-Beep -h 622 -p 5864 -n 5932
Pause-Console -p 5932 -n 6055
Console-Beep -h 466 -p 6055 -n 6140
Pause-Console -p 6140 -n 6270
Console-Beep -h 466 -p 6270 -n 6355
Pause-Console -p 6355 -n 6461
Console-Beep -h 349 -p 6461 -n 6540
Pause-Console -p 6540 -n 6661
Console-Beep -h 622 -p 6661 -n 6721
Pause-Console -p 6721 -n 6874
Console-Beep -h 698 -p 6874 -n 6946
Pause-Console -p 6946 -n 7074
Console-Beep -h 622 -p 7074 -n 7134
Pause-Console -p 7134 -n 7261
Console-Beep -h 466 -p 7261 -n 7330
Pause-Console -p 7330 -n 7470
Console-Beep -h 466 -p 7470 -n 7545
Pause-Console -p 7545 -n 7670
Console-Beep -h 349 -p 7670 -n 7751
Pause-Console -p 7751 -n 7874
Console-Beep -h 622 -p 7874 -n 7946
Pause-Console -p 7946 -n 8082
Console-Beep -h 698 -p 8082 -n 8155
Pause-Console -p 8155 -n 8311
Console-Beep -h 466 -p 8311 -n 8377
Pause-Console -p 8377 -n 8389
Console-Beep -h 466 -p 8389 -n 8482
Pause-Console -p 8482 -n 8545
Console-Beep -h 466 -p 8545 -n 8639
Pause-Console -p 8639 -n 8832
Console-Beep -h 349 -p 8832 -n 8995
Pause-Console -p 8995 -n 9151
Console-Beep -h 349 -p 9151 -n 9295
Pause-Console -p 9295 -n 9470
Console-Beep -h 349 -p 9470 -n 9626
Pause-Console -p 9626 -n 9882
Console-Beep -h 466 -p 9882 -n 11051
Pause-Console -p 11051 -n 11114
Console-Beep -h 698 -p 11114 -n 12116
Pause-Console -p 12116 -n 12213
Console-Beep -h 622 -p 12213 -n 12276
Pause-Console -p 12276 -n 12343
Console-Beep -h 587 -p 12343 -n 12424
Pause-Console -p 12424 -n 12491
Console-Beep -h 523 -p 12491 -n 12554
Pause-Console -p 12554 -n 12662
Console-Beep -h 932 -p 12662 -n 13709
Pause-Console -p 13709 -n 13769
Console-Beep -h 698 -p 13769 -n 14238
Pause-Console -p 14238 -n 14353
Console-Beep -h 622 -p 14353 -n 14444
Pause-Console -p 14444 -n 14528
Console-Beep -h 587 -p 14528 -n 14638
Pause-Console -p 14638 -n 14734
Console-Beep -h 523 -p 14734 -n 14821
Pause-Console -p 14821 -n 14959
Console-Beep -h 932 -p 14959 -n 16144
Pause-Console -p 16144 -n 16171
Console-Beep -h 698 -p 16171 -n 16646
Pause-Console -p 16646 -n 16788
Console-Beep -h 622 -p 16788 -n 16885
Pause-Console -p 16885 -n 16963
Console-Beep -h 587 -p 16963 -n 17063
Pause-Console -p 17063 -n 17163
Console-Beep -h 622 -p 17163 -n 17260
Pause-Console -p 17260 -n 17369
Console-Beep -h 523 -p 17369 -n 18723
Pause-Console -p 18723 -n 18856
Console-Beep -h 349 -p 18856 -n 18913
Pause-Console -p 18913 -n 18950
Console-Beep -h 349 -p 18950 -n 19025
Pause-Console -p 19025 -n 19050
Console-Beep -h 349 -p 19050 -n 19125
Pause-Console -p 19125 -n 19165
Console-Beep -h 466 -p 19165 -n 20359
Pause-Console -p 20359 -n 20378
Console-Beep -h 698 -p 20378 -n 21528
Pause-Console -p 21528 -n 21578
Console-Beep -h 622 -p 21578 -n 21663
Pause-Console -p 21663 -n 21763
Console-Beep -h 587 -p 21763 -n 21848
Pause-Console -p 21848 -n 21959
Console-Beep -h 523 -p 21959 -n 22065
Pause-Console -p 22065 -n 22181
Console-Beep -h 932 -p 22181 -n 23354
Pause-Console -p 23354 -n 23381
Console-Beep -h 698 -p 23381 -n 23960
Pause-Console -p 23960 -n 23975
Console-Beep -h 622 -p 23975 -n 24075
Pause-Console -p 24075 -n 24175
Console-Beep -h 587 -p 24175 -n 24248
Pause-Console -p 24248 -n 24359
Console-Beep -h 523 -p 24359 -n 24434
Pause-Console -p 24434 -n 24571
Console-Beep -h 932 -p 24571 -n 25753
Pause-Console -p 25753 -n 25771
Console-Beep -h 698 -p 25771 -n 26334
Pause-Console -p 26334 -n 26375
Console-Beep -h 622 -p 26375 -n 26475
Pause-Console -p 26475 -n 26571
Console-Beep -h 587 -p 26571 -n 26650
Pause-Console -p 26650 -n 26765
Console-Beep -h 622 -p 26765 -n 26831
Pause-Console -p 26831 -n 26971
Console-Beep -h 523 -p 26971 -n 28078

#Change your default color scheme back in your ISE

Notice how we don’t actually use hard coded values on the [console]::beep and Start-Sleep functions? The reason for this is that over time, the playhead for each individual console can get off just a tiny bit depending on CPU speed and the audio output buffer. These tiny delays add up over time and cause the consoles to get out of sync with each other. In order to get around this issue, we calculate the time based on its sync with the [Diagnostics.Stopwatch].

If our fixed playhead note start time isn’t activated until after the current stopwatch time, then we subtract the delay amount from the total note, allowing the notes to catch up.

Showing The PowerShell Command Window

You may be familiar with the fact that even when deploying a .ps1 in interactive mode, the PowerShell window will not be visible on the target machine. To get around this, we’re going to run an additional PowerShell process using the Start-Process command.

Start-Process powershell.exe -ArgumentList '-Command "& {
  Write-Output \"Hello from PDQ Deploy\"

Note the character escape on the quotations: \". Because we’re using the -Command "& { }" argument, all quotations need to be escaped.

On the PowerShell step, on the Options tab, set your Run As to Deploy User (Interactive)

Happy PowerShelling!

*2006 may not be that long ago, but in computer terms, we’re approaching ancient history.

Reading The Hosts File With PowerShell (local and remote)

2 CommentsPowerShell

Today’s blog focuses on reading the hosts file with PowerShell. Though there are many reasons that someone may modify the hosts file of a machine, it can easily get out of hand with entries scattered about your network.

Whatever the story, most of us have had reason to read or modify info in the hosts file at one point in our lives. We’re going to cover reading the hosts file with PowerShell locally as well as remotely for multiple machines. Yay!

Reading the hosts file with PowerShell

The hosts file is, simply put, a mapping of host names to corresponding IP addresses. You can go explore the how and the why of using it, but that’s outside the scope of this blog.

It’s easy enough to browse to the hosts file location and open the file manually. On modern versions of Windows, it’s stored here (you’ll need admin access to modify it):


But, what about keeping tally of all the machines on your network? Do you really want to manually browse to this file on each machine? This is most definitely a rhetorical question. The correct answer is an emphatic, “No!”

So, what do we do? We use PowerShell of course! Reading the hosts file with PowerShell is a breeze.

Getting the entire contents of hosts file with PowerShell

In order to do this, we are going to make use of the Get-Content cmdlet. This cmdlet will read the contents of a file.

If you only need to quickly see the entire contents of the hosts file, then this super simple one-liner should do the trick:

Get-Content $env:SystemRoot\System32\Drivers\etc\hosts

That’s simple enough and gets us the basic info that we’re looking for.

But, what if we want to only grab the actual entries instead of the entire file? Easy peasy with PowerShell.

Getting all entries from hosts file

In order to get all the entries from the hosts file, we’re going to use regular expressions to compare against every line in the hosts file.

Additionally, we will also log the output to a file. Having a log file will make it much easier to see all the results at a glance.

$LogFile = "\\MyScripts\Logs\hosts file results.csv"
$Pattern = '^(?<IP>\d{1,3}(\.\d{1,3}){3})\s+(?<Host>.+)$'
$File    = "$env:SystemDrive\Windows\System32\Drivers\etc\hosts"
$Entries = @()

(Get-Content -Path $File)  | ForEach-Object {
    If ($_ -match $Pattern) {
        $Entries += "$env:COMPUTERNAME,$($Matches.IP),$($Matches.Host)"

$Entries | Tee-Object -FilePath $LogFile -Append

Voila! It’s fairly simple and it gets you clean results with only the actual entries in the hosts file (rather than the entire file contents).

Fantastic! Now, let’s move on to doing this for all the machines!

Getting entries from hosts file for multiple machines

So, we’ve got this fancy script to get our hosts file entries and log them to a file. Getting them from multiple machines is also a snap.

Here are a few different ways that you can accomplish this:

  • PDQ Deploy and PowerShell steps
  • PDQ Inventory and Remote Command
  • Remote PowerShell and Invoke-Command
  • Directly access the files on the remote computers via UNC path


PDQ Deploy and PowerShell steps

Here are the steps to use PDQ Deploy with these PowerShell scripts.

  1. Create a PDQ Deploy Package with a PowerShell Step that includes your script.
  2. Deploy to your targets and verify your log file.

Like magic, you can now deploy to all your targets and save your results to a log file on some UNC path. Go you!

PDQ Inventory and Remote Command

Here are the steps to use PDQ Inventory with these PowerShell scripts.

  1. Select your targets and use Remote Command.
  2. Save your PowerShell script to a file and call that file from PowerShell Remote Command.
  3. Select all targets to see combined results. Computers with no results will simply show, “Return code: 0” since they successfully ran but didn’t have any results.

Ta da! It’s that easy. It’s very quick to select some machines and then see what they have in their hosts file.

Remote PowerShell and Invoke-Command

This requires that you have previously configured remote PowerShell for your targets. Otherwise, you’ll receive errors when attempting to connect to your targets. I’ve added Test-WSMan to filter those results.

Additionally, we’ll need to change how we’re logging to file otherwise we’ll run into double-hop authentication issues. 

$LogFile   = "\\MyScripts\Logs\hosts file results.csv"
$Result    = @()
$Computers = @("FRY", "UTER", "WOLVERINE")

$MyScript = {

    $Pattern = '^(?<IP>\d{1,3}(\.\d{1,3}){3})\s+(?<Host>.+)$'
    $File    = "$env:SystemDrive\Windows\System32\Drivers\etc\hosts"

    (Get-Content -Path $File)  | ForEach-Object {
        If ($_ -match $Pattern) {

Foreach ($Computer in $Computers) {

    If ( [bool](Test-WSMan -ComputerName $Computer -ErrorAction SilentlyContinue)  ) {

        $Result += Invoke-Command -ComputerName $Computer -ScriptBlock $MyScript


$Result | Tee-Object -FilePath $LogFile -Append


Directly read remote hosts file via UNC path

This method is simply using the direct UNC path to the hosts files. In this example, I’m assuming the system drive is C.

$LogFile   = "\\MyScripts\Logs\hosts file results.csv"
$Pattern   = '^(?<IP>\d{1,3}(\.\d{1,3}){3})\s+(?<Host>.+)$'
$Entries   = @()
$Computers = @("FRY", "UTER", "WOLVERINE") 

Foreach ($Computer in $Computers) {

    $file = "\\$Computer\c$\Windows\System32\Drivers\etc\hosts"
    (Get-Content -Path $File) | ForEach-Object {
        If ($_ -match $Pattern) {
            $Entries += "$computer,$($Matches.IP),$($Matches.Host)"

$Entries | Tee-Object -FilePath $LogFile -Append

This will probably be the fastest method to get the hosts file info.

Wrapping Up

That’s it! Now, you have a bunch of ways to tackle the task of reading all your hosts file records.

These are just examples, so you’ll likely want to modify them for your environment. One change that I can think of, for example, is importing your list of computers. In my examples, I am using a static list of computers.

In any case, have fun with it!

Happy PowerShelling!


Escaping the Patch Management Cycle With Auto Deployment

Leave a commentAuto Deploy, PDQ Deploy

Do you enjoy repetitive tasks, busy work, and thoughtless clicking of buttons? If you do, then this blog might not be for you. This blog is for people looking for a better solution to patch management and software updates.

Are you staying late at work trying to update all of your machines to the latest version of Java, Flash, Chrome, etc? We feel ya. We’ve all been there.

Unless you’re a robot who enjoys repetitive tasks, everybody has better things to do than to worry about manual patch management and software updates. After all, those cans of Dr Pepper and Corgi videos aren’t going to enjoy themselves.

Well, today’s your lucky day, friend! PDQ Deploy has this fabulous feature called Auto Deployment that makes patch management and software updates an absolute snap!

Patch Management and Software Updates

We all have software that needs updating. If you’re managing computers, then you are probably well aware of the challenge of keeping all of your computers up-to-date.

The old inefficient way – one by one

Updating every computer one at a time is a very slow process. It’s prone to problems and sadness… but mostly sadness.

Here’s what this process typically looks like:

  • Finding and downloading the latest software
  • Physically going to a computer
    • Bonus points if you use a remote solution
  • Running the installer
  • Click clickity clicking through the installer
  • Waiting for the installer to finish
  • Crying a little bit on the inside
  • Rinse and repeating for every single computer

First of all, nobody likes this approach. Why? Because it’s full of hair-pulling and sadness. Unfortunately, this is common at many places.

The better way – Auto Deployment with PDQ Deploy

With the Auto Deployment approach, here is what patch management could look like:

  • Sitting back and relaxing
  • Learning PowerShell (check out our PowerShell blogs!)
  • Annoying your co-workers with paper airplanes
  • Drinking a beer (or two)
  • Smiling with the knowledge that you don’t have to manually install software for all of your computers!

I don’t know about you, but this process sounds much more appealing than the hair-pulling and eye-gouging that comes with manual software updates. Also, it takes all the busy work out and replaces it with valuable free time.

Sounds nice, right? So, let’s get on with the good stuff and show you how to set it up!

Patch Management Done Right – Auto Deployment with PDQ Deploy

So, what is Auto Deployment? Auto Deployment is a feature in PDQ Deploy that allows you to automatically deploy new versions of software packages as they become available in the PDQ Deploy Package Library.

We test these packages thoroughly to ensure that they install silently and are prepped for full automation. As a result, this means that you can rest assured that the software will work for you the first time. (Read more about the Package Library here – link)

Configuring Auto Deployment

Setting up Auto Deployment in PDQ Deploy consists of 3 easy steps:

  1. Create a Schedule
  2. Attach a Schedule to a Package in the Package Library
  3. Enjoy your new free time

So, pop open PDQ Deploy and follow along!

  1. Create a schedule

    • Click New Schedule in PDQ Deploy
      PDQ Deploy - New Schedule Button
    • Add a Schedule Name
      PDQ Deploy - Add Schedule Name
    • Add triggers
      PDQ Deploy - Schedules - Add Triggers
    • Add target computers
      PDQ Deploy - Schedules - Add Targets
  2. Attach a schedule to a package in the Package Library

    • Select Package Library.
      PDQ Deploy - Auto Deploy - Select Package Library
    • Select a Package.
      PDQ Deploy - Auto Deploy - Select a package
    • Select New Auto Deployment using existing schedule.
      PDQ Deploy - Auto Deploy - Add New Auto Deployment using existing schedule
    • Select your schedule and click OK.
      PDQ Deploy - Auto Deploy - Select Schedule and click OK
    • Now, your new Auto Deployment package will show up in its own fancy section. It will run according to the schedule and triggers that you defined.
      PDQ Deploy - Auto Deploy Page
  3. Enjoy your new free time

    • Of course, enjoying free time is up to you. Since you have just saved a lot of time and effort by using Auto Deployment, you should pat yourself on the back and go do something fun.

Extra things to consider

While this is just one simple example of an Auto Deployment setup, you may find that you have different needs. Because of this, we allow for many different configurations since everybody has different needs.

Here are some common questions we get about Auto Deployment packages:

Can I have multiple Auto Deployment packages in a single schedule? Yes!
You can attach a mixture of Auto Deployment packages and regular packages to a single schedule.

Can I install older versions of software? You bet!
Just like any package in the Package Library, you can choose older versions of software to install automatically.

Can I test Auto Deployment packages before deploying them to all of my machines? Of course!
With the Auto Deployment Approval Policy, you can set each Auto Deployment to approve updates immediately, manually, or on a schedule. It’s up to you and your needs.
This is configured in the Preferences.

PDQ Deploy - Preferences - Package Library

Can I modify the Auto Deployment package? Definitely!
We allow the ability to create pre-steps and post-steps within an Auto Deployment package. Just double-click your Auto Deployment package to open up the editor.

Auto Deploy - Google Chrome

Check out our PDQ Deploy Help Documentation for more detailed info.

Still not convinced? Watch a quick demo!

Wrapping Up

As you can see, we really turn it up to 11 with Auto Deployment for your patch management and software updates. So, do yourself a favor and try it out! Otherwise, you’ll kick yourself for not finding this solution sooner!

Simplify Your Scripting Life By Creating PowerShell ISE snippets

3 CommentsPowerShell

This post is dedicated to the forgetful. I have learned to cope with my forgetfulness by creating PowerShell ISE snippets.

I’ll be the first to admit that I tend to forget things. All the time. So much, in fact, that it may even seem intentional.

Does this sound familiar? Have you ever…

  • Opened up old scripts in order to remember exactly how you used a particular cmdlet?
  • Saved script templates so that you’d have an example of a particular cmdlet or syntax?
  • Ripped out your hair in frustration because you can’t find those old files or templates?!

Awesome. You’re human. We’ve all done that. Especially us forgetful folks.

Now, wouldn’t it be fabulous if there was a much simpler way to save your awesome syntax *and* your hair?

Well, you’ve come to the right place!

PowerShell ISE Snippets

When a problem comes along, yoooouuu must snippet.    ~ Devo. Maybe.

The PowerShell ISE has a slick little feature called snippets that you may or may not be familiar with! They were introduced way back in version 3 of the ISE.

You may already be using this feature without realizing it. Have you ever pressed Ctrl+J while using the ISE? Maybe you’ve right-clicked and opened up the context menu and selected Start Snippets. Both of these pop up the available snippets!

Go on! Try it out! All you need to do is select a snippet from what’s available.

At this point, you may be thinking, “That’s pretty nifty, but what good does that do me?”.

Lots of good, I say. Lots!

You will find that there are many default snippets that are available for you to use right out of the box. How thoughtful of the PowerShell team!

  • Need a Do While snippet? Done.
  • Need a Try/Catch snippet? Piece of Cake.
  • Need DSC template snippets? Fuhgeddaboudit!

Now, this is all fine and dandy, but what happens when you want something that’s simply not available? 

You pick up your mighty PowerShell hammer and create it!



Brace yourself. You’re going to love this. There is a cmdlet made specifically for creating PowerShell ISE snippets. *gasp!*

It’s called New-IseSnippet and it is wonderfully wonderful.

New-IseSnippet only has a few parameters, so it is really easy to get a new snippet created. Here is a list of those parameters.

-Title string (required)
This is what shows up in the snippets popup. It’s also the name of the snippet file.

-Description string (required)
This is what shows up in the description section of the snippets popup.

-Text string (required)
This is the PowerShell code that is actually added to your editor.

-Author string
This shows up in the snippet file itself rather than within the editor.

-CaretOffset Int32
This is the character offset for the position of the cursor after adding the snippet to your editor.

Here is where some of the parameters will show up within the snippet.

Now, enough with the talk. Less talk and more typing!


Creating PowerShell ISE Snippets with New-IseSnippet

Hands down, the hardest part of this entire process is coming up with a snippet that you want to create.

To start, let’s keep it simple and find something that you often use in your code. I often find myself using Test-Path in an If statement, so here’s an example snippet that I might create:

$Title       = "If Test-Path"
$Description = "If Test-Path valid do something. Or Do something else. You decide."
$Author      = "Kris"
$Text        = @'

If (Test-Path $SomePath) {

    # If Path valid

} Else {

    # If Path not valid


New-IseSnippet -Title $Title -Description $Description -Author $Author -Text $Text


Give that a spin. When you open up the snippets popup menu, you’ll see “If Test-Path” is an available snippet to use.

Now, when you select it, you should magically see If Test-Path appear.

Easy peasy. You’ve got this down. You’re pretty much a pro at this now.

So, let’s add another luscious layer to this delectable cake.


Creating PowerShell ISE Snippets with a PowerShell ISE Snippet

While on the subject of PowerShell ISE snippets, I decided to create a snippet that creates snippets, a little “snipception” if you will. Deep, I know.

Mostly, I wanted to give an example of using the -CaretOffset parameter and thought that this would be a fun example.

$Title       = "Snippet Template"
$Description = "'When a problem comes along, yooouu must snippet...' ~Devo. Maybe."
$Author      = "Mr. Snippet"

$Text = @'

$Title        = ""
 $Description = ""
 $Author      = ""
 $Text        = @"


New-IseSnippet -Title $Title -Description $Description -Author $Author -Text $Text

New-IseSnippet -Title $Title -Description $Description -Author $Author -Text $Text -CaretOffset 16 -Force


This will create a snippet called Snippet Template that you can use for creating even more snippets!

The -CaretOffset 16 part means that the cursor will start after the 16th character when the snippet is used.


Wrapping up

Well, that’s basically it. As you saw, it is fantastically fabulous. So, if you use the ISE, you should take a look at creating your own custom snippets. 

#Snippets4Ever #PowerShellLife or, however kids these days portray their excitement over snippets and PowerShell.

Happy PowerShelling!



Just in case you were wondering (and I’m sure you were), your newly created snippets will be stored in your user profile directory:


These are saved as XML files (.ps1xml files). That means that you can use all the powers of XML manipulation to create, modify, save, backup, and even cherish those files. Hurray!

Uninstall Skype for Business with OCT or Click-to-Run

Leave a commentUncategorized

The Powers From On-High have declared that no more shall Skype for Business be installed in your organization. No more recipe sharing, pictures of Ms. Coddlebottom’s trip to Aunt Bethany and Uncle Cleatus’ gator farm, or HR infractions in the form of wildly inappropriate memes involving kitchen utensils and spray foam. You have been tasked, and you will prevail.

Depending on which of the two methods you used to install Skype for Business, there are three methods of expungement. The first uses the Office Customization Tool (OCT), the second uses PDQ Inventory and C2R, and the third uses an XML and C2R.

If my math is right, that’s one for the OCT and two for the C2R. Below is an overview of the steps, but for a more in-depth dive, visit the Install/Uninstall Skype for Business article.

Uninstall using Office Customization Tool (OCT)

The ability to uninstall as a feature of Office 2016 is rather easy. The steps are the same as installing Skype for Business with the exception of the MSP. After an Office 2016 (OCT ) installation, follow these steps to install.

  1. With the exception of Set feature installation states, create another MSP the same way you would during an initial setup, as seen below:
    how to uninstall skype for business
  2. Save the MSP, the default name is SkypeUninstall.MSP.
  3. Create a PDQ Deploy package with a PowerShell step followed by an Install step. Both steps are necessary to prevent a failure, the PowerShell script is as follows:
    Get-Process "Lync*" | Stop-Process -Force
  4. Add the SkypeUninstall.MSP file to the Install step and watch as the magic that is PDQ Deploy adds the necessary parameters for you. Information on the Conditions and Options tab are included in the Deploy Office 2016 article.
  5. Save the package and deploy. It is recommended to test a deployment first.

Uninstall using PDQ Inventory and C2R

This method only applies to the C2R version of Skype for Business.

  1. In PDQ Inventory, navigate to the Applications page of the individual Computer window.
  2. Click on Skype for Business 2016. Copy the uninstall string listed in the Uninstall column, as seen below:
    "C:\Program Files\Common Files\Microsoft Shared\ClickToRun\OfficeClickToRun.exe" scenario=install scenariosubtype=ARP sourcetype=None productstoremove=SkypeforBusinessRetail.16_en-us_x-none culture=en-us version.16=16.0
  3. Create a new PDQ Deploy package with a Command step.
  4. Paste the uninstall string into the Command and delete the last two statements, culture=en-us version.16=16.0. The string should now look as follows:
    "C:\Program Files\Common Files\Microsoft Shared\ClickToRun\OfficeClickToRun.exe" scenario=install scenariosubtype=ARP sourcetype=None productstoremove=SkypeforBusinessRetail.16_en-us_x-none
  5. Save the package and deploy. As usual, we recommend you test this first.

Uninstall using an XML and C2R

This method only applies to the C2R version of Skype for Business.

  1. From Microsoft’s site, download the Office 2016 Deployment Tool (C2R).
  2. Create a shared directory for the C2R/Skype for Business “deployment”: \\server\share\
  3. Install the Office 2016 Deployment Tool for C2R and select \\server\share\ as the extraction location.
  4. The deployment tool will create configuration.xml, copy this to SkypeRemove.xml in the same directory.
  5. Edit SkypeRemove.xml. The XML should look similar to this (change the Language ID and Product ID as appropriate):
       <Product ID="SkypeforBusinessRetail" >
        <Language ID="en-us" />
     <Display Level="None" />
  6. Create a new PDQ Deploy package with a Command Step. Modify to match your \\server\share choices from above:
    "\\server\share\setup.exe" /configure "\\server\share\SkypeRemove.xml"

    On the Options tab, select the Run As option to Deploy User (Interactive)

  7. Save the package and deploy.

Notes and Addenda of Some Import:

  • Office 2016 Deployment Tool (C2R) supports these Product IDs.
  • It is recommended using the Run As option Deploy User (interactive) when uninstalling (and installing) Office products,
  • The products listed are for United States English (en-us). For use with other languages, please see the Microsoft Language Identifiers site.
  • The process for uninstalling Skype for Business 2013 is similar to 2016. You will need to download the Office 2013 Deployment Tool as well as use the correct Product ID for the 2013 version, which is either LyncRetail or LyncEntryRetail.
  • Error 17002. This error occurs if the Lync.exe process is still running when an uninstall is attempted, specifically the Skype for Business feature (OCT) uninstall.
  • Make certain you are uninstalling the appropriate product as expressed by the Product ID defined by Microsoft. Skype for Business has two Office 2016 options: SkypeforBusinessRetail and SkypeforBusinessEntryRetail.

See Also…
Deploy Office 2016 Using The Microsoft Office Customization Tool
Deploy Office 365
Silently Installing Office 365
Admin Arsenal Live! : Uninstalling Microsoft Office with PDQ Deploy
Admin Arsenal Live! : Adding and Removing Microsoft Office Components
Configuring and Deploying the Microsoft Office Customization Toolkit
Preparing The Office Customization Toolkit For Deployment
Deploy the Office Customization Toolkit Remotely

Enforcing Execution of Browser Extensions Explicitly – Part II

Leave a commentUncategorized

Part the Second: Internet Explorer

A few weeks ago, we posted about how to manage Chrome Extensions. This week, we’re doing the same for Internet Explorer (IE), the other enterprise browser. And like Chrome, we’re using the best tool for the job, Group Policy. (See the note at the end of this blog for information about IE’s future).

Let’s get to it.

Add-on Management for Internet Explorer:

The first thing you want to do is set up Internet Explorer the way you want it set for your users. This means all the add-ons they could possibly need should be included. You can add some of the pre-built add-ons from the IE Gallery. You’ll notice, however, the Gallery is a lot smaller than it used to be and certain things no longer work. 404 Page Cannot Be Displayed. Sad! Other add-ons can be included by deploying programs with IE add-ons included (e.g. Adobe Reader, Adobe Acrobat, Office, Java, etc.)

Once you’ve selected all the add-ons, go to manage add-ons in IE, right-click one of the add-ons and select More Information. You’re going to need the Class ID for the GPO. Copy the More Information into Notepad or other text editor so you can copy the Class ID.

Repeat this process for all the add-ons you want to manage in IE.

Now create the GPO.

Internet Explorer Add-on management should already be included in Group Policy. Open the GPMC, create a new Group Policy, edit that policy and navigate to Computer Configuration > Policies > Administrative Templates > Windows Components > Internet Explorer > Security Features > Add-on Management. You should see something like this:

We’re going to set up the Add-on List. Open that setting, enable it, and click Show… next to Add-on List. Add your Class IDs you retrieved earlier and choose the value you want. The values are as follows:

0 = The add-on is disabled and cannot be changed

1 = The add-on is enabled and cannot be changed.

2 = The add-on is enabled and can be changed.

Here’s an example of the add-ons with values for the Add-on List setting:

The next thing is to deny all the add-ons not defined in the Add-on List. It’s pretty straightforward. Open the Deny all add-ons unless specifically allowed in the Add-on List and enable the setting.

That’s it. Save the GPO, apply it wherever makes sense, and you’re finished.

Next, let’s run some tests.

First, we deploy the Shockwave Player and Java to a machine with IE installed. We see some add-ons in the Manage Add-ons properties of IE.

Next, we wait or run gpupdate on the target machine, restart IE. Go to Manage Add-ons again, and voila:

Next, we’ll take a look at Bethany Coddlebottom’s machine (the GPO has not been applied)…

Move that machine into range of the GPO, run gpupdate, and restart IE:

That’s it.


As you likely know, on January 12, 2016, support for older IE versions ended. Security updates would still be provided for the latest supported version through the OS lifecycle, but no additional IE releases were planned. You can read more here.