Windows Assessment and Deployment Kit (Windows ADK) Preview

With the recent Windows 10 Technical Preview version 10.0.10041, developer tools were published as well as hardware tools. At the bottom of the hardware tools page, you can find the preview version of the Windows Assessment and Deployment Kit (Windows ADK).

Here’s the PowerShell script to download the files required by ADK (~3GB) that uses the cmdlets from the BITS module.

#Requires -Version 4
#Requires -RunAsAdministrator

Function Get-ADKFiles {
Begin {
    $HT = @{}
    $HT += @{ ErrorAction = 'Stop'}
    # Validate target folder
    try {
        Get-Item $TargetFolder @HT | Out-Null
    } catch {
        Write-Warning -Message "The target folder specified as parameter does not exist"
    # March 24, 2015
    $PatchLevel = "10.0.10041"
Process {
    $adkGenericURL = (Invoke-WebRequest -Uri  -MaximumRedirection 0 -ErrorAction SilentlyContinue)
    # 302 = redirect as moved temporarily
    if ($adkGenericURL.StatusCode -eq 302) {

        # Currently set to
        # Resolving download root for:
        $MainURL = $adkGenericURL.Headers.Location
        $InstallerURLs = DATA {
            ConvertFrom-StringData @'
                103=Application Compatibility Toolkit-x64_en-us.msi
                104=Application Compatibility Toolkit-x86_en-us.msi
                105=Assessments on Client-x86_en-us.msi
                106=Assessments on Server-x86_en-us.msi
                148=Flashing Tools-x86_en-us.msi
                149=Imaging And Configuration Designer-x86_en-us.msi
                152=Kits Configuration Installer-x86_en-us.msi
                153=Microsoft Compatibility Monitor-x86_en-us.msi
                155=Toolkit Documentation-x86_en-us.msi
                156=User State Migration Tool-x86_en-us.msi
                157=Volume Activation Management Tool-x86_en-us.msi
                162=Windows Assessment Services - Client (AMD64 Architecture Specific, Client SKU)-x86_en-us.msi
                163=Windows Assessment Services - Client (AMD64 Architecture Specific, Server SKU)-x86_en-us.msi
                164=Windows Assessment Services - Client (Client SKU)-x86_en-us.msi
                165=Windows Assessment Services - Client (Server SKU)-x86_en-us.msi
                166=Windows Assessment Services - Client (X86 Architecture Specific, Client SKU)-x86_en-us.msi
                167=Windows Assessment Services-x86_en-us.msi
                168=Windows Assessment Toolkit (AMD64 Architecture Specific)-x86_en-us.msi
                169=Windows Assessment Toolkit (X86 Architecture Specific)-x86_en-us.msi
                170=Windows Assessment Toolkit-x86_en-us.msi
                171=Windows Deployment Customizations-x86_en-us.msi
                172=Windows Deployment Tools-x86_en-us.msi
                173=Windows PE x86 x64 wims-x86_en-us.msi
                174=Windows PE x86 x64-x86_en-us.msi
                175=Windows System Image Manager on amd64-x86_en-us.msi
                176=Windows System Image Manager on x86-x86_en-us.msi
                177=WPT Redistributables-x86_en-us.msi
        $PatchesURLs = DATA {
            ConvertFrom-StringData @'
        "Installers","Patches\$PatchLevel" | ForEach-Object -Process {
            # Create target folders if required as BIT doesn't accept missing folders
            If (-not(Test-Path (Join-Path -Path $TargetFolder -ChildPath $_))) {
                try {
                    New-Item -Path (Join-Path -Path $TargetFolder -ChildPath $_) -ItemType Directory -Force @HT
                } catch {
                    Write-Warning -Message "Failed to create folder $($TargetFolder)/$_"
        # Get adksetup.exe
        try {
            Invoke-WebRequest -Uri "$($MainURL)adksetup.exe" -OutFile  "$($TargetFolder)\adksetup.exe" @HT
        } catch {
            Write-Warning -Message "Failed to download adksetup.exe because $($_.Exception.Message)"
        # Create a job that will downlad our first file
        $job = Start-BitsTransfer -Suspended -Source "$($MainURL)Installers/$($InstallerURLs['0'])" -Asynchronous -Destination (Join-Path -Path $TargetFolder -ChildPath ("Installers/$($InstallerURLs['0'])")) 
        # Downlod installers
        For ($i = 1 ; $i -lt $InstallerURLs.Count ; $i++) {
            $URL = $Destination = $null
            $URL = "$($MainURL)Installers/$($InstallerURLs[$i.ToString()])"
            $Destination = Join-Path -Path (Join-Path -Path $TargetFolder -ChildPath Installers) -ChildPath (([URI]$URL).Segments[-1] -replace '%20'," ")
            # Add-BitsFile
            $newjob = Add-BitsFile -BitsJob $job -Source  $URL -Destination $Destination
            Write-Progress -Activity "Adding file $($newjob.FilesTotal)" -Status "Percent completed: " -PercentComplete (($newjob.FilesTotal)*100/($InstallerURLs.Count))
        # Donwload Patches
        For ($i = 0 ; $i -lt $PatchesURLs.Count ; $i++) {
            $URL = $Destination = $null
            $URL = "$($MainURL)Patches/$PatchLevel/$($PatchesURLs[$i.ToString()])"
            $Destination = Join-Path -Path (Join-Path -Path $TargetFolder -ChildPath "Patches/$PatchLevel") -ChildPath (([URI]$URL).Segments[-1] -replace '%20'," ")
            # Add-BitsFile
            $newjob = Add-BitsFile -BitsJob $job -Source  $URL -Destination $Destination
        # Begin the download and show us the job
        Resume-BitsTransfer  -BitsJob $job -Asynchronous
        while ($job.JobState -in @('Connecting','Transferring','Queued')) {
            Write-Progress -activity "Downloading ADK files" -Status "Percent completed: " -PercentComplete ($job.BytesTransferred*100/$job.BytesTotal)
        Switch($job.JobState) {
             "Transferred" {
                Complete-BitsTransfer -BitsJob $job
             "Error" {
                # List the errors.
                $job | Format-List
            default {
                # Perform corrective action.
    } else {
        Write-Warning -Message "Guessing the ADK location returned the status code $($adkGenericURL.StatusCode)"
End {}

Let’s see how to use the above script:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned -Force
.  ~/documents\get-ADKFiles.ps1
mkdir ~/Downloads\ADK.10.0.10041 -Force
Get-ADKFiles -TargetFolder ~/Downloads\ADK.10.0.10041

Now you’ve got the tools to build WinPE (Windows Preinstallation Environment) with PowerShell 5.0 😎

A forensic point of view of Desired State Configuration (DSC)

Every piece of new technology carries intrinsically a new balance of benefits/risks and brings new security trade-offs from a forensic perspective.

I’d like to give a forensic point of view on Desired State Configuration (DSC) as it isn’t an exception of the above rule.

The following sentence inspired me

Windows 10 and Server 2016 will have PowerShell version 5.0. PowerShell 5.0 includes a feature called “Desired State Configuration”, which is similar to Chef, and will be the future of Windows security templates, such as for DoD STIGs and enforcing Windows-related critical controls.


First, let’s correct quickly the above sentence. PowerShell Desired State Configuration aka DSC is already built-in into PowerShell version 4.0 and shipped along with Windows 8.1 and 2012 R2. DSC is actually already present. I know the course SEC505 targets Windows and I also don’t want you to believe that DSC is a Windows thing only. It’s actually a declarative language and distributed heterogeneous configuration management platform that will allow you to target both Windows and Linux operating systems.

Now let’s examine DSC from 2 different angles and security stances: attack/defense.

DSC will allow you to deploy security settings (registry based), features (Bitlocker,…), anything actually … that will help hardening the configuration of your assets and protect these assets. Yes, Jason Fossen is right, it will help you implement faster security templates and controls. Because of the simplicity of DSC, you’ll also be able to scale out more easily and quickly.

But, even if you declare everything in your configuration either set to present or absent, DSC won’t be able to detect and handle something new that has not been previously declared.
Let’s think of services or firewall rules,… for example. Although you’ve inventoried every known and expected services or firewall rules, if a malware creates a random service name and open a random port in your firewall rules, DSC cannot do anything about it. Once this malicious service or firewall rule is known and identified, DSC can of course help you remediate and fix the problem by deploying a new configuration that takes care of it.

DSC is currently more a post-mortem remediation tool and cannot help you identify the unknown (usually malicious).

DSC could theoretically enforce a better security posture if it wasn’t based only on a declared list of absent/present things. DSC is built in mind with the concept of idem-potency which is not ground-breaking but a very good layer to built on top of and that will for sure make the success and foster the adoption of DSC in the IT landscape.

If the list of configuration items wasn’t treated as a strict list of things to be set to present and absent, I could declare known things to be set to present or absent and have a third implicit rule by default that would set anything (*.*) not declared to absent. It would somehow mimic the way the Applocker works in Windows where you can combine both a whitelist (present known items), a blacklist (absent known items) and an implicit rule that blocks unknown items.


From a attacker perspective DSC could be used to achieve persistence.

Let’s think of a small configuration that would download a zip file from the Internet, escaping your Antivirus detection, expand the archive to deliver the malicious payload, make sure the malicious service or process is in a running state. A malware could leverage DSC to deploy this configuration to your computer(s). Currently tools like autoruns.exe from Sysinternals can scan the WMI repository for permanent events but I don’t think it’s currently able to scan for a malicious DSC configuration or a malicious WMI provider.

From an architecture perspective, the pull server is also an attractive target because once compromised, it allows to deliver the payload to all the managed computer nodes that pull their configuration from it. Having an unsecured pull server puts your data center at risks and is worst than having none.

Let’s think bigger and that the attacker has great DSC skills. I don’t like to spread FUD but let’s imagine a second that an attacker compromised your fabric where he found unused (and fortunately limited) compute, storage and networking resources. DSC would allow him to deploy Hyper-V (or another hypervisor), create an external and internal virtual switch, a rogue virtual machine plugged onto these two virtual network switches. This virtual machine would be binding the private subnet and its Internet connected network interface, could host a rogue Dhcp, Dns, Vpn, Proxy… server and could be responsible for encrypting network traffic. Then, the attacker could provision virtual machines on this private subnet – an army of zombie computers – to carry on his malicious duties and consume your (unused yet) data center resources. He could send spam, perform DoS (denial of service) attacks and even use Docker-like technologies to reach a greater VM density. If you think of the recent attack on Sony in 2014 where about one hundred terabytes were exfiltrated before it got discovered, the scary scenario I imagined could be feasible. The attack could also take place on the public consumer market where the attacker would perform the same attack on your Windows 8.1, Windows 10 or Ubuntu workstation. By using DSC, the attacker could easily raise and control a botnet, an army of zombie virtual computers. The DSC pull server could be considered as his C&C (Command and Control server) in this case.

DSC can be considered as a great opportunity and facilitator by attackers because it helps scaling out and utilizing compromised resources to their full potential.

BPUG / Mach 18, 2015 / meeting summary and presentation materials

This first meeting of the Basel PowerShell User Group (BPUG) in Switzerland was a great experience.

We had a great time. It’s actually the 1rst PowerShell User Group in Switzerland, some people came from Basel of course but also from Bern, Luzern,…
I hope everybody who joined enjoyed it πŸ˜€

The material I presented is available for download on this link: the powerpoint presentation and the demo script

Again, thank you StΓ©phane for organizing it, thanks to the sponsor and thank you if you attended and joined this user group.

If you’ve attended, please fill-in this little survey ( > ) , it shouldn’t take more than 5 seconds. Thanks!

PowerShell DSC rocks 😎

Basel PowerShell User Group Meeting: March, 2015

The 1rst meeting of the Basel PowerShell User Group (BPUG) is scheduled on March 18, 2015.

StΓ©phane van Gulick (@stephanvg) who created this User Group already announced the kickoff on his blog in this post

I’ve joined this User Group because it’s the best place to meet IRL PowerShell community members, those who are interested in and/or enthusiast about Windows PowerShell.

I’m super excited to give a presentation at this first meeting πŸ˜€
I’ll present a session about how I got my hands-on Desired State Configuration (DSC).

To join us for this meeting, you can use the following links

You can also join the group on this link:

Hope to see you there!

Pi Day

Today is March 14, 2015 and it’s considered as Pi Day (3.1415).

What’s Pi?

What’s Pi in PowerShell?

([math] | Get-Member -Force -Static -Name PI).PSBase | fl *

What does this mean?

Well, it means that the System.Math .Net Class has a static property to represent the constant Pi as system.double type.

When you just want to see the representation of Pi in PowerShell, you’ll do


Note that there are 14 digits after the decimal point.

In .Net, we have 20 digits after the decimal point.

Can we force PowerShell to give more than 14 digits after the decimal point ?

for ($i=14;$i -le 20 ; $i++) {
"{0:N$i}" -f [math]::PI

The answer seems to be negative if I convert the Pi value to a string using the Numeric Format Specifier 😦

To get a more precise/approximative representation of Pi, I did


Both gives us 16 digits after the decimal point.

Now, let’s have fun! Let’s discover how suprising PowerShell can be πŸ˜€ and do:

3.14159265358979 -eq [math]::PI
3.14159265358979d -eq [math]::PI
3.14159265358979323846 -eq [math]::PI
3.14159265358979323846d -eq [math]::PI
3.14159265358979323846264338327 -eq [math]::PI
3.14159265358979323846264338327d  -eq [math]::PI

Surprising, isn’t it? What does it actually mean?
The double representation of Pi with 14 digits after the decimal point (3.14159265358979) doesn’t equal to the .Net Pi value whereas its decimal value (3.14159265358979d) does.

3.14159265358979d -eq 3.14159265358979323846
([decimal]3.14159265358979) -eq ([double]3.14159265358979323846)

If the double has 15 digits or more after the decimal point, it equals to the .Net Pi value.

3.141592653589793 -eq [math]::PI

I hope that your brain didn’t melt like mine πŸ˜›
Happy Pi Day πŸ™‚