top of page

Search this site

95 results found with an empty search

  • AD CS Says “Certificate Template Not Supported”

    A certificate template can exist in Active Directory, be published on the CA, have the correct OID and still fail enrollment. In this case, the affected servers had enrolled successfully before, which made the failure more confusing. As their certificates approached renewal, both automatic enrollment and manual re-enrollment started failing, despite the template appearing to be configured correctly. The Symptoms Member Server Logs Event ID 6 (0x80094800) Automatic certificate enrollment for local system failed (0x80094800) The requested certificate template is not supported by this CA. Event ID 13 0x80094800 CERTSRV_E_UNSUPPORTED_CERT_TYPE The requested certificate template is not supported by this CA. CA Sever Logs: Oops, and this is why WEC\WEF is being implemented. The CA logged a more useful warning: Event ID 77 The ToyoMemberServerIPSec Certificate Template could not be loaded. Element not found. 0x80070490 WIN32: ERROR_NOT_FOUND Event ID 53 Certificate enrollment for Local system failed to enroll for a ToyoMemberServerIPSec certificate... The requested certificate template is not supported by this CA. 0x80094800 CERTSRV_E_UNSUPPORTED_CERT_TYPE These would normally sends you straight to the CA console to check whether the template has been issued. Which I did, and it was. In this case, the CA could see the request but could not load the certificate template because a basic permission had been removed from the template: Authenticated Users — Read. The requested template OID was: 1.3.6.1.4.1.311.21.8.4730629.14882920.7291564.14825634.11292136.38.10267230.1384975 which correctly mapped to: Toyo Member Server IPSec So the template existed. The request referenced the correct template. The CA had previously issued certificates from it. The important line was: The ToyoMemberServerIPSec Certificate Template could not be loaded. Check that the template really exists You can query the certificate templates directly from Active Directory. $Base = "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=TOYO,DC=LOC" Get-ADObject ` -SearchBase $Base ` -LDAPFilter "(objectClass=pKICertificateTemplate)" ` -Properties displayName,msPKI-Cert-Template-OID | Where-Object { $_.DisplayName -eq "Toyo Member Server IPSec" } | Select-Object Name,DisplayName,msPKI-Cert-Template-OID In this case the result was correct: Name : ToyoMemberServerIPSec DisplayName : Toyo Member Server IPSec msPKI-Cert-Template-OID : 1.3.6.1.4.1.311.21.8.4730629.14882920.7291564.14825634.11292136.38.10267230.1384975 That also rules out one common problem: an old template being deleted and recreated with the same display name but a different OID. Check whether the CA is issuing it From the CA: certutil -CATemplates Or specify the CA explicitly: certutil -config "TOYONUC01.TOYO.LOC\TOYO-TOYODC01-CA" -CATemplates You can also query the CA object in Active Directory: $Base = "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=TOYO,DC=LOC" $CA = Get-ADObject ` -SearchBase $Base ` -LDAPFilter "(cn=TOYO-TOYODC01-CA)" ` -Properties certificateTemplates,dNSHostName $CA.certificateTemplates | Sort-Object ToyoMemberServerIPSec should appear in the list. If it does not, publish it from: Certification Authority > Certificate Templates > New > Certificate Template to Issue If it is already published, check the template permissions. The actual fault On the affected template, Authenticated Users had been removed. The CA therefore could not correctly load the template from Active Directory. Check the ACL with PowerShell: $Template = Get-ADObject ` -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=Domain,DC=com" ` -LDAPFilter "(cn=TemplateName)" (Get-Acl "AD:$($Template.DistinguishedName)").Access | Select-Object ` IdentityReference, ActiveDirectoryRights, AccessControlType, IsInherited | Format-Table -AutoSize Look for: NT AUTHORITY\Authenticated Users with Read permission. Authenticated Users does not need to be allowed to enroll, a typical permission set might be: Authenticated Users Read Member Server Certificate Group Read Enroll Autoenroll The dedicated server group controls who is allowed to obtain the certificate. Authenticated Users : Read allows the template to be discovered and read correctly by the AD CS infrastructure. The fix Open: certtmpl.msc Open the affected template and select: Security Add: Authenticated Users and grant: Read Do not grant Enroll or Autoenroll unless that is genuinely intended. The servers or groups that should receive the certificate should retain their own: Read Enroll Autoenroll After correcting the template, allow AD replication to complete. You can force the CA to reload its configuration by restarting Certificate Services: Restart-Service CertSvc Be aware that this temporarily stops certificate issuance. Then on an affected client: gpupdate /force certutil -pulse certutil -pulse triggers certificate autoenrollment processing. Check the enrollment policy as well If there is any uncertainty about how the client is obtaining certificate policy, this is useful: Get-CertificateEnrollmentPolicyServer -Scope All -Context Machine | Format-List * For normal domain enrollment you will usually see something similar to: Url : LDAP: AuthType : Kerberos AutoEnrollmentEnabled : True IsDefault : True Context : Machine That confirms the machine is using the normal Active Directory enrollment policy rather than Certificate Enrollment Web Services.

  • Signed WDAC: What Changes to Secure Boot, UEFI and Recovery?

    Windows Defender Application Control, now App Control for Business, controls what software Windows is allowed to run at the Kernel level. Applications, scripts and drivers can be approved by publisher, file identity, certificate or hash, with anything outside the policy blocked. An enforced WDAC policy is already a strong security control. Signing the policy takes it further because it protects the WDAC policy itself and links that protection into the UEFI and Secure Boot environment. That turned out to be rather more significant than simply putting a digital signature on a .cip file. In my home lab, systems that had previously booted happily from deployment USB media stopped doing so after the WDAC policy was signed. Hyper-V VMs showed similar behaviour when rebuilding from a mounted ISO. Apparently I had secured the machines against unauthorised software and, rather efficiently, my normal rebuild process. This is not the first time I've "secured" myself out of my own system, everyday is a school day. Secure Boot Secure Boot protects the system before Windows starts. The UEFI firmware checks that the boot software is signed by a trusted authority before allowing it to execute. Windows Boot Manager then continues that trusted process through the Windows loader, kernel and boot-critical components. Secure Boot therefore answers a fairly simple question: Can I trust what is starting Windows? Once Windows is running, Secure Boot does not decide whether every application or driver should be allowed to execute. That is where WDAC comes in. WDAC WDAC extends that trust into Windows. Instead of allowing software to run and waiting for antivirus or EDR to decide whether it is malicious, WDAC defines what is permitted to execute. The rule type determines how broad that trust becomes. Rule What It Trusts Security Maintenance Hash One exact binary Very High Very High FilePublisher Specific signed file, publisher and minimum version High Medium Publisher Software signed by an approved publisher Medium Low Certificate Software signed by an approved certificate Medium Low FileName Trusted file metadata Medium-Low Medium FilePath Software running from an approved location Low Low Publisher rules are convenient but relatively broad. Trusting software signed by Dell, HP or Microsoft can potentially trust other applications using the same approved publisher identity. FilePublisher is more restrictive because it includes the particular file and minimum version. For a tightly controlled environment I prefer: -Level FilePublisher -Fallback Hash This gives signed applications some flexibility to update while unsigned or unusual applications fall back to an exact hash. Unsigned WDAC An unsigned WDAC policy does not mean the applications themselves are unsigned. The policy can still validate software using Publisher, FilePublisher, certificates and hashes. Unsigned refers to the WDAC policy itself. An enforced unsigned policy can therefore provide very strong application control, but someone with sufficient administrative access may potentially remove or replace that policy. If an attacker gains Administrator access, the policy deciding what Administrator is allowed to run becomes an obvious target. Signed WDAC Signing addresses that weakness. The WDAC policy is digitally signed using an authorised policy-signing certificate. Windows verifies that the security policy making application control decisions has not been modified. More importantly, that protection extends beyond C:\Windows. Signed policies are written to the EFI System Partition under \EFI\Microsoft\Boot\CiPolicies\Active\ and written into UEFI NVRAM variables. Once activated, the policy becomes a persistent part of the pre-OS trust state. Removing or updating it requires deploying a new policy signed by the same authorized key, simply deleting the .cip file will render the system unbootable. VBS and HVCI Virtualization-Based Security (VBS) uses the Windows hypervisor to create a protected area of memory. HVCI, or Memory Integrity, uses that isolation to protect Code Integrity from normal kernel-mode code. This works particularly well with WDAC. WDAC defines which applications and drivers are trusted, while HVCI helps protect the mechanism enforcing those decisions from kernel-level tampering. Signing then protects the WDAC policy itself. Together the controls reinforce each other: Secure Boot protects startup, HVCI protects Code Integrity, WDAC controls what can execute and signing protects the WDAC policy from being replaced. Why UEFI Matters Without UEFI-backed protection, bypassing WDAC offline would be relatively straightforward. Assuming Bitlocker isn't enabled, boot WinPE, mount the Windows volume, delete the policy and restart. Signed WDAC is designed to make that considerably harder. The machine expects the authorised signed policy to remain present and valid. Removing or replacing it incorrectly is likely to stop Windows booting. It's worth being clear about what is happening here: Normal signed WDAC does not replace the UEFI Platform Key, KEK, db or dbx. Secure Boot remains the root of trust. Signed WDAC uses that protected environment to protect its own policy. It is therefore more accurate to say that signing extends the Secure Boot trust model into Windows Code Integrity. What About the Windows Boot Files? Signed WDAC does not re-sign files such as: bootmgfw.efi winload.efi ntoskrnl.exe Secure Boot and Windows Trusted Boot already protect those components. WDAC controls the drivers and executable code Windows is permitted to load. Signing then protects the WDAC policy from being changed. Each control has a different job, but together they create a much stronger chain of trust. USB and Hyper-V Generation 2 This is where signing becomes operationally challenging. Because signed WDAC writes state into UEFI NVRAM, the hardware enforces this security state before the OS even loads. When you attempt to boot a standard WinPE environment, mounted ISO or deployment USB, the UEFI environment evaluates that boot media against the machine's protected state. If the USB media lacks the necessary signed binaries or policy context, it gets blocked. The ease of wiping and rebuilding physical devices or VMs from a USB or mounted ISO is officially over, at least without a trip into the firmware settings to disable Secure Boot. PCRs, Measured Boot and BitLocker The TPM adds another layer through Platform Configuration Registers, or PCRs. Secure Boot determines whether trusted boot components are allowed to execute. Measured Boot records evidence of what actually happened during startup. BitLocker commonly uses PCR 7 and PCR 11 when sealing its TPM protector on Secure Boot systems. Changes to the protected boot environment can therefore cause BitLocker to see a different measured state and request the recovery key. For that reason, I temporarily suspend BitLocker before the initial signed WDAC deployment. First check the current PCR profile: manage-bde -protectors -get C: Then suspend BitLocker: Suspend-BitLocker ` -MountPoint "C:" ` -RebootCount 0 Deploy the signed WDAC policy and reboot. Once the machine has successfully started and the policy is confirmed as active: Resume-BitLocker -MountPoint "C:" Suspending BitLocker does not decrypt the disk. It temporarily prevents a planned boot-security change from becoming an unnecessary recovery-key exercise. And, obviously, make sure the recovery key actually exists somewhere useful before changing Secure Boot or deploying signed WDAC. Finding that out afterwards would add an unnecessary level of excitement. Unsigned vs Signed WDAC The practical difference is fairly simple. Capability Unsigned WDAC Signed WDAC Controls applications and drivers Yes Yes Uses Publisher/FilePublisher/Hash rules Yes Yes Works with VBS/HVCI Yes Yes Protects the policy from replacement No Yes Makes Administrator policy tampering harder No Yes Uses UEFI/Secure Boot for policy protection No Yes Makes offline policy bypass harder No Yes Changes recovery considerations Limited Significant Final Thoughts Secure Boot protects how Windows starts. HVCI protects Code Integrity. WDAC controls what Windows is allowed to run. Signing then protects the WDAC policy itself and ties that protection back into the UEFI and Secure Boot environment. That is a great security model. I learned the hard way after discovering that my USB media and ISOs I had been happily using to rebuild machines had suddenly become considerably less useful. So, technically, signed WDAC worked perfectly. I had successfully stopped unauthorised software, protected the policy from administrators and made offline tampering considerably harder. Unfortunately, the administrator it was protecting the machines from appeared to be me.

  • When NTLM Hardening Breaks SID Lookup: Diagnosing RPC Endpoint Mapper and LSA Failures

    NTLM hardening can expose dependencies that are not obvious during normal Windows administration. In other words, the lab was working perfectly well until I decided it clearly wasn't secure enough. I’d successfully hardened the lab to the point where even Windows itself was being treated as a security threat, a very solid effort on my part... Idiot I was trying to configure Windows Event Collector server with a source-initiated WEC subscription. When an Active Directory security group was added to the subscription, Event Viewer failed to resolve the group: The specified domain either does not exist or could not be contacted. The account CONTOSO.LOC\RG_WEC_Subscription cannot be translated to a security identifier. This resulted in a slight detour from WEC and WEF, whilst I fixed the lab. Testing the SID translation directly produced an even more misleading error: ([System.Security.Principal.NTAccount]'CONTOSO\RG_WEC_Subscription').Translate( [System.Security.Principal.SecurityIdentifier] ) Result: Exception calling "Translate" with "1" argument(s): "The trust relationship between this workstation and the primary domain failed." The obvious conclusion would be a failed computer account trust, It wasn't. The machine trust was healthy, DNS worked, Kerberos worked, LDAP worked and SYSVOL was accessible. Microsoft documents that enabling the 'Enable RPC Endpoint Mapper Client Authentication' cannot be used with 'Network security: Restrict NTLM: Incoming NTLM traffic – Deny all accounts'. Microsoft recommends retaining the NTLM restriction rather than enabling authenticated RPC endpoint resolution where the two conflict. The Configuration That Caused the Problem The member server had the following Group Policy enabled: Computer Configuration Policies Administrative Templates System Remote Procedure Call Enable RPC Endpoint Mapper Client Authentication Configured as: Enabled The corresponding registry setting is: HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Rpc EnableAuthEpResolution When enabled, RPC clients authenticate to the Endpoint Mapper for RPC calls containing authentication information. The domain controllers were also hardened with: Computer Configuration Policies Windows Settings Security Settings Local Policies Security Options Network security: Restrict NTLM: Incoming NTLM traffic Configured as: Deny all accounts The effective registry value on the domain controllers was: reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictReceivingNTLMTraffic Result: RestrictReceivingNTLMTraffic REG_DWORD 0x2 Deny all accounts prevents incoming NTLM authentication from both domain and local accounts. Microsoft records audit and block information for this policy under the NTLM Operational event log. The member server's outgoing NTLM policy was only configured for auditing: reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictSendingNTLMTraffic Result: RestrictSendingNTLMTraffic REG_DWORD 0x1 In this configuration 1 represents Audit all, rather than an outbound NTLM block. Microsoft recommends using Audit all before moving to Deny all so that remaining NTLM dependencies can be identified. The important combination was therefore: System Setting Configuration Member server RPC Endpoint Mapper Client Authentication Enabled Member server Outgoing NTLM Audit all Domain controllers Incoming NTLM Deny all accounts The result was a failure in Windows SID/name resolution while most other domain functionality continued to work. Why the Error Was Misleading The error returned by Windows was: The trust relationship between this workstation and the primary domain failed. A broken secure channel can certainly produce that error, so the first step was to test it: Test-ComputerSecureChannel -Verbose Result: VERBOSE: Performing the operation "Test-ComputerSecureChannel" on target "WEC01". True VERBOSE: The secure channel between the local computer and the domain CONTOSO.LOC is in good condition. This was then tested against each domain controller individually: Test-ComputerSecureChannel -Server DC01 -Verbose Test-ComputerSecureChannel -Server DC02 -Verbose Test-ComputerSecureChannel -Server DC03 -Verbose All returned: True At that point, resetting the computer account or removing and rejoining the server to the domain would have been the wrong action. Check Domain Controller Discovery The next checks confirmed that the server could find and communicate with Active Directory: whoami $env:LOGONSERVER nltest /dsgetdc:contoso.loc nltest /sc_query:contoso.loc A healthy nltest /dsgetdc result should identify a domain controller and report capabilities similar to: GC DS LDAP KDC TIMESERV WRITABLE DNS_DC DNS_DOMAIN DNS_FOREST nltest /sc_query should return: Trusted DC Connection Status Status = 0 0x0 NERR_Success Again, this confirmed that Netlogon and the machine secure channel were functioning. Test the SID Lookup Directly The Windows account translation could be reproduced independently of WEC. For a domain group: ([System.Security.Principal.NTAccount]'CONTOSO\RG_WEC_Subscription').Translate( [System.Security.Principal.SecurityIdentifier] ) This failed. Testing several objects made the behaviour more obvious: $Accounts = @( 'CONTOSO\AdminUser', 'CONTOSO\Domain Computers', 'CONTOSO\RG_WEC_Subscription' ) foreach ($Account in $Accounts) { try { $SID = ([System.Security.Principal.NTAccount]$Account).Translate( [System.Security.Principal.SecurityIdentifier] ) "$Account = $SID" } catch { "$Account = FAILED - $($_.Exception.Message)" } } The result looked like: CONTOSO\AdminUser = S-1-5-21-xxxxxxxx-xxxx CONTOSO\Domain Computers = FAILED - The trust relationship between this workstation and the primary domain failed. CONTOSO\RG_WEC_Subscription = FAILED - The trust relationship between this workstation and the primary domain failed. This was an important diagnostic result. A currently logged-on user could be resolved, while domain security groups could not. The WEC problem was therefore not specific to Event Viewer. Windows account-to-SID translation itself was failing. Windows uses LSA account lookup mechanisms to translate account names and SIDs. Query the Group SID Directly Through LDAP LDAP provided another useful test because it allowed the group SID to be read directly from each domain controller without using the failing account-name translation mechanism. $DCs = 'DC01','DC02','DC03' foreach ($DC in $DCs) { $Root = [ADSI]"LDAP://$DC/RootDSE" $Base = [ADSI]( "LDAP://$DC/" + $Root.defaultNamingContext ) $Search = New-Object ` System.DirectoryServices.DirectorySearcher($Base) $Search.Filter = ` '(&(objectClass=group)(sAMAccountName=RG_WEC_Subscription))' $Result = $Search.FindOne() if ($Result) { $SID = New-Object ` System.Security.Principal.SecurityIdentifier( $Result.Properties['objectsid'][0], 0 ) "$DC : $SID" } else { "$DC : Group not found" } } All three domain controllers returned the same SID: DC01 : S-1-5-21-xxxxxxxx-xxxxxxxx-xxxxxxxx-12117 DC02 : S-1-5-21-xxxxxxxx-xxxxxxxx-xxxxxxxx-12117 DC03 : S-1-5-21-xxxxxxxx-xxxxxxxx-xxxxxxxx-12117 This ruled out: AD replication Missing group Different group objects LDAP connectivity Incorrect SID Check RPC and SMB Connectivity Because SID/name lookup can involve RPC, TCP 135 and SMB were checked next: Test-NetConnection DC01 -Port 135 Test-NetConnection DC01 -Port 445 Expected: TcpTestSucceeded : True The same tests were performed against each domain controller. SYSVOL access was also tested: Get-ChildItem \\DC01.contoso.loc\SYSVOL This succeeded. Normal SMB communication to Active Directory was therefore available. Where firewalls exist between domain members and domain controllers, remember that TCP 135 is only the RPC Endpoint Mapper. RPC services may subsequently use dynamic high ports, so allowing TCP 135 alone does not prove that every RPC operation will succeed. Verify Kerberos Kerberos was also checked explicitly: klist get cifs/DC01.contoso.loc A successful result should show a ticket for: cifs/DC01.contoso.loc The ticket in this case used AES and had been issued by a domain controller. LDAP Kerberos tickets were also already present: klist with entries similar to: ldap/DC01.CONTOSO.LOC ldap/DC02.CONTOSO.LOC GC/DC02.CONTOSO.LOC/CONTOSO.LOC At this stage the basic AD stack was working: DNS Working Kerberos Working LDAP Working SMB Working SYSVOL Working Netlogon Working Secure Channel Working SID Lookup Failing Check the NTLM Policies The member server was checked for outgoing NTLM restrictions: reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictSendingNTLMTraffic Result: RestrictSendingNTLMTraffic REG_DWORD 0x1 This was Audit all. The domain controllers were checked for incoming NTLM restrictions: reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictReceivingNTLMTraffic Result: RestrictReceivingNTLMTraffic REG_DWORD 0x2 The DCs were denying incoming NTLM. The RPC Endpoint Mapper Client Authentication policy on the member server was simultaneously requiring authenticated endpoint resolution. NTLM Event Logs NTLM auditing and blocking events are recorded under: Event Viewer Applications and Services Logs Microsoft Windows NTLM Operational Event IDs in the 8001 to 8004 range are associated with NTLM auditing and restriction activity. The recent events can be queried with PowerShell: Get-WinEvent ` -FilterHashtable @{ LogName = 'Microsoft-Windows-NTLM/Operational' Id = 8001,8002,8003,8004 } | Select-Object TimeCreated,Id,Message | Format-List The Security log can provide supporting evidence as well. For network logons, Event ID 4624 can be inspected for: Logon Type: 3 Authentication Package: NTLM The Fix The NTLM restriction on the domain controllers was intentional security hardening and did not need to be removed. The conflicting RPC policy was overridden on the affected member server: Computer Configuration Policies Administrative Templates System Remote Procedure Call Enable RPC Endpoint Mapper Client Authentication Set: Disabled An OU-specific GPO can be used where a wider security baseline enables the setting. Apply policy: gpupdate /force The RPC Endpoint Mapper Client Authentication setting requires a reboot before the change takes effect. After restarting the server, the SID translation was tested again: ([System.Security.Principal.NTAccount]'CONTOSO\Domain Computers').Translate( [System.Security.Principal.SecurityIdentifier] ) and: ([System.Security.Principal.NTAccount]'CONTOSO\RG_WEC_Subscription').Translate( [System.Security.Principal.SecurityIdentifier] ) Both now returned valid SIDs. Final Configuration The resulting hardening configuration kept the important NTLM restriction: Domain Controllers Network security: Restrict NTLM: Incoming NTLM traffic Deny all accounts The conflicting member-server policy was disabled: Member Server System Remote Procedure Call Enable RPC Endpoint Mapper Client Authentication Disabled The problem was not that NTLM had been disabled. The problem was that one RPC policy still expected to use an authentication mechanism that another policy had deliberately removed.

  • Zero Trust for the Home Lab - IPSec (Part 4)

    The Road to the World's Most Secure Home Lab.... So far in the pursuit of the World's most secure home lab, the following have been implemented: Part 1 - Zero Trust Introduction Part 2 - VLAN Tagging and Firewalls with pfSense Part 3 - pfSense and 802.1x What's Covered in this Blog This post covers implementing IPSec using certificates for authentication and data encryption across my Windows Domain. This is not for the faint of heart. What Is Zero Trust - Recap Zero Trust is a security framework that assumes no user, device, or network segment is inherently trustworthy, regardless of where it sits in the network. The core principles include: Verify explicitly – Always authenticate and authorize access. Use least privilege access – Limit access to only what's needed. Assume breach – Design as if attackers are already in the network. How IPSec Addresses Zero Trust Security Zero Trust assumes the network is hostile, even internal traffic can't be trusted without verification. Every connection must be authenticated, authorized, and encrypted. IPSec (Internet Protocol Security) is a key enabler: IPSec Overview IPSec is a suite of protocols designed to secure IP communications by authenticating and encrypting each IP packet. It lends itself to Zero Trust by enforcing confidentiality, data integrity, origin authentication, and replay protection. When deployed in a Windows environment, IPSec leverages Active Directory and the Microsoft Public Key Infrastructure (PKI), also known a Certificate Authority (CA). End-to-End Encryption: All internal traffic should be encrypted. IPSec encrypts IP packets at the network layer, ensuring confidentiality and integrity from endpoint to endpoint, protecting data regardless of the underlying application or network. This can be challenging when accessing services that aren't inherently secure or encrypted, such as the Internet. Mutual Authentication: With a CA managing digital certificates, IPSec can perform strong mutual authentication between devices. Identity Assurance: The use of a CA provides control over credentials that defines certificate lifespans, whether to issue or revoke them as needed. IPSec Technical Components Security Associations (SA): An IPSec Security Association (SA) are 2 unidirectional agreements between two endpoints defining traffic security, specifying the encryption, authentication methods, keys, and lifetime for that session. These are negotiated automatically via IKE (Internet Key Exchange), ensuring both sides agree on how to protect the data in transit. AH vs. ESP IPSec offers two main ways to protect packets: Authentication Header (AH) – IP Protocol 51 Authenticates the entire IP packet (including headers) to ensure data integrity and source authenticity. AH does not encrypt the payload, your data remains visible. Rarely used in practice; largely obsolete in modern IPSec deployments. Encapsulating Security Payload (ESP) – IP Protocol 50 Encrypts and optionally authenticates the payload, provides: Confidentiality (via encryption) Data integrity and authentication (via HMAC) Modes: Transport Mode: Encrypts only the payload, IP header is exposed. Tunnel Mode: Encrypts the entire original IP packet and adds a new IP header. Obvious Choice: ESP is the standard choice for secure, encrypted communications in Windows IPSec. IKEv2 Microsoft strongly recommends IKEv2 as the default key management protocol: Supports certificate and EAP authentication methods. Built-in NAT Traversal with UDP port 4500 encapsulation. Robust against network disruptions and supports mobility. Provides streamlined, secure negotiation of SAs. Aligns well with 802.1X for device/network authentication. Windows IPSec implementations starting with Windows 7 and Server 2008 R2 default to IKEv2 for VPNs and IPSec tunnels. Unfortunately, this feature isn't supported through GPO, so we will have to settle for IKEv1. The impact of GPO's not natively supporting IKEv2 results in RSA certificates and not ECC IPSec Certificate support. You'll also need to remember it's IKEv1 when configuring swanctl.conf for Linux. Quick and Main Modes Phase 1: IKE SA Establishment (Main Mode or Aggressive Mode) This phase establishes the ISAKMP/IKE Security Association, which provides a secure, authenticated channel for subsequent negotiation. It includes: Peer authentication using certificates, pre-shared keys, or Kerberos Diffie-Hellman key exchange to derive shared secrets Agreement on encryption, integrity, and hashing algorithms Traffic in this phase uses UDP port 500. Phase 2: IPSec SA Negotiation (Quick Mode) Phase 2 leverages the secure channel from Phase 1 to: Establish one or more IPSec Security Associations (SAs) Define the protected traffic flows using traffic selectors (source/destination IPs, ports, protocols) Generate fresh keying material for encryption and integrity Quick Mode messages are protected by the IKE SA established in Phase 1. The outcome is the creation of ESP SAs for actual packet level protection. Ports & Protocols: Crucial! Required Windows firewall rules, both Inbound and Outbound: UDP Port 500: IKE (initial negotiations) UDP Port 4500: IKE NAT Traversal (when devices are behind NAT) IP Protocol 50: ESP (for the encrypted data) IP Protocol 51: AH (don't use) Basic CA and GPO Configuration: Ensure every Windows Domain client trusts the Windows Root CA, and deploy it using GPO if necessary. Enable auto-enrollment of certificates in Group Policy, certificate templates with the Autoenroll permission will do just that, and enroll automatically. Crucial! Certificates should not serve multiple purposes. The IPSec certificate must exclude other Application policies to avoid conflicts and processing errors. Additional Logging I've enabled the three IPSec auditing policies at the root of the Domain to assist with initial testing and troubleshooting. These settings generate a high volume of event logs, but once IPSec is stable and set to 'Required', logging can be reduced to capture only failures. Client Certificates No TPM..... Not all of my Windows clients and servers are blessed with a TPM, case in point, the Intel Skull Canyon and the Gen 6 NUC - Hyper-V host, they still cling to life with retirement being long overdue. Without the TPM there's no support for Microsoft Platform Crypto Provider. The fallback option when a TPM isn't available is to use the Microsoft Software Key Storage Provider, targeting the correct provider is managed through Active Directory groups controlling certificate enrollment. Create the following AD Groups. If you have followed the 802.1x blog, the client groups will have already been created: For Computer objects that do not support TPM RG_CA_WksAuthCert_Deny_TPM_Supt RG_CA_MemberServer_Deny_TPM_Supt For Computer objects that do support TPM RG_CA_MemberServer_Allow_TPM_Supt RG_CA_WksAuthCert_Allow_TPM_Supt Workstation Authentication Client - TPM Supported Workstation Authentication Template: Right-click Certificate Templates and select Manage. Right-click the Workstation Authentication template and select Duplicate Template. General Tab: Template display name: Toyo Workstation IPSec Validity period: 1 years Renewal period: 6 weeks Check 'Publish certificate in Active Directory.' Compatibility Tab: Set compatibility levels to Windows Server 2016 and Windows 10 Cryptography Tab: Provider Category: Key Storage Provider Algorithm Name: RSA RSA is supported for key generation and storage in the TPM. ECC (Elliptic Curve Cryptography) isn't generally supported for TPM storage of certificates. Minimum key size: 2048 Request hash: SHA256 Requests must use one of the following providers: Microsoft Platform Crypto Provider Microsoft Platform Crypto Provider is the Key Storage Provider (KSP) that allows certificates and their private keys to be stored in the Trusted Platform Module (TPM). If no TPM is accessible, the certificate will fail to enroll. Subject Name Tab: Under 'Build from this Active Directory Information' Subject name format: Common Name is selected Include this information in the alternative sub name: Check DNS Extensions Tab: Select Application Policies and click Edit.... Ensure Client Authentication is present. Add IP Security IKE Intermediate > Click OK. This isn’t required for 802.1X, but it will be relevant in the next article on IPsec. Security Tab: Ensure Domain Computers is removed Add RG_CA_WksAuthCert_Allow_TPM_Supt and Allow Read, Enroll and AutoEnroll. Click Apply and OK. Workstation Authentication Client - TPM Not Supported Toyo Workstation Authentication Template: Right-click the Toyo Workstation IPSec template and select Duplicate Template. General Tab: Update the name to show that the TPM isn't supported Cryptography Tab: Provider Category: Key Storage Provider Algorithm Name: RSA Minimum key size: 2048 Request hash: SHA256 Requests can use any provider available on the subject's computer. Security Tab: Ensure 'Domain Computers' is removed Add RG_CA_WksAuthCert_Deny_TPM_Supt and Allow Read, Enroll, and AutoEnroll. Authenticated User with Read must remain otherwise the CA itself is unable to read the Template. Click Apply and OK. Member Server Certificates Duplicate the 'Computer v2' certificate template General Tab: Template display name: Toyo Member Server IPSec. Validity period: 1 years Renewal period: 6 weeks Check 'Publish certificate in Active Directory.' Compatibility Tab: Set compatibility levels to Windows Server 2016 and Windows 10 Cryptography Tab: Provider Category: Key Storage Provider Algorithm Name: RSA RSA is supported for key generation and storage in the TPM. ECC (Elliptic Curve Cryptography) is supported for certificate storage in the TPM, it cannot be used with GPO configured IPSec. GPO IPSec policies rely on IKEv1 only, which limits authentication to RSA. Although PowerShell (Set-NetIPSecRule) can configure the key module to use IKEv2, this capability cannot be deployed or managed via Group Policy. Minimum key size: 2048 Request hash: SHA256 Requests must use one of the following providers: Microsoft Platform Crypto Provider Microsoft Platform Crypto Provider is the Key Storage Provider (KSP) that allows certificates and their private keys to be stored in the Trusted Platform Module (TPM). If no TPM is accessible, the certificate will fail to enroll. Subject Name Tab: Under 'Build from this Active Directory Information' Subject name format: Common Name is selected Include this information in the alternative sub name: Check DNS Extensions Tab: Select Application Policies and click Edit.... Remove Client Authentication and Server Authentication. Add IP Security IKE Intermediate > Click OK. Security Tab: Ensure Domain Computers and Domain Controllers are removed Add RG_CA_MemberServer_Allow_TPM_Supt Allow Read, Enroll, and AutoEnroll. Click Apply and OK. Domain Controller Duplicate the 'Domain Controller Authentication' Template, which should be deployed already. All of my domain controllers are virtual and equipped with a vTPM, allowing them to use the Microsoft Platform Crypto Provider. If your environment differs, separate the certificate templates as previously outlined for clients and servers. General Tab: Template display name: Toyo Domain Controller IPSec. Validity period: 1 years Renewal period: 6 week Do not 'Publish certificate in Active Directory.' Compatibility Tab: Set compatibility levels to Windows Server 2016 and Windows 10 Cryptography Tab: Provider Category: Key Storage Provider Algorithm Name: RSA RSA is supported for key generation and storage in the TPM. ECC (Elliptic Curve Cryptography) is supported for certificate storage in the TPM, it cannot be used with GPO configured IPSec. GPO IPSec policies rely on IKEv1 only, which limits authentication to RSA. Although PowerShell (Set-NetIPSecRule) can configure the key module to use IKEv2, this capability cannot be deployed or managed via Group Policy. Minimum key size: 2048 Request hash: SHA256 Requests must use one of the following providers: Microsoft Platform Crypto Provider Microsoft Platform Crypto Provider is the Key Storage Provider (KSP) that allows certificates and their private keys to be stored in the Trusted Platform Module (TPM). If no TPM is accessible, the certificate will fail to enroll. Subject Name Tab: Under 'Build from this Active Directory Information' Subject name format: Common Name is selected Include this information in the alternative sub name: Check DNS Extensions Tab: Select Application Policies and click Edit.... Remove Client Authentication, Server Authentication and Smart Card Logon. Add IP Security IKE Intermediate > Click OK. Security Tab: Leave the Default Security settings Click Apply and OK. Publish the New Templates: In the Certification Authority console Right click Certificate Templates, select New, then Certificate Template to Issue. Select your newly created Toyo Templates. Restart the clients to automatically enroll the certificate or gpupdate /force IPSec Certificates The end result will be a dedicated set of certificates purpose built for IPSec that caters for devices with and without a TPM. The Somewhat Scary Stuff Begins Here.....IPSec Request The "Request IPSec" policy is a relatively safe starting point for introducing IPSec into your environment without disrupting existing communication. Rather than enforcing encryption, it negotiates secure connections when possible and gracefully falls back to plaintext. Create a new GPO for each tier of service, Domain Controller, Member Servers and Clients, name appropriately to show that these policies are specifically for IPSec. Try and refrain from using the root domain policy or bundling the update into another already established GPO. Don't create or modify Root level IPSec GPO's, not only is it bad practice, it could to lead to a rather serious outage of the entire Domain. Consistency across all GPOs is critical, any mismatch in settings will lead to IPSec negotiation failures. Exceptions for Routers and AP's: The Domain Controller IPSec policy was deployed first, with the following rules configured. In addition to the standard 'Request inbound and outbound' rule, exemptions were added for the router IP to allow Internet access and for the PiHole servers for DNS resolution. The Build LAN exception for 192.168.60.0/24 (VLAN60) allows communication with clients and servers that have yet to join the domain and, therefore, can't establish an IPSec tunnel due to missing certificates. The exceptions for VLAN60 include DC's and the CA servers. Some follow-up actions are needed to create the additional VLAN and Firewall in pfSense. GPO_IPSec_DomainControllers: Navigate to Computer Configuration > Policies > Windows Settings > Security Settings > Windows Defender Firewall with Advanced Security. Right click on Connection Security Rules and New Rule... Rule Type: Custom Endpoints: Any IP Address Requirements: Request authentication for inbound and outbound connections. Authentication Method: Advanced Customize..... Customize Advanced Authentication Methods: First Authentication Add Computer Certificate from this CA Select the Enterprise Root Certificate Protocols and Ports: Any. Profile: Check only the Domain profile. It's unlikely the DC's and Servers will roam, consider selecting all 3 profiles. Name: Add a meaningful name. IPSec Settings Tab: Right-click on Windows Defender Firewall with Advanced Security Click on the IPSec Setting Tab Customize.... Customize IPSec Defaults: For Main Mode, Quick Mode and Authentication Method, click on Advanced. Customize each in turn, following the guide below Key exchange (Main Mode): Click Add.. Integrity algorithm: SHA-256 Encryption algorithm: AES-CBC 256 Key exchange algorithm: Elliptic Curve Diffie-Hellman P-256 Key exchange options: Use Diffie-Hellman for enhanced security. Data Protection (Quick Mode): Require encryption for all connection security rules that use these settings: Enable this option to encrypt the data, without it, only the authentication process is encrypted. Protocol: ESP (recommended) Encryption algorithm: AES-GCM 128 Integrity algorithm: AES-GCM 128 Note: AES-GCM-128 and 256 are supported by Rocky Linux, AES-GMC-192 is not supported Authentication Method: First Authentication Add Computer Certificate from this CA Select the Enterprise Root Certificate Copy the First IPSec GPO: Don't make things difficult by recreating the GPO's for each tier of OU, copy and paste the first IPSec policy in Group Policy Objects: Navigate to Group Policy Objects Right click, GPO_IPSec_DomainController and Copy Paste and rename 'Copy of GPO_IPSec_DomainController' to GPO_IPSec_MemberServers Repeat, and create GPO_IPSec_Workstations. Link the GPO's to their corresponding OU. IPSec Require Mode and the Network Profile Race Condition Crucial! When IPSec is configured in Require mode within a domain, all inbound traffic must be authenticated, which results in a race condition during system startup. DC's, Windows clients and Servers rely on the Network Location Awareness (NLA) service to determine which firewall profile (Domain, Private, or Public) to assign based on whether it can reach a domain controller. However, if IPSec is in Require mode on the DC and the client hasn't yet established an IPSec Security Association (SA), all unauthenticated attempts to reach domain services (like LDAP or Kerberos) are silently dropped. This creates a loop: The client can't authenticate because it hasn’t established IPSec yet. It can’t establish IPSec because the DC won’t respond to unauthenticated traffic. As a result, the client falls back to the Public profile, blocking IPSec negotiation as it not enabled for IPSec. To get around this catch 22, the following IPSec Exemption Mode rules are required to allow unencrypted network communication at system startup. While this introduces gaps in the IPSec enforcement policy, the majority of ports remain configured with the 'Require' setting. Critically, the two most commonly targeted services—SMB (445) and RDP (3389) are still enforced, mitigating the highest-risk vectors. Note - Don't think setting Request for these ports is an option. DHCP UDP 67, 68 Clients, Server DNS UDP/TCP 53 DC, Clients, Server SMB\CIFS TCP 445 DC, Clients, Servers Kerberos UDP/TCP 88, 464 DC, Clients, Server LDAP TCP 389, 636 DC, Clients, Server ESP (IPsec payload) IP Protocol 50 N/A DC, Clients, Server IKEv1 and IKEv2 UDP 500 DC, Clients, Server DC Exemptions The domain controller exemptions permit Endpoint 1 to initiate connections from any source port to specific service ports (e.g., TCP/UDP 88 for Kerberos), and allow Endpoint 2 to send traffic from any source port to the same service ports on remote systems. Server and Client Exemptions Clients and servers initiating connections to a remote DC service port require Endpoint 2 to allow traffic from any source port to a specific destination port. Note: Both IPSec and exemption rules are initially configured with an open Any/Any endpoint setting. This approach makes life a little easier when investigating connectivity issues. Once the environment is fully configured, tested and stable, a remediation step will be carried out to harden the policies to allow names services and subnets. Firewalls.... What the.......I did warn you. You may encounter a situation where enabling IPSec Request rules causes the Windows Firewall to enforce stricter behavior. Even previously reliable and well-established firewall rules may begin to block traffic unexpectedly, such as group policies failing to apply. Crucial! Firewalls, particularly the Windows Firewall, will be the most significant source of pain during implementation. While pfSense may present occasional challenges, the majority of connectivity and policy enforcement problems were from Windows. Ensure that Firewall logging is enabled and reporting correctly. Test the Request Policy: Update the policy on the DC's, Member Servers and Clients with gpupdate /force. Windows Firewall - wf.msc To confirm that IPSec is functioning correctly in Request mode, start by opening wf.msc (Windows Defender Firewall with Advanced Security). Under the Monitoring section, navigate to Security Associations > Main Mode and Quick Mode to view active IPSec tunnels. Clicking on Connection Security Rules shows the accumulation of policies that are actively being applied. Main Mode Quick Mode Eventlogs Open Event Viewer (eventvwr) Paste the following event IDs and filter for IPSec events, remove the chaff. 5440, 5441, 5442, 5450, 5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459 Review the logs That’s the first step in implementing IPSec using Request mode, which carries minimal risk of service disruption. However, domain joined machines, including domain controllers, will still accept traffic from devices that aren’t using IPSec. This includes any unmanaged or potentially insecure IoT devices. Now it gets serious..... Now for the Really Scary Stuff .....IPSec Required Implementing Require IPSec policies enforces strict authentication and encryption, all inbound and outbound traffic will be encrypted, unless there's an exemption rule. Any misconfiguration of policy or certificates, expect a service outage. Thoroughly test all scenarios in a controlled environment before applying Require mode. You assume full responsibility for any service impact, and proceed at your own risk. Be prepared for some frustration, check the DC firewall rules, it may not be IPSec, and good luck!!!! The Plan Now that I've provided the appropriate warning and my conscience is clear, it's time to implement Require IPSec rules...gradually Given the above warning, switching from Request to Require without a staged rollout isn’t the smartest move. Request mode provides the necessary failsafe, it plays nicely and maintains connectivity during deployment, something Require mode does not. Even if IPSec tunnels appear to negotiate successfully in testing, enforcing Require can break communication with systems that are slightly off-kilter. Make sure you have physical access to the system and choose your test targets carefully. There’s a recovery mechanism, hacking the Registry, if things go sideways. Let’s avoid dragging out the crash cart if we can help it. Make sure every client, server and domain controller is on and their policies are up to date prior to proceeding. My target is a DC, I've plenty of them, easy to replace, minimal chance of data loss, and it helps being able to unpick the GPO and have it apply locally to that DC. Don't pick a DC with a FSMO role, especially the PDC emulator. Required GPO: Connect Group Policy Management to the target DC. This helps revert the GPO if network connectivity is lost. Create a new GPO, name it GPO_IPSec_Require. Remove Authenticated Users from the Security Filtering. Add the nominated DC, in my case TOYODC19-3 This filters the GPO to the named DC and no others Connection Security Rules: Edit the GPO and navigate to the Connection Security Rules Created a new Connection Security Rule. Using the previous procedure, match the settings except for the Requirement page. Select 'Require authentication for inbound and outbound connections' Post Require Checks: Run gpupdate on the DC. If the stars align and so do the certificates, CRL and policy, the more restrictive policy takes preseedence, Required Mode is now in operation. Congratulations. Verify access to other domain resources and network shares, testing as many connections as possible. Open wf.msc, confirm entries in Main and Quick mode Staged Deployment: This is a gradual deployment, only fools rush in....and they’re usually the ones pulling an all nigther trying to fix their mess. Link the 'GPO_IPSec_Require' to the Servers and Workstations OU's. Add to the Security Filtering additional computer objects, ensure both types of objects, those with and those without a TPM. Validate connectivity after a gpupdate. The extent of testing and validation depends on your risk acceptance level. If you're confident everything's working as expected, update the existing Request IPSec GPOs to Require. Once that's done, you can safely remove the temporary GPO_IPSec_Require, its served its purpose. Whoa there, Mine's not Working.... Another fine mess...the network isn’t connecting because IPSec can’t establish a secure tunnel. When in “Require” mode, no tunnel means no traffic, so you’re stuck until it’s fixed. Start by checking the Security Event IDs like 5450, 5451, or 5442. These will point to why the IPSec negotiation failed, whether it’s a certificate issue, authentication error, or policy mismatch. Then, open wf.msc and look under Monitoring > Security Associations for Main Mode and Quick Mode. If there are no active associations, that confirms the tunnels have either collapsed or never got created in the first place. If you can’t identify the problem right away, temporarily switch GPO_IPSec_Require back to “Request”. This is very unlikely to restore connectivity, if you werent already on the DC with GPO Management open, update the policy and gpupdate. With connectivity restored, resolve any issues highlighted in the Event logs, then try Required again. If the Event logs provide no clues, verify that both the separate authentication certificate and the IPSec certificate are properly enrolled, combining them into a single certificate will break IPSec. Thoroughly check all GPO IPSec settings for any misconfigurations. Request mode lets connections pass whether or not IPSec succeeds, while Require mode blocks anything that doesn’t meet IPSec strict criteria, which is why Request often “just works” while Require can fail if the environment isn’t perfectly configured. No Connectivity, no GPO... Without connectivity, there is little chance of any GPO ever reapplying, undoing the Require. There is one solution, delete the Registry hive for the GPO Settings: Open Regedt32 Browse to HKLM:\Software\Policies\Microsoft\WindowsFirewall. Delete WindowsFirewall. Reboot Another Step in the Journey to Zero Trust is Over After questioning my sanity, and whether I truly really wanted to go through with enabling IPsec, it's finally in place. It wasn’t without its challenges, enabling "Required" led to a fair bit of pain, including network profiles switching to Public from Domain, leading to denial of services and some other random dropped network connections. Still, I think (still not entirely sure) the effort was worth it. I'm now at least one step closer to Zero Trust, and what I’m convinced will be the world’s most secure home lab. Related Posts: Part 1 - Zero Trust Introduction Part 2 - VLAN Tagging and Firewalls with pfSense Part 3 - pfSense and 802.1x Part 4 - IPSec for the Windows Domain Part 5 - AD Delegation and Separation of Duties Part 6 - Yubikey and Domain Smartcard Authentication Setup Part 7 - IPSec between Windows Domain and Linux using Certs

  • Still Running Office 2019? Reduce the Risk with Group Policy

    Microsoft Office 2019 reached the end of extended support on 14 October 2025. The applications will continue to work, but Microsoft no longer provides security fixes for vulnerabilities subsequently discovered in Office 2019. For organisations that cannot immediately replace Office 2019, Group Policy can be used to reduce some of the risk. It cannot make an unsupported version of Office secure again, and it cannot fix an unpatched vulnerability in Word, Excel, Outlook or another Office executable. What it can do is remove or restrict many of the mechanisms commonly used to turn a malicious document into a successful compromise. These same Group Policy hardening principles can also be applied to Office 2021, Office LTSC 2021/2024 and Microsoft 365 Apps, although the available policy settings and defaults should be checked against the current Office ADMX templates before deployment. The objective is to put several controls between the document and the operating system. Internet / Email Document | v Mark of the Web | v Protected View | v Office File Validation | +----+----+ | | Macro Block ActiveX/OLE Block | v Office | v Defender ASR | +-- X PowerShell +-- X CMD +-- X WScript +-- X Executable creation +-- X Process injection No single setting in this article should be considered a complete defence. The benefit comes from applying the controls together. A warning before applying these policies Some of the policies below can prevent legitimate Office functionality. An organisation may have Excel workbooks using VBA, Word templates containing macros, applications that depend on ActiveX, Excel workbooks using external data connections, Office add-ins supplied by third-party products or internal systems that use DDE, OLE or Trusted Locations. Turning everything on across the estate without testing could therefore break business processes. I would strongly recommend deploying the policies to a representative pilot group first. Defender Attack Surface Reduction rules should initially be placed into Audit mode. Existing macros, add-ins, templates and data connections should be identified before the more restrictive settings are enforced. Where an exception is genuinely required, create a narrowly scoped exception GPO rather than weakening the main Office hardening policy for everyone. 1. Install the Office Administrative Templates Office 2019 uses the Office 16.0 policy model. This means that when the Office Administrative Templates are installed, Group Policy paths will normally appear as: Microsoft Office 2016 Microsoft Word 2016 Microsoft Excel 2016 Microsoft PowerPoint 2016 The latest Office Administrative Templates should be copied into the domain Central Store so that the settings can be managed consistently from Group Policy Management. A sensible GPO layout would be: SEC - Office 2019 - Hardening - Computer SEC - Office 2019 - Hardening - User The Computer GPO can contain Defender ASR and certificate settings. The User GPO can contain the Office application policies. 2. Block macros originating from the Internet Macros remain one of the more obvious routes from a malicious document into executable code. Microsoft recommends the Block macros from running in Office files from the Internet policy as part of its Office security guidance. For Word: User Configuration Policies Administrative Templates Microsoft Word 2016 Word Options Security Trust Center Configure: Block macros from running in Office files from the Internet Enabled The equivalent policy should be configured for the Office applications installed in the organisation, including: Microsoft Excel 2016 Microsoft PowerPoint 2016 Microsoft Access 2016 (Application Settings > Security) Microsoft Visio 2016 Microsoft Project 2016 (No Setting) Microsoft documents separate Internet macro policies for the individual Office applications. Compatibility warning This can prevent macro-enabled documents downloaded through browsers, received by email or otherwise carrying Mark of the Web from running their macros. Do not solve this by creating a broad Trusted Location or automatically removing Mark of the Web from downloaded files. That would remove much of the protection the policy provides. 3. Require signed VBA macros If macros are not required at all, the strongest position is: VBA Macro Notification Settings Disable all macros without notification That is unlikely to be practical everywhere. Where VBA is required, I would use: VBA Macro Notification Settings Disable all except digitally signed macros and, where available: Require macros to be signed by a trusted publisher Enabled Apply the equivalent setting to Word, Excel, PowerPoint and other applications that support VBA. Trusted publisher certificates should be deployed centrally rather than allowing users to establish their own arbitrary trust relationships. For example: Computer Configuration Policies Windows Settings Security Settings Public Key Policies Trusted Publishers Only approved code-signing certificates should be placed here. Compatibility warning This is likely to expose old internal spreadsheets and templates containing unsigned VBA. Before enforcement, identify which macros are still required and sign the ones that have a legitimate business purpose. Do not simply allow unsigned macros because several old spreadsheets fail. 4. Disable ActiveX ActiveX can provide legitimate functionality, but it also substantially increases the amount of executable behaviour available inside an Office document. ACSC recommends disabling ActiveX when hardening Office. Configure: User Configuration Policies Administrative Templates Microsoft Office 2016 Security Settings Set: Disable All ActiveX Enabled The corresponding policy registry location is: HKCU\Software\Policies\Microsoft\Office\Common\Security with: DisableAllActiveX = 1 Compatibility warning Older Excel workbooks, Access applications and internally developed Office solutions may depend on ActiveX controls. This is one of the settings I would specifically test against Finance, engineering and legacy line-of-business applications before general enforcement. 5. Enforce Protected View Protected View provides another barrier between an untrusted document and the local system. For Word: User Configuration Policies Administrative Templates Microsoft Word 2016 Word Options Security Trust Center Protected View Configure: Do not open files from the Internet zone in Protected View Disabled Do not open files in unsafe locations in Protected View Disabled Turn off Protected View for attachments opened from Outlook Disabled The wording is slightly counter-intuitive. The policies say Do not open, so setting them to Disabled ensures that Protected View remains active. Also configure: Set document behaviour if file validation fails Enabled Block files Apply the equivalent settings to Excel and PowerPoint. For Excel, also consider: Always open untrusted database files in Protected View Enabled 6. Enforce Office File Validation Office File Validation checks older binary Office formats before allowing Office to process them normally. For Word: Microsoft Word 2016 Word Options Security Configure: Turn off file validation Disabled For Excel: Microsoft Excel 2016 Excel Options Security Configure: Turn off file validation Disabled For PowerPoint: Microsoft PowerPoint 2016 PowerPoint Options Security Configure: Turn off file validation Disabled The intention is to ensure validation cannot simply be disabled. 7. Preserve Mark of the Web Mark of the Web, or MOTW, is particularly important because Office uses it to determine that a document originated from an untrusted Internet location. Microsoft explains that files downloaded from Internet or Restricted zones can carry this information and that Office uses it when deciding whether macros should run. Configure: User Configuration Policies Administrative Templates Windows Components Attachment Manager Set: Do not preserve zone information in file attachments Disabled Because the policy is negatively worded, Disabled means Windows continues to preserve zone information. I would also configure: Hide mechanisms to remove zone information Enabled This removes the normal Explorer mechanism that allows a user to unblock a downloaded file. It does not make MOTW impossible to remove by an administrator or other tooling, but it stops the normal user workflow from casually bypassing the protection. 8. Disable Trusted Documents When a user chooses to trust a document, Office can remember that decision. For an unsupported Office installation, I would avoid allowing that previous user decision to become a persistent security bypass. For Word: Microsoft Word 2016 Word Options Security Trust Center Configure: Turn off trusted documents Enabled Turn off Trusted Documents on the network Enabled Repeat for Excel and PowerPoint. Where installed, review the equivalent settings for Visio and the other Office applications. 9. Restrict Trusted Locations Trusted Locations deserve particular attention. Microsoft explains that files in a Trusted Location can bypass some Office security checks, including the handling normally applied to files carrying Mark of the Web. Microsoft recommends using Trusted Locations sparingly and does not recommend network Trusted Locations. For Word, Excel, PowerPoint and the other relevant applications, locate: Trust Center Trusted Locations Configure: Allow Trusted Locations on the network Disabled Where practical: Disable all trusted locations Enabled This is the preferred security position. If a Trusted Location is genuinely required, define the exact location through a dedicated exception policy. Avoid creating Trusted Locations such as: C:\Users C:\Users\Public C:\Temp %APPDATA% %LOCALAPPDATA% \\FileServer\Shared \\Domain\DFSRoot A Trusted Location should contain controlled application content and normal users should ideally not have permission to place arbitrary files into it. Compatibility warning Trusted Locations are frequently used to make old Office applications work without constant security prompts. Disabling them may therefore reveal dependencies that have existed unnoticed for years. Identify and correct those dependencies rather than automatically turning the Trusted Location back on for the whole organisation. 10. Disable Excel DDE Dynamic Data Exchange is old technology and may still exist in some business processes. It also provides functionality that can be abused. For Excel: User Configuration Policies Administrative Templates Microsoft Excel 2016 Excel Options Security Trust Center External Content Configure: Don't allow Dynamic Data Exchange (DDE) server launch in Excel Enabled Don't allow Dynamic Data Exchange (DDE) server lookup in Excel Enabled Also configure: Always prevent untrusted Microsoft Query files from opening Enabled ACSC includes DDE and external-content restrictions in its Office hardening recommendations. Compatibility warning There are still applications that use DDE to pass information into Excel. This setting therefore needs testing against applications that generate spreadsheets or interact directly with a running Excel instance. 11. Prevent Word automatically updating external links For Word: User Configuration Policies Administrative Templates Microsoft Word 2016 Word Options Advanced Configure: Update automatic links at Open Disabled This reduces automatic retrieval or updating of linked external content when a document is opened. 12. Harden Excel external content Where the Administrative Templates do not provide the required control directly, Group Policy Preferences can be used. Create: User Configuration Preferences Windows Settings Registry Under: HKCU\Software\Microsoft\Office\16.0\Excel\Security create: DataConnectionWarnings REG_DWORD 2 RichDataConnectionWarnings REG_DWORD 2 WorkbookLinkWarnings REG_DWORD 2 For Word: HKCU\Software\Microsoft\Office\16.0\Word\Security create: AllowDDE REG_DWORD 0 Compatibility warning Excel is often used as a front end for databases, SQL Server, web services, Power Query and other external sources. Do not assume that every external connection is malicious. This area should be tested against users who depend heavily on Excel for reporting. 13. Disable OLE package activation Object Linking and Embedding provides another way of placing active content inside Office documents. The following registry settings can be deployed through Group Policy Preferences. For Word: HKCU\Software\Microsoft\Office\16.0\Word\Security PackagerPrompt REG_DWORD 2 For Excel: HKCU\Software\Microsoft\Office\16.0\Excel\Security PackagerPrompt REG_DWORD 2 For PowerPoint: HKCU\Software\Microsoft\Office\16.0\PowerPoint\Security PackagerPrompt REG_DWORD 2 Compatibility warning Documents containing legitimate embedded packages may no longer behave as users expect. Again, test rather than assuming the feature is unused. 14. Control Office add-ins Add-ins are another source of executable code inside an Office process. Where add-ins are required, configure the relevant Office applications to require signed add-ins. For example: Require that application add-ins are signed by Trusted Publishers Enabled Disable Trust Bar Notification for unsigned application add-ins and block them Enabled Where an Office application does not require add-ins at all: Disable all application add-ins Enabled Repeat this for the installed Office applications where the corresponding policy is available. Compatibility warning This is another policy likely to affect third-party software. PDF products, document management systems, finance applications, CRM systems and other products may install Office add-ins. Inventory them before blocking unsigned add-ins. 15. Prevent PowerPoint launching programs PowerPoint presentations can contain actions designed to execute external programs. Configure: User Configuration Policies Administrative Templates Microsoft PowerPoint 2016 PowerPoint Options Security Set the program execution policy so PowerPoint cannot run external programs. Where presented as: Run Programs configure: Disable - don't run any programs 16. Force Excel file extensions to match the file type A file presented as one format should not silently contain a different format internally. For Excel: User Configuration Policies Administrative Templates Microsoft Excel 2016 Excel Options Security Configure: Force file extension to match file type Enabled Select: Always match file type 17. Review legacy Office file formats Old Office formats increase the amount of legacy parsing code that Office must expose. Review: Word 2016 Word Options Security Trust Center File Block Settings And the equivalent locations for Excel and PowerPoint. Candidates for blocking include obsolete formats such as: Excel 2.x Excel 3.x legacy macro sheets obsolete Word converters old PowerPoint formats DIF and SYLK where not required I would not automatically block: .doc .xls .ppt Without first determining whether the organisation still has legitimate business documents in those formats. A surprising amount of historical corporate information can still exist as Office 97-2003 files. 18. Add Defender Attack Surface Reduction rules The Office policies above try to prevent malicious content from running. Attack Surface Reduction provides another control if something gets further than expected. Microsoft's current ASR rule set includes several rules specifically targeting Office behaviour. The complete list of ASR rules is located at the end of this blog. Configure: Computer Configuration Policies Administrative Templates Windows Components Microsoft Defender Antivirus Microsoft Defender Exploit Guard Attack Surface Reduction Enable: Configure Attack Surface Reduction rules I would consider the following Office-related rules. Block all Office applications from creating child processes D4F940AB-401B-4EFC-AADC-AD5F3C50688A This is one of the most useful rules in the baseline. It can prevent behaviour such as: WINWORD.EXE | +-- powershell.exe or: EXCEL.EXE | +-- cmd.exe or: WINWORD.EXE | +-- wscript.exe Block Office applications from creating executable content 3B576869-A4EC-4529-8536-B80A7769E899 This makes it harder for Office processes to drop executable payloads. Block Office applications from injecting code into other processes 75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84 Block Win32 API calls from Office macros 92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B Block executable content from email client and webmail BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550 Block Office communication applications from creating child processes 26190899-1602-49E8-8B27-EB1D0A1CE869 Microsoft lists these rules and GUIDs in the current ASR documentation. 19. Start ASR in Audit mode Do not immediately place these rules into Block across the organisation. ASR uses: 1 = Block 2 = Audit 6 = Warn Microsoft documents both the rule modes and Group Policy deployment. Start with: 2 for the Office-related rules. This allows legitimate behaviour to be identified without immediately breaking it. Once the environment has been reviewed, change clean rules to: 1 for Block. Compatibility warning The child-process rule can block legitimate Office automation. For example, an internal Excel macro may deliberately launch: powershell.exe cmd.exe cscript.exe wscript.exe That does not mean the ASR rule should be abandoned. It means the dependency needs to be identified and assessed. Avoid broad ASR exclusions such as: C:\Users\* C:\ProgramData\* C:\Windows\Temp\* An exclusion should be as narrow as possible. 20. Consider restricting Office network access This is not something I would automatically deploy everywhere, but it can be useful on particularly restricted systems. If Word or PowerPoint has no legitimate reason to communicate directly with the Internet, outbound firewall rules could be considered for: WINWORD.EXE POWERPNT.EXE MSPUB.EXE VISIO.EXE Potentially also: EXCEL.EXE Excel may legitimately access: SQL Server Power Query sources internal web services SharePoint linked workbooks REST APIs external data feeds Network restrictions should therefore be treated as an additional hardening layer rather than part of the initial deployment. 21. Create separate exception GPOs Avoid changing the baseline because one application stops working. For example: SEC - Office 2019 - Exception - Finance Signed Macro SEC - Office 2019 - Exception - Approved Trusted Location SEC - Office 2019 - Exception - Legacy Add-in Scope them using dedicated security groups such as: GG-Office2019-Exception-FinanceMacro An exception should record: Application Business owner Reason Affected users Policy being relaxed Compensating controls Review date An exception should be exactly that: an exception. It should not gradually become the configuration used by most of the organisation. 22. Review ASR events ASR events are recorded in: Applications and Services Logs Microsoft Windows Windows Defender Operational Useful events include: 1121 ASR rule blocked activity 1122 ASR rule audit activity Microsoft documents Audit and Block behaviour and provides troubleshooting guidance for ASR deployments. These events can also be collected centrally using Windows Event Forwarding. That makes it possible to see which Office applications are attempting behaviour that would be blocked before moving the rule into enforcement. 23. Verify the deployed GPO Generate a Group Policy report: gpresult /h C:\Temp\Office2019-GPO.html RSoP can also be used: rsop.msc What the hardened Office path looks like Once the policies are applied, an untrusted Office document has considerably more work to do. Untrusted Office document | v Mark of the Web | v Protected View | v Office File Validation | +----> Internet macro? -------- BLOCK | +----> Unsigned VBA? ---------- BLOCK | +----> ActiveX? --------------- BLOCK | +----> OLE package? ----------- BLOCK | +----> DDE? ------------------- BLOCK | v Office | +----> PowerShell? ------------ ASR BLOCK | +----> CMD? ------------------- ASR BLOCK | +----> WScript? --------------- ASR BLOCK | +----> Create executable? ----- ASR BLOCK | +----> Process injection? ----- ASR BLOCK That is a very different proposition from leaving an unsupported Office installation with its default configuration. Final thoughts Office 2019 being out of support does not mean every installation will immediately be compromised. It does mean that the security position has changed. A newly discovered Office 2019 vulnerability may no longer receive a security update from Microsoft. If Office 2019 has to remain installed for a period of time, it makes sense to reduce the amount of functionality available to an attacker. Block Internet macros. Require signatures for the macros that genuinely need to remain. Disable ActiveX where possible. Keep documents in Protected View. Preserve Mark of the Web. Restrict Trusted Locations. Disable unnecessary DDE and OLE functionality. Control add-ins and put Defender ASR around the Office processes. Just as importantly, test the configuration before enforcing it. A hardened Office deployment that breaks a critical finance workbook is ikely to survive longer than your job. Audit first, understand what the organisation actually uses, enforce the controls that work and create tightly scoped exceptions for the things that genuinely need them. Office 2019 should be replaced with a supported version, eg LibreOffice. Complete list of ASR Rules Rule name in Microsoft Intune Rule name in Microsoft Configuration Manager GUID Category Standard protection rules Block abuse of exploited vulnerable signed drivers (Device) n/a 56a863a9-875e-4185-98a7-b882c64b5ce5 Misc Block credential stealing from the Windows local security authority subsystem same 9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2 Lateral movement & credential theft Block persistence through WMI event subscription n/a e6db77e5-3df2-4cf1-b95a-636979351e5b Lateral movement & credential theft Block Adobe Reader from creating child processes n/a 7674ba52-37eb-4a4f-a9a1-f0f9a1619a2c Productivity apps Block all Office applications from creating child processes Block Office application from creating child processes d4f940ab-401b-4efc-aadc-ad5f3c50688a Productivity apps Block executable content from email client and webmail same be9ba2d9-53ea-4cdc-84e5-9b1eeee46550 Email Block executable files from running unless they meet a prevalence, age, or trusted list criterion Block executable files from running unless they meet a prevalence, age, or trusted list criteria 01443614-cd74-433a-b99e-2ecdc07bfc25 Polymorphic threats Block execution of potentially obfuscated scripts same 5beb7efe-fd9a-4556-801d-275e5ffc04cc Script Block JavaScript or VBScript from launching downloaded executable content same d3e037e1-3eb8-44c8-a917-57927947596d Script Block Office applications from creating executable content same 3b576869-a4ec-4529-8536-b80a7769e899 Productivity apps Block Office applications from injecting code into other processes same 75668c1f-73b5-4cf0-bb93-3ecf5cb7cc84 Productivity apps Block Office communication application from creating child processes n/a 26190899-1602-49e8-8b27-eb1d0a1ce869 Email, Productivity apps Block process creations originating from PSExec and WMI commands n/a d1e49aac-8f56-4280-b9ba-993a6d77406c Lateral movement & credential theft Block rebooting machine in Safe Mode n/a 33ddedf1-c6e0-47cb-833e-de6133960387 Misc Block untrusted and unsigned processes that run from USB same b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4 Polymorphic threats Block use of copied or impersonated system tools n/a c0033c00-d16d-4114-a5a0-dc9b3a7d2ceb Misc Block Webshell creation for Servers n/a a8f5898e-1dc8-49a9-9878-85004b8a61e6 Misc Block Win32 API calls from Office macros same 92e97fa1-2edf-4476-bdd6-9dd0b4dddc7b Productivity apps Use advanced protection against ransomware same c1db55ab-c21a-4637-bb3f-a12568109d35 Polymorphic threats

  • LOL Drivers, why kernel drivers are the new attack surface

    Why Old Signed and Legitimate are a Risk Old but legitimately signed drivers are dangerous because they provide a trusted execution path straight into the Windows kernel, where most modern security controls have no visibility. Once a vulnerable driver is loaded, an attacker can abuse known flaws to gain arbitrary kernel read and write access, disable security features, tamper with credential protections, and hide processes or files, all while appearing “trusted” because the driver is signed. This technique, commonly called BYOVD (Bring Your Own Vulnerable Driver), bypasses application control, kernel exploit mitigations, and many EDR hooks, allowing attackers to operate below the operating system’s security boundary. LOLDrivers.io to the Rescue LOLDrivers is a curated, continuously maintained catalogue of Windows drivers that have been abused, or are suitable for abuse, in real attacks. The list covers both malicious drivers and legitimate signed drivers with exploitable flaws. Visit LOLDrivers, its a great resource, its free, and the database of browserable drivers is awesome. The original goal was to embed an offline reference of the LOLDrivers dataset into the security tool I am building. Instead, I decided to release my own PowerShell implementation. This script creates a local, offline copy of the LOLDrivers database and provides clear, colour-coded output when a match is detected. What “Living Off the Land Drivers” actually means Living off the land usually refers to abusing built-in system tools. LOLDrivers applies the same concept to the kernel. Instead of dropping custom malware, attackers load a signed, trusted, but vulnerable driver and use it as a control interface into kernel memory. Once loaded, these drivers can be used to: Read and write arbitrary kernel memory Kill protected security processes Disable EDR hooks Bypass HVCI and protected process light (PPL) Load unsigned kernel code The risk categories in LOLDrivers LOLDrivers splits drivers into functional risk classes. This is important, because not all of them are malicious by design. Vulnerable but legitimate drivers These are signed drivers shipped by vendors that expose IOCTL handlers or memory primitives that can be abused. They are frequently used for: Arbitrary kernel read/write Token manipulation Security product termination Callback and hook removal These are the backbone of most BYOVD chains. Explicitly malicious drivers These drivers contain intentionally malicious functionality. They are often used as stealth rootkits or kernel loaders. Typical capabilities include: Process hiding File hiding Credential interception Persistence enforcement These drivers usually exist only to support a wider malware framework. Dual-use operational drivers “Dual-use” drivers are legitimate software for admins, OEMs, and hardware vendors, but dangerous in the wrong hands. These drivers are not exploits, but they expose kernel-level control surfaces that attackers can directly abuse. Typical capabilities include: Physical memory access MSR and PCI configuration Debug and hardware inspection features When abused, they provide the same primitives as a kernel exploit, without triggering exploit detection. Why Microsoft’s blocklist is not enough Microsoft maintains a kernel driver blocklist, but: It is reactive It is incomplete It does not cover every vulnerable version It is often bypassed by version pinning or re-signing What Needs to Be Done At a minimum, organisations must start treating driver loading as a high-risk security boundary, not a background system event. If you are not monitoring driver activity, you are blind to one of the most reliable attacker techniques in use today. The baseline controls should include: Integrate LOLDrivers intelligence into Sysmon, using the curated driver blocklist and metadata maintained by Magicsword.io, so that known vulnerable and malicious drivers can be detected at load time. Log every driver load event, not just failures. Silent, successful driver loads are how attackers bypass EDR and kernel protections. Continuously compare loaded drivers against the LOLDrivers dataset, both in real time and retrospectively, so newly classified drivers can be flagged even after they have already been seen in the environment. Alert based on abuse category, not just a hash match. A driver used for credential theft, EDR bypass, or kernel memory access represents a fundamentally different risk than a generic vulnerable driver, and should be triaged accordingly. Finally, credit where it's due Credit goes to the LOLDrivers project, without their work, this attack surface would remain largely undocumented, leaving defenders blind to a class of kernel-level abuse that is actively exploited. Show your support and visit their site.

  • Windows Network Auditing: Finding the Process, Service, Port and IP Behind the Firewall Rule

    Windows firewall troubleshooting is rarely as simple as allowing one executable and one port. An application may appear to use TCP 443, but the actual connection can be created by a Windows service, a child process, System, or one of the services running inside svchost.exe. The Network Process tools help expose that relationship by capturing Windows network endpoints and correlating them with processes, executable paths, command lines, services, ports and IP addresses. There are 2 versions - https://github.com/Tenaka/Windows-Network-Analysis-Tool/tree/main Network Process – Lite v2 Network Process – InDepth v2 Both produce the same core CSV reports, making it easy to start with Lite and move to InDepth when more evidence is required. What the tools capture The scripts repeatedly query the Windows TCP and UDP endpoint tables during a configurable capture period. They record: TCP connections and listeners UDP endpoints Local and remote IP addresses Local and remote ports TCP connection states Process IDs and process names Executable paths and command lines Parent processes Windows services hosted by each process First and last observation times The number of times each endpoint was seen They also inventory running processes, Windows services and configured network interface addresses. This provides a useful link between the network connection and the Windows component responsible for creating it. Lite or InDepth? The Lite version is designed for quick audits and routine fault finding. By default, it runs for 30 seconds and samples network endpoints every 500 milliseconds. It collects the core connection, process, service, IP address and port data without performing signature checks, DNS lookups or raw event logging. Lite is suitable when the problem is easy to reproduce and the objective is simply to identify the applications, services, ports and destinations involved. The InDepth version runs for 60 seconds by default and samples every 250 milliseconds. It also enables: Reverse DNS lookups Process owner collection Executable file metadata Authenticode signature checks Raw endpoint samples Connection event tracking The faster sampling gives InDepth a better chance of detecting short-lived connections during authentication, certificate validation, service discovery or application startup. SHA-256 file hashing is available but disabled by default because it increases disk access and processing overhead. Running the tools Run the scripts from an elevated Windows PowerShell session. & ".\network process - lite v2.ps1" For a longer capture: & ".\network process - lite v2.ps1" ` -DurationSeconds 120 ` -OutputFolder "C:\Logs\NetworkAudit" For a more detailed investigation: & ".\network process - indepth v2.ps1" ` -DurationSeconds 300 ` -OutputFolder "C:\Logs\NetworkAudit" Start the capture immediately before reproducing the fault. Launch the application, perform the login or connection attempt and continue until the failure occurs. Starting the script after the problem has happened may miss the connections that caused it. Understanding the reports The main report is Connections.csv. It shows the network endpoint together with the process, executable, service, local address, local port, remote address and remote port. Ports.csv presents the same evidence from a port-focused view, while IPAddresses.csv lists interface addresses and all IP addresses observed during the capture. Processes.csv shows the processes present during the audit and summarises their network activity. Services.csv links Windows services to the process IDs, ports and addresses they used. The InDepth version also produces Raw.csv and Events.csv. These show individual samples and connection changes such as when an endpoint first appeared, changed state or disappeared. Firewall troubleshooting The main purpose of the tools is to show what Windows is actually using rather than relying on the visible application name. For example, a VPN client may display its own executable, but parts of the authentication process may be performed by: svchost.exe System a background service a web authentication component a child process Allowing only the visible VPN executable through the firewall may therefore allow the connection to start but fail when the application reaches MFA, certificate validation or another Windows-hosted dependency. The reports can help answer: Which executable opened the connection? Which service was running inside svchost.exe? Which remote address and port were used? Did the connection appear only during login? Was the destination public, private, loopback or IPv6? Was the executable digitally signed? This evidence can be used to create a more targeted firewall rule instead of broadly allowing all traffic from svchost.exe. Interpreting ports correctly For a normal outbound HTTPS connection, the local port will usually be a temporary high-numbered port and the remote port will be TCP 443. The temporary local port should not normally be added to the firewall rule. It is automatically selected by Windows and changes between connections. A TCP listener is different. The local port is the port on which the computer is waiting for inbound connections. The reports label TCP entries as Connected or Listener, but they do not claim that every connected session is specifically inbound or outbound. Direction must be inferred from the local and remote ports, the application role and the firewall context. Working with svchost.exe A single svchost.exe process can host one Windows service or several services. The tools list all services associated with the process ID. When the svchost.exe command line identifies a specific service, the script can attribute the traffic to it. When several services share the same process and there is no clear service identifier, the report records the process as shared rather than guessing. This is intentional. A shared service process narrows the investigation, but it does not always prove which individual service created the connection. What the tools cannot prove These scripts are endpoint auditing tools. They are not packet analysers and they do not read firewall decisions. They cannot prove that: A firewall allowed or blocked a packet A remote server received the connection A TLS handshake completed Authentication succeeded A certificate was accepted Data was returned by the remote service Packet loss or routing failure occurred A connection stuck in SYN-SENT may indicate that Windows attempted to connect but received no reply. The cause could be a firewall, routing issue, unavailable server or incorrect destination. The results should therefore be compared with firewall logs, application logs, VPN gateway logs or packet capture when deeper evidence is required. Known limitations Both scripts use polling. A connection that opens and closes entirely between two samples may be missed. The InDepth version reduces this risk by sampling more frequently, but it cannot guarantee capture of every connection. UDP reporting is also limited. Windows exposes the local UDP endpoint, but the standard endpoint table does not provide the remote UDP peer. The scripts can show which process owns the local UDP port, but not where the UDP traffic was sent. Reverse DNS results should also be treated carefully. A returned name may belong to a CDN, proxy, cloud provider or load balancer and may not be the hostname originally requested by the application. Applications using proxies, secure web gateways or VPN tunnels may show only the gateway or proxy address rather than the final destination. Choosing the right tool Use Lite for quick checks, repeatable faults and initial firewall baselines. Use InDepth when: The fault is intermittent Authentication fails partway through svchost.exe is involved Connections are very short-lived Process ownership or signature information is required A detailed event timeline is needed These tools do not replace Wireshark or firewall logging. They provide the Windows process and service context that those tools often lack. That context is frequently the missing piece when an application has already been allowed through the firewall but still fails to work. Instead of asking only: Which port does this application need? the better questions become: Which process opened the connection? Was it the application, a child process, a service or svchost.exe? Which local and remote addresses were used? Was the port a listener, a destination port or an ephemeral source port? Did the dependency exist for the whole session or only during authentication? Answering those questions makes it possible to create firewall rules that are narrow enough to remain secure and complete enough to let the application work.

  • Creating and Enforcing a Signed WDAC Policy with PowerShell

    Windows Defender Application Control (WDAC) was previously known as DeviceGuard, now it's named App Control for Business. It is one of the strongest application-control technologies available in Windows. From this point forward, it will be referred to as WDAC. Creating a basic WDAC policy is relatively straightforward. Creating a signed WDAC policy that boots correctly, survives administrative tampering and can still be safely updated is considerably more challenging. I've lost count of the Windows systems that failed to survive signing and ended with a BSoD. The problem with devising a signed policy is that the information is spread across separate pages covering policy creation, rule options, certificate signing, deployment, Secure Boot and policy removal. Turning those individual components into a reliable end-to-end process required a fair amount of effort and trial and error, heavy on the error. This article describes the lab process used to: Scan a Windows 11 reference system. Create and test an audit policy. Convert it to unsigned enforcement. Add an authorised policy update signer. Sign the policy using SignTool. Deploy it to Windows and the EFI system partition. Confirm that removing the Windows policy file does not simply disable enforcement. Important: This is a lab proof of concept. The scripts and procedures described here are not currently suitable for an enterprise production deployment. Download and prepare the lab files Download the WDAC signing lab from: https://github.com/Tenaka/WDAC-Signing Extract the archive and copy the included subdirectories into: C:\WDAC The completed folder structure should contain the numbered scripts and the included Windows SDK signing files. Open Windows PowerShell or PowerShell ISE as an administrator, then run the scripts in numerical order, with reboots in between each script. When using the standard PowerShell, set the execution policy for the current lab session: Set-ExecutionPolicy -ExecutionPolicy Bypass -Force The repository includes the required SignTool.exe files. During the setup stage, these files are copied into the path expected by the signing scripts. Create the destination directory: New-Item ` -Path 'C:\Program Files (x86)\Windows Kits\10\bin\64' ` -ItemType Directory ` -Force Copy the included signing tools: Copy-Item ` -Path 'C:\WDAC\10.0.22621.0\x64\*' ` -Destination 'C:\Program Files (x86)\Windows Kits\10\bin\64' ` -Recurse ` -Force Once the files are in place, the lab scripts can locate and use SignTool.exe without requiring the full Windows SDK to be installed. What an unsigned WDAC policy does A WDAC policy enforces application-control and code-integrity rules that determine which kernel-mode drivers and user-mode code, including executables, DLLs, supported scripts and Windows Installer files, are permitted to run. These rules are deployed as compiled binary policy files. For this article, we will use the modern multiple-policy format, saved as {PolicyGUID}.cip. This format is used by current Windows 11 deployments and supports multiple base and supplemental policies, clearer policy identification and modern management through tools such as CiTool.exe. The older SiPolicy.p7b format is primarily associated with legacy single-policy deployments, older Windows versions and Group Policy-based management. The .cip format is not inherently more secure; it is used here because it provides the more flexible and current WDAC policy-management model. In the lab, the initial policy is generated by scanning the complete Windows system drive: New-CIPolicy ` -ScanPath 'C:\' ` -UserPEs ` -MultiplePolicyFormat ` -FilePath $AuditXml ` -Level FilePublisher ` -Fallback SignedVersion,Publisher,Hash The main rule level is FilePublisher, with fallbacks to: SignedVersion Publisher Hash This provides a useful balance for a lab system. Publisher-based rules are preferred where possible, while hashes provide a final fallback for unsigned or unusual files. The -UserPEs option includes user-mode executable files and enables user-mode code integrity, or UMCI. The XML policy is then converted into a deployable .cip file: ConvertFrom-CIPolicy ` -XmlFilePath $AuditXml ` -BinaryFilePath $PolicyCip The policy is deployed using CiTool.exe: CiTool.exe --update-policy $PolicyCip -json Microsoft documents CiTool.exe as the command-line utility for listing, updating and removing multiple-policy-format App Control policies. Audit mode comes first The first version of the lab policy is created in audit mode. Rule option 3 enables audit behaviour: Set-RuleOption -FilePath $AuditXml -Option 3 In audit mode, Windows records applications that would have been blocked, but it does not prevent them from running. This stage is critical. A filesystem scan only finds files that exist when the scan takes place. It does not automatically account for every file that might later be: Downloaded by an application. Extracted from an installer Created during an update. Loaded from a temporary directory. Unpacked from a driver package (HP Universal Drivers on first use). Before moving to enforcement, every required application, service, script and administrative tool should be launched, including HP printers with their first-use universal printer cab drivers. The lab review script collects relevant events from: Microsoft-Windows-CodeIntegrity/Operational The audit review includes event IDs: 3076 3089 3099 For example: Get-WinEvent -FilterHashtable @{ LogName = 'Microsoft-Windows-CodeIntegrity/Operational' Id = 3076,3089,3099 StartTime = (Get-Date).AddDays(-1) } Any required application appearing in the audit events must be resolved before enforcement is enabled. Moving to unsigned enforcement Once the audit events have been reviewed, the policy is copied and its version is increased: Copy-Item $AuditXml $EnforcedXml -Force Set-CIPolicyVersion ` -FilePath $EnforcedXml ` -Version '1.0.1.0' Audit mode is then removed: Set-RuleOption ` -FilePath $EnforcedXml ` -Option 3 ` -Delete The policy is converted again and redeployed with CiTool.exe. After restarting, applications that are not authorised by the policy are blocked. At this point, WDAC is enforcing application control, but the policy is still unsigned. Also at this point PowerShell will be in 'Constrained Language Mode' with unsigned scripts failing to load. The weakness of an unsigned WDAC policy An unsigned WDAC policy can provide effective application control, but it does not protect the policy itself. Rule option 6 is present by default: Enabled:Unsigned System Integrity Policy This option allows Windows to load the policy without a digital policy signature. Microsoft states that when option 6 is removed, the policy must be signed and its trusted update certificates must be defined in the UpdatePolicySigners section. The weakness is that a process running with sufficient administrative privileges can replace or remove any unsigned policy. The policy might successfully block users from running unauthorised software, but an administrator is able to remove the policy and eliminate its enforcement. Microsoft claims that unsigned policies allow malware to modify or remove WDAC, but that oversimplifies reality: WDAC is designed to stop untrusted code before it runs. In most cases, malware cannot simply launch a payload and delete the policy because the malware itself is blocked by the policy. The greater risk is administrative abuse. If an attacker gains local administrator or SYSTEM-level access, they may not need to run an obviously malicious executable. Instead, they can abuse trusted, Microsoft-signed tools and administrative interfaces already allowed by the system. This is commonly known as a Living off the Land technique. Tools such as CiTool.exe, PowerShell or other trusted management components may be used to modify or remove an unsigned WDAC policy through legitimate administrative mechanisms. An unsigned WDAC policy is therefore highly effective at stopping unauthorised applications and commodity malware. What it does not fully protect against is a trusted administrator—or an attacker operating with equivalent privileges—deliberately disabling the policy. In simple terms: An unsigned WDAC policy controls applications, but it does not securely control the administrator who owns the machine. For lightly managed systems this may be acceptable. For a locked-down system where the application-control policy must resist local administrative tampering, the policy needs to be signed. What changes when the WDAC policy is signed Signing the policy is not the same as signing an executable file: A signed WDAC policy introduces an authorised policy-update chain. The installed policy identifies one or more certificates that are allowed to sign future updates. Windows can then reject policy replacements that have not been signed by an authorised certificate. Microsoft describes signed App Control policies as providing its highest level of policy protection and helping prevent policy tampering or removal, including by an administrator. This changes the security model: Unsigned policy Windows loads the policy without a policy signature. The policy can enforce executable, script and driver rules. An administrator can remove or replace the policy. Removing the active policy removes its enforcement. Signed policy Windows validates the policy’s PKCS#7 signature. Future policy updates must be signed by an authorised update signer. An arbitrary unsigned replacement policy is rejected. The policy can be protected through the Secure Boot and EFI boot process. Improper removal can cause a boot failure rather than cleanly disabling enforcement. Lab prerequisites The working lab uses: Windows 11. UEFI firmware. Secure Boot enabled. Windows PowerShell 5.1. The built-in ConfigCI PowerShell module. CiTool.exe. A code-signing certificate. Microsoft SignTool, seperate download. A disposable virtual machine or test system. At least one checkpoint taken before signed enforcement. The script stops immediately if Secure Boot is not enabled: if (-not (Confirm-SecureBootUEFI)) { throw 'Secure Boot is not enabled.' } It also verifies that it is running in Windows PowerShell rather than PowerShell 7: if ($PSVersionTable.PSEdition -ne 'Desktop') { throw 'Run this procedure from Windows PowerShell 5.1.' } SignTool is required Microsoft SignTool is required to produce the signed WDAC policy. SignTool is included with the Windows SDK and is installed under the SDK Bin directory. The exact path varies depending on the SDK version and installed components. The lab uses: C:\Program Files (x86)\Windows Kits\10\bin\64\signtool.exe The initial scan script checks for SignTool before beginning the full C:\ scan: if (-not $SignTool -or -not (Test-Path -LiteralPath $SignTool -PathType Leaf)) { throw 'SignTool.exe was not found. Install the Windows SDK Signing Tools before scanning C:\.' } This prevents the system from completing the long scan and audit process only to discover later that the required signing tool is unavailable. Creating the lab signing certificate The lab creates a self-signed code-signing certificate in the Local Machine certificate store: $Certificate = New-SelfSignedCertificate ` -Type CodeSigningCert ` -Subject 'CN=Tenaka WDAC Lab Policy Signer' ` -FriendlyName 'Tenaka WDAC Lab Policy Signer' ` -CertStoreLocation 'Cert:\LocalMachine\My' ` -KeyAlgorithm RSA ` -KeyLength 3072 ` -HashAlgorithm SHA256 ` -KeyExportPolicy Exportable ` -Provider 'Microsoft Software Key Storage Provider' ` -NotAfter (Get-Date).AddYears(5) The public certificate is exported as a .cer file: Export-Certificate ` -Cert $Certificate ` -FilePath $CerPath ` -Force The certificate and private key are also backed up as a password-protected .pfx file: Export-PfxCertificate ` -Cert $Certificate ` -FilePath $PfxPath ` -Password $PfxPassword ` -ChainOption EndEntityCertOnly ` -CryptoAlgorithmOption AES256_SHA256 ` -Force The script validates: The private key exists. The key uses RSA. The RSA key size is supported. The certificate contains the Code Signing EKU. The exported public certificate matches the certificate containing the private key. The Code Signing EKU is: 1.3.6.1.5.5.7.3.3 This is acceptable for a controlled lab. It is not how an enterprise signing key should normally be managed. Adding the authorised update signer The unsigned enforced policy is copied to create the signed-policy XML: Copy-Item $EnforcedXml $SignedXml -Force The certificate is then added as an update signer: Add-SignerRule ` -FilePath $SignedXml ` -CertificatePath $CerPath ` -Update The -Update switch is important. It creates an entry in the policy’s UpdatePolicySigners section. This tells Windows which certificate is authorised to sign future policy versions. The script validates that at least one update signer exists: $UpdateSignerCount = @( $SignedPolicyDocument.SiPolicy.UpdatePolicySigners.UpdatePolicySigner ).Count if ($UpdateSignerCount -lt 1) { throw 'No UpdatePolicySigner was found.' } Signing a policy without correctly configuring its update signer can make future policy updates or removal extremely difficult. Removing unsigned-policy support The policy version is increased again: Set-CIPolicyVersion ` -FilePath $SignedXml ` -Version '1.0.2.0' Rule option 6 is then removed: Set-RuleOption ` -FilePath $SignedXml ` -Option 6 ` -Delete Removing option 6 changes the policy from a policy that may be unsigned into one that must be signed. Microsoft documents that removing option 6 requires the policy and any applicable supplemental policies to be signed. It also requires trusted future update certificates to be defined in the policy. The lab also confirms that supplemental policies are not enabled: Set-RuleOption ` -FilePath $SignedXml ` -Option 17 ` -Delete ` -ErrorAction SilentlyContinue This proof of concept uses a single base policy rather than a base-and-supplemental-policy design. Lab recovery options Two recovery-related policy options are retained: Set-RuleOption -FilePath $SignedXml -Option 9 Set-RuleOption -FilePath $SignedXml -Option 10 These represent: Enabled:Advanced Boot Options Menu Enabled:Boot Audit on Failure Option 9 allows the advanced boot menu to be made available to a physically present user. Option 10 allows Windows to switch the policy into audit mode when a boot-critical driver is blocked, helping the operating system start instead of immediately failing. Microsoft documents both behaviours in its policy rule-option reference. These options are useful during development and testing. Their use in a production security baseline should be deliberately reviewed. Converting and signing the policy The signed XML is first converted into a binary .cip file: ConvertFrom-CIPolicy ` -XmlFilePath $SignedXml ` -BinaryFilePath $PolicyCip SignTool then generates a detached PKCS#7 signature. The WDAC policy content OID is: 1.3.6.1.4.1.311.79.1 The working signing command is: & $SignTool sign ` /v ` /sm ` /s My ` /sha1 $CertificateThumbprint ` /fd SHA256 ` /p7 $SignedOutput ` /p7co 1.3.6.1.4.1.311.79.1 ` $PolicyCip The relevant switches are: /v enables verbose output. /sm selects the Local Machine certificate store. /s My selects the Personal certificate store. /sha1 selects the exact certificate by thumbprint. /fd SHA256 uses SHA-256 as the file digest algorithm. /p7 creates detached PKCS#7 output. /p7co specifies the WDAC policy content OID. Microsoft’s signed-policy procedure uses SignTool with /p7, the WDAC content OID and a supported digest algorithm. SignTool creates a file named using the original filename with .p7 appended: {PolicyID}.cip.p7 The script copies that signed output into the final policy directory and renames it to: {PolicyID}.cip The .cip extension does not mean the file is still the original unsigned binary. The final file contains the PKCS#7-signed policy content. Verifying the signed policy The lab doesn't assume that a successful SignTool exit code is sufficient. The public certificate is temporarily trusted on the lab system, and SignTool is used to verify the PKCS#7 signature: & $SignTool verify ` /p7 ` /v ` /debug ` $FinalSignedCip The policy is also parsed using: certutil.exe -asn $FinalSignedCip Finally, its SHA-256 hash is recorded: Get-FileHash ` $FinalSignedCip ` -Algorithm SHA256 This provides a known hash for the final signed policy before deployment. Deploying the signed policy The first signed policy is copied to the Windows Code Integrity policy directory: C:\Windows\System32\CodeIntegrity\CiPolicies\Active The script then mounts the EFI system partition and copies the same policy to: EFI\Microsoft\Boot\CiPolicies\Active The EFI partition is located using: $EfiPartition = ( Get-Partition | Where-Object IsSystem | Select-Object -First 1 ).AccessPaths[0] It is mounted with: mountvol.exe C:\EFIMount $EfiPartition The signed policy is then copied into the EFI policy directory. Microsoft identifies both the Windows Code Integrity directory and the EFI system partition as possible policy locations for multiple-policy-format App Control policies. The script calculates the hash of: The original signed policy. The Windows copy. The EFI copy. Deployment is stopped if the three hashes do not match. if (($SourceHash -ne $OsHash) -or ($SourceHash -ne $EfiHash)) { throw 'Source, OS and EFI hashes do not match.' } The EFI partition is unmounted and the computer is restarted. What happened when the Windows policy was deleted The most important lab result came after signed enforcement was confirmed. The signed policy file was deleted from: C:\Windows\System32\CodeIntegrity\CiPolicies\Active Applications that were not allowed by the policy continued to be blocked. Deleting the Windows copy did not disable enforcement because the signed policy had also been deployed into the EFI system partition. This demonstrates an important difference between removing a file and performing an authorised policy removal: Deleting the operating-system copy of a signed WDAC policy is not the same as removing the active policy. The policy remained available through: EFI\Microsoft\Boot\CiPolicies\Active and continued to participate in the Secure Boot-backed startup process. This should not be interpreted as meaning that every possible deletion of every signed-policy copy will always leave Windows running normally. The accurate conclusion is: Removing only the Windows copy may not disable the policy when an EFI copy remains. An unsigned replacement cannot simply overwrite the signed policy. Future updates must be signed by an authorised update signer. Improperly removing all copies of an active signed policy may result in a boot failure rather than a clean removal. Microsoft specifically warns that signed policies must be removed through the supported replacement process. How a signed policy is removed correctly A signed base policy should not simply be deleted. Microsoft’s documented removal process requires a signed replacement policy that uses the same policy identity and re-enables rule option 6. At a high level: Start with the current signed-policy XML. Retain the same PolicyID. Increase, or at least retain, the existing policy version. Add option 6 back to the policy. Retain the authorised update signer. Convert the replacement policy to .cip. Sign it using a certificate authorised by the existing policy. Deploy the signed replacement. Restart the computer. Remove the policy using CiTool.exe or the appropriate policy-removal process. The replacement is still signed, allowing the currently installed policy to authorise the update. However, the replacement re-enables unsigned-policy support. After the required restart, the Secure Boot protection is deactivated and the policy can be removed normally. Losing the signing private key could therefore create a serious recovery problem. The certificate, private key and recovery procedure must be protected before signed enforcement is deployed. Post-signing validation After restarting, the lab checks Secure Boot: Confirm-SecureBootUEFI It then records the active policies: CiTool.exe --list-policies -json The target policy should report values equivalent to: IsSignedPolicy : True IsEnforced : True IsAuthorized : True IsOnDisk : True The post-signing review also collects events: 3077 3089 3099 Event 3077 is particularly important because it records code that was blocked while the policy was in enforcement mode. The policy should then be tested across two complete shutdown and startup cycles. Required applications should continue to work, while deliberately unauthorised applications should remain blocked. Final thoughts An unsigned WDAC policy does provide effective application control. It can block unauthorised executables, scripts, DLLs and drivers, but it does not fully protect the policy itself. A local administrator, is able to remove the policy and eliminate its enforcement. Signing the WDAC policy changes that security model. The policy defines which certificate is authorised to approve future versions, and Windows validates the signed policy during startup. When the policy is also deployed to the EFI system partition, its enforcement becomes tied to the Secure Boot-backed startup process. This additional protection does, however, introduce risk and administrative overhead. The signing certificate and private key become critical security assets. They must be securely stored, backed up and available whenever the policy needs to be updated or removed. If the authorised signing key is lost, expired or unavailable, maintaining the policy can become extremely difficult. Every policy change must also follow a controlled lifecycle. The policy version must be managed correctly, the update signer must remain valid, the replacement policy must be signed, and the deployment and recovery process must be tested before the change reaches production systems. A mistake in an unsigned policy may block an application. A mistake in a signed policy can prevent the operating system from starting. Signed WDAC therefore provides a much stronger application-control boundary, particularly on systems where local administrators should not be able to bypass enforcement. That protection comes at the cost of additional certificate management, change control, testing, recovery planning and operational responsibility. For tightly controlled or high-security devices, that overhead may be justified. For general-purpose systems, an unsigned policy may provide a more practical balance between application control, supportability and recovery.

  • Understanding Windows File Altitude: A Deep Dive into File System Filter Drivers

    When delving into the intricate workings of Windows file system architecture, one of the more technical concepts that often emerges is file altitude. If you’ve ever explored file system filter drivers or engaged in low-level system development, understanding this concept is crucial. This blog aims to break down the complexities of Windows file altitude, the role it plays in the kernel, and how it affects file system operations. What is a Windows File System Filter Driver? Before diving into file altitude, it’s essential to understand the role of file system filter drivers. In Windows, a filter driver operates within the kernel mode and can monitor, modify, or extend the functionality of file system operations. These drivers can be inserted into the I/O request path, between the application and the underlying file system, to intercept and possibly modify file operations such as read, write, and delete requests. File system filter drivers are typically used for: Antivirus solutions: to monitor and block malicious activities. File encryption or compression: to apply encryption or compression on the fly. Backup solutions: to intercept and manage file access for consistent backups. File system auditing or monitoring: for logging file system activities or imposing policies. Introducing the Concept of File Altitude In a system where multiple filter drivers are installed, there needs to be a way to define their order of operation. This is where altitude comes into play. Simply put, file altitude is a numerical value that dictates the position of a filter driver within the file system stack. The higher the altitude, the closer a driver is to the application layer (and further from the actual file system). Windows ensures that these altitudes are registered and properly sequenced to avoid conflicts between drivers that might need to operate in a specific order. How Altitude Works Imagine a scenario where multiple drivers are installed for various purposes (e.g., an antivirus, a backup tool, and a logging tool). These drivers all want to interact with I/O requests. Without an ordering mechanism, there could be conflicts: An antivirus might want to inspect a file before any backup software reads it. The backup software might need to know the original state of a file before encryption is applied. Altitude values help resolve this by assigning each filter driver a priority based on its altitude. Windows ensures that the drivers with the highest altitudes receive I/O requests first, while those with lower altitudes are closer to the file system (and see the request last). Altitude Numbering System The altitude value is a floating-point number ranging from 0.000000 to 999999.999999. By convention, the lower the altitude number, the closer the driver is to the file system itself, and the higher the number, the closer it is to user mode operations. Upper-range altitudes (e.g., 380000-499999) are typically reserved for drivers like encryption and compression tools that need to operate closer to user-mode applications. Middle-range altitudes (e.g., 200000-379999) are often used by antivirus software, which needs to filter I/O requests before they reach the disk. Lower-range altitudes (e.g., 0-199999) are usually occupied by drivers that need to interact closely with the file system itself, such as volume managers and file system encryption. Each filter driver registered with the system must provide a unique altitude to prevent collisions or ordering issues. Managing Altitude in Windows The Windows OS provides a centralized mechanism for managing filter driver altitudes. Filter Manager, a built-in component of Windows starting from Windows Server 2003, facilitates the registration and sequencing of these filter drivers. It ensures that drivers operate in the correct order based on their altitude, preventing lower-altitude drivers from inadvertently disrupting higher-altitude ones. Querying Altitude You can query a system's file system filter driver altitudes using the `fltmc` utility in the command prompt. This utility displays loaded filter drivers, their altitudes, and their current operational state. fltmc filters fltmc instances The output of this command might look like: Registering a Driver with an Altitude When developing or installing a new file system filter driver, you need to register the driver with an appropriate altitude to ensure that it functions correctly within the filter stack. The driver installation process typically handles this via INF files or registry entries. Altitudes are not chosen arbitrarily; they are managed and assigned by Microsoft. Developers must register for an altitude by contacting Microsoft’s filter manager team to ensure that no two drivers conflict by using the same altitude. Handling Altitude Conflicts Altitude conflicts can arise when two or more drivers attempt to register for the same or similar altitudes, especially if one driver isn’t aware of the other. If a conflict occurs: It can lead to unpredictable system behavior, including I/O request handling errors. In worst-case scenarios, it could result in BSODs (Blue Screens of Death) due to improper sequencing of I/O operations. By adhering to the altitude registration process, conflicts are minimized. The filter manager enforces altitude uniqueness to prevent these kinds of operational failures. Practical Example: Antivirus and Backup Solutions Consider a scenario where an antivirus solution and a backup tool are installed on the same machine: Antivirus Filter: This filter driver operates at an altitude of 350000. When an application requests to read or write a file, the antivirus filter intercepts the request first. It scans the file for malicious content before passing it down the stack. Backup Filter: This filter driver is at altitude 250000. After the antivirus completes its scanning, the request moves to the backup filter, which monitors the file for any changes, making a backup copy if necessary. File System Operations: Finally, the request is passed down to the actual file system, which handles the physical read or write operations. Without the correct altitude order, the backup software might try to back up a file before it has been scanned by the antivirus software, potentially saving a corrupted or infected file. Conclusion In summary, file altitude is a critical mechanism in the Windows file system architecture that governs the order in which filter drivers process I/O requests. By assigning a specific altitude to each filter driver, Windows ensures that drivers operate in the correct sequence, minimizing conflicts and ensuring the integrity of file system operations. Whether you're developing file system tools or managing enterprise-level systems, understanding and properly handling file altitude is crucial for maintaining system stability and security.

  • Tested to the Limit: Finding the Fastest USB Flash Drive

    In this article, I’ll compare 11 USB pens to find out which one deserves to be crowned the fastest. Buying a USB flash drive is often treated as a simple choice based on capacity and price, but performance can vary dramatically between products that appear similar on the packaging. Two 64 GB USB 3.x drives may cost almost the same, yet one can complete a large transfer several times faster than the other. Advertised figures usually emphasise maximum read speed, while sustained write speed, cache behaviour, and mixed-file performance are often less obvious. A cheaper drive may save a few pounds at purchase but cost far more in waiting time when copying installation media, deployment files, backups, or large datasets. Choosing the right USB drive therefore means looking beyond capacity and connector type and considering how it performs with the workload it will actually be used for. This test was designed to compare a selection of USB flash drives using the same computer, source files, destination paths, filesystem, and PowerShell-based test process. The aim was not to reproduce a laboratory storage benchmark, but to measure the time taken to complete common file-copy operations under controlled and repeatable conditions. USB Devices Tested Device all purchased before 20 June 26 from Amazon Cost Advertised Read (MBs) Advertised Write (MBs) Type 1 Kingston DataTraveler Kyson USB 3.2 Gen 1 64GB £16-00 60 200 USB-A 2 Kingston DataTraveler Exodia DTX/64GB-2P Flash Drive USB 3.2 Gen 1 £8-48 60 100 USB-A 3 Generic USB Stick 64GB USB 3.0 Flash Drive £9-99 70 20 USB-A 4 Kingston DataTraveler G4 - DTIG4/64GB USB 3.1 £13-58 60 10 USB-A 5 Integral USSD 256GB Turbo-C USB 3.2 Gen 2x2 £49-95 2000 1300 USB-C 6 OSCOO SU001 128GB - USB-A & USB-C 3.2 (Dual Connector) £39-99 500 550 USB-A and USB-C 7 SanDisk Ultra Dual Drive Go, USB Type-C & Type-A Flash Drive 128GB £21-85 400 150 USB-A and USB-C 8 SanDisk Ultra Flair 64GB USB 3.0 £15-08 150 150 USB-A 9 Amazon Basics 128 GB, USB 3.1 £21-49 130 30 USB-A 10 Kingston DataTraveler 70 - DT70/128GB £12-65 400 625 USB-C 11 Amazon Basics USB Flash Drive USB C and USB A Dual Ports £25-70 400 not known USB-A and USB-C Test computer All tests were carried out on a 2024 ASUS ROG Zephyrus G16. The laptop provides USB-A, USB-C, and Thunderbolt 4 connections, allowing compatible drives and dual-connector devices to be tested through the different connection types available on the same computer. A second Samsung 990 Pro NVMe SSD was installed and dedicated to the USB performance tests. The Windows operating system, applications, page file, and normal background activity remained on the primary system drive. The benchmark source files and local read-back destination were stored on the dedicated Samsung 990 Pro. This reduced the likelihood of operating-system activity competing with the benchmark for storage access and ensured that the local source and destination were considerably faster than the USB devices being tested. The same source files and folder locations were used for every device. Test process Each USB device was formatted as NTFS using the default allocation unit size before testing. NTFS was required because the test included individual files larger than the 4 GB maximum file size supported by FAT32. The benchmark was run using a PowerShell script written specifically for the test. At the start of each session, the script prompts for: The name and model of the USB device. The connection or port type being used. The target drive, which was normally assigned as E:\. The script then performs a write test by copying each test workload from the dedicated Samsung 990 Pro to the USB device. Once the write has completed, it performs a read test by copying the same data from the USB device back to a separate folder on the dedicated local SSD. Only the actual copy operation is timed. File discovery, destination preparation, result validation, and cleanup are performed outside the timed section. Robocopy is used to perform the transfers. Large-file tests use unbuffered I/O to reduce the effect of the Windows file cache. The mixed-file test uses a single copy thread so that every device is tested with the same level of concurrency. After each operation, the script verifies that the destination contains the expected number of files and total number of bytes. The elapsed time, calculated transfer rate, test type, direction, device name, connection type, filesystem, disk information, and host details are written to CSV files. Each device and connector combination is recorded as a separate test session. This is particularly important for drives with both USB-A and USB-C connectors, as the two interfaces can be compared independently. Test workloads Three different workloads were selected. 5 GB ISO file The ISO test represents a typical large, continuous file such as Windows installation media, a recovery image, or a software distribution image. A single large file gives a useful indication of sequential transfer performance. Its size is also large enough to expose some short-duration cache behaviour while remaining practical to repeat across several devices. 30 GB single file The 30 GB file is used to measure sustained sequential performance. Many flash drives can write quickly for the first few gigabytes by using a faster cache area. Once that cache is full, the transfer rate may fall significantly. A 30 GB file is large enough to show whether the advertised or initial write speed can be maintained throughout a longer transfer. This test is therefore particularly useful when comparing short-burst write performance with sustained write performance. Mixed-file collection The mixed-file test contains 8 GB of data spread across 2,166 files. This workload represents a more typical collection of deployment scripts, drivers, applications, documents, configuration files, and supporting content. Copying many files introduces additional filesystem and metadata operations, so performance can be substantially lower than when copying one large file. This test is relevant to USB drives used for Windows deployment, technical support, software installation, and general file storage, where the workload is rarely limited to a single continuous file. Recorded results For each workload, the test records: Write speed from the dedicated local SSD to the USB device. Read speed from the USB device back to the dedicated local SSD. Total elapsed time. Decimal megabytes per second. Binary mebibytes per second. File count and total bytes. Device and connection details. Pass or fail validation status. The resulting figures are then compared with the manufacturers’ advertised transfer speeds. Where a manufacturer only publishes an advertised read speed, the measured write result is reported separately rather than being compared against an unsupported write claim. They are intended to show how the drives compare when completing the same practical workloads, rather than to represent the maximum theoretical bandwidth of the USB or Thunderbolt connection. Advertised speed comparison The advertised figures supplied with the test list were used as the comparison baseline, with one important adjustment. Some entries appear to have the advertised read and write columns reversed when compared with typical manufacturer wording. For consistency, the comparison below uses normalised read/write values where required. The most important figure in this report is the 30 GB sustained write speed, because this shows how the device behaves once any short-term cache benefit has been exhausted. Rank Device and the best tested connection Advertised read/write 30 GB read Read achieved 30 GB write Write achieved 30 GB write time 1 Integral USSD 256GB Turbo Thunderbolt 4 2000 / 1300 2043 MB/s 102% 509 MB/s 39% 1m 03s 2 OSCOO SU001 128GB USB-C 550 / 500 528 MB/s 96% 442 MB/s 88% 1m 13s 3 SanDisk Ultra Dual Drive Go Thunderbolt 4 400 / 150 412 MB/s 103% 71 MB/s 47% 7m 33s 4 Amazon Basics USB-C and USB-A Dual Port Thunderbolt 4 400 / unknown 313 MB/s 78% 38 MB/s — 13m 57s 5 SanDisk Ultra Flair 64GB USB 3.0 USB-A 150 / 150 153 MB/s 102% 33 MB/s 22% 16m 02s 6 Amazon Basics 128GB USB 3.1 USB-A 130 / 30 141 MB/s 108% 30 MB/s 100% 17m 57s 7 Generic USB Stick 64GB USB 3.0 USB-A 70 / 20 111 MB/s 158% 27 MB/s 137% 19m 37s 8 Kingston DataTraveler Kyson USB-A 200 / 60 226 MB/s 113% 21 MB/s 34% 26m 04s 9 Kingston DataTraveler 70 DT70 Thunderbolt 4 400 / 625* 87 MB/s 22% 15 MB/s 2% 35m 33s 10 Kingston DataTraveler Exodia USB-A 100 / 60 94 MB/s 94% 14 MB/s 23% 38m 39s 11 Kingston DataTraveler G4 USB-A 60 / 10 105 MB/s 175% 12 MB/s 118% 45m 24s *The Kingston DataTraveler 70 DT70 advertised figures require verification. The supplied figures do not align with the measured behaviour of the tested device, so the percentage comparison should be treated only as a comparison against the supplied listing values. Main finding The advertised read speeds were generally much closer to the measured results than the advertised write speeds. Several devices met or exceeded their advertised read speed during the sustained 30 GB read test. This included the Integral Turbo-C, SanDisk Ultra Dual Drive Go, SanDisk Ultra Flair, Amazon Basics 128GB, Generic USB stick, Kingston Kyson, and Kingston G4. Write performance was much less consistent. The biggest difference between advertised and measured performance appeared during the 30 GB write test. The Integral Turbo-C reached 2043 MB/s read, slightly exceeding its advertised 2000 MB/s read figure. However, its sustained 30 GB write speed was 509 MB/s, which is only 39% of the supplied 1300 MB/s write figure. The OSCOO SU001 was the strongest sustained performer relative to its advertised figures. It reached 528 MB/s read and 442 MB/s write, achieving approximately 96% of its advertised read speed and 88% of its advertised write speed. Sustained write performance The 30 GB write test produced the clearest separation between devices. The fastest device, the Integral Turbo-C, completed the 30 GB write in 1 minute and 3 seconds. The slowest device, the Kingston DataTraveler G4, required 45 minutes and 24 seconds. That makes the fastest result approximately 43 times faster than the slowest result for the same file, on the same laptop, using the same source SSD and the same test script. For Windows deployment work, this difference is significant. A slow USB device can add a large amount of waiting time when copying operating system images, application installers, driver packs, scripts, and deployment content. Cache behaviour The 5 GB ISO test and 30 GB file test show whether a device can maintain its initial write speed over a longer transfer. Device 5 GB write 30 GB write Reduction SanDisk Ultra Flair 81 MB/s 33 MB/s 58% lower Integral Turbo-C 1219 MB/s 509 MB/s 58% lower SanDisk Ultra Dual Drive Go 161 MB/s 71 MB/s 56% lower Amazon Basics USB-C and USB-A Dual Port 51 MB/s 38 MB/s 24% lower The Integral Turbo-C almost reached its advertised write speed during the 5 GB ISO test, writing at 1219 MB/s. Over the larger 30 GB file, the average dropped to 509 MB/s. This suggests the device is capable of very high short-burst writes, but that speed is not maintained across a larger sustained transfer. The OSCOO SU001 behaved differently. It wrote the 5 GB ISO at 444 MB/s and the 30 GB file at 442 MB/s. That makes it one of the most consistent devices tested. Mixed-file performance The mixed-file test used 8 GB of data across 2,166 files. This is closer to a real deployment USB containing applications, scripts, drivers, configuration files, and supporting folders. Rank Device and the best tested connection Mixed write Mixed read 1 Integral Turbo-C — Thunderbolt 4 552 MB/s 1312 MB/s 2 OSCOO SU001 — USB-C 323 MB/s 444 MB/s 3 SanDisk Ultra Dual Drive Go — Thunderbolt 4 72 MB/s 335 MB/s 4 Amazon Basics USB-C and USB-A Dual Port — USB-C 41 MB/s 286 MB/s 5 SanDisk Ultra Flair — USB-A 32 MB/s 139 MB/s 6 Amazon Basics 128GB USB 3.1 — USB-A 24 MB/s 130 MB/s 7 Generic USB Stick 64GB USB 3.0 — USB-A 22 MB/s 104 MB/s 8 Kingston DT70 — Thunderbolt 4 13 MB/s 82 MB/s 9 Kingston Exodia — USB-A 13 MB/s 89 MB/s 10 Kingston Kyson — USB-A 6 MB/s 177 MB/s 11 Kingston G4 — USB-A 3 MB/s 43 MB/s The mixed-file test was particularly damaging for the Kingston G4 and Kingston Kyson. The Kyson read performance was strong at 177 MB/s for mixed files, but its mixed-file write speed was only 6 MB/s. This makes it unsuitable for workloads that involve repeatedly writing large collections of smaller files. The Kingston G4 performed worst overall in the mixed-file write test at 2.75 MB/s. Connector comparison Several dual-connector or USB-C devices were tested through more than one connection type. OSCOO SU001 Connection 30 GB read 30 GB write Mixed write USB-C 528 MB/s 442 MB/s 323 MB/s USB-A 524 MB/s 432 MB/s 314 MB/s Thunderbolt 4 port 524 MB/s 411 MB/s 238 MB/s The OSCOO produced very consistent large-file results across USB-A and USB-C. It did not benefit from the Thunderbolt 4 port because the device itself is the limiting factor rather than the laptop port. SanDisk Ultra Dual Drive Go Connection 30 GB read 30 GB write Mixed write Thunderbolt 4 port 412 MB/s 71 MB/s 72 MB/s USB-A 400 MB/s 70 MB/s 52 MB/s USB-C 412 MB/s 69 MB/s 53 MB/s The SanDisk Ultra Dual Drive Go was consistent across all connector types for large-file read and write performance. The Thunderbolt 4 connection did not materially improve large-file performance, indicating that the USB drive is the limiting factor. Amazon Basics USB-C and USB-A Dual Port Connection 30 GB read 30 GB write Mixed write USB-C 319 MB/s 38 MB/s 41 MB/s Thunderbolt 4 port 313 MB/s 38 MB/s 41 MB/s USB-A 286 MB/s 38 MB/s 40 MB/s The Amazon Basics dual-port drive delivered consistent write performance across all three tested connections. Read performance was better through USB-C and Thunderbolt 4 than USB-A, but write speed remained around 38 MB/s regardless of connector. This makes it a reasonable read-focused device, but not a strong choice for repeated large writes. Integral Turbo-C Connection 30 GB read 30 GB write Mixed write Thunderbolt 4 port 2043 MB/s 509 MB/s 552 MB/s USB-A via adapter 1065 MB/s 467 MB/s 368 MB/s USB-C 1068 MB/s 464 MB/s 410 MB/s The Integral Turbo-C was the fastest device tested. It delivered the highest overall read performance through the Thunderbolt 4 port, reaching 2043 MB/s on the 30 GB read test. It also produced the fastest sustained write result, completing the 30 GB write at 509 MB/s. Performance remained strong through both USB-C and the USB-A adapter. Over USB-C, the drive reached 1068 MB/s read and 464 MB/s sustained write. Through the USB-A adapter, it produced a very similar large-file result, reaching 1065 MB/s read and 467 MB/s sustained write. Thunderbolt 4 provided the strongest overall performance, especially for read speed and mixed-file transfers. However, the USB-C and USB-A adapter results show that the Integral Turbo-C remains a very fast option even when Thunderbolt is not available Kingston DataTraveler 70 Connection 30 GB read 30 GB write Mixed write Thunderbolt 4 port 87 MB/s 15 MB/s 13 MB/s USB-C 29 MB/s 10 MB/s 9 MB/s The Kingston DataTraveler 70 DT70 was one of the weakest performers in the test. Its read speed was consistent at around 84–87 MB/s, but its write speed remained between 13–15 MB/s across all workloads. The 30 GB sustained write completed at 14.64 MB/s and took 36 minutes and 41 seconds. Price-to-performance Using sustained 30 GB write speed divided by purchase price, the ranking changes slightly. Rank Device Price 30 GB write Write speed per £ 1 OSCOO SU001 £39.99 442 MB/s 11.05 MB/s per £ 2 Integral Turbo-C £49.95 509 MB/s 10.19 MB/s per £ 3 SanDisk Ultra Dual Drive Go £21.85 71 MB/s 3.26 MB/s per £ 4 Generic USB Stick £9.99 27 MB/s 2.74 MB/s per £ 5 SanDisk Ultra Flair £15.08 33 MB/s 2.22 MB/s per £ 6 Kingston Exodia £8.48 14 MB/s 1.64 MB/s per £ 7 Amazon Basics USB-C and USB-A Dual Port £25.70 38 MB/s 1.50 MB/s per £ 8 Amazon Basics 128GB USB 3.1 £21.49 30 MB/s 1.39 MB/s per £ 9 Kingston Kyson £16.00 21 MB/s 1.29 MB/s per £ 10 Kingston DT70 £12.65 15 MB/s 1.16 MB/s per £ 11 Kingston G4 £13.58 12 MB/s 0.87 MB/s per £ The OSCOO SU001 remains the best value when using its highest measured sustained write result, achieving 11.05 MB/s per £. The Integral Turbo-C remains close behind at 10.19 MB/s per £, while also delivering the fastest absolute performance in the test. The USB-A adapter result shows that it remains a high-performance option even when Thunderbolt 4 is not available. Initial awards Fastest overall Integral USSD 256GB Turbo-C USB 3.2 Gen 2x2 The Integral was the fastest device in the test by a large margin. It reached 2043 MB/s read and 509 MB/s sustained write through the Thunderbolt 4 port. It is the best option where maximum transfer speed is the priority. Thunderbolt 4 delivered the highest read speed, but the USB-C and USB-A adapter results also remained very strong, both exceeding 460 MB/s sustained write in the 30 GiB test. Best all-round USB drive Integral USSD 256GB Turbo-C USB 3.2 Gen 2x2 The Integral was the fastest device in the test by a large margin. It reached 2043 MB/s read and 509 MB/s sustained write through the Thunderbolt 4 port, making it the clear performance leader. It also performed strongly over USB-C and through the USB-A adapter, with both connections delivering more than 460 MB/s sustained write in the 30 GB test. Thunderbolt 4 provided the highest read speed, but the Integral remained a very fast option across all tested connection types. Best conventional dual-connector flash drive SanDisk Ultra Dual Drive Go The SanDisk Ultra Dual Drive Go was much slower than the Integral and OSCOO on sustained writes, but it performed consistently across USB-A, USB-C, and Thunderbolt 4 ports. Its read speed was close to the supplied advertised figure, making it a useful read-focused deployment or support drive. Best budget surprise Generic USB Stick 64GB USB 3.0 The generic USB stick exceeded its supplied advertised figures and outperformed several branded budget drives in sustained write speed. It was not fast, but for its price it performed better than expected. Most consistent against advertised write speed Amazon Basics 128GB USB 3.1 The Amazon Basics 128GB USB 3.1 drive measured 29.92 MB/s against a supplied advertised write speed of 30 MB/s. It was not a fast device, but it was one of the few drives where the sustained write result closely matched the supplied write figure. Weakest result Kingston DataTraveler G4 The Kingston G4 had the slowest sustained 30 GB write time and the weakest mixed-file write performance. It completed the 30 GB write at 11.82 MB/s and the mixed-file write at only 2.75 MB/s. For a Windows deployment USB, this level of write performance would be a significant limitation. Conclusion The final results show that USB flash drive performance cannot be judged by capacity, connector type, or USB version alone. Several drives achieved strong read speeds, and many came close to or exceeded the supplied advertised read figures. Sustained write performance was far less predictable. Some devices dropped sharply when moving from the 5 GB ISO test to the 30 GB sustained write test, suggesting that short-burst performance can give a misleading impression of real-world behaviour. The Integral Turbo-C is the fastest device tested, but the OSCOO SU001 is the strongest all-round result when consistency, sustained write speed, connector flexibility, and price are considered together. The main practical finding is simple: two USB drives with similar packaging and USB version labels can behave completely differently. In this test, the difference between the fastest and slowest 30 GB write result was more than 40 times.

  • PowerShell QuickEdit, Why It Wrecks Scripts

    My scripting language of choice is PowerShell. For my sins, and there are plenty, I am a Microsoft engineer. Life choices were made, clearly not all of them wise. Still, PowerShell is built into Windows. Then there is PowerShell's QuickEdit. QuickEdit is one of those “helpful” Windows console features that sounds useful right up until it parks a Tank on top of your deployment script. It lets you interact with a running PowerShell window, select text directly from the console, and copy it. Wonderful. Marvellous. Exactly what nobody asked for during an unattended build. The problem is that when QuickEdit decides text is being selected, PowerShell stops dead in its tracks. Just stop. Your carefully written script, which may be installing applications, configuring Windows, applying security settings, or doing several hours of build work, suddenly sits there doing absolutely nothing. And the trigger? A mouse click. A tiny drag. A badly timed brush across the console window. Sometimes, it feels like the mouse only has to think about PowerShell from across the room and that is enough. The script freezes, the build stalls, and you are left wondering why it's taking so long to complete I could almost forgive it if QuickEdit only caused problems when I deliberately selected text. But no, that would be far too reasonable. Instead, it has a special gift for interrupting scripts at exactly the wrong moment, when there's deadlines. And breathe... And then there's Turning QuickEdit Off QuickEdit can be turned off from the PowerShell window properties, but in true Microsoft fashion, changing the setting does not always mean the console window currently open will pay the slightest bit of attention. That would be too easy. Registry changes are not always picked up by an already running console, because apparently asking Windows to apply the setting you just changed to the thing you are actually using is an unreasonable expectation. Somewhere deep inside the operating system, a committee clearly decided that the correct behaviour was “yes, we have accepted your change, no, we will not be using it yet.” So, for reliable behaviour, close PowerShell and reopen it, because naturally even turning off the thing that randomly pauses your scripts requires the traditional Microsoft ritual of shutting it down and starting it again. And breathe... (again)... Clearly, I'm having a bad Microsoft day. Where QuickEdit Is Configured QuickEdit settings are stored in the user console registry settings. The main location is: HKCU:\Console PowerShell also has per-application console settings under: HKCU:\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe HKCU:\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe The values used are: QuickEdit = 0 InsertMode = 0 Setting QuickEdit to 0 disables QuickEdit.Setting InsertMode to 0 keeps console input behaviour predictable. Disable QuickEdit for the Current User This function disables QuickEdit for the currently logged-on user. Function Disable-ConsoleQuickEdit { Set-ItemProperty -Path 'HKCU:\Console' -Name 'QuickEdit' -Value 0x00000000 -Force Set-ItemProperty -Path 'HKCU:\Console' -Name 'InsertMode' -Value 0x00000000 -Force Set-ItemProperty -Path 'HKCU:\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe' -Name 'QuickEdit' -Value 0 -Force Set-ItemProperty -Path 'HKCU:\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe' -Name 'InsertMode' -Value 0 -Force Set-ItemProperty -Path 'HKCU:\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe' -Name 'QuickEdit' -Value 0 -Force Set-ItemProperty -Path 'HKCU:\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe' -Name 'InsertMode' -Value 0 -Force } This only affects the current user profile. Disable QuickEdit for New Users To apply the same setting to new user profiles, update the Default User registry hive. Function DefaultUser-ConsoleQuickEdit { & REG LOAD HKLM\DEFAULT C:\Users\Default\NTUSER.DAT $RegistrySettings = @( @{ RelativePath = "Console"; Name = "QuickEdit"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console"; Name = "InsertMode"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe"; Name = "QuickEdit"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe"; Name = "InsertMode"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe"; Name = "QuickEdit"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe"; Name = "InsertMode"; Value = 0; Type = "DWord" } ) foreach ($Setting in $RegistrySettings) { $FullPath = "HKLM:\DEFAULT\$($Setting.RelativePath)" if (!(Test-Path $FullPath)) { $Item = New-Item -Path $FullPath -Force if ($Item -and $Item.Handle) { $Item.Handle.Close() } } New-ItemProperty -Path $FullPath -Name $Setting.Name -PropertyType $Setting.Type -Value $Setting.Value -Force | Out-Null } [gc]::Collect() [gc]::WaitForPendingFinalizers() & REG UNLOAD HKLM\DEFAULT } This affects users created after the change is made. Disable QuickEdit for Administrator Before First Logon If the local Administrator profile exists but has not been used yet, the same settings can be written directly into its profile hive. Function Administrator-ConsoleQuickEdit { try { Get-ChildItem C:\Users\Administrator\NTUSER.DAT -ErrorAction Stop & REG LOAD HKLM\DEFAULT C:\Users\Administrator\NTUSER.DAT $RegistrySettings = @( @{ RelativePath = "Console"; Name = "QuickEdit"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console"; Name = "InsertMode"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe"; Name = "QuickEdit"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe"; Name = "InsertMode"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe"; Name = "QuickEdit"; Value = 0; Type = "DWord" }, @{ RelativePath = "Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe"; Name = "InsertMode"; Value = 0; Type = "DWord" } ) foreach ($Setting in $RegistrySettings) { $FullPath = "HKLM:\DEFAULT\$($Setting.RelativePath)" if (!(Test-Path $FullPath)) { $Item = New-Item -Path $FullPath -Force if ($Item -and $Item.Handle) { $Item.Handle.Close() } } New-ItemProperty -Path $FullPath -Name $Setting.Name -PropertyType $Setting.Type -Value $Setting.Value -Force | Out-Null } [gc]::Collect() [gc]::WaitForPendingFinalizers() & REG UNLOAD HKLM\DEFAULT } catch { } } This is useful in build environments where the Administrator account may be enabled or used later. Recommended Usage For deployment scripts or image builds, QuickEdit should be disabled early in the process. Disable-ConsoleQuickEdit DefaultUser-ConsoleQuickEdit Administrator-ConsoleQuickEdit This covers the current user, future users, and the local Administrator profile where it exists. Final Thoughts QuickEdit is useful for manual console work, but it is not ideal for automation. A single accidental click inside the console window can make a script appear to hang. For build scripts, deployment scripts, and first boot configuration, that risk is not worth keeping. Disabling QuickEdit makes PowerShell-based automation more predictable, which is exactly what you want during a build or deployment.

  • PowerShell ISE Dark Theme, Half Finished, Half Broken, Very Microsoft

    ISE Dark Theme, Scuppered by Microsoft PowerShell ISE has a dark theme, let's face it, it's sub-optimal, half-arsed and clearly created by Microsoft. Before anyone reaches for the pitchfork, yes, Visual Studio Code is the better editor. It has extensions, Git integration, better formatting, better search, better debugging, better everything really. However, PowerShell ISE wins in one very specific place, real Windows administration. It's installed by default on every Windows client and Server. There is absolutely no way on this round earth that VS Code will be installed on my Servers and Domain Controllers. I prefer a dark theme when coding or scripting, there's less glare and eye strain... and here Microsoft strikes again. Change the background to the Dark Theme and the editor looks better for about three seconds, right up until normal text renders a nice shade of black on a dark blue background, XML turns into a red and blue crime scene, and half your unattended install file becomes harder to read than Microsoft licensing. ISE does not treat all text the same. PowerShell code uses one set of token colours. Plain text uses another setting. XML has its own separate colour dictionary. That means setting a dark background is not enough. You also need to fix script tokens, plain editor text, console text, warning text, error text, and XML token colours. a text file an xml file Does no one at Microsoft test anything......... So I Fixed it myself with a Tenaka ISE Theme The Tenaka theme fixes the dark mode correctly.. I hope. It sets a dark blue editor background, off-white main text, bronze commands, yellow parameters, green variables, muted strings, blue type/member highlighting, and readable warning and error colours. The output window is dark blue with off-white text, errors are still red. It also fixes XML separately, which matters if you work with unattended install files, deployment XML, or configuration files. XML tags, attributes, quoted strings, comments, and plain command text inside XML are all given their own readable colours. How to Configure ISE Tenaka Theme Clearly dazzled by this frankly magnificent colour selection, you will obviously want to know how to apply the Tenaka Theme to PowerShell ISE. Default Profile This is easy, unless Constrained Language Mode is your thing, then skip this and go to importing a theme. Copy the script to the path below, inserting your username for Expand Script $DarkBlue = '#FF0B1F2A' # very dark blue $NearWhite = '#FFEAF4F8' # near white $Bronze = '#FFD19047' # bronze/gold $Yellow = '#FFFFD166' # warm yellow $MutedText = '#FFB7CBD6' # muted grey/blue $BlueAccent = '#FF4FC3F7' # light blue $Green = '#FF7CFC98' # green $Copper = '#FFB56A2F' # darker bronze/copper $Red = '#FFFF6B6B' # red # WPF colour objects, required for XML token colours $DarkBlueColor = [System.Windows.Media.ColorConverter]::ConvertFromString($DarkBlue) $NearWhiteColor = [System.Windows.Media.ColorConverter]::ConvertFromString($NearWhite) $BronzeColor = [System.Windows.Media.ColorConverter]::ConvertFromString($Bronze) $YellowColor = [System.Windows.Media.ColorConverter]::ConvertFromString($Yellow) $MutedTextColor = [System.Windows.Media.ColorConverter]::ConvertFromString($MutedText) $BlueAccentColor = [System.Windows.Media.ColorConverter]::ConvertFromString($BlueAccent) $GreenColor = [System.Windows.Media.ColorConverter]::ConvertFromString($Green) # Main editor background and plain text $psISE.Options.ScriptPaneBackgroundColor = $DarkBlue $psISE.Options.ScriptPaneForegroundColor = $NearWhite # Console / output pane $psISE.Options.ConsolePaneBackgroundColor = $DarkBlue $psISE.Options.ConsolePaneTextBackgroundColor = $DarkBlue $psISE.Options.ConsolePaneForegroundColor = $MutedText # Normal / unknown text $psISE.Options.TokenColors.Item('Unknown') = $NearWhite # Commands and functions $psISE.Options.TokenColors.Item('Command') = $Bronze $psISE.Options.TokenColors.Item('CommandArgument') = $NearWhite # Parameters $psISE.Options.TokenColors.Item('CommandParameter') = $Yellow # PowerShell keywords $psISE.Options.TokenColors.Item('Keyword') = $Bronze # Variables $psISE.Options.TokenColors.Item('Variable') = $Green # Strings $psISE.Options.TokenColors.Item('String') = $MutedText # Numbers $psISE.Options.TokenColors.Item('Number') = $Yellow # Operators $psISE.Options.TokenColors.Item('Operator') = $NearWhite # Brackets, braces, parentheses, separators $psISE.Options.TokenColors.Item('GroupStart') = $NearWhite $psISE.Options.TokenColors.Item('GroupEnd') = $NearWhite $psISE.Options.TokenColors.Item('StatementSeparator') = $NearWhite $psISE.Options.TokenColors.Item('LineContinuation') = $NearWhite # Types, for example [string], [int], [System.IO.File] $psISE.Options.TokenColors.Item('Type') = $BlueAccent # Object members, for example .Name, .FullName $psISE.Options.TokenColors.Item('Member') = $BlueAccent # Comments $psISE.Options.TokenColors.Item('Comment') = $Copper # Errors $psISE.Options.ErrorForegroundColor = $Red $psISE.Options.ErrorBackgroundColor = $DarkBlue # Warnings $psISE.Options.WarningForegroundColor = $Yellow $psISE.Options.WarningBackgroundColor = $DarkBlue # XML syntax highlighting $psISE.Options.XmlTokenColors.Item('Text') = $NearWhiteColor $psISE.Options.XmlTokenColors.Item('ElementName') = $BronzeColor $psISE.Options.XmlTokenColors.Item('Attribute') = $YellowColor $psISE.Options.XmlTokenColors.Item('QuotedString') = $MutedTextColor $psISE.Options.XmlTokenColors.Item('Tag') = $BlueAccentColor $psISE.Options.XmlTokenColors.Item('Quote') = $MutedTextColor $psISE.Options.XmlTokenColors.Item('Comment') = $GreenColor $psISE.Options.XmlTokenColors.Item('CommentDelimiter') = $GreenColor $psISE.Options.XmlTokenColors.Item('CharacterData') = $NearWhiteColor $psISE.Options.XmlTokenColors.Item('MarkupExtension') = $BlueAccentColor C:\Users\\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1 Restart ISE Creating a Theme Alternatively, paste the script into PowerShell ISE and run it with F8. This applies the Tenaka Theme for the current session. To save it as a reusable theme, open: Tools > Options > Manage Themes > Export When exporting, keep the original file extension, " .StorableColorTheme.ps1xml ". If the extension is changed, ISE won't recognise the file and the theme will not import later. Here's the link to Github Enjoy. And obviously, if you think you have a better colour scheme, you are free to be wrong, but do drop a comment in the box below. The Tenaka Theme is, quite clearly, the best ISE theme everrrrrrrr. Links: https://github.com/Tenaka/ISEColour

bottom of page