This is a place for Systems Administrators and IT Professionals to find and share ideas, solutions and templates. If you have something that helps you solve a problem, chances are it will help someone else too. So pay it forward and send an email to TheAgreeableCow at gmail. Full mudos to you!

Tuesday, 17 May 2016

Ransomware Mitigation Matrix


By now ransomware ought to have your attention. From a deployment perspective, it can be purchased cheaply and it comes with administrative consoles and installation packages that receive regular patches and updates that rival some commercial software. The malware infects you in new and changing ways, with network shares being discovered beyond mapped drives, RDP is becoming a 'Remote Distribution Protocol' and your backups are in a game of hide and seek.

This is a practical guide to reducing your risk of being exposed to malware in general, with a specific focus on Ransomware. This is not a new phenomena in IT circles, but the changing landscape makes it a threat that deserves more than a cursory review.

Having layers of protection reduces your risk.

The matrix below outlines three layers of risk mitigation, which is an important point to note; There is no silver bullet to preventing Ransomware and malware in general for that matter. You can have the best and most expensive email filtering in the world and still be exposed to staff downloading dodgy content from personal webmail. Throw in a top notch web proxy you say, only to find someone connecting a BYOD device or loading malware from a USB they found in the car park!

Defend your environment in three ways;
  1. Perimeter - Prevent malware from entering your network
  2. Runtime - Prevent Malware from running on your network
  3. Damage Control - Reduce impact of an outbreak
Having a layered strategy also allows you to defend your network even if you can't afford or maintain a premium product in one layer or another. Firewalls and email/web gateways whilst very effective, can be expensive and complex for example. So as much as this post mentions specific solutions, it's also about strategies - there is a lot you can do that is free or low cost and achievable with low administrative overheads. Further, by spreading your protection, it allows you to set policies and practices that are not over zealous or (mis)designed in ways that cripple your staff's productivity.

Which strategies should you apply?

The matrix below lists dozens of items to mitigate ransomware. Of these, the top three things you can do to protect your data are:
  1. Conduct regular backups and test restoration
  2. Separate access control to your backup files
  3. Make copies of your backups off network
 As pessimistic as this seems, insuring your data really is your best line of defense. It doesn't matter how many attacks you brush aside, it only takes one to sneak through using a new vector and your data will be compromised. At this point, all recommendations are not to pay any ransom and simply restore from backup.

OK, so backup are solid, what next? Realistically, mitigation is a balance between effectiveness and impact. That is, IT administrative effort, financial costs and the productivity burdens placed on your staff. A quick note on effectiveness - the items below are viewed in terms of the contribution towards mitigating ransomeware. Some items (such as a strong password policy or email TLS), may be very good at servicing a particular technical requirement. However in context, they may score a low effectiveness as they don't really contribute greatly in the overall threat profile or solution deliverables.

Initially, look for the easy wins (highly effective items, with minimal impact). There is also a lot of reward in clever network design that won't cost you a cent. Then look for solutions that are effective  over time with consistent return. Relegate solutions with a waning effectiveness, that requires constant IT attention and negatively impacts your staff productivity. As such, look for areas where effectiveness is steadily above both IT administration overheads and user impact.

Ransomware Mitigation Matrix

The second half of this post discusses these mitigation techniques in more detail.

Email Gateways
A strong email gateway is an excellent investment towards mitigating malware and assisting staff productivity through the reduction in illegitimate email traffic.

  • Malware and malicious object scanning should be automatic and thorough with dynamic updates for heuristic and signature based detection. Suspect items should be quarantined and fully separated from initial user access.
  • Greylists and Blacklists are techniques to reduce spam and malware traffic by deferring unknown sender requests and blocking servers (IP addresses), with poor reputation.
  • Anti-spoofing technologies such as DMARC, SPF and DKIM provide a level of confidence towards emails that seemingly originate from your own company - those that users are likely to open and action without question. Advanced threat solutions from companies like Mimecast take this further with strict anti-spoofing policies and even impersonation protection by quarantining email from domains or sender display names that match or are similar to those in your company's domain. 
  • Attachment sandboxing goes beyond signature based or heuristic scanning by preemptively opening attachments to analyse their behavior (such as automatically executing macros), before they reach your network.
  • URL scanning works as a realtime proxy to re-write hyperlinks in emails that force the destination web page to be inspected when clicked. This is particularly useful for seemingly benign sites that may pass initial inspection, only to weaponise a payload a short while after delivery.
  • Attachment policies allow an administrator to define specific files types that are outright unsuitable for email traffic and those which may be legitimate, but require further inspection. Typically any active content (scripts, executables etc), should be blocked, archives should be unpacked and inspected and even Office documents need to be treated with care if they contain macros. Enterprise solutions such as Mimecast block over 240 file types by default and there are a number of open source solutions such as ExeFilter that provide a good foundation.

