Category Archives: Tips

Extract Content From MSI Files

To extract the contents of a Microsoft Software Installer (MSI) file you need to run the following command against the MSI that you are working with:

msiexec /a <FullPathToMSISourceFile> /qb TARGETDIR=<FullPathToExtractedContentFolder>

So a working example of this would be as follows:

msiexec /a "C:\Temp\Nutanix-VirtIO-1.2.3-x64.msi" /qb TARGETDIR="C:\Temp\Extract"

/ JC

Intune | Force Microsoft Edge Update to Latest Version During Windows Autopilot

Quick and simple post today. Had a customer deploying Windows 10 IoT Enterprise LTSC 2021 (yes I am aware that IoT Enterprise and LTSC are not officially supported for Windows Autopilot at time of writing but it works fine so… ) and there was a requirement to update the version of Edge included in this version of Windows so that it was at a version which supported some of the more recent Intune Configuration Profile policy settings. Should this not happen then the policies would not apply until such time as Edge updated itself which may be some time after a user had logged into the device.

To accomplish this I wrapped the following PowerShell script into a Win32 app and had it configured as a Blocking application on the Enrolment Status Page (ESP) being used for Autopilot.

The result is Microsoft Edge updating to the latest available version before any users log in for the first time.

<#
.DESCRIPTION
    PowerShell script to force update of Microsoft Edge Stable
.EXAMPLE
    PowerShell.exe -ExecutionPolicy ByPass -File <ScriptName>.ps1
.NOTES
    VERSION     AUTHOR              CHANGE
    1.0         Jonathan Conway     Initial script creation
#>

$Exe = Get-ChildItem -Path "${env:ProgramFiles(x86)}\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe"
$Arguments = "/silent /install appguid={56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}&appname=Microsoft%20Edge&needsadmin=True"
return (Start-Process $($Exe.FullName) -ArgumentList $Arguments -NoNewWindow -PassThru -Wait).ExitCode

Be sure to configure the detection method according to your environment. For me, I set this to a version of “Greater than or equal to: 100.0.0000.00” to detect the installation but you may want to use a higher version number depending on your own circumstances:

Let me know if this works for you (or if you have any issues with the script) in the comments.

/ JC

ConfigMgr OSD | Windows 10 Disk Partitioning to Correctly Include Recovery Tools Partition

Edit 28/02/24: Updated to reflect increase of Recovery partition to 2048Mb.

How should disks be partitioned for Windows 10 so that the Recovery Partition is configured properly? Turns out the answer isn’t straightforward and that the standard tools provided provided in ConfigMgr by Microsoft don’t quite allow you to do it properly by default…

WinRE is important as it is used by many of the reset features used in Windows 10, especially in Modern Management scenarios. This includes manual recovery, Factory Reset and newer options such as Windows Autopilot Reset.

This partition is used to help recover an OS when not bootable which is why it needs to be located on a separate partition. This partition should be placed immediately after the Windows partition to allow Windows to modify and recreate the partition in the future if future updates (i.e. newer versions of Windows) require a larger Recovery Image. It also allows the device to be rebuilt (i.e., have the OS reinstalled) without affecting the Recovery Partition.

If this resizing/recreation of the Recovery Partition can’t be done during OS upgrades then the ability to use the WinRE environment can be removed and is tricky to remediate afterwards.

To produce this post I have read through a lot of other well-respected blogs and also analysed what a lot of experts have suggested on Twitter etc. This article is the summary of that analysis as well as providing a script written by me which can be used during ConfigMgr Task Sequences to create the required disk partitions correctly. The main resources I used were:

miketerrill.net

garytown.com

Lets start with the recommendations from Microsoft.

UEFI | GPT

For UEFI, Microsoft recommend the following partition layout for Windows 10 (Docs link can be found here):

diagram of default partition layout: system, msr, windows, and recovery
Microsoft Recommended Partition Layout

