SCCM / SMS and BATCH Scripting

 

SMS/SCCM & Batch Files

 
SMS/SCCM & Batch Files & running .BAT files from UNC in SMS/SCCM – and How to use it whit in OSD and TS

THE PROBLEM

When you run a .BAT file from a UNC path, the first thing you might notice is the warning about "UNC paths are not supported.  Defaulting to the Windows Directory"

All this really means is that the current working folder is your Windows folder, and not the UNC path to where the script is sitting.

The problem with this is that any commands inside your .bat file that try to call or reference a file that you know is in the same UNC path as the .bat file will come up empty because the directory is now Windows.

Notice that the batch files can be used within WinPE and with full OS trough CM client.

Once CM Client execute program form SCCM DP (even though it is set as UNC), it treat is as LOCAL Path (C:\Somthing..)

Also it is important to know it TS are executed within WinPE and if looking for Fix Drive letter, it is different drive later than later in full OS.

 Recommended approach

You can get the folder from where the script is being run by using %~dp0.

When a .BAT file is being executed, %0 evaluates to the full drive, path, filename and extension of the .bat file itself.  %1 refers to the first parameter passed in, %2 to the second parameter and so on.  So if you had a .bat file that looked like this:

SNIPPET #1 - .BAT FILE THAT ECHO'S IT'S OWN FILENAME

@ECHO OFF
ECHO %
0
PAUSE

OUTPUT #1
When you run it you would get the drive, path, filename and extension of the .bat file right there in the output

Now, since we have the full drive and path, let's just use some Windows Shell scripting magic to remove the filename and extension and just return the drive and path:

Here are the commands you can use to modify that %0 (which contains a drive, path, filename and extension)

(taken from the syntax help on the FOR command...run FOR /? from a command prompt, and replace %I with %0)