Web Proxies
In order for malware to run on your network, it must first be delivered to your network. A web proxy provides an intermediary hop between your users and the Internet at large.
  • Malware and malicious object scanning is a primary defense against direct and indirect downloading of unwanted active content. The market is very competitive, but well worth your time to research. Look for reputable signature and heuristic scanning technologies.
  • Categorisation and Blacklists can impact users if over zealous, but they do provide administrators with a tool to identify and separate users from undesirable content. This could be anticipated (such as unscrupulous or antisocial sites, P2P networks etc) or known threats based on IP/DNS reputation subscription services.
  • Attachment policies for web proxies are much like email gateways as they represent a managed layer of blocking or inspection of content. I highly suggest a policy of least access, where active content (including archives, executables, scripts, malformed files and Office files with embedded scripts or macros), are denied by default. Approved download sites can be whitelisted over time, which certainly makes for more work upfront, but can really pay off in the long term.

Whilst traditionally seen as simple port/protocol filters, modern enterprise firewalls also provide a excellent investment towards intrusion prevention and application control.

  • Application Control allows an administrator to define access controls to Risk Categories (for example on a scale of 1-5), general Application Categories (such as TOR, P2P File Sharing or Webmail) and even Specific Applications (such as Dropbox or Facebook). It's important to note here that IT are not the "Internet Police". Our role is to advise and implement policy that best aligns with the business and risk profiles. These should generally be driven by other business units such as Human Resources and operational management.
  • Geo-blocking involves restricting network communications from entire countries, primarily breaking the link between your network and payload delivery. Depending on your business requirements, this might be a simple and effective decision. However, it's a very broad brush and can greatly impact legitimate traffic and is easily diluted - especially considering a lot of malware originates from the United States.
  • Port and IPS Control is essentially what most people think of when discussing firewalls. It's the traditional perimeter defense to keep the bad guys out by blocking illegitimate traffic. It's strength lies in good rule design and strong Intrusion Prevention signatures.
  • Prevent Access to 'Command and Control' Centers by blocking traffic from known bad IP addresses, either through vendor subscription services or sites like Ransomware Tracker. The process is quite reactive and it can be hard to keep up with the constantly changing lists.

Irrespective of the number of technical processes you have in place, at some point the users are going to play an important role in protecting your company's digital assets.
  • Security Awareness Training is a very effective way to raise awareness of the risks of malware and give your users practical ways to identify and avoid infection (both in the office and at home). With a recent surge in phishing attempts, it's important to think about the human factor in this equation. Look for training that doesn't embarrass and alienate users. Rather one that provides continuous cycle of assessment and education such as Wombat Security.
  • Password Policies help prevent the mis-use of legitimate accounts - why bother breaking down the door, when you have a key to open it! Length trumps complexity, but there is a good balance to find that matches your users and business profile.

Client computer security if done properly, represents a great opportunity to mitigate ransomware at both the Perimeter and Runtime stages. If done poorly, it really puts a great burden on the rest of your strategies to perform flawlessly.
  • Software Application Policies such as SRP and Applocker are some of your strongest defense strategies, by preventing unknown or unwanted software from running on your computer. Earlier Software Restriction Polices whilst effective, were complex and hard to maintain. Applocker (for those on modern Windows Enterprise platforms), make the process much easier. Combining the default rules, generated rules (perhaps simplified to a handful of publisher whitelists), with some auditing, is an effective and low impact way to get started.
  • Macro Management is becoming more important with the rise in phishing attacks, particularly if you are not able to provide in-line sandboxing of Office files. Group Policies such as Protected View can apply settings to warn or block macros from running automatically. In practice however, I've seen users become complacent and just habitually click their way though to an infection. If suitable, perhaps look to only allow macros that are signed and trusted.
  • Antivirus and anti-malware software is another one of those default areas that you need to invest in. Unfortunately, their effectiveness is waning and so realistically they are just another tool in your toolkit - one that you want to have, but not one that you solely rely on.
  • Firewalls also play an important role at the client level by restricting workstation to workstation propagation. Even if you don't enable within the domain, ensure to turn it on for mobile devices that roam to home or public networks.
  • Malware mitigation software such as EMET, DEP and Antihook, work much like antivirus, but focus on analysing software heuristics and behavior (as opposed to signature definitions).
  • Enforcing the UAC prompt (as annoying as it can be), places a pause on the automated running of software with elevated access. Ideally you'll combine this with separated access control.
  • Disabling Windows Scripting Host or re-writing file associations for scripting files (such as .js or .hta), will prevent these common vectors from triggering,. Unfortunately, they are often required for legitimate processes, so test appropriately.
  • Showing all file extensions can help avoid masking tricks with files that use double extensions such as yourfile.doc.exe. To enable push out the registry key "HideFileExt" to 0.
  • Enable web browser features such Popup and Ad Blocking as well SmartScreen filters to reduce your attack surface. Particularly is you are unable to use a web proxy solution.
  • Sandboxing can also be done client side using software such as Sandboxie or Hybrid Analysis. They give your IT team and even users a way to test files securely before exposing them directly to your network.
  • Managing mobile media such as USB thumb drives is still an important, albeit reducing vector for infection. This can be mitigated through user awareness training or technical prevention with Group Policy or endpoint security software.