From this diagram we can see that Microsoft recommend a ‘System‘ partition’ (also known as a EFI System Partition (ESP)) which provides a device with a partition to boot from. It shouldn’t contain any files other than what is intended for booting the device.

‘System’ Partition

Following that is a ‘Microsoft Reserved‘ partition (MSR) which is used for partition management. No user data can be stored on this partition.

‘Microsoft Reserved’ Partition

The next partition is the ‘Windows‘ partition which is obviously used for the Windows Operating System.

‘Windows’ Partition

And the last partition (and the one which causes the most questions) is the ‘Recovery Tools‘ partition which will host a copy of the ‘Windows Recovery Environment’ (WinRE). WinRE is a recovery environment that can repair common causes of unbootable operating systems.

The Recovery Tools partition presents a problem as there is no built-in way in a Task Sequence of ensuring that the Recovery Tools partition is located at the end of the disk (i.e., after the Windows partition) and is configured correctly – this is the main reason for writing this blog post.

The table below summarises the best recommended sizes for each partition based on the Microsoft recommendations and also various experts around the web:

NameSize (Mb)Format
System (EFI)360 fixed sizeFAT32
MSR128 fixed size
Windows (Primary)100% of remaining space on diskNTFS
Recovery 2048 fixed sizeNTFS
UEFI Disk Partitions
UEFI | GPT Format and Partition Disk Step

BIOS | MBR

For traditional BIOS, Microsoft recommend the following partition layout for Windows 10 (Docs link can be found here). Note that ‘BIOS | MBR’ is now considered legacy and has limited use case scenarios with Modern Device Management. Many modern security controls are based on the newer UEFI firmware and so ‘BIOS | MBR’ and is therefore rarely used:

diagram of default partition layout: system, windows, and recovery

From this diagram we can see that Microsoft again recommends a ‘System‘ partition which is used to boot the device.

‘System’ Partition

Following that is the ‘Windows‘ partition to be used for the Windows 10 operating system.

‘Windows’ Partition

And the final partition is once again the ‘Recovery Tools‘ partition which was mentioned previously in the UEFI section above.

The table below summarises the best recommended sizes for each partition based on the Microsoft recommendations and also various experts around the web:

NameSize (Mb)Format
System360 fixed sizeNTFS
Windows (Primary)100% of remaining space on diskNTFS
Recovery 2048 fixed sizeNTFS
Traditional BIOS Disk Partitions
BIOS | MBR Format and Partition Disk Step

Recovery Tools Partition Solution

To create the Recovery Tools partition in the location and size required we need to use ‘Diskpart’ to create the Recovery Partition once the built-in ‘Format and Partition Disk‘ step has been completed.

The way this is done is to shrink the ‘Windows’ partition by the size needed (in this case 984Mb) and create a new partition with that newly-available space called ‘Recovery’.

For UEFI deployments, the ‘Recovery Tools’ partition needs to have it’s ‘ID‘ set to ‘de94bba4-06d1-4d40-a16a-bfd50179d6ac‘, be given the GPT attribute of ‘0x8000000000000001‘ and needs to be set to have a Partition Type of ‘27‘ so that it is hidden.

To accomplish this I wrote a PowerShell script to run Diskpart with the required settings. The script should be added to the Task Sequence just after the built-in ‘Format and Partition Disk’ step as per the images below:

Location of ‘Create Recovery Partition’ Step

The script works best when entered as a PowerShell script as part of a ‘Run PowerShell Script‘ task in a Task Sequence:

‘Create Recovery Partition’ Script Task

The script for automating the creation of the Recovery Partition is embedded below. It will detect if the device is configured for BIOS or UEFI and create the partition accordingly:

<#
.DESCRIPTION
    Script to create Recovery Partition during OSD and hide System Partition (if needed) on MBR

    This script requires the following optional Boot Image components: 'WinPE-DismCmdlets', 'WinPE-PowerShell', 'WinPE-StorageWMI'
