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 {
[CmdletBinding()]
param(
    [parameter(Mandatory)]
    [system.string]$TargetFolder
)
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"
        break
    }
 
    # March 24, 2015
    $PatchLevel = "10.0.10041"
 
}
    
Process {
    
    $adkGenericURL = (Invoke-WebRequest -Uri http://go.microsoft.com/fwlink/?LinkID=525592  -MaximumRedirection 0 -ErrorAction SilentlyContinue)
    
    # 302 = redirect as moved temporarily
    if ($adkGenericURL.StatusCode -eq 302) {

        # Currently set to http://download.microsoft.com/download/2/E/7/2E74CA3D-858C-4401-B6FF-3E1C2D1D5F0C/adk/
        # Resolving download root for: http://go.microsoft.com/fwlink/?LinkID=525592
        $MainURL = $adkGenericURL.Headers.Location
    
        $InstallerURLs = DATA {
            ConvertFrom-StringData @'
                0=0302dc615b0a5fd4810430b2cdacb5e3.cab
                1=036c618de505eeb40cca35afad6264f5.cab
                2=0708be5ffbe332f6a1571c929c1322a5.cab
                3=0a3a39d2f8a258e1dea4e76da0ec31b8.cab
                4=0b63b7c537782729483bff2d64a620fa.cab
                5=0c48c56ca00155f992c30167beb8f23d.cab
                6=0ce2876e9da7f82aac8755701aecfa64.cab
                7=0d981f062236baed075df3f42b1747db.cab
                8=11bdc4a4637c4d7ab86107fd13dcb9c6.cab
                9=125b1c8c81e36ec9dbe5abf370ff9919.cab
                10=1439dbcbd472f531c37a149237b300fc.cab
                11=14f4df8a2a7fc82a4f415cf6a341415d.cab
                12=1616336d1700fbea038fd3dc4c6c917b.cab
                13=186c4aa0cae637da0996e87ababf5b71.cab
                14=18e5e442fc73caa309725c0a69394a46.cab
                15=1bd4f044e271b42b110fe533720c10e9.cab
                16=1f90b0f7321fab8dcdedaba3b30415f3.cab
                17=23ca402f61cda3f672b3081da79dab63.cab
                18=24b9e5f1f97c2f05aa95ee1f671fd3cc.cab
                19=2517aec0259281507bfb693d7d136f30.cab
                20=268b1a41f6bd2906449944b964bf7393.cab
                21=27c0562eb1efb3ad282cf987ae40e873.cab
                22=2e134b026e871c5e8e547b6711578fb3.cab
                23=2e82f679c8709f838e7c839f7864ac84.cab
                24=3585b51691616d290315769bec85eb6f.cab
                25=3611bd81544efa3deb061718f15aee0c.cab
                26=36e3c2de16bbebad20daec133c22acb1.cab
                27=377a2b6b26ea305c924c25cf942400d6.cab
                28=3814eaa1d4e897c02ac4ca93e7e7796a.cab
                29=388dee738d7d1c99d6fe776a85ee32f8.cab
                30=38d93b8047d5efb04cf01ab7ec66d090.cab
                31=3b71855dfae6a44ab353293c119908b8.cab
                32=3d610ba2a5a333717eea5f9db277718c.cab
                33=3dc1ed76e5648b575ed559e37a1052f0.cab
                34=3e602662e913edefa58e52e04e900bf8.cab
                35=3eaef6a740a72a55f4a0ac3039d05419.cab
                36=413a073d16688e177d7536cd2a64eb43.cab
                37=450f8c76ee138b1d53befd91b735652b.cab
                38=45c632fb53b95fe3bd58a6242325afa6.cab
                39=4d2878f43060bacefdd6379f2dae89b0.cab
                40=4defb086385752d8cd0d1432900fb4ca.cab
                41=4e56c6c11e546d4265da4e9ff7686b67.cab
                42=4fc82a5cedaab58e43b487c17f6ef6f3.cab
                43=500e0afd7cc09e1e1d6daca01bc67430.cab
                44=527b957c06e68ebb115b41004f8e3ad0.cab
                45=56dd07dea070851064af5d29cadfac56.cab
                46=56e5d88e2c299be31ce4fc4a604cede4.cab
                47=57007192b3b38fcd019eb88b021e21cc.cab
                48=5775a15b7f297f3e705a74609cb21bbc.cab
                49=5ac1863798809c64e85c2535a27a3da6.cab
                50=5d984200acbde182fd99cbfbe9bad133.cab
                51=5eea85046f0c2112e2fcd0bac2c2cfc8.cab
                52=625aa8d1c0d2b6e8cf41c50b53868ecd.cab
                53=630e2d20d5f2abcc3403b1d7783db037.cab
                54=662ea66cc7061f8b841891eae8e3a67c.cab
                55=6894c1e1e549c4ab533078e3ff2e92af.cab
                56=690b8ac88bc08254d351654d56805aea.cab
                57=69f8595b00cf4081c2ecc89420610cbd.cab
                58=6a68bedadf2564eeef76c19379aae5ef.cab
                59=6bdcd388323175da70d836a25654aa92.cab
                60=6cc7aebd21947dbd8ea4884662780188.cab
                61=6d2cfb2c5343c33c8d9e54e7d1f613f9.cab
                62=6d3c63e785ac9ac618ae3f1416062098.cab
                63=6da2af86cb1227e66cf9bc85f2786782.cab
                64=6dc62760f8235e462db8f91f6eaa1d90.cab
                65=6e142759ce3a6e36e52e089caffaffe1.cab
                66=7011bf2f8f7f2df2fdd2ed7c82053d7f.cab
                67=732eefaf52275b7a708311a31c82c814.cab
                68=7608a6c73562800dd82c513d6d2dcd94.cab
                69=77adc85e5c49bbd36a91bb751dc55b39.cab
                70=781e7c95c1b6b277057c9b53b7b5a044.cab
                71=791b388183dc99f779aa6adadab92e9a.cab
                72=7a8eaeba46cc44d02a9a46fcbb641a12.cab
                73=7c11b295fb7f25c6d684b1957e96a226.cab
                74=7c195d91008a0a6ad16e535ac228467d.cab
                75=83bd1072721871ea0bdc4fab780d9382.cab
                76=84cf100ee76440117226cfb9af196ba3.cab
                77=8624feeaa6661d6216b5f27da0e30f65.cab
                78=870d7f92116bc55f7f72e7a9f5d5d6e1.cab
                79=8bc062474f7e4aa85efdc73d3fe8b442.cab
                80=8c9919a5e8638dd2b352b0a218939370.cab
                81=8d25d56b34194978403f6bba33f419c5.cab
                82=8f264641cdc436354282a744033e7850.cab
                83=9050f238beb90c3f2db4a387654fec4b.cab
                84=93ed81ef8cf2e77c6ebc8aba5d95b9cf.cab
                85=94cae441bc5628e21814208a973bbb9d.cab
                86=9722214af0ab8aa9dffb6cfdafd937b7.cab
                87=97b6e3671e2e5d03ea25df25a8056e70.cab
                88=9d2b092478d6cca70d5ac957368c00ba.cab
                89=9f0be655144a0c68c7f087465e1ad4f9.cab
                90=9f8944e2cc69646284cd07010e7eee99.cab
                91=a011a13d3157dae2dbdaa7090daa6acb.cab
                92=a03686381bcfa98a14e9c579f7784def.cab
                93=a1d26d38d4197f7873a8da3a26fc351c.cab
                94=a22d6a2483a921a887070cd800030e47.cab
                95=a29a0c716f903f42aca181dca250f681.cab
                96=a30d7a714f70ca6aa1a76302010d7914.cab
                97=a32918368eba6a062aaaaf73e3618131.cab
                98=a565f18707816c0d052281154b768ac0.cab
                99=a7eb3390a15bcd2c80a978c75f2dcc4f.cab
                100=aa25d18a5fcce134b0b89fb003ec99ff.cab
                101=aa4db181ead2227e76a3d291da71a672.cab
                102=abbeaf25720d61b6b6339ada72bdd038.cab
                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
                107=b0189bdfbad208b3ac765f88f21a89df.cab
                108=b3892d561b571a5b8c81d33fbe2d6d24.cab
                109=b4687bc42d465256ad1a68aec6886f83.cab
                110=b5227bb68c3d4641d71b769e3ac606a1.cab
                111=b6758178d78e2a03e1d692660ec642bd.cab
                112=bbf55224a0290f00676ddc410f004498.cab
                113=bd00e61b3056a8aa44b48303f6fa1e62.cab
                114=be7ebc1ac434ead4ab1cf36e3921b70e.cab
                115=c300c91a497ea70c80a6d0efc9454c35.cab
                116=c6babfeb2e1e6f814e70cacb52a0f923.cab
                117=c98a0a5b63e591b7568b5f66d64dc335.cab
                118=cd23bfdfd9e3dfa8475bf59c2c5d6901.cab
                119=cfb8342932e6752026b63046a8d93845.cab
                120=d2611745022d67cf9a7703eb131ca487.cab
                121=d344672ad340db2b98b706ff06350843.cab
                122=d519967dbb262c80060d9efb5079aa23.cab
                123=d562ae79e25b943d03fc6aa7a65f9b81.cab
                124=dotNetFx45_Full_x86_x64.exe
                125=e0509d502dcdae109023403fc3bc8ac4.cab
                126=e5f4f4dc519b35948be4500a7dfeab14.cab
                127=e65f08c56c86f4e6d7e9358fa99c4c97.cab
                128=ea9c0c38594fd7df374ddfc620f4a1fd.cab
                129=eacac0698d5fa03569c86b25f90113b5.cab
                130=eb90890d25e1dee03cf79844d9f823f4.cab
                131=ec093852a41cbd9d167b714e4f4a2648.cab
                132=ed711e0a0102f1716cc073671804eb4c.cab
                133=eea40dab42b1052e4d55a25291e91ccd.cab
                134=eebe1a56de59fd5a57e26205ff825f33.cab
                135=f051f100a86ad4c94057a1d5280d9283.cab
                136=f2a850bce4500b85f37a8aaa71cbb674.cab
                137=f480ed0b7d2f1676b4c1d5fc82dd7420.cab
                138=f4e72c453e36ce0795c8c9fcaae2b190.cab
                139=f6aa96e71953e06cb7a3f69e76804b6d.cab
                140=f7699e5a82dcf6476e5ed2d8a3507ace.cab
                141=f8f7800500b180b8a2103c40ce94f56a.cab
                142=fa7c072a4c8f9cf0f901146213ebbce7.cab
                143=fbcf182748fd71a49becc8bb8d87ba92.cab
                144=fcc051e0d61320c78cac9fe4ad56a2a2.cab
                145=fd5778f772c39c09c3dd8cd99e7f0543.cab
                146=fe2c9602686dc1bcbf80a0f18bd54b49.cab
                147=fe43ba83b8d1e88cc4f4bfeac0850c6c.cab
                148=Flashing Tools-x86_en-us.msi
                149=Imaging And Configuration Designer-x86_en-us.msi
                150=InstallRegHiveRecoveryDriverAmd64.exe
                151=InstallRegHiveRecoveryDriverX86.exe
                152=Kits Configuration Installer-x86_en-us.msi
                153=Microsoft Compatibility Monitor-x86_en-us.msi
                154=SQLEXPR_x86_ENU.exe
                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
                158=wasinstaller.exe
                159=WimMountAdkSetupAmd64.exe
                160=WimMountAdkSetupArm.exe
                161=WimMountAdkSetupX86.exe
                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
                178=WPTarm-arm_en-us.msi
                179=WPTx64-x86_en-us.msi
                180=WPTx86-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)/$_"
                    break
                }
            }
        }
        # 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 http://technet.microsoft.com/en-us/library/dd819411.aspx
            $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 http://technet.microsoft.com/en-us/library/dd819411.aspx
            $newjob = Add-BitsFile -BitsJob $job -Source  $URL -Destination $Destination
        }
    
        # Begin the download and show us the job
        Resume-BitsTransfer  -BitsJob $job -Asynchronous
    
        # http://msdn.microsoft.com/en-us/library/windows/desktop/ee663885%28v=vs.85%29.aspx
        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
                break
            }
             "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.

Source: http://cyber-defense.sans.org/blog/2015/03/19/powershell-for-securing-windows-sec505-course

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.

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.

Attack

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 Innobit.ch and thank you if you attended and joined this user group.

If you’ve attended, please fill-in this little survey ( > http://1drv.ms/1FxKTmo ) , 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 powershelldistrict.com 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: http://powershellgroup.org/basel

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

[math]::PI

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

([math]::PI).ToString("G17")
([math]::PI).ToString("r")

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 🙂