Securing your servers is an important measure across all three threat areas, but particularly important in Runtime and Reducing Impact of an Outbreak.
  • Detecting and Actioning unusual behavior is critical to alerting you to the fact that something nefarious is happening in your environment and gives you the opportunity to shut it down as soon as possible. This could be something simple like a custom honeypot monitor through to event log monitoring and high end IDS solutions. For example LogRythymEventSentryBroIDS, pfSense. They are particularly effective if responses are automated (as opposed to say just an email), although obviously this can be impacting with false positives.
  • Hide Network Shares by creating them with an appended dollar sign, such as \\server\sharename$ for example. This will prevent malware from enumerating shares that are not mapped, but would otherwise be easily discoverable on the network.
  • Application hardening is essential if your exposing servers to the internet at large. This primarily focuses on edge services such as websites, proxies, Remote Access gateways etc. Design with Best Practices in mind, implement a DMZ and apply hardening tools such as IISCrypto.
  • DNS Management can compliment your other efforts by providing yet another layer of control to your Internet connections. Have a look at OpenDNS.
  • Document Management Systems are a considerable financial investment, require significant administrative resources and will impact your users. However, they do provide an excellent layer of abstraction between your users and the underlying document stores. Examples include SharePoint, iManage or even cloud services such as NetDocuments and Office365.
  • File Screens are Group Policy enforced rules that prevent certain types of files from being saved to your network. They can be useful to prevent downloading of executable content (for example if you're using Folder Redirection on My Downloads) and also to provide an early warning system of an outbreak.
  • Enforce Muti-Factor Authentication to restrict password propagation, particularly for remote and privileged access. RSA SecurID, Google Authenticator.
  • Enforcing secure communications for services such as websites (https) and email traffic (TLS) provides a way to mitigate traffic interception for phising bait
  • Enabling Shadow Copies used to be a solid solution for quick file restoration. However, a simple one liner using vssadmin can easily remove all shadow copies without a trace, now making this a rare option for recovery.

Permissions and Access Controls
The principle of least privilege means giving a user account only those privileges which are essential to that user's work. It's a principal that should be fundamentally incorporated into every facet of your systems designs.
  • Configure Access Control by assigning local/RDP login and share access appropriately. Segment networks based on user roles and access requirements. Ransomeware cannot encrypt a file that the user does not have write access to. 
  • Manage Privileged Accounts by creating secondary administrative accounts for those users that need administrative access. Ideally, take this a step further and block these admin accounts from any access to the Internet (via a web proxy for example). All daily work and web access uses only the standard user account.

Applying critical and security patches for your client and server operating systems, applications and device firmware is a fundamental part of IT operations. It is highly administrative and often impacting to users (when things go wrong). However, it is an important part of reducing your vulnerability to malware. Make the process as automated as possible (eg  Ninite, PDQ Deploy, WSUS) and reduce your disruption by deploying initially to test groups and devices before mass production deployment.

Further Reading
There is a lot of information around to help reduce your risk of being infected by ransomware and malware. Do your research and find effective solutions that align with your IT resources, users and business profile.
         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Monday, 8 September 2014

Set a Desktop Wallpaper using PowerShell

This script will apply a desktop wallpaper from a variety of sources and optionally overlay some text, using PowerShell.

The wallpaper sources include:
  • A solid colour (the "no wallpaper" option)
  • A specific or random picture from a directory
  • A Google Image search

The Text Overlay feature provides optional BGInfo style text directly onto the wallpaper image with control over the content, font, size, colour and position.

The script can be run manually, at logon or even repeatedly via a scheduled task to update the wallpaper regularly.

Wallpaper example showing the text overlay


The Shell syntax is very straight forward
        Set-Wallpaper [Source] [Selection] 
    MyPics Examples
        .\Set-Wallpaper.ps1 MyPics *
        .\Set-Wallpaper.ps1 MyPics coolpic.jpg
    Web Example
        .\Set-Wallpaper.ps1 Web 'Ayers Rock'

    Colour Example
        .\Set-Wallpaper.ps1 Colour Blue

Please note,  Powershell v3 or later is required due to the invoke-webrequest cmdlet in the Web module.

Setup Options

All of the options in the script can be set via the Wallpaper Variables section.

# MyPics Options
[STRING]$PicturesPath = [environment]::getfolderpath("MyPictures")+"\wallpaper"
[BOOLEAN]$ResizeMyPics = $False  

# Web Options
[INT]$MaxResults = 10
[INT]$DaysBetweenSearches = 7
[BOOLEAN]$ResizeWebPics = $True
[STRING]$WebProxyServer = ""

# Text Overlay Options
[BOOLEAN]$TextOverlay = $True   
[STRING]$TextColour = "White"
[STRING]$FontName = "Arial"
[INT]$FontSize = 14
[BOOLEAN]$ApplyHeader = $True
[STRING]$TextAlign = "Right"
[STRING]$Position = "High"     

# Wallpaper Style Options
[STRING]$Style = "Fit"         

# Available Colours
$Grey = @(192,192,192)
$Black = @(0,0,0)
$White = @(255,255,255)
$Red = @(220,20,60)
$Green = @(0,128,0)
$Yellow = @(255,255,0)
$Blue = @(0,0,255)
$CornflourBlue = @(100,149,237)

My Pictures Wallaper

The 'MyPics' option will source pictures from a nominated folder ('My Pictures\Wallpaper' by default). You can either choose a specific picture or a wildcard *. Using the wildcard with a scheduled task allows the wallpaper to change regularly. 

Pictures can optionally be re-sized proportionately to match the screen resolution.

Google Images Wallpaper

The 'Web' option will perform a Google image search based on your search term and automatically download a number of high resolution pictures. These are then randomly chosen as the desktop wallpaper. Again the script can be run again manually or via a scheduled task to rotate between the downloaded pictures. 

To avoid repeated downloads each time the script runs with the same search term, simply adjust the $DaysBetweenSearches variable. By default, the script will only repeat a search after a week.

As the images can vary greatly in size, using the re-size variable is recommended here as it will keep the image (and any text overlays) consistent.

Typical download results using the syntax:   set-wallpaper Web 'mountains'

Colour Wallpaper

The solid colour wallpaper is the most straight forward and is essentially a "no wallpaper" option. The result is a plain background as the script simply draws a rectangle in the colour of your choice, at the same resolution of the screen. Extra colours can be added by updating a new variable with the relevant RGB values.

Text Overlay

Mudos for the text overlay proof of concept found on this post, which combines text and your chosen desktop. The text can be anything you like, including dynamic data sourced through powershell and wmi queries such as the computer name, OS or boot time.

There are a number of variables that control the font and where about's on the image the text is placed.

Example Text Overlay on a plain colour wallpaper


There are a number of included functions that tie all of this together. 
  • Get-MyImages chooses pictures for the 'MyPics' option
  • Set-WebProxy allows the Google search connection through a web proxy
  • Get-GoogleImages downloads and chooses pictures for the 'Web' option
  • Set-ImageSize optionally re-sizes pictures proportionately to match screen resolution
  • New-Wallpaper creates the actual bitmap (colour or picture) and combines the text overlay
  • Update-Wallpaper applies the actual wallpaper to your desktop
  • Set-Wallpaper validates the pipeline input and initiates all of the other sub-functions as required

Here's the full script as posted on Git Hub (select the 'Raw' option at the bottom to copy/paste)

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Sunday, 10 August 2014

Password and Phrase Generator (using PowerShell GUI)

Creating a good password is not as easy as it used to be. Regular English words as passwords are a terrible idea and simply adding a few numbers or characters doesn't help much. The trick to creating a good password is finding the right balance between length and complexity. Here's an article on Stanford University's password policy, which is a great example of getting that mix right.

There are a bunch of password generators out there and even some phrase generators. The TAC Password and Phrase Generator will create both.

Creating Passwords

As soon as the script is run, a password is generated, based on the default settings. Simply increase or decrease the character count and select the complexity as required.

Random passwords of varying complexity from the ASCII table of acceptable password characters

Creating Phrases

Select the 'Words' radio button and increase or decrease the word count as required. By default, words are sourced from a random page on Reddit. You can of course experiment with any sub-reddit you like to theme your phrase.

Phrases from random words selected in real time from posts on Reddit.

You might have heard about the xkcd Password Generator, which is a great insight into the use of password phrases (in this case based on a small static list of common words making them easy to remember, but also easier to crack).

So why words from Reddit? Because it contains a vast and dynamic pool of words that represent the varied nature of the site itself. Once a pool of words has been randomly selected, it is then filtered to remove short words ( anything less than 4 characters), duplicates and common words.

Common Words Filter
Using ongoing samples of words from Reddit, a collection of common words is maintained and used as an exclusion list when generating phrases.

TIP! Download the latest version of the ExcludedCommonWords.txt
and save it in the same location as your PowerShell script.

The graph below shows a typical "Count of Unique Words" distribution. In this example, the common words account for around 40% of Total Words in a pool. However, as you can see they only account for a very small percentage of Unique Words. This means that phrases will be generated from uncommon words, making them harder to crack.

500 common words are automatically excluded from generated phrases


Every time you hit 'Generate' another password is created. Each time it is copied to your clipboard for easy pasting into another application. Use the Mask option to hide the password on screen. The Export feature is useful for bulk transfer of passwords to another application. Please do NOT keep saved passwords in a text file for any period of time!

Please note that this tool simply provides random passwords and phrases in a novel manner. Be sensible with the passwords you choose and use them at your own risk. I am not responsible for anything that happens as a result of your password choice. 

Here's the script to the latest version (v1.3).There may seem like a lot of code here, but most of it is for the generation of the form.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Tuesday, 22 July 2014

Sysadmin Modular Report for SSL Certificates (now with check for key size of 1024 bits)

The SysAdmin Modular Reporting framework provides a consistent, flexible data collection and reporting tool with 'traffic light' style alerts for your environment. Written in Powershell using an easy to follow style, the framework collates any number of user generated plugins (function scripts), into a single report for any Windows system supporting Powershell.

Learn about the framework in the new Quick Start Guide (pdf).

Getting started
  1. Download modules from GitHub links below*
  2. Save to a server with Active Directory Powershell Tools
  3. Customise Global_Variables.ps1 as required (variables apply to all modules)
  4. Customise Module_Variables.ps1 as required (variables apply to this module)
  5. Review the plugins (reorder, remove, update thresholds etc)
  6. Run the report  Get-SAMReport Certificates [Email/OnScreen]
Review the scripts on GitHub
*I encourage you to review and understand any script downloaded from the internet. Also ensure to "unblock" each .ps1 files (Right click | Properties | Unblock), to avoid the [D] Do not run [R] Run once [S] Suspend security prompts.


SAMReports can provide a very detailed look into the health of your environment. You can view the relevant data that has been gathered and quickly see any Warnings or Alerts based on your thresholds. The overall title of the report will reflect the worst result, so for example if there were 6 sections and only one showed a Warning, the report title will be coloured as a Warning.

The result is a rich report with clear status indicators giving you an instant overview and the details to back it up.

      Picture 1. Sample Report showing plugins for the stores in a typical certificate chain


The independent plugin system is very flexible and provides an easy way to only report on information that you need. The template style provides a consistent output, but also makes it easy to adapt or add new plugins. The warnings or alerts are based on a failed test or data falling outside of thresholds that you can define.

Each plugin can generate four types of output:
  • Results Text (html formatted)
  • Results Data (html formatted table)
  • Results Status (Alert, Warning, Good colour codes)
  • A File (either saved to the \output folder or included as an email attachment)

About the Certificates Module

UPDATE: The report now includes a check for a key length that is less than 2048 bits. 

The report will list details for all certificates in the relevant stores, for all of your servers. There is even an option to log and remove any expired certificates.

This is a list of the current plugins for the Certificates module, which cover the certificate stores for a typical certificate chain:
  • 00 Module Variables.ps1   (loads AD snap-in, sets server scope, log file location etc)
  • 01 List Personal Certificates.ps1
  • 02 List Intermediate Certificates.ps1
  • 03 List 3rd Party Root Certificates.ps1
  • 04 List Trusted Root Certificates.ps1
There are a number of variables you can customise to change the scope of what is shown in the report, such as:

#Reporting variables
$MaxDays = 1095
$WarnDays = 90
$AlertDays = 30
$WarnKeySize = 2048

#Certificate Store Properties
$StoreLocation = "LocalMachine" #"LocalMachine","CurrentUser"
$StoreName = "My"   #"My","CA","AuthRoot","Root"
$OpenFlag = "ReadWrite"  #"ReadOnly","ReadWrite"

#Purge Variable
$PurgeExpired = $False          #$True or $False
$PurgeDays = -90

This is the core of each script, to show how it collects info from each store and builds it into the main report.

#Create an Array and run query
$ResultsData = @()
foreach ($Server in $Servers) {
    if (Test-Connection -computername $Server -count 1 -quiet){
        $stores = New-Object System.Security.Cryptography.X509Certificates.X509Store("\\$Server\$StoreName",$StoreLocation)
        $Certificates = $stores.Certificates | Select FriendlyName, serialNumber, Issuer, Subject, PublicKey, @{Label="Expires";Expression={($_.NotAfter)}}, @{Label="Days";Expression={($_.NotAfter - (Get-Date)).Days}}
        Add-content -path $Logfile -value "Server: $Server"
        Add-content -path $Logfile -value "Store: $StoreLocation\$StoreName"
        Add-content -path $Logfile -value " "

        foreach ($Certificate in $Certificates) {
            #Build Report
            if ($Certificate.Issuer -ne $null -and $Certificate.days -lt $MaxDays){
                $obj = New-Object PSobject
                $obj | Add-Member -MemberType NoteProperty -name "Server" -value $Server
                $obj | Add-Member -MemberType NoteProperty -name "Name" -value $Certificate.FriendlyName
                $obj | Add-Member -MemberType NoteProperty -name "Issuer" -value $Certificate.Issuer
                $obj | Add-Member -MemberType NoteProperty -name "Subject" -value $Certificate.Subject
                $obj | Add-Member -MemberType NoteProperty -name "Key Size" -value $Certificate.PublicKey.key.KeySize
                $obj | Add-Member -MemberType NoteProperty -name "Expires" -value $Certificate.Expires
                $obj | Add-Member -MemberType NoteProperty -name "Days" -value $Certificate.Days
                $ResultsData += $obj

                # Update Text and Alert count based on your criteria
                $Name = $Certificate.FriendlyName
                $Days = $Certificate.Days
                $Size = $Certificate.PublicKey.key.KeySize

                if ($Days -lt 0){
                    $AlertText += "!RED!Alert: Certificate $Name on $Server has expired "
                    $AlertCount += $AlertCount.count + 1            
                elseif ($Days -lt $AlertDays){
                    $AlertText += "!RED!Alert: Certificate $Name on $Server is expiring in $Days days"
                    $AlertCount += $AlertCount.count + 1            
                elseif ($Days -lt $WarnDays){
                    $WarningText += "!ORANGE!Warning: Certificate $Name on $Server is expiring in $Days days"
                    $WarningCount += $WarningCount.count + 1        
                if ($Size -lt $WarnKeySize){
                    $WarningText += "!ORANGE!Warning: Certificate $Name on $Server does not meet minimum key size of $WarnKeySize"
                    $WarningCount += $WarningCount.count + 1            
            #Log and Purge Old Certs
            If ($PurgeExpired -eq $True){
                $Name = $Certificate.FriendlyName
                $Issuer = $Certificate.Issuer
                $Subject = $Certificate.Subject
                $Expired = $Certificate.Expires
                $Days = $Certificate.Days
                $SerialNumber = $Certificate.serialNumber
                if ($Certificate.Issuer -ne $null -and $Certificate.days -lt $PurgeDays){
                    Add-content -path $Logfile -value "Name: $Name"
                    Add-content -path $Logfile -value "Issuer: $Issuer"
                    Add-content -path $Logfile -value "Subject: $Subject"
                    Add-content -path $Logfile -value "Expired: $Expired"
                    Add-content -path $Logfile -value "Days: $Days"
                    Add-content -path $Logfile -value " "
                    $PurgeCert = $stores.Certificates.Find("FindBySerialNumber",$SerialNumber,$FALSE)[0]
                    $ExpiredCount += $ExpiredCount.count + 1
    Add-content -path $Logfile -value "$Server Completed (Purge = $PurgeExpired). $ExpiredCount expired certificates deleted."
    Add-content -path $Logfile -value "-------------------------------------------------------------------"
    Add-content -path $Logfile -value " "
    $ExpiredCount = 0

More Info

This is a community driven project if you have any suggestion or module scripts you have created, I would love to include them here - with full mudos to you of course.

See the main SysAdmin Modular Reports page for more details, including working with Scheduled Tasks and downloads for other modules.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Saturday, 1 February 2014

Deploying and Customising Windows 8.1 using SCCM, Group Policy and Powershell

It was a bold direction Microsoft took with the interface changes in Windows 8. One that has has caused much discussion in the IT ranks. The changes in Windows 8.1 come a long way to resolve the technical limitations many people found with the original release. I don't want to delve into this argument as there are better forums for doing so. Suffice to say that some companies, like mine, are pushing ahead with Windows 8.1 and this article aims to capture some of the techniques, tips and tricks we used to do so.

Any System Administrator worth their salt will know what will fly in their company and what won't. To ease the impact of change on our staff, I like to 'tick-tock' between Operating System and Core Application upgrades, when I do a new Standard Operating Environment (SOE). I had just finished a 'tock' cycle which was focusing on new core applications such as Office, Acrobat, Lync as well as upgrades to our specific Practice and Document Management software. So this environment upgrade was only going to focus on a change to the OS and more specifically, just for laptops and tablets where I feel that Windows 8.1 truly shines.

Systems Center Configuration Manager (SCCM) Task Sequence

I'll have to assume that my audience is somewhat proficient with SCCM, so I will just focus on some of the more specific techniques used with this SOE release. As a minimum, you'll need to ensure that your're pretty up to date with your SCCM version, ADK and patches.

Our target devices were all Dell and included a Venue Pro 11 tablet as well as Latitude 12 and Latitude 14 laptops. It's well worth investing some time getting your driver libraries sorted, so if you're a Dell shop head on over to their Enterprise Client Wiki.

Here's a high level overview of the current task sequence we're using. Where possible, I avoid the use of a "Golden Image" and aim for a complete and flexible build from the original Windows 8.1 ISO.

Copy SXS source files to local computer

Having some OS source files available on your local hard disk makes updates, such as .NET 3.5 much easier. We simply created a Package which was the ISO's SXS directory. Then run the following command line sequence, linked to that package.

xcopy ".\*.*" "C:\Windows\Support\" /D /E /C /I /Q /H /R /Y /S
DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:c:\Windows\Support\sxs

Removing default apps

There are some apps that you just cannot remove from Windows 8.1 (such as the camera). However, there are quite a few that your can. We do  this via a powershell script.

$AppList = "Microsoft.BingFinance",

ForEach ($App in $AppList) {
   $AppxPackage = Get-AppxProvisionedPackage -online | Where {$_.DisplayName -eq $App}
   Remove-AppxProvisionedPackage -online -packagename ($AppxPackage.PackageName)
   Remove-AppxPackage ($AppxPackage.PackageName)

 Copy a Start Screen layout to the default user profile

Using a test device, create the Start screen layout that you're looking for (grouping, naming etc). Then grab the %AppData%\Local\Microsoft\Windows\AppsFolderLayout.bin file and drop it in a package for deployment to the default user profile.

xcopy ".\*.*" "C:\Users\Default\AppData\Local\Microsoft\Windows" /D /E /C /I /Q /H /R /Y /S

Create and Import Customised Tiles

We used a Windows 8 app called Obly Tile to create a series of new start screen tiles for our core company applications and intranet sites. Along with the previous two steps, the end results gives us a very streamlined Start Screen with familiar icons for users. Once you have created your titles, create a package out of the Obly Tile application, source folder structure it creates and an use a simple batch script to copy into the default Start Menu

if not exist "C:\Program Files\OblyTile" md "C:\Program Files\OblyTile" 
xcopy "OblyTile\*.*" "C:\Program Files\OblyTile" /s /y
xcopy "Start Menu\*.*" "C:\ProgramData\Microsoft\Windows\Start Menu" /s /y

Application Association

Some file types, such a JPEGs for example, may be associated with apps that you don't want to use. One way to update this is by updating the associations first on a test device, then exporting the AppAssoc.xml file. NB. This only works for new user profiles on that device.

"dism /online /Export-DefaultAppAssociations:C:\temp\AppAssoc.xml"

Add the xml file and batch file to import it into to your package.

"dism /online /Import-DefaultAppAssociations:AppAssoc.xml"

Group Policy

Once the machine has been deployed we implement a number of Group Policy settings to customise our final image. Every company is different, so these are just what works for us.

We typically have three Computer Policies; one for all SOE computers, then one each for the handful of special tweaks relating to either Windows 7 or Windows 8. Make sure you grab the latest Windows 8.1 ADMX files from a test build and import into Active Directory GP.

Separate Windows 7 and Windows 8 Profiles

There can be some potential corruptions between the two profile version, plus we wanted new profiles to ensure we got a consistent Start Screen experience for new users. Most of the users items such as Desktop, Favorites, My Documents etc are taken care of with Folder redirection. So by using the technique below, we were able to create separate profiles for our users, allowing them to switch back and forth between Windows 7 desktops and Windows 8 tablets and laptops.

In both the Windows 7 and Windows 8 Group Policies create a System Environment Variable (Preferences | Windows Settings | Environment Variables) and called in OSVer, with a Value of Win7 or Win8 respectively.

Then in Active Directly, set up their profile path to use the variable.


Computer Policies

Force Internet Explorer to open in Desktop mode
Windows Components/Internet Explorer/Internet Settings
Set how links are opened in Internet Explorer =  Always in Internet Explorer

Disable SkyDrive
Windows Components/SkyDrive
Prevent the usage of SkyDrive for file storage =  Enabled  

Disable Windows Store
Windows Components/Store
Turn off the Store application = Enabled 

Allow local powershell scripts to run (eg logon.ps1 script)
Windows Components/Windows PowerShell
Turn on Script Execution = Enabled  
Execution Policy Allow local scripts and remote signed scripts 

Computer Preferences

Remove First Use Animation
Action Create 
Key path SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System 
Value name EnableFirstLogonAnimation 
Value type REG_DWORD 
Value data 0x0 (0) 

User Policies

Disable Edge Help Tips
Windows Components/Edge UIhide
Disable help tips Enabled

Disable IE SPDY/3 network protocol
Windows Components/Internet Explorer/Internet Control Panel/Advanced Page
Allow Internet Explorer to use the SPDY/3 network protocol Disabled

User Preferences

Boot to Desktop
Action Replace 
Key path Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage\ 
Value name OpenAtLogon 
Value type REG_DWORD 
Value data 0x0 (0) 

Disable DPI Scaling
Action Replace 
Key path Control Panel\Desktop 
Value name Win8DpiScaling 
Value type REG_DWORD 
Value data 0x1 (1)  

Set DPI pixels

Action Replace 
Key path Control Panel\Desktop 
Value name LogPixels 
Value type REG_DWORD 
Value data 0x60 (96)

This is probably going to be an ongoing project and I'm sure others have some great tips, so I'l keep updating as they come in.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Sunday, 18 August 2013

Creating SSL certificates for Exchange 2010 Edge servers

I recently moved from an on-premise email security gateway to a cloud service. As such, I had to setup some new Exchange Edge roles and install SSL certificates on them to provide TLS encryption. As there is a limited GUI, all of this needs to be done via powershell. Here is a quick, high level overview of the steps taken.

Generate Cert Request
 $data = New-ExchangeCertificate -GenerateRequest -SubjectName "c=AU, o=IT Dept," -PrivateKeyExportable $true  
 Set-Content -Path "c:\Temp\mailcert.req" -Value $Data  

Submit Request to CA
  • Common name should be the public name eg. 
  • Add in additional 'Subject Alternate Names' for the actual server names eg.

Complete Certificate Request
 Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path c:\Temp\mail_mydomain_com_au.cer -Encoding Byte -ReadCount 0))  

Note the thumbprint that is shown when successfully imported.

Assign the certificate to SMTP service
 Get-ExchangeCertificate -Thumbprint ABCD12345ABCD12345ABCD12345ABCD12345ABCD | Enable-ExchangeCertificate -Services SMTP  

Update the intermediate Certs

  • Download and run the Digicert Certificate Utility (, on the edge server.
  • "Repair" the cert if it's showing any missing/misplaced intermediate certificates

Export the certificate (and repeat import on second server)
$file = Export-ExchangeCertificate -Thumbprint ABCD12345ABCD12345ABCD12345ABCD12345ABCD -BinaryEncoded:$true -Password (Get-Credential).password  
Set-Content -Path "c:\Temp\mailcert.pfx" -Value $file.FileData -Encoding Byte  
Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path c:\Temp\mailcert.pfx -Encoding Byte -ReadCount 0)) -Password (Get-Credential).password  
Get-ExchangeCertificate -Thumbprint ABCD12345ABCD12345ABCD12345ABCD12345ABCD | Enable-ExchangeCertificate -Services SMTP  

Update intermediate cert via Digicert Certificate Utility as above
Complete a synchronisation cycle (on an internal Hub Transport server)

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Wednesday, 7 August 2013

Automatically re-size and import photos into Active Directory with Powershell

This script is a great example of how IT can hand back responsibility one of those trivial admin jobs to a non-IT department. You know the scenario; Marketing or HR get all of the staff photos together and send them to IT for posting to Active Directory for a bunch of relevant systems such as Outlook, Lync or a SharePoint corporate directory. Every time a photo changes, it's yet another request into IT. Well, if you implement this script, you'll never have to worry about manually re-sizing and importing these photos again!

In summary, the script bulk imports photos into AD, by selecting them from a network share based on their age. It will even re-size the photos on the fly according to Microsoft's recommendations, whilst ensuring to keep the original proportions. The cool thing is, that you can launch it from a scheduled task, so all someone has to do is save any new photos to the nominated location and they will get imported automatically.

During the import process the photos get checked against valid users in AD, so they need to be in the format of username.jpg. Everything is logged and if this test fails it will be added to the user friendly email output which can again become someone else's responsibility to receive and action. IT can get CC'd on this of course and step in as necessary.

The syntax to use is as follows

    Set-ADPhotos SourcePath Days

For example

    .\Set-ADPhotos '\\Server1\sharename' 1

The 'Source Path' can be any local folder or network share that's accessible. The photos are then copied down to a local working path for the actual import. Both the original photo (if one exists) and the new photos are date stamped and backed up. So if you have to restore a photo, you can simply place a copy (as username.jpg), back into the working directory and do a manual run without having to wait for the next schedule.

The 'Days' parameter is used to filter the import of photos based on the modified date. So for example '1' will only import photos modified in the last day. Assuming you run this as a scheduled task, it's important then to match the schedule with the the number of days entered.

Finally, if you're a Lync shop, the script can trigger an update of the Address Book which gets the photos out to the clients pretty quickly.

Here's the full script, or download it from GitHub.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^