.EXAMPLE
    PowerShell.exe -ExecutionPolicy ByPass -File <ScriptName>.ps1
.NOTES

    VERSION     AUTHOR              CHANGE
    1.5         Jonathan Conway     Initial script creation
#>

# Loads the Task Sequence environment
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment

# Configures script log path to match tsenv logs folder
$LogPath = $tsenv.Value("_SMSTSLogPath")

# Determines if firmware configured as UEFI
$UEFI = $tsenv.Value("_SMSTSBootUEFI")

# Get OS Disk information
[string]$OSDrivePartitionNumber = (Get-Disk | Where-Object {$PSItem.BusType -ne 'USB'} | Get-Partition | Where-Object {$PSItem.Size -gt '5GB' -and $PSItem.Type -eq 'Basic'}).PartitionNumber

# Recovery partition size in Mb
$RecoveryPartitionSize = '2048'

If ($UEFI -eq $true) {

    'select disk 0',
    'list partition',
    "select partition $OSDrivePartitionNumber",
    "shrink desired=$RecoveryPartitionSize minimum=$RecoveryPartitionSize",
    'create partition primary',
    'format quick fs=ntfs label=Recovery',
    'set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"',
    'gpt attributes=0x8000000000000001',
    'list partition' | diskpart | Tee-Object -FilePath "$LogPath\Pwsh-OsdDiskpart.log"
}

else {
    'select disk 0',
    'list partition',
    "select partition $OSDrivePartitionNumber",
    "shrink desired=$RecoveryPartitionSize minimum=$RecoveryPartitionSize",
    'create partition primary',
    'format quick fs=ntfs label=Recovery',
    'set id=27',
    'list partition',
    'select partition 1', 'set id=17', 'list partition' | diskpart | Tee-Object -FilePath "$LogPath\Pwsh-OsdDiskpart.log"
}

The script uses variables for the OS Drive Partition and Recovery Partition Size so both of these can be modified according to specific requirements in the event that this is needed.

So this solution should allow you to correctly configure the disk partitions needed to install Windows 10 and also ensure that a functional Recovery Tools partition is always present.

/ JC

PowerShell: Automate Naming of Captured WIM File During MDT Reference Image Creation

If you’re Old Skool like me and still use MDT to produce Windows 10 Reference Images then this script may be useful to save some time and hassle.

The script basically automates the creation of the filename for the backup WIM file so that all that is required to produce a new image bi-annually (or as often as you like) is to run a Build & Capture Task Sequence which (providing the VM has access to WSUS or Microsoft Update) will include the all the latest patches.

It produces a filename in the following format which includes the Windows 10 version being captured, architecture, language and the date.

W10X64_20H2_en-GB_19042.572_2020-10-22_1525.wim

Because the date includes the time the image is captured, the filename will always be unique so there will never be an occasion where the image can’t be captured to a pre-existing WIM file being present with the same name.

The net result is that the Reference Image creation can be as simple as booting a VM, choosing a Task Sequence then collecting the WIM file it produces at the end of the process.

The script produces an MDT variable called ‘%WimFileName%‘ which is then used to populate the ‘BackupFile‘ property in the Task Sequence – this is demonstrated in the images below:

Configure: Set WIM Filename
Set: BackupFile

The script content is embedded below. Copy and paste into a blank text file and save as ‘Pwsh-SetWimFilename.ps1‘ and copy it into your MDT Deployment share in the following location:

DeploymentShare\Scripts\Custom

Script Content:

<#
.DESCRIPTION
    Script to automate the naming of the WIM File Name during MDT OSD
.EXAMPLE
    PowerShell.exe -ExecutionPolicy ByPass -File <ScriptName>.ps1 [-Debug]
.NOTES
    Author(s):  Jonathan Conway
    Modified:   17/11/2021
    Version:    1.5

    Option [-Debug] switch can be run locally to output results to screen to test WIM File Name is correct
#>

Param (
    [Switch]$Debug
)

Begin {

    # Variables: Information from Registry
    $OsRegistryInfo = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
    [string]$DisplayVersion = $OsRegistryInfo.DisplayVersion
    [string]$ReleaseId = $OsRegistryInfo.ReleaseId
    [string]$Ubr = $OsRegistryInfo.UBR
    [string]$EditionId = $OsRegistryInfo.EditionID
    [string]$OsCurrentBuildNumber = $OsRegistryInfo.CurrentBuildNumber

    # Variables: Change 'ReleaseID' to new Windows Release naming format if Windows 10 20H2 or later
    if ($ReleaseId -gt '2004' -and $ReleaseId -lt '2009') {

        if ($ReleaseId -match "^(..)(01|02|03|04|05|06)$") {
            [string]$ReleaseId1stHalf = $ReleaseId.Substring(0, 2)
            [string]$ReleaseId2ndHalf = $ReleaseId.Substring(2, 2)
            [string]$ReleaseId2ndHalfReplaced = $ReleaseId2ndHalf -replace "$ReleaseId2ndHalf", "H1"
            [string]$ReleaseId = "$ReleaseId1stHalf" + "$ReleaseId2ndHalfReplaced"
        }

        if ($ReleaseId -match "^(..)(07|08|09|10|11|12)$") {
            [string]$ReleaseId1stHalf = $ReleaseId.Substring(0, 2)
            [string]$ReleaseId2ndHalf = $ReleaseId.Substring(2, 2)
            [string]$ReleaseId2ndHalfReplaced = $ReleaseId2ndHalf -replace "$ReleaseId2ndHalf", "H2"
            [string]$ReleaseId = "$ReleaseId1stHalf" + "$ReleaseId2ndHalfReplaced"
        }

    }

    elseif ($ReleaseId -ge '2009') {
        $ReleaseId = $DisplayVersion
    }

    # Variables: Information from WMI
    $OsWmiInfo = Get-CimInstance -ClassName 'Win32_OperatingSystem'

    # Variables: OS 'Caption' information
    $Caption = $OsWmiInfo.Caption
    [String]$RegExPattern = '(Microsoft\ (Windows|Hyper-V)\ (10|11|Server\ (2016.*?|2019.*?)))'
    [String]$MachineOS = ($Caption | Select-String -AllMatches -Pattern $RegExPattern | Select-Object -ExpandProperty 'Matches').Value

    # Variables: Media Language
    [string]$OsLanguageNumberCode = $OsWmiInfo.OSLanguage

    if ($OsLanguageNumberCode -eq '2057') {
        $OsLanguage = 'en-GB'
    }
    if ($OsLanguageNumberCode -eq '1033') {
        $OsLanguage = 'en-US'
    }

    # Variables: Date Information
    $BuildDate = Get-Date -Format "yyyy-MM-dd_HHmm"

    # Variables: OS Architecture
    if ($OsWmiInfo.OSArchitecture -eq '64-bit') {
        $Architecture = 'X64'
    }
    if ($OsWmiInfo.OSArchitecture -eq '32-bit') {
        $Architecture = 'X86'
    }

}

