Powershell script for Windows Activation using /fta Token Auth via Smart Card

I have frankensteined a script to handle invoking the slmgr.vbs to perform a Windows Activation via user select Smart Card token.  I have left the portions credited to the original programmer but suspect that the method used for parsing arguments is not properly passing the thumbprint information.  Any insight anyone can offer to help me isolate the issue is greatly appreciated.  When executed I am seeing the following:

PS C:\WINDOWS\system32> C:\Users\Administrator\Desktop\DeployRimpacBuild\Scripts\02-TokenActivateWindows10.ps1
Activating using the following Thumbprint: 26EBD904347CCF547A82721C920ED662BA61E9DD
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

Error: option fta needs <Certificate Thumbprint> [<PIN>]
Windows Software Licensing Management Tool
Usage: slmgr.vbs...

My script code is as follows:

#Author: WO1 Kevin Shultz
#Command: 351st CACOM
#Date: 06MAY2018
#Description: Preps Windows 10 AGM for RIMPAC 2018 Mission Laptops
#             Configures Policy, User Interface, User Account Creation, Windows and Office Activation

#requires -Version 2
Function Invoke-VBScript {
       Run VBScript from PowerShell
       Used to invoke VBScript from PowerShell

       Will run the VBScript in a separate job using cscript.exe
       Path to VBScript.
       Accepts relative or absolute path.
    .PARAMETER Argument
       Arguments to pass to VBScript
       Wait for VBScript to finish  
       Invoke-VBScript -Path '.\VBScript1.vbs' -Arguments '"MyFirstArgument"', '"MySecondArgument"' -Wait
       Run VBScript1.vbs using cscript and wait for the script to complete.
       Displays progressbar while waiting.
       Returns script output as single string.
       '.\VBScript1.vbs', '.\VBScript2.vbs' | Invoke-VBScript -Arguments '"MyArgument"'
       Starts both VBScript1.vbs and VBScript2.vbs in separate jobs simultaneously.
       Both scripts will be run using the same arguments.
       Returns job items.
       [PSCustomObject]@{Path='.\VBScript1.vbs';Arguments='"Script1"'},[PSCustomObject]@{Path='.\VBScript2.vbs';Arguments='"Script2"'} | Invoke-VBScript -Wait -Verbose
       Runs two scripts after each other, waiting to one to complete
       before starting next.
       Each script will run with different parameters.
       Displays progressbar while waiting.
       Returns script output in one single string per script.
       Written by Simon Wåhlin
        [ValidateScript({if(Test-Path $_){$true}else{Throw "Could not find script: [$_]"}})]


        Write-Verbose -Message 'Locating cscript.exe'
        $cscriptpath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\cscript.exe'
        if(-Not(Test-Path -Path $cscriptpath))
            Throw 'cscript.exe not found.'
        Write-Verbose -Message ('cscript.exe found in: {0}' -f $cscriptpath)
            $ResolvedPath = Resolve-Path -Path $Path
            Write-Verbose -Message ('Processing script: {0}' -f $ResolvedPath)
                $ScriptBlock = [scriptblock]::Create(('& "{0}" "{1}" "{2}"' -f $cscriptpath, $ResolvedPath,($Argument -join '" "')))
                $ScriptBlock = $ScriptBlock = [scriptblock]::Create(('& "{0}" "{1}"' -f $cscriptpath, $ResolvedPath))
            Write-Verbose -Message 'Starting script'
            if($PSCmdlet.ShouldProcess($ResolvedPath,'Invoke script'))
                $Job = Start-Job -ScriptBlock $ScriptBlock
                    $Activity = 'Waiting for script to complete: {0}' -f $ResolvedPath
                    Write-Progress -Activity $Activity -Id 1
                    $i = 1
                    While($Job.State -eq 'Running')
                        $WaitTime = (Get-Date) - $Job.PSBeginTime
                        Write-Progress -Activity $Activity -Status "Waited for $($WaitTime.TotalSeconds -as [int]) seconds." -Id 1 -PercentComplete ($i%100)
                        Start-Sleep -Seconds 1
                    Write-Progress -Activity $Activity -Status 'Waiting' -Id 1 -Completed
                    $Result = Foreach($JobInstance in ($Job,$Job.ChildJobs))
                        if($JobInstance.Error -ne $null)
                            Throw $JobInstance.Error.Exception.Message
                    Write-Output -InputObject ($Result -join "`n")
                    Remove-Job -Job $Job -Force -ErrorAction SilentlyContinue
                    Write-Output -InputObject $Job
            Write-Verbose -Message 'Finished processing script'

#Enable Bypass for overriding policies to execute VBS, etc...
Set-ExecutionPolicy Bypass

$SCSerials = certutil -scinfo -silent | Where{$_ -match 'Serial Number: (\S+)'} | ForEach {$Matches[1]}
$SelectedThumb = Get-ChildItem Cert:\CurrentUser\my | Where{$_.SerialNumber -in $SCSerials} | Select Subject,Issuer,NotBefore,NotAfter,Thumbprint | Out-GridView -Title 'Select a smartcard certificate.' -OutputMode Single |% Thumbprint
$UserCert = Get-Item Cert:\CurrentUser\My\$SelectedThumb
$CertThumbPrint = $UserCert.Thumbprint

$VBPath = 'C:\Windows\System32\slmgr.vbs'

Write-Host "Activating using the following Thumbprint: $CertThumbPrint" -ForegroundColor Green

#Run SLMGR.VBS to force token activation of Windows 10
Invoke-VBScript -Path $VBPath -Argument '"/fta $CertThumbPrint"' -Wait

I have tried passing the /fta and thumbprint as a single argument, multiple arguments, etc...  All to no avail.  Thank you in advance for your help.

0 Comments   [ + ] Show comments

Answers (1)

Posted by: captain_planet 4 years ago
Black Belt
I still always forget how to embed code on this forum....in any case:

Try changing this:
Invoke-VBScript -Path $VBPath -Argument '"/fta $CertThumbPrint"' -Wait

To this:
Invoke-VBScript -Path $VBPath -Argument @("/fta",$CertThumbPrint) -Wait

'Argument' (not 'Arguments' as in the usage comments for the function) is an array of strings.  The VBScript engine will see /fta as being one argument, and the thumbprint as being the other.  In your example you pass them both as one argument.
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