%~I - expands %I removing any surrounding quotes (")
 %~fI- expands %I to a fully qualified path name
 %~dI- expands %I to a drive letter only
 %~pI- expands %I to a path only
 %~nI- expands %I to a file name only
 %~xI- expands %I to a file extension only
 %~sI- expanded path contains short names only
 %~aI- expands %I to file attributes of file
 %~tI- expands %I to date/time of file
 %~zI- expands %I to size of file
 %~$PATH:I   - searches the directories listed in the PATH environment variable and expands %I to the fully qualified name of the first one found. If the environment variable name is not defined or the file is not found by the search, then this modifier expands to the empty string

The modifiers can be combined to get compound results:

 %~dpI - expands %I to a drive letter and path only
 %~nxI - expands %I to a file name and extension only
 %~fsI - expands %I to a full path name with short names only
 %~dp$PATH:I - searches the directories listed in the PATH
 environment variable for %I and expands to the drive letter and path of the first one found.
 %~ftzaI - expands %I to a DIR like output line

So, let's combine the "d" and "p" to get the drive and path

SNIPPET #2 - .BAT FILE THAT ECHO'S IT'S OWN PATH

@ECHO OFF
ECHO %~dp0
PAUSE

OUTPUT #2
When you run this, you'll get just the drive (in the case of UNC's that's a \\) and path

So, if you have a more complex .BAT file and want to execute any programs that exist in the same folder as the .BAT file sits, you simply need to reference %~dp0.  Perhaps it would be easier to understand if we set a variable called THISDIR...

SNIPPET #3 - .BAT FILE THAT SETS VARIABLE AND CALLS PROGRAMS

@ECHO OFF
SETLOCAL

Set THISDIR = %~dp0

"%THISDIR%file.exe"
"%THISDIR%myFile.exe" /f1"%THISDIR%myINI.ini"

NOTES: You need quotes around your files if there are spaces in the path.

  1. %~dp0 includes the trailing backslash \ so you use %THISDIR%File.exe instead of %THISDIR%\File.exe
  2. SETLOCAL is just something that I use to make sure we're only changing variables in the current script's scope.
  3. Obviously you wouldn't have a PAUSE in a real script that you send to a bunch of machines or it will hang :)

SUMMARY:

  1. When you run a .bat file from a UNC path, the current working directory gets set to c:\Windows.
  2. %0 evaluates to the full drive, path, filename and extension of the .bat file. (%1, %2, etc refer to the parameters)
  3. %~dp0 evaluates to the drive & path of the current .bat file, essentially to what the current working directory WOULD be if UNC paths were supported.
  4. %~dp0 includes the trailing backslash so if you're going to use it to reference files, use
    %~dp0FILENAME.EXE not %~dp0\FILENAME.EXE
     or, if you put %~dp0 into a variable called THISDIR, use
    %THISDIR%FILENAME.EXE not %THISDIR%\FILENAME.EXE
  5. If your path contains spaces, you'll need quotes around things. 
 

An typical example of SMS/SCCM and Batch script:

 
 
@echo off
REM CLM Install for XP
CLS
PUSHD %~dp0
IF EXIST "C:\PROGRAM FILES(x86)" (GOTO :x64) ELSE (GOTO :x86)
:x64
REM CLM Isn't installed on XP 64
GOTO :EOF
:x86
if exist "C:\Program Files\Microsoft Certificate Lifecycle Manager Client\Pin\changepin.cmd" (GOTO :UPDATE) Else (GOTO :INSTALL)

:UPDATE
echo ***UPDATING Microsoft Certificate Lifecycle Manager Client**
(MsiExec.exe /X{1741E3D4-0118-4D1C-9C6E-10AE88E690D9} /qb!-)
(MsiExec.exe /X{1741E3D4-0118-4D1C-9C6E-10AE88E690D8} /qb!-)
(MsiExec.exe /X{C2522022-5137-407E-95B7-536BB35438BF} /qb!-)
(msiexec.EXE /I "CLM.msi" ALLUSERS=1 /qb!-)
GOTO :EOF
:INSTALL
ECHO ***Installing Microsoft Certificate Lifecycle Manager Client***
(msiexec.EXE /I "CLM.msi" ALLUSERS=1 /qb!-)
GOTO :EOF
 
 

An typical example of software app install

 
 
::@echo off
setlocal ENABLEDELAYEDEXPANSION
set LogDir=C:\XME\Base\System
if "%AllUsersProfile%"=="C:\ProgramData" set LogDir=C:\XOM\Logs\System
if not exist %LogDir% md %LogDir%
set LogFile=%LogDir%\FlashPlayer_10.2.159.1.log
if "%AllUsersProfile%"=="C:\ProgramData" (
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{1171A62F-05D2-11D1-83FC-00A0C9089C5A} /grant=SYSTEM=F>>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{1171A62F-05D2-11D1-83FC-00A0C9089C5A} /revoke=Everyone>>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{1171A62F-05D2-11D1-83FC-00A0C9089C5A} /revoke="Anonymous Logon">>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{1171A62F-05D2-11D1-83FC-00A0C9089C5A}\Programmable /grant=SYSTEM=F>>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{1171A62F-05D2-11D1-83FC-00A0C9089C5A}\Programmable /revoke=Everyone>>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{1171A62F-05D2-11D1-83FC-00A0C9089C5A}\Programmable /revoke="Anonymous Logon">>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{D27CDB6E-AE6D-11cf-96B8-444553540000} /revoke=Everyone>>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{D27CDB6E-AE6D-11cf-96B8-444553540000} /revoke="Anonymous Logon">>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{D27CDB70-AE6D-11cf-96B8-444553540000} /revoke=Everyone>>%LogFile%
 "%~dp0subinacl.exe" /regkey HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{D27CDB70-AE6D-11cf-96B8-444553540000} /revoke="Anonymous Logon">>%LogFile%
 "%~dp0uninstall_flash_player.exe" -uninstall
)
:: Uninstall all previous versions that don't share our upgrade code
MsiExec.exe /x {0050A2A6-651B-46A4-9D54-397A71CEBAE5} /quiet /norestart REBOOT=ReallySuppress
MsiExec.exe /x {5BC1A414-8A9B-4FBA-A179-F90629C58662} /quiet /norestart REBOOT=ReallySuppress
MsiExec.exe /x {9327F829-C030-40D3-9B32-0B099956F700} /quiet /norestart REBOOT=ReallySuppress
MsiExec.exe /x {EDB7AFE8-7495-4083-AE43-41C2C4696C72} /quiet /norestart REBOOT=ReallySuppress
:: Uninstall this version
MsiExec.exe /x {716C9261-D85A-4C9F-88E3-B696579B95B0} /quiet /norestart
:: Install this version.  Upgrade code should remain unchanged, thereby causing recent older versions to uninstall automatically
"%~dp0Flash.msi" /q /norestart /l*vx "%LogFile%" ALLUSERS=1
set ExitCode=%ErrorLevel%
if not "%AllUsersProfile%"=="C:\ProgramData" call :FixIE
exit %ExitCode%
 
:FixIE
 regsvr32 /s actxprxy.dll
 regsvr32 /s shdocvw.dll
 regsvr32 /s urlmon.dll
 regsvr32 /s oleaut32.dll
 regsvr32 /s mshtml.dll
 regsvr32 /s browseui.dll
 regsvr32 /s shell32.dll
 regsvr32 /s msjava.dll
 regsvr32 /s dispex.dll
 regsvr32 /s vbscript.dll
 regsvr32 /s scrrun.dll
 for /f "tokens=3" %%i in ('reg query "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v "Version"^|find /i "REG_SZ"') do @set IEVersion=%%i
 if "%IEVersion:~0,1%"=="8" reg add "HKCR\TypeLib\{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}\1.1\0\win32" /ve /t REG_SZ /d %SystemRoot%\system32\ieframe.dll /f
 goto :EOF

 

Scripting for 64-bit machines with SCCM

 Whenever a 32-bit application attempts to access %windir%\System32, the access is redirected to %windir%\SysWOW64 – because the SCCM client is 32-bit. 

Therefore the 32-bit applications can access the native system directory by substituting %windir%\Sysnative for %windir%\System32. WOW64 recognizes Sysnative as a special alias used to indicate that the file system should not redirect to 32 bit sub-system.

Some of MS links about this are here.

 

 
Comments