Process {

    # Microsoft Hyper-V Server
    if ($MachineOS -like 'Microsoft Hyper-V Server*') {
        # Variables: Set OS Prefix
        $HypervPrefix = 'HVS'

        # Variables: Set Windows Server Version
        $WindowsServerVersion = $MachineOS.TrimStart("Microsoft Hyper-V Server")

        # Hyper-V Server: Create Wim File Name string
        $WimFileName = "$HypervPrefix" + "$WindowsServerVersion" + "$Architecture" + '_' + "$OsLanguage" + '_' + "$OsCurrentBuildNumber" + '.' + "$Ubr" + '_' + "$BuildDate" + '.' + 'wim'
    }

    # Microsoft Windows 10
    if ($MachineOS -like 'Microsoft Windows 10*') {
        # Variables: Set OS Prefix
        $Os = 'W10'

        # Variables: OS Edition
        if ($EditionId -eq 'Enterprise') {
            $Edition = 'ENT'
        }
        if ($EditionId -eq 'IoTEnterprise') {
            $Edition = 'IOT'
            $ReleaseId = $OsRegistryInfo.DisplayVersion
        }
        if ($EditionId -eq 'EnterpriseS') {
            $Edition = 'IOT'
            $Channel = 'LTSC'
        }
        if ($EditionId -eq 'Professional') {
            $Edition = 'PRO'
        }

        if ($EditionId -eq 'EnterpriseS') {
            # Windows 10 IoT LTSC: Create Wim File Name string
            $WimFileName = "$Os" + "$Architecture" + '_' + "$Edition" + '_' + "2019" + '_' + "$Channel" + '_' + "$OsLanguage" + '_' + "$OsCurrentBuildNumber" + '.' + "$Ubr" + '_' + "$BuildDate" + '.' + 'wim'
        }
        else {
            # Windows 10: Create Wim File Name string
            $WimFileName = "$Os" + "$Architecture" + '_' + "$Edition" + '_' + "$ReleaseId" + '_' + "$OsLanguage" + '_' + "$OsCurrentBuildNumber" + '.' + "$Ubr" + '_' + "$BuildDate" + '.' + 'wim'
        }

    }

    # Microsoft Windows 11
    if ($MachineOS -like 'Microsoft Windows 11*') {
        # Variables: Set OS Prefix
        $Os = 'W11'

        # Variables: Set Display Version
        $OsDisplayVersion = $OsRegistryInfo.DisplayVersion

        # Variables: OS Edition
        if ($EditionId -eq 'Enterprise') {
            $Edition = 'ENT'
        }
        if ($EditionId -eq 'IoTEnterprise') {
            $Edition = 'IOT'
        }
        if ($EditionId -eq 'Professional') {
            $Edition = 'PRO'
        }

        # Windows 10: Create Wim File Name string
        $WimFileName = "$Os" + "$Architecture" + '_' + "$Edition" + '_' + "$OsDisplayVersion" + '_' + "$OsLanguage" + '_' + "$OsCurrentBuildNumber" + '.' + "$Ubr" + '_' + "$BuildDate" + '.' + 'wim'
    }

    # Microsoft Windows Server
    if ($MachineOS -like 'Microsoft Windows Server*') {
        # Variables: Set OS Prefix
        $ServerPrefix = 'WS'

        # Variables: Set Windows Server Version
        $WindowsServerVersion = $MachineOS.TrimStart("Microsoft Windows Server")

        # Windows Server: Create Wim File Name string
        $WimFileName = "$ServerPrefix" + "$WindowsServerVersion" + "$Architecture" + '_' + "$OsLanguage" + '_' + "$OsCurrentBuildNumber" + '.' + "$Ubr" + '_' + "$BuildDate" + '.' + 'wim'
    }

}

End {

    # If Debug is true then write WIM file name to host
    if ($Debug) {
        Write-Host "Caption is:         `"$Caption`"" -BackgroundColor 'Green' -ForegroundColor 'Black'
        Write-Host "MachineOS is:       `"$MachineOS`"" -BackgroundColor 'Green' -ForegroundColor 'Black'
        Write-Host "MachineOS is:       `"$EditionId`"" -BackgroundColor 'Green' -ForegroundColor 'Black'
        Write-Host "WIM File Name is:   `"$WimFileName`"" -BackgroundColor 'Green' -ForegroundColor 'Black'
    }

    else {
        # Set MDT Task Sequence Variable to be used to populate 'BackupFile'
        $tsenv:WimFileName = "$WimFileName"
    }

}

It is possible to test the output of the script by copying the script onto a device and running it with the ‘-debug’ switch. This will display the WIM Filename in the PowerShell console so you can check to see if it is correct:

Debug Script Output

/ JC

MCM Software Updates | Load Balancing with Even and Odd Collections

Recently a customer asked me to help BAU Support find a way to reduce the impact of deploying Windows 10 Software Updates (LCU) over their Wireless LAN in a particular building with a large number of clients. The last round of patching had pretty much destroyed their WiFi during the deployment. I decided the first thing to do was to load balance the deployments by devising a way of splitting the clients roughly into two groups.

I created MCM Collections based on Odd and Even numbers i.e. if a device ends in an odd number become a member of one collection and if it ends in an even number it becomes a member of another collection.

To accomplish this I used square brackets to define a range of characters as part of the WQL query for the Collections: One for devices ending in an odd number and one for devices ending in an event number.

This query results in devices ending in odd numbers:

/* Odd Numbers */
select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,
SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,
SMS_R_SYSTEM.ResourceDomainORWorkgroup,
SMS_R_SYSTEM.Client from SMS_R_System
where SMS_R_System.Name like "%[13579]"

And another collection returning only devices ending in even numbers:

/* Even Numbers */
select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,
SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,
SMS_R_SYSTEM.ResourceDomainORWorkgroup,
SMS_R_SYSTEM.Client from SMS_R_System
where SMS_R_System.Name like "%[02468]"

The next issue was that not all client device names ended with a number – some ended with a letter. Fantastic…

To cater for this I divided the alphabet by odd and even letters and added the odd letters to odd query and the even letters to the even query.

The resultant query returned only devices ending in odd numbers or letters:

/* Odd Numbers and Odd Letters */
select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,
SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,
SMS_R_SYSTEM.ResourceDomainORWorkgroup,
SMS_R_SYSTEM.Client from SMS_R_System
where SMS_R_System.Name like "%[13579acegikmoqsuwy]"

And conversely, the following query returned only devices which ended with an even number or letter:

/* Even Numbers and Even Letters */
select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,
SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,
SMS_R_SYSTEM.ResourceDomainORWorkgroup,
SMS_R_SYSTEM.Client from SMS_R_System
where SMS_R_System.Name like "%[02468bdfhjlnprtvxz]"

This isn’t the perfect solution (there won’t be an exact 50% split of devices) but it was good enough for my customer as a tactical solution.

Used in conjunction with MCM Phased Deployments etc. should see a large reduction in the load on the WLAN and allow users to work normally during patching in the future.

/ JC

Testing ConfigMgr packages & applications before adding them into ConfigMgr using PsExec.exe

To test that an application is 99.9% sure to work when deployed via ConfigMgr it is important to initially test installers by running them in the SYSTEM context on a test machine.

Applications and Packages run under the SYSTEM context when deployed via ConfigMgr and can behave differently when compared to running them as a Local Administrator account or a standard user.

Testing them with PsExec (from the Microsoft PSTools suite – part of Microsoft Sysinternals) means that you can be pretty sure that they will work once you’ve added them into ConfigMgr but saves you time before you create the package/application, distribute the content and test in a deployment etc. only to find it fails and have to start over again.

Running the command below from an ‘Administrator’ command prompt will mimic the ConfigMgr deployment by running any commands issued in the resulting Command Prompt as the LOCAL SYSTEM account:

psexec -s -i cmd.exe

You’ll know that the command prompt is running as SYSTEM by running ‘whoami’ as per the screenshot below:

Once tested in this way, you can go ahead and add your package or application into ConfigMgr and be confident that any deployments to clients via Software Distribution or Task Sequence will be successful.

/ JC

WMI/WQL “LIKE” Query Wildcards With Examples

Quick post today.

Standard Windows/DOS wildcards don’t work in WMI “LIKE” queries as they use WQL language instead:

Multiple Characters = "%" (Percentage)
Single Character    = "_" (Underscore)

