Correct Horse Battery Staple for PowerShell, AKA Random Memorable Password Generator

I’m a fan of using for generating temporary passwords for users, rather than always using a static password. The site itself is a reference to the XKCD webcomic, and yes, I’m aware that there are plenty of opinions on the web about this topic.


I’ve had the idea in the back of my mind for a while to see if I could replicate the site’s functionality in PowerShell. I noticed that the source code for the site is on GitHub, so I ducked over there to check out the word list.

I found that it’s possible to replicate most of the functionality of the site with just two lines of PowerShell (although it doesn’t result in very readable code):

  1. I used Invoke-WebRequest to grab the word list from GitHub
  2. I then expanded out the Content property, and split it up given the comma delimiter
  3. I then used a combination of the Range operator, Foreach-Object, [string]::join,Get-Random and the TextInfo class to generate a given number of passwords along these rules:
    1. 4 random words, each with the first letter capitalised
    2. A separator in between
    3. A random number between 1 and 99 at the end

Note that this isn’t failure-proof, and isn’t intended to be used in any complex scenario. There’s no error handling, and not much flexibility built in. It’s just a quick function you could put into your PowerShell profile.

You can, at least, do the following:
A PowerShell window displaying the output of Get-RandomPassword. Also shows the function being called with a Count parameter as well as a separator parameter

Here’s the code:

ADFS 3.0 Error: The Web request failed because the web.config file is malformed

Had a strange one today after an Azure outage. One of my Server 2012 R2 ADFS proxies wouldn’t start the ADFS service.

When looking in the logs, it appeared like a case of simply having to re-establish the proxy trust, but I got a different error when trying to start the service:

The federation server proxy could not be started.
Reason: Error retrieving proxy configuration from the Federation Service.

Additional Data
Exception details:
An error occurred when attempting to load the proxy configuration.

There were other errors in the ADFS Event logs about a malformed config file:

The Web request failed because the web.config file is malformed.

User Action:
Fix the malformed data in the web.config file.

Exception details:
Root element is missing. (C:\Windows\ADFS\Config\microsoft.identityServer.proxyservice.exe.config)
Root element is missing.

When I opened the abovementioned config file, it was empty. I compared this to the config file on the other ADFS proxy, and that one looked like a normal config file.

My solution, and what ended up fixing the issue in the end, was simply to copy the contents of the .config file from the working ADFS proxy to the broken one. I could then re-establish the proxy trust, and everything started running again.

I’m not sure if this would work, but in case you don’t have another ADFS proxy to grab the config file from, here’s a sanitised version of mine:

<?xml version="1.0" encoding="utf-8"?>
<section name="microsoft.identityServer.proxyservice" type="Microsoft.IdentityServer.Management.Proxy.Configuration.ProxyConfiguration, Microsoft.IdentityServer.Management.Proxy, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<congestionControl latencyThresholdInMSec="8000" minCongestionWindowSize="64"
enabled="true" />
<connectionPool connectionPoolSize="200" scavengeInterval="5" />
<diagnostics eventLogLevel="15" />
<host tlsClientPort="49443" httpPort="80" httpsPort="443" name="" />
<proxy address="" />
proxyTrustRenewPeriod="21600" />
<!-- <system.serviceModel>
<messageLogging logEntireMessage="true"
</system.serviceModel> -->

Once I’d resolved the problem, I did a bit of searching around for this error message, and it appears that other people have had the same problem previously, with no resolution listed in the one thread that I looked at on the TechNet forums.

Script to create new local admin account for use with LAPS

I’ve got a bunch of older SOE machines that still had the local Administrator account enabled. As part of implementing Microsoft LAPS, I wanted to disable that account, and use a newly-created ‘LocalAdmin’ account with LAPS.

The account is created with a randomly-generated GUID as the password. The account’s password is going to come under the management of LAPS anyway. Additionally, it would be a terrible idea to hard-code a password into a script that’s stored in Sysvol.

If an account with that name already exists, the script will quit. Some basic events are also logged to the Event Log to indicate what happened.

My first revision of the script used ADSI to create the account and add it to the Administrators group, but I found that my mileage varied with that method. Some computers had the account created, but it wasn’t a member of Administrators.

It’s now set up to use plain “NET USER” and “NET LOCALGROUP” commands. This is an example of what would be executed:
2016-04-04 16_01_06

This script is designed to be set up as a computer Startup Script:

Configure Desired State Configuration (DSC) on CentOS 7

Here’s a quick guide on how to set up DSC on CentOS 7. This requires OMI and DSC for Linux. It’s a bit of a pain to track down the downloads for these, and the OMI one doesn’t play ball when using wget, so I’ve put them on Dropbox for ease of use:

I always use the Minimal installation of CentOS. I started with CentOS-7-x86_64-Minimal-1511.iso

  1. Install CentOS, configure an IP address
  2. Connect in via SSH, or the console, run the following commands:
    1. yum install wget -y
    2. cd /home
    3. wget
    4. wget
    5. tar -zxvf omi1084
    6. tar -zxvf dsc_linux_111
    7. rpm -ivh omi-1.0.8.ssl_100.x64.rpm
    8. systemctl start omid.service
    9. rpm -ivh dsc-1.1.1-70.ssl_100.x64.rpm

To test connectivity from a Windows machine, do the following:

$session = New-CimSession -Credential (Get-Credential) -Authentication Basic -ComputerName <name or IP here> -SessionOption (New-CimSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -UseSsl)
Get-CimInstance -CimSession $session -ClassName OMI_Identify -Namespace root/omi

You’ll be prompted to enter credentials after that first line. Then, after running Get-CimInstance you should see an output as per below:

2016-02-28 12_36_47

The CentOS machine is now ready to receive configs using DSC. I’ll be blogging more related stuff soon, but there’s a great write-up on the PowerShell Documentation pages that goes into more detail:

Get started with Desired State Configuration (DSC) for Linux

List email addresses for ActiveSync device associations in Office 365

Today I had to get a list of email addresses for iOS users associated with a specific Office 365 tenant.

Using the Get-MobileDevice cmdlet in Exchange/Office 365 PowerShell is handy, but it only shows the user’s name, not their email address:

There are some older solutions around on the web that involve running a Get-Mailbox, and then iterating through each mailbox to get the ActiveSync device information. This seemed like overkill to me, as I only needed a basic list.

I ended up with the following one-liner, which uses Calculated Properties to grab the email address:

Get-MobileDevice -ResultSize Unlimited | Select-Object @{Name='User';Expression={(Get-Mailbox -Identity $_.UserDisplayName) | Select-Object -expand WindowsEmailAddress}},DeviceID,DeviceImei,DeviceOS,DeviceType,DeviceUserAgent,DeviceModel | Export-Csv C:\temp\mobile_devices.csv

This allowed me to open the CSV in Excel and filter down the list until I was left with the information that we were after.

Your mileage may vary using this command, as we’re matching a ‘UserDisplayName’ field on a Microsoft.Exchange.Data.Directory.SystemConfiguration.MobileDevice to the ‘Identity’ field on a Microsoft.Exchange.Data.Directory.Management.Mailbox.

Create a Scheduled Task to keep all Chocolatey Packages up-to-date

Rebuilding your PC is always a drag, even with useful utilities like Ninite.

I recently created a PowerShell DSC script that I can use whenever I need to rebuild my PC. As part of that, I used the cChoco provider to automatically install applications using Chocolatey. I’ll be writing a blog post with more details shortly.

That’s a great way to get the applications installed, but not for keeping them up-to-date. Chocolatey allows you to run ‘choco upgrade all’ manually to do this:

Command prompt window showing the results of a 'choco upgrade all -y' command

Rather than manually create the scheduled task to automate this, I created this short PowerShell script:

The script will:

  1. Locate the choco.exe binary (It’ll quit if it can’t find it in the path)
  2. Set up a scheduled task that runs said binary at system startup

Note that this script will only work on Windows 8 and newer machines, because it relies on the *-ScheduledTask cmdlets.

Use PowerShell to list all Windows Performance Counters and their numeric IDs

I’ve been looking into using Zabbix again lately, and was delighted to see that they’ve now released a refreshed and improved version 3.0

Whilst I was browsing some of my old Chrome bookmarks for Zabbix, I came across their article about Windows performance counters. They mention that performance counters in Windows have localised names, and that if you’re running systems in several different languages, you need to refer to the counters by their ID, rather than by name, when configuring monitoring.

This can be achieved by looking the list up in the registry, but it’s all just stored as a multi-line string value:


This isn’t ideal if you’re searching for something specific, or you just want a nicely-formatted output. I’ve created a quick PowerShell function that outputs these values, and allows you to use standard PowerShell operations to search and filter.

For example, output to a text file:

Get-PerformanceCounter | Out-File c:\temp\perfcounters.txt

Results in this:

Or you could do something like this:

Get-PerformanceCounter | Where-Object {$_.CounterName -like 'file write*'}

Which results in this:

CounterID CounterName              
--------- -----------              
       12 File Write Operations/sec
       18 File Write Bytes/sec

Or, you could sort them by name:

Get-PerformanceCounter | Sort-Object -Property 'CounterName' | Format-Table -AutoSize

Which would result in the following output

CounterID CounterName                                                   
--------- -----------                                                   
     7024 # Bytes in all Heaps                                          
    10686 # exceptions                                                  
     7014 # GC Handles                                                  
     6986 # Gen 0 Collections                                           
     6988 # Gen 1 Collections                                           
     6990 # Gen 2 Collections                                           
    10688 # images                                                      
     7018 # Induced GC                                                  
     7124 # Link Time Checks                                            
     7086 # of CCWs                                                     
     7108 # of current logical Threads                                  
     7110 # of current physical Threads                                 
     7112 # of current recognized threads                               
     7150 # of Exceps Thrown                                            
     7152 # of Exceps Thrown / sec                                      
     5046 # of failed workflow jobs                                     
     5048 # of failed workflow jobs/sec                                 
     7154 # of Filters / sec                                            
     7156 # of Finallys / sec                                           
     7072 # of IL Bytes Jitted                                          
     7090 # of marshalling                                              
     7070 # of Methods Jitted                                           
     7030 # of Pinned Objects                                           
     5050 # of resumed workflow jobs                                    
     5052 # of resumed workflow jobs/sec                                
     5054 # of running workflow jobs                                    
     5056 # of running workflow jobs / sec                              
     7032 # of Sink Blocks in use          

Here’s the code: