Get Computer Name from ConfigMgr AdminService in WinPE

Got a question on Twitter yesterday on how to send a computer name to the MDT Monitoring Service really early in the OSD process. In fact even before the TS Environment is initialized and any ConfigMgr variables are being read. The scenario was basically that they wanted to see the real computer name in the Deployment Workbench Monitoring node instead of the temporary MININT-ABCDEF type name that WinPE sets.

The challenge is: When starting DaRT before the TS Environment itself, for example to provide the PXE password remotely, the client don't yet know its real computer name even when prestaged in ConfigMgr. So the machine need a way to look it up without access to the TS Environment. A perfectly good candidate for a custom web service, or why not using the native AdminService in ConfigMgr.

Note: This is obviously a bit of an odd case, but if you think about it, there are plenty of other information you can ask for, and even set, in ConfigMgr via its AdminService. You can info about applications, packages, users, and much more…

Monitoring node in Deployment Workbench showing the computer name.

Server Side Prerequisites

On my ConfigMgr server, I did the following:

  • I made sure the ConfigMgr AdminService was operational
  • I granted the service account (VIAMONSTRA\CM_WS) the Read-only Analyst role.
  • I prestaged a computer (STO-W10PEER-001), using its MAC Address
STO-W10PEER-001 prestaged with its MAC Address

The hack (I mean the script)

This example script connects to the ConfigMgr AdminService, and looks up the computer name based on the client Mac Address. Then the script launches DART, and send the computer name to the MDT Monitoring Service. In this example I assume you have already setup the DART integration per this post: https://www.deploymentresearch.com/adding-dart-to-configmgr-boot-images-and-starting-it-earlier-than-early/

Credits: Big thanks to @NickolajA and @MoDaly_IT. I maaaaaay have borrowed the AdminService Try / Catch logic from their Invoke-CMApplyDriverPackage.ps1 script 🙂

Note: To have your boot image launch this script instead of the EnableDart.wsf, copy the StartDart.ps1 script to Deploy\Scripts and change the command line in the Unattend.xml file to:
PowerShell -ExecutionPolicy Bypass -File X:\Deploy\Scripts\StartDart.ps1

WARNING: This is just an example script, for security reason you may want to ask for username and password instead of providing it in the script. Normally you can use task sequence variables to make it a bit harder to find them, but in this specific scenario there is no task sequence environment loaded yet.

# Add some basic logging, feel free to replace with any "real" ConfigMgr loogging function
$Logfile = "$env:SystemDrive\Windows\Temp\StartDart.log"

# Delete any existing logfile if it exists
If (Test-Path $Logfile){Remove-Item $Logfile -Force -ErrorAction SilentlyContinue -Confirm:$false}

Function Write-Log{
	param (
    [Parameter(Mandatory = $true)]
    [string]$Message
   )

   $TimeGenerated = $(Get-Date -UFormat "%D %T")
   $Line = "$TimeGenerated : $Message"
   Add-Content -Value $Line -Path $LogFile -Encoding Ascii

}

# Get the Mac Address
$NetworkAdapters = Get-CimInstance -Namespace "root\cimv2" -Class Win32_NetworkAdapterConfiguration -Filter `
    "NOT MacAddress LIKE '' and  `
    NOT Description LIKE '%miniport%'" 
$FirstWiredMacAddress = ($NetworkAdapters | Select -First 1).MacAddress
Write-Log "Mac Address found was $FirstWiredMacAddress"

#$FirstWiredMacAddress = "00:15:5D:E1:01:01"

# Set Credentials
$UserName = "VIAMONSTRA\CM_WS"
$Password = "[email protected]"
$EncryptedPassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($UserName, $EncryptedPassword)

# Call the AdminService, request Computer Name
# Try / Catch logic borrowed from Invoke-CMApplyDriverPackage.ps1 developed by @NickolajA and @MoDaly_IT
$SiteServer = "cm01.corp.viamonstra.com"
Write-Log "About to connect to AdminService on $SiteServer as $UserName"

try {
    $ComputerName = ((Invoke-RestMethod "https://$SiteServer/AdminService/V1.0/Device" -Credential $Credential -ErrorAction Stop).value | 
        where-object{$_.MacAddress -eq $FirstWiredMacAddress}).Name
}
catch [System.Security.Authentication.AuthenticationException] {

	Write-Log "The remote AdminService endpoint certificate is invalid according to the validation procedure. Error message: $($PSItem.Exception.Message)"
	Write-Log "Will attempt to set the current session to ignore self-signed certificates and retry AdminService endpoint connection"
					
	# Attempt to ignore self-signed certificate binding for AdminService
	# Convert encoded base64 string for ignore self-signed certificate validation functionality
	$CertificationValidationCallbackEncoded = "DQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0AOwANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB1AHMAaQBuAGcAIABTAHkAcwB0AGUAbQAuAE4AZQB0ADsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQBjAHUAcgBpAHQAeQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4AUwBlAGMAdQByAGkAdAB5AC4AQwByAHkAcAB0AG8AZwByAGEAcABoAHkALgBYADUAMAA5AEMAZQByAHQAaQBmAGkAYwBhAHQAZQBzADsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAcAB1AGIAbABpAGMAIABjAGwAYQBzAHMAIABTAGUAcgB2AGUAcgBDAGUAcgB0AGkAZgBpAGMAYQB0AGUAVgBhAGwAaQBkAGEAdABpAG8AbgBDAGEAbABsAGIAYQBjAGsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAewANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHAAdQBiAGwAaQBjACAAcwB0AGEAdABpAGMAIAB2AG8AaQBkACAASQBnAG4AbwByAGUAKAApAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAewANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAaQBmACgAUwBlAHIAdgBpAGMAZQBQAG8AaQBuAHQATQBhAG4AYQBnAGUAcgAuAFMAZQByAHYAZQByAEMAZQByAHQAaQBmAGkAYwBhAHQAZQBWAGEAbABpAGQAYQB0AGkAbwBuAEMAYQBsAGwAYgBhAGMAawAgAD0APQBuAHUAbABsACkADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAUwBlAHIAdgBpAGMAZQBQAG8AaQBuAHQATQBhAG4AYQBnAGUAcgAuAFMAZQByAHYAZQByAEMAZQByAHQAaQBmAGkAYwBhAHQAZQBWAGEAbABpAGQAYQB0AGkAbwBuAEMAYQBsAGwAYgBhAGMAawAgACsAPQAgAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAZABlAGwAZQBnAGEAdABlAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAATwBiAGoAZQBjAHQAIABvAGIAagAsACAADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAFgANQAwADkAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBlAHIAdABpAGYAaQBjAGEAdABlACwAIAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAWAA1ADAAOQBDAGgAYQBpAG4AIABjAGgAYQBpAG4ALAAgAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIABTAHMAbABQAG8AbABpAGMAeQBFAHIAcgBvAHIAcwAgAGUAcgByAG8AcgBzAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKQANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHIAZQB0AHUAcgBuACAAdAByAHUAZQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAfQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB9AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAfQANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB9AA0ACgAgACAAIAAgACAAIAAgACAA"
	$CertificationValidationCallback = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($CertificationValidationCallbackEncoded))
					
	# Load required type definition to be able to ignore self-signed certificate to circumvent issues with AdminService running with ConfigMgr self-signed certificate binding
	Add-Type -TypeDefinition $CertificationValidationCallback
	[ServerCertificateValidationCallback]::Ignore()
					
	try {
		# Call AdminService endpoint to retrieve package data
		$ComputerName = ((Invoke-RestMethod "https://$SiteServer/AdminService/V1.0/Device" -Credential $Credential -ErrorAction Stop).value | 
            where-object{$_.MacAddress -eq $FirstWiredMacAddress}).Name
	}
	catch [System.Exception] {
        Write-Log "Failed to retrieve computer name from AdminService. Error message: $($PSItem.Exception.Message)" 
		# Throw terminating error
		$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
		$PSCmdlet.ThrowTerminatingError($ErrorRecord)
	}
}
catch {
    Write-Log "Failed to retrieve computer name from AdminService. Error message: $($PSItem.Exception.Message)" 
	# Throw terminating error
	$ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty)
	$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}

Write-Log "Computer name from AdminService is $ComputerName"
	
# Start the DART Script with OSDComputerName parameter
$MDTMonitorServer = "cm01.corp.viamonstra.com"
$Argument = "X:\Deploy\Scripts\EnableDart.wsf /EventService:http://$MDTMonitorServer`:9800 /_SMSTSCurrentActionName:`"Booted into WinPE`" /OSDComputerName:$ComputerName"
Write-Log "About to launch EnableDart.wsf script, connecting to monitor service at $MDTMonitorServer"
Write-Log "Check the X:\MININT\SMSOSD\SMSLOGS\EnableDart.log for details on that script."
$DartProcess = Start-Process -FilePath wscript.exe -ArgumentList $Argument -NoNewWindow -PassThru

# Wait five seconds to allow DART to initialize
Start-Sleep -Seconds 5
About the author

Johan Arwidmark

5 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

>