Script Holder

Grab Task Sequence XML

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<#
.Synopsis
   Grab the XML component of a Task Sequence and display in Internet Explorer. 
   Version 0.5 - Akin Akintayo

.DESCRIPTION
   Grab the XML component of a Task Sequence ready for use in an XML viewing format.
   The XML file is prepended with an XML stylesheet template snippet.

   If the XML format stylesheet does not exist, it is downloaded from the Internet.

   The ConfigMgr Admin Console must be installed on this computer because related modules are needed.

   If all the prerequistes are met, the Task Sequence data is displayed in Internet Explorer

   The files are placed in the folder defined by the line $Script:OutputFolder = "C:\Repository\TSXMLDOC" within the Get-XMLTemplate function.

   If the tsDocumentorv2.xsl file has already been downloaded, just place it in this folder, so the script doesn't download it again.

.PARAMETER TaskSequence
   Specifies the name of the Task Sequence.
   If the script is run on the command line, enclose the Task Sequence Name in single quotes.
   If run from the PowerShell console, don't use quotes even if the name contains spaces.

.PARAMETER Sitecode
   Specifies the ConfigMgr Sitecode where the Task Sequence is been referenced.

.EXAMPLE
   Get-TaskSequenceXML -TaskSequence 'Task Sequence Name' -Sitecode XXX

#>

[CmdletBinding()]
Param(
  [Parameter(Mandatory=$True,
                Position=1,
                HelpMessage="Enter the Name of the Task Sequence, Use single quotes.")]
                [string]$TaskSequence,
 
   [Parameter(Mandatory=$True,
                HelpMessage="Enter the Site Code of the ConfigMgr Site")]
                [string]$SiteCode
)

# Set Global variables

$Script:OutputFolder = $null
$Script:TSXMLTemplate = $null
$initParams = @{}

Function 
Test-Admin {
    <#
        .SYNOPSIS
            Short function to determine whether the logged-on user is an administrator.

        .EXAMPLE
            Do you honestly need one?  There are no parameters!

        .OUTPUTS
            $true if user is admin.
            $false if user is not an admin.
    #>
    [CmdletBinding()]
    Param()

    $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
    $isAdmin = $currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)

    Return $isAdmin
}

Function
Get-XMLTemplate {
        # The output folder where the XML file will be saved, create the path, if it does not exist
        $Script:OutputFolder = "C:\Repository\TSXMLDOC"
        $Script:TSXMLTemplate = "$($Script:OutputFolder)\tsDocumentorv2.xsl"
        $DownloadURL = "https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/6127/00/00/03/20/49/89/tsDocumentorv2.xsl"

        If(!(Test-Path $Script:TSXMLTemplate))
            {
                If(!(Test-Path $Script:OutputFolder))
                    {
                        New-Item -ItemType Directory -Force -Path $Script:OutputFolder
                    }

                Try 
                    {
                        (New-Object System.Net.WebClient).DownloadFile($DownloadURL, $Script:TSXMLTemplate)
                    }
                Catch
                    {
                            Write-Host "Exception caught: $_"
                            Exit
                    }
            }
}

Function
Import-SCCMModule {
      # Import SCCM PowerShell Module
            If ((Get-Module ConfigurationManager) -eq $null) {
                Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams
            }

}


Function
ConnectToSiteCode {
                
        # Connect to Site Code
        If ((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) 
        {
            $ProviderMachineName = (Get-WmiObject -class SMS_ProviderLocation -Namespace root\SMS).Machine | Select-Object -first 1

            New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
        }
        # Set the current location to be the site code.
        Set-Location "$($SiteCode):\" @initParams

}


Function
Create-TSXMLOutput {
            # Prepend the final output file with the XML Stylesheet header
            $TSXMLSnippet = @('<?xml version="1.0"?>
            <?xml-stylesheet type="text/xsl" href="tsDocumentorv2.xsl" mce_href="tsDocumentorv2.xsl"?>')

            $datestring = (Get-Date).ToString("s").Replace(":", "-")

            # The XML filename concatenated with the current time stamp
            $TSXMLFileName = "$($TaskSequence) - $($datestring).XML"

            # The full path to the Task Sequence XML
            $OutputTSXMLPath = "$($Script:OutputFolder)\$($TSXMLFileName)"

            # Read the Task Sequence and create the XML file
            New-Item -Path $($OutputTSXMLPath) -ItemType File -Value $($TSXMLSnippet)
            (Get-CMTaskSequence | Where-Object {$_.Name -eq "$($TaskSequence)"}).Sequence | Out-File $($OutputTSXMLPath) -Append -Encoding ascii

            # Create an object of the IE application and launch the XML file
            $IE = New-Object -ComObject InternetExplorer.Application

            # Get the XML file and show it in IE
            $IE.Navigate("$($OutputTSXMLPath)")
            $IE.Visible = $True
}

If (Test-Admin) {
        Get-XMLTemplate
        Import-SCCMModule
        ConnectToSiteCode
        Create-TSXMLOutput
        }
Else 
    {
    Write-Host "You can only run this script in Administrator mode, please abort and restart in Admin mode"
    Break
    }

Driver Source replacement



1
Get-WmiObject SMS_Driver -Namespace root\SMS\site_<SITECODE> | Where{$_.ContentSourcePath -like "*<StringToBeReplaced>} | %{$_.contentsourcepath = $_.contentsourcepath -replace "<StringToBeReplaced>", "<ReplacementString>";$_.put()}

Manipulating and export/import CSV file

Export to CSV

For Drivers:

Get-CMDriver | select LocalizedDisplayName, ContentSourcePath, CI_ID | Export-Csv $home\documents\Drivers.csv

For Driver Packages:

Get-CMDriverPackage | select Name, PkgSourcePath, PackageID | Export-Csv $home\documents\DriverPackages.csv

Imports from CSV

For Drivers:

Import-Csv $home\documents\drivers.csv | %{Set-CMDriver -Id $_.CI_ID -DriverSource $_.ContentSourcePath}

For Driver Packages:

Import-Csv $home\Documents\DriverPackages.csv | %{Set-CMDriverPackage -Id $_.PackageID -DriverPackageSource $_.PkgSourcePath}


Replace all drivers


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Set-CMQueryResultMaximum -Maximum 5000

$drivers = get-cmdriver

foreach ($driver in ($drivers)) {

     If ($driver.ContentSourcePath -like "*PackageSource*hp drivers*";){

               $newPath = $driver.ContentSourcePath -replace 'PackageSource\\Drivers\\HP Drivers','DriverPackages\HP'

               Write-host -ForegroundColor Cyan "Changing PkgSourcePath for $($driver.Name)..."

               $newPath

               Set-CMDriver -Id $driver.CI_ID -DriverSource $NewPath

               timeout 5

           }


            If ($driver.ContentSourcePath -like "*PackageSource*dell*"){

                $newPath = $driver.ContentSourcePath -replace 'PackageSource\\Drivers\\Dell Drivers','DriverPackages\Dell'

                Write-host -ForegroundColor Cyan "Changing PkgSourcePath for $($driver.Name)..."

                $newPath

                Set-CMDriver -Id $driver.CI_ID -DriverSource $NewPath

                timeout 5

           }


           if ($driver.ContentSourcePath -like "*PackageSource*sony*"){

                $newPath = $driver.ContentSourcePath -replace 'PackageSource\\Drivers\\Sony Drivers','DriverPackages\Sony'

                Write-host -ForegroundColor Cyan "Changing PkgSourcePath for $($driver.Name)..."

                $newPath

                Set-CMDriver -Id $driver.CI_ID -DriverSource $NewPath

                timeout 5

           }

}


Add Computer to Multiple AD Groups

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#requires -Version 3.0
Param (
    [Parameter(Mandatory,ValueFromPipeline)]
    [String[]]$Groups,
    [switch]$Passthru
)

Begin {
    Try { Import-Module ActiveDirectory -ErrorAction Stop }
    Catch { logit " Unable to load Active Directory module"; Exit }
    $Result = @()
}

Process {
    ForEach ($Group in $Groups)
    {   Try {
            Add-ADGroupMember $Group -Members (Get-ADComputer $env:ComputerName) -ErrorAction Stop
            $Result += [PSCustomObject]@{
                Group = $Group
                AddMembers = $env:ComputerName
            }
        }
        Catch {
            logit "Error adding Computer to $Group because $($Error[0])"
            $Result += [PSCustomObject]@{
                Group = $Group
                AddMembers = $Error[0]
            }
        }
    }
}

End {
    If ($Passthru)
    {   $Result
    }
}

Command line: 

.\Add-MultipleGroups.ps1 -Groups "testgroup1","testgroup2"

Source: https://community.spiceworks.com/topic/459481-adding-users-to-multiple-security-groups-in-ad


Error Handling

Global variable $ErrorActionPreference = 'Stop'

-ErrorAction Stop

-ErrorAction SilentlyContinue

-ErrorAction Ignore

Add Ad Group Member 

Add-ADGroupMember -id <Name of the Group> -Members <SamAccountName$>

Add-ADGroupMember -id <Name of the Group> -members "Distinguished Name"

Add-ADGroupMember -id <Name of the Group> -Members (Get-ADComputer $env:ComputerName)

#Get the content of the file and store it in a variable called $List

$List=Get-Content path\filename

#For each element in the $list, execute the code To add computers into the group

$List | foreach {Add-ADGroupMember -id <Name of the Group> -MEMBERS (Get-ADComputer $_) }

Source: http://c-nergy.be/blog/?p=4221

Add User to Multiple AD Groups

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#requires -Version 3.0
Param (
    [Parameter(Mandatory,ValueFromPipeline)]
    [String[]]$Groups,
    [Parameter(Mandatory)]
    [String[]]$Users,
    [switch]$Passthru
)
Begin {
    Try { Import-Module ActiveDirectory -ErrorAction Stop }
    Catch { Write-Error "Unable to load Active Directory module, is RSAT installed?"; Exit }
    $Result = @()
}
Process {
    ForEach ($Group in $Groups)
    {   Try {
            Add-ADGroupMember $Group -Members $Users -ErrorAction Stop
            $Result += [PSCustomObject]@{
                Group = $Group
                AddMembers = $Users -join ", "
            }
        }
        Catch {
            Write-Error "Error adding members to $Group because $($Error[0])"
            $Result += [PSCustomObject]@{
                Group = $Group
                AddMembers = $Error[0]
            }
        }
    }
}

End {
    If ($Passthru)
    {   $Result
    }
}

Command line: 

.\Add-MultipleGroups.ps1 -Groups "testgroup1","testgroup2" -users user1,user2,user3,user4

PowerShell Credential Management

This example shows how to create a credential object that is identical to the object that Get-Credential returns without prompting the user. This method requires a plain text password, which might violate the security standards in some enterprises.
The first command saves the user account name in the $User parameter. The value must have the "Domain\User" or "ComputerName\User" format.

$User = "Domain01\User01"
The second command uses the ConvertTo-SecureString cmdlet to create a secure string from a plain text password. The command uses the AsPlainText parameter to indicate that the string is plain text and the Force parameter to confirm that you understand the risks of using plain text.

$PWord = ConvertTo-SecureString –String "P@sSwOrd" –AsPlainText -Force
The third command uses the New-Object cmdlet to create a PSCredential object from the values in the $User and $PWord variables.

$Credential = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $User, $PWord

Write ADSI Attribute for AD Computer Object


$strCompFQDN = Get-ADComputer -Filter {Name -eq "$env:ComputerName"} -Properties DistinguishedName
$strForADSI = "LDAP://"+$StrCompFQDN.DistinguishedName
$StrADSIComputer.departmentNumber
$StrADSIComputer.Put("departmentNumber","Devices")
$StrADSIComputer.SetInfo()
$StrADSIComputer.Get("departmentNumber")

$strForADSI = "LDAP://"+$strCompFQDN
$strADSIComputer = [adsi] $strForADSI
$StrADSIComputer.Get("departmentNumber")

ZTI Dump TS Variables

<job id="ZTIConnect">
<script language="VBScript" src="ZTIUtility.vbs"/> 
<script language="VBScript">
   
Set env = CreateObject("Microsoft.SMS.TSEnvironment")    
For each v in env.GetVariables      
oLogging.CreateEntry v & " = " & env(v), LogTypeInfo    
Next
</script>
</job> 

Dump TS Variables

Set env = CreateObject("Microsoft.SMS.TSEnvironment") 
For each v in env.GetVariables    
WScript.Echo v & " = " & env(v) 

Next 


Using PowerShell for TS Variables


If you would prefer to use PowerShell, the same thing can be done with it: 

# Determine where to do the logging $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment $logPath = $tsenv.Value("_SMSTSLogPath") $logFile = "$logPath\$($myInvocation.MyCommand).log"# Start the logging Start-Transcript $logFile
# Write all the variables and their values $tsenv.GetVariables() | % { Write-Host "$_ = $($tsenv.Value($_))" }
# Stop logging Stop-Transcript 

Save that as “DumpVar.ps1” in the MDT “Scripts” folder, and run it using PowerShell.exe (as long as execution of scripts has been enabled):

PowerShell.exe –File "%ScriptRoot%\DumpVar.ps1"


Some Registry Settings

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer]
"ActiveSetupDisabled"=dword:00000000
"ActiveSetupTaskOverride"=dword:00000001
"AsyncRunOnce"=dword:00000001
"AsyncUpdatePCSettings"=dword:00000001
"DisableAppInstallsOnFirstLogon"=dword:00000001
"DisableResolveStoreCategories"=dword:00000001
"DisableUpgradeCleanup"=dword:00000001
"EarlyAppResolverStart"=dword:00000001
"FileOpenDialog"="{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}"
"FSIASleepTimeInMs"=dword:0000ea60
"GlobalFolderSettings"="{EF8AD2D1-AE36-11D1-B2D2-006097DF8C11}"
"IconUnderline"=dword:00000002
"ListViewPopupControl"="{8be9f5ea-e746-4e47-ad57-3fb191ca1eed}"
"LVPopupSearchControl"="{fccf70c8-f4d7-4d8b-8c17-cd6715e37fff}"
"MachineOobeUpdates"=dword:00000001
"NoWaitOnRoamingPayloads"=dword:00000001
"TaskScheduler"="{0f87369f-a4e5-4cfc-bd3e-73e6154572dd}"
"AccessDeniedDialog"="{100B4FC8-74C1-470F-B1B7-DD7B6BAE79BD}"
"SmartScreenEnabled"="RequireAdmin"
"GlobalAssocChangedCounter"=dword:00000002

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System

EnableFirstLogonAnimation DWORD

0 = Disable first sign-in animation

1 = Enable first sign-in animation

http://www.tenforums.com/tutorials/2411-user-first-sign-animation-turn-off-window-10-a.html

Using Powershell to Register a file in the GAC


http://stackoverflow.com/questions/679064/using-powershell-to-register-a-file-in-the-gac

<#.SYNOPSIS Installing Assemblies to Global Assembly Cache (GAC).
DESCRIPTION This script is an alternative to the GACUTIL available in the .NET Framework SDK. 
It will put the specified assembly in the GAC.

.EXAMPLE .\Add-AssemblyToGlobalAssemblyCache.ps1 -AssemblyName C:\Temp\MyWorkflow.dll 

This command will install the file MyWorkflow.dll from the C:\Temp directory in the GAC.

.EXAMPLE Dir C:\MyWorkflowAssemblies | % {$_.Fullname} | .\Add-AssemblyToGlobalAssemblyCache.ps1 

You can also pass the assembly filenames through the pipeline making it easy to install several assemblies in one run. 

The command above will install all assemblies from the directory C:\MyWorkflowAssemblies, run this command -

.PARAMETER AssemblyName Full path of the assembly file
.PARAMETER PassThru If set, script will pass the filename given through the pipeline 
.NOTES April 18, 2012 | Soren Granfeldt (soren@granfeldt.dk) - initial version
.LINK http://blog.goverco.com#>

[CmdletBinding()]
PARAM( [Parameter(Mandatory=$true, ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] 
[ValidateNotNullOrEmpty()] [string] $AssemblyName = "",
[switch]$PassThru)
BEGIN
{ $me = $MyInvocation.MyCommand -Replace '\.ps1#39;, '' Write-Debug "BEGIN: $Me" if ( $null -eq ([AppDomain]::CurrentDomain.GetAssemblies() |? 
{ $_.FullName -eq "System.EnterpriseServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" }) ) 
{ [System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | Out-Null } 

$PublishObject = New-Object System.EnterpriseServices.Internal.Publish}

PROCESS { Write-Debug "PROCESS: $me" 
foreach ($Assembly in $AssemblyName) 
{ if ( -not (Test-Path $Assembly -type Leaf) ) 
{ throw "The assembly '$Assembly' does not exist." }
$LoadedAssembly = [System.Reflection.Assembly]::LoadFile($Assembly)

if ($LoadedAssembly.GetName().GetPublicKey().Length -eq 0) 
{ throw "The assembly '$Assembly' must be strongly signed." } 

Write-Verbose "Installing: $Assembly" $PublishObject.GacInstall($Assembly)

if ($PassThru) 
{ $_ } }}
END

{ Write-Debug "END: $me"}

Add a DLL to the GAC

1. Run the Power Shell console as Administrator.
2. Enter the following PowerShell

Set-location "c:\Folder Path"            
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")            
$publish = New-Object System.EnterpriseServices.Internal.Publish            
$publish.GacInstall("c:\Folder Path\DLL.dll")            
iisreset

Remove DLL to the GAC

1. Run the PowerShell console as Administrator.
2. Enter the following Power Shell
Set-location "c:\Folder Path"            
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")            
$publish = New-Object System.EnterpriseServices.Internal.Publish            
$publish.GacRemove("c:\Folder Path\DLL.dll")            
iisreset




Script to Copy OEM Folders in MDT

<job id="CopyOEM"> <script language="VBScript" src="ZTIDiskUtility.vbs"/> <script language="VBScript" src="ZTIUtility.vbs"/> <script language="VBScript">
' // ***************************************************************************' // ' // File:      CopyOEM.wsf' // ' // Author:    Michael Niehaus' // ' // Version:   1.0' // ' // Purpose:   Copy $OEM$\$1 and $OEM$\$$ files to the current OS.  This script' //            is designed to run in Windows PE right after the "Install OS" ' //            step.' // ' // Usage:     cscript CopyOEM.wsf [/debug:true]' // ' // ***************************************************************************
' ------------- DISCLAIMER ------------------------------------------------- ' This script code is provided as is with no guarantee or waranty concerning ' the usability or impact on systems and may be used, distributed, and ' modified in any way provided the parties agree and acknowledge the ' Microsoft or Microsoft Partners have neither accountabilty or ' responsibility for results produced by use of this script. ' Microsoft will not provide any support through any means. ' ------------- DISCLAIMER ------------------------------------------------- 
Dim sOEM, sDestinationDrive

' Find the OEM path
If oFSO.FolderExists(oEnvironment.Item("DeployRoot") & "\Control\" & oEnvironment.Item("TaskSequenceID") & "\$OEM$") then sOEM = oEnvironment.Item("DeployRoot") & "\Control\" & oEnvironment.Item("TaskSequenceID") & "\$OEM$" ElseIf oFSO.FolderExists(oEnvironment.Item("SourcePath") & "\$OEM$") then sOEM = oEnvironment.Item("SourcePath") & "\$OEM$" ElseIf oFSO.FolderExists(oEnvironment.Item("DeployRoot") & "\" & oEnvironment.Item("Architecture") & "\$OEM$") then sOEM = oEnvironment.Item("DeployRoot") & "\" & oEnvironment.Item("Architecture") & "\$OEM$" ElseIf oFSO.FolderExists(oEnvironment.Item("DeployRoot") & "\$OEM$") then sOEM = oEnvironment.Item("DeployRoot") & "\$OEM$" Else sOEM = "" End if

' Copy the OEM content ($1, $$) to the right place
sDestinationDrive = oUtility.GetOSTargetDriveLetter If oFSO.FolderExists(sOEM & "\$1") then oLogging.CreateEntry "Copying from " & sOEM & "\$1 to " & sDestinationDrive, LogTypeInfo oFSO.CopyFolder sOEM & "\$1", sDestinationDrive, true End if If oFSO.FolderExists(sOEM & "\$$") then oLogging.CreateEntry "Copying from " & sOEM & "\$$ to " & sDestinationDrive & "\Windows", LogTypeInfo oFSO.CopyFolder sOEM & "\$$", sDestinationDrive & "\Windows", true End if
</script></job>

Script to Asset Tag Surface Pro in Task Sequence

https://blogs.technet.microsoft.com/jchalfant/set-surface-pro-3-asset-tag-during-a-configuration-manager-task-sequence/


' ################# DISCLAIMER' Microsoft provides script, macro, and other code examples for illustration only, ' without warranty either expressed or implied, including but not' limited to the implied warranties of merchantability and/or fitness for a particular purpose. ' This script is provided 'as is' and Microsoft does not' guarantee that the following script, macro, or code can be used in all situations.
' Version 1.0 | Initial Release | 4/9/15' Version 1.1 | Added support for Surface Pro 4 and Surface 3 | 12/1/2015
Dim StartupPath, Log, ExitCode ' Set variables
Set oTSEnviroment = CreateObject("Microsoft.SMS.TSEnvironment") ' Create TSEnvironmentSet oTSProgressUI = CreateObject("Microsoft.SMS.TSProgressUI") ' Create TSProgressUISet objFSO = CreateObject("Scripting.FileSystemObject")' Create FileSystemObjectSet objShell = WScript.CreateObject("WScript.Shell") ' Create Wscript.ShellStartupPath = objFSO.GetParentFolderName(wscript.ScriptFullName) ' Get current path of script
Set objWMI = GetObject("winmgmts:\\.\root\CIMV2") ' Connect to WMISet colItems = objWMI.ExecQuery("select * from win32_systemenclosure",,48) ' Query Win32_ComputerSystem Class to receive SMBIOSAssetTag property For Each objItem in colItems    SMBIOS = objItem.SMBIOSAssetTag ' Get SMBIOSAssetTag    If objItem.SMBIOSAssetTag = "" Then SMBIOS = "0" ' Needed to add for Surface Pro 4 and Surface 3 since it's Null not 0Next
If SMBIOS = 0 Then ' If Asset Tag = 0 Prompt to set it oTSProgressUI.CloseProgressDialog ' Close current progress for Computer Name MsgBox Name = inputbox("Please enter AssetTag since it was not detected in the UEFI settings:" ,"Please Enter Asset Tag") ' Prompt Name InstallEXE "AssetTag.exe", "-s " & Name ' Run AssetTag utility Name = Name  If ExitCode = 0 Then ' AssetTag set successfully this will require a restart though ElseIf ExitCode = 775 Then ' Exit code 775 means UEFI firmware needed to be updated to support setting the Asset Tag MsgBox "You need to apply the latest UEFI firmware update to support setting the asset tag" wscript.quit(ExitCode) Else ' Any other exit code set generic error MsgBox "Failed to set the asset tag: valid characters include A-Z, a-z, 0-9, period and hyphen. Error code: " & ExitCode wscript.quit(ExitCode) End IfElse ' If Asset Tag is not 0 move on and set Computer Name with the current Asset Tag Name = SMBIOSEnd If
' oTSEnviroment("OSDComputerName") = Name ' Set OSDComputerName variable
Sub InstallEXE (FileName, Switch) ' Sub To Perform And Monitor EXE Set objExec = objShell.Exec(StartupPath & "\" & FileName & " " & Switch) ' Set command line Do While objExec.Status = 0 ' Loop while running EXE Wscript.Sleep 1000 ' Sleep 1 second Loop ' Loop While Installer Is Running ExitCode = objExec.ExitCode ' Exit CodeEnd Sub