For reference, the corresponding Windows wildcards are:

Multiple Characters = "*" (Asterisk) 
Single Character    = "?" (Question Mark)

Note: when using wildcards in ConfigMgr Task Sequences pay attention to what is being done. If you’re querying a value from WMI then you should use “%” and “_” as wildcards:

SELECT * FROM Win32_ComputerSystem WHERE Name LIKE 'PC%'
SELECT * FROM Win32_ComputerSystem WHERE Name LIKE 'PC_____'

If you’re querying a Task Sequence variable then the Windows wildcards (“*” and “?” should be used:

OSDComputerName LIKE "PC*"
OSDComputerName LIKE "PC?????"

/ JC

Confirm Service Account Credentials The Easy Way with PowerShell (e.g. MCM Network Access Account)

Sometimes you will have an AD Service Account configured and you might not be sure what the password is – a good example of this that sometimes catches me out is the MCM Network Access Account.

To safely test the account username and password we can use PowerShell with the following simple and safe command:

Start-Process -FilePath winver.exe /c -Credential (Get-Credential)

This will attempt to run “winver.exe” and a prompt will appear asking for credentials:

AccountCredsPrompt

If the account credentials that you enter are not correct you will see the following error:

AccountCredsFail

But if the credentials provided are correct then “winver.exe” will open as expected and no error message will be produced:

AccountCredsSuccess

Simple but effective 🙂

/ JC

Add CMTrace.exe to Computers Being Deployed via Task Sequence

To make sure you have CMTrace.exe available for use on machines that are deployed via ConfigMgr Task Sequences you can add a “Run Command Line” task immediately after the “Apply Operating System Image” that copies the executable from the boot image being used to deploy the OS (CMtrace.exe is included by default ConfigMgr WinPE boot images – WinPE is mapped as X:\ during OSD) and results in it being available once OSD completes:

 cmd /c xcopy X:\SMS\BIN\x64\CMTrace.exe %OSDTargetSystemDrive%\Windows\System32\ /E /H /C /I /Q /Y

This command line will need to be amended in the unlikely scenario (it’s 2017 after all) that you’re deploying a 32-bit Operating System to change the xcopy target path accordingly.

/ JC

Note: This was originally documented on TechNet yonks ago: Link

Use Task Scheduler to Schedule Server Reboot Out of Hours

You may from time to time have a requirement to reboot a server out of hours after implementing a change that requires a restart.

Rather than logging in at Silly O’Clock at night you can use the Windows Task Scheduler to set up a Task to have an unattended reboot occur out of hours.

Open “Task Scheduler” from the Start menu and select “Create New Task“.

Complete the “General” tab by adding the following values for “Name“, “Account” and “Configure for“:

1

By using the “SYSTEM” account we can be sure that the required permissions to reboot/shutdown the computer are present.

On the “Triggers” tab click on “New” and configure a time suitable for your environment. In my example I have chosen a one time event at “22:00:00” as this is deemed out of hours:

2

On the “Actions” tab click on “New” and configure the task as per below:

3

In the “Program/script” field add the word “shutdown“.

In the “Add arguments (optional)” field make sure the following is added:

/r /t 0 /c "Planned Server Reboot via Task Scheduler Task" /f

Click “OK” twice and you’re done.

The command that you have just configured passes the following instructions to the “Shutdown.exe” executable:

  • /r = Reboot
  • /t 0 = waits 0 seconds before restarting
  • /c = comment to be added into the System log in Event Viewer
  • /f = forces the reboot even if users are logged on, programs are open, files are locked etc.

/ JC

Creating Custom WinPE 3.1 Boot Image (For Deploying Windows XP from SCCM 2012 R2) Automated via Batch File

Recently a customer wanted the ability to be able to rebuild Windows XP machines (!) via SCCM 2012 R2 by just adding machines into a rebuild collection.

This doesn’t work out of the box with the version of WinPE that ships with SCCM so to get it to work you need to create a custom Boot image based on WinPE 3.1, add it into ConfigMgr and associate it with the Windows XP Task Sequence – this allows WinPE to pre-stage onto the local disk and for the machine to successfully reboot into it.

The following code can be added into a Batch File and executed as an Administrator to automate the creation of the Boot Image and add the required components.

@echo off

echo:
echo # REMOVE DIRECTORY IF IT EXISTS
echo:

RD C:\TEMP\WinPE\LegacyWinPEx86 /S /Q

echo:
echo # CREATE X86 WINPE FOLDER STRUCTURE
echo:

CALL "C:\Program Files\Windows AIK\Tools\PETools\copype.cmd" x86 C:\TEMP\WinPE\LegacyWinPEx86

echo:
echo # COPY WIM FILE TO ISO\SOURCES DIRECTORY AND RENAME AS BOOT.WIM
echo:

COPY C:\TEMP\WinPE\LegacyWinPEx86\winpe.wim C:\TEMP\WinPE\LegacyWinPEx86\ISO\sources\boot.wim

echo:
echo # MOUNT THE BOOT.WIM FILE IN THE MOUNT DIRECTORY
echo:
Dism /Mount-Wim /WimFile:C:\TEMP\WinPE\LegacyWinPEx86\ISO\sources\boot.wim /index:1 /MountDir:C:\TEMP\WinPE\LegacyWinPEx86\mount

echo:
echo # ADD OPTIONAL COMPONENTS TO WINPE IMAGE
echo:

Dism /image:C:\TEMP\WinPE\LegacyWinPEx86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-wmi.cab"
Dism /image:C:\TEMP\WinPE\LegacyWinPEx86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-scripting.cab"
Dism /image:C:\TEMP\WinPE\LegacyWinPEx86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-wds-tools.cab"
Dism /image:C:\TEMP\WinPE\LegacyWinPEx86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-hta.cab"
Dism /image:C:\TEMP\WinPE\LegacyWinPEx86\mount /Add-Package /PackagePath:"C:\Program Files\Windows AIK\Tools\PETools\x86\WinPE_FPs\winpe-mdac.cab"

echo:
echo # SET SCRATCH SPACE TO 128MB
echo:

Dism /Set-ScratchSpace:128 /Image:C:\TEMP\WinPE\LegacyWinPEx86\mount

echo:
echo # ADD ANY REQUIRED DRIVERS TO THE IMAGE
echo:

Dism /Image:C:\TEMP\WinPE\LegacyWinPEx86\mount /Add-Driver /Driver:C:\TEMP\WinPE\Drivers /Recurse

echo:
echo # UNMOUNT IMAGE AND COMMIT CHANGES
echo:

Dism /Unmount-Wim /MountDir:C:\TEMP\WinPE\LegacyWinPEx86\mount /Commit

/ JC

Log Into Windows Locally Without Entering The Computername Prefix Every Time

If (like me) you need to log in locally to Windows machines quite a lot, it can be an annoyance to have to type in the Computername prefix every time you need to do so e.g “CLIENT1\Administrator”.

Luckily Microsoft have given us a shortcut way of doing this so we can save time. Just substitute the Computername for a “.\”

So “CLIENT1\Administrator” would become “.\Administrator”

Simples.

/ JC

How Many Activations Do I Have Left On My Licence Keys?

To find out this information you’d normally have to go through the pain in the arse that is “telephoning Microsoft”.

Far easier though is to import the keys into the Volume Activation Management Tool (VAMT) and use it to check online with Microsoft over the Interweb.

VAMT is part of the Windows Assessment and Deployment Kit (Windows ADK) and can be downloaded for nothing from:

http://www.microsoft.com/en-gb/download/details.aspx?id=39982

Simply import the relevant keys and use the “Refresh product key data online” to retrieve the number of activations left.

/ JC