Monday, 5 December 2016

Using PSEXEC and Batch to remotely patch servers

I have written before about the power of using PSEXEC to patch servers and run a query against them however nothing is more powerful then when you use PSEXEC combination with batch scripts.

So today I'm going to show you how to patch all your servers, first I'm going to assume you have a list of servers and that you are going to run PSEXEC against them.

for /f %i in (c:\list1.txt) do psexec -c -d \\%i c:\batchfile.bat

Seems easy so far right? now in that batch file it's going to have to find out if the server is x86 or x64 it can do this very quickly and easily using the if "%PROCESSOR_ARCHITECTURE%"=="AMD64" this returns a true or false statement value because either you have x64 or you don't and since we don't have 128bit servers yet we won't have to worry about a third option just yet.

So this is what our batch file might look like using else to specify the response if the server is not x64

net use X: \\server\share\
@echo off 
setlocal 
set PATHTOFIXES=x:\update 


if "%PROCESSOR_ARCHITECTURE%"=="AMD64" GOTO X64 else GOTO X86
:X64
:X86
:END


%PATHTOFIXES%\SQLServer2014SP2-KB3171021-x64-ENU.exe /quiet /norestart 

goto END

%PATHTOFIXES%\SQLServer2014SP2-KB3171021-x86-ENU.exe /quiet /norestart 

goto END

net use x: /d


Now you might be thinking this is great and can now use this to patch my 32bit and 64bit windows, and you'd be right you can, however, since more than 90 percent of use have to work with more than one version of windows you'll quickly realise this solves only half the problem as how do you patch windows 2008 and 2012 in the same file right?

Well not to worry we have a way around that as well, all we have to do is find the OS version and then knowing what that version is pass it to the correct line in the batch file.
For version numbers, you can get this from the Microsoft pages https://msdn.microsoft.com/en-us/library/ms724832(VS.85).aspx

So here is a simple example, I know that version 6.3 is Windows 2012R2 so I can run that and get either a yes or no value if yes do this if not continue.

ver | findstr /i "6\.3\." > nul
if %ERRORLEVEL% EQU 0 (
GOTO W2K12R2 )

this works great but can lead to really long scripts when using more than two or three OS version, as you can imagine that's a lot of typing for simple get version.  So a quicker version is to create one check that can run against all the version,

echo off
for /f "tokens=4-5 delims=. " %%i in ('ver') do set VERSION=%%i.%%j
if "%version%" == "10.0" echo Windows Server 2016
if "%version%" == "6.3" echo Windows Windows 2012R2
if "%version%" == "6.2" echo Windows Windows 2012
if "%version%" == "6.1" echo Windows Windows 2008R2
if "%version%" == "6.0" echo Windows Windows 2008

So now we can determine the windows version we can use that without is true or false x64 statement and create simple patching, I won't lie to you this will still be a big batch file however you can make it easy to read by filling up the empty space with comments.

Remember that for every OS you will have two version x86 and x64 so the more version of windows the bigger the batch file will be.

net use X: \\server\share\
@echo off 
setlocal 
set PATHTOFIXES=x:\update 

for /f "tokens=4-5 delims=. " %%i in ('ver') do set VERSION=%%i.%%j
if "%version%" == "10.0" GOTO W2K16
if "%version%" == "6.3" GOTO W2K12R2
if "%version%" == "6.2" GOTO W2K12
if "%version%" == "6.1" GOTO W2K8R2
if "%version%" == "6.0" GOTO W2K8

#WINDOWS 2008 PATCHING GOES HERE
:W2K8
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" GOTO W2K8X64 else GOTO W2K8X86

#Patches for windows 2008 x64
:W2K8X64
%PATHTOFIXES%\Windows2008-KB######-x64-LLL.exe /quiet /norestart 
GOTO END

#Patches for windows 2008 x86
:W2K8X86
%PATHTOFIXES%\Windows2008-KB######-x86-LLL.exe /quiet /norestart 
GOTO END


#WINDOWS 2008R2 PATCHING GOES HERE
:W2K8R2
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" GOTO W2K8R2X64 else GOTO W2K8R2X86

#Patches for windows 2008R2 x64
:W2K8R2X64
%PATHTOFIXES%\Windows2008R2-KB######-x64-LLL.exe /quiet /norestart 
GOTO END

#Patches for windows 2008R2 x86
:W2K8R2X86
%PATHTOFIXES%\Windows2008R2-KB######-x86-LLL.exe /quiet /norestart 
GOTO END


#WINDOWS 20012 PATCHING GOES HERE
:W2K12
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" GOTO W2K12X64 else GOTO W2K12X86

#Patches for windows 2012 x64
:W2K12X64
%PATHTOFIXES%\Windows2012-KB######-x64-LLL.exe /quiet /norestart 
GOTO END

#Patches for windows 2012 x86
:W2K12X86
%PATHTOFIXES%\Windows2012-KB######-x86-LLL.exe /quiet /norestart 
GOTO END


#WINDOWS 20012R2 PATCHING GOES HERE
:W2K12R2
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" GOTO W2K12R2X64 else GOTO W2K12R2X86

#Patches for windows 2012R2 x64
:W2K12R2X64
%PATHTOFIXES%\Windows2012R2-KB######-x64-LLL.exe /quiet /norestart 
GOTO END

#Patches for windows 2012R2 x86
:W2K12R2X86
%PATHTOFIXES%\Windows2012R2-KB######-x86-LLL.exe /quiet /norestart 
GOTO END


:W2K16
echo OS = Windows 2016 I don't have patches for that
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" GOTO W2K16X64 else GOTO W2K16X86

:W2K16X64
echo I wish I had patches for that :)
GOTO END

:W2K16X86
echo still don't have patches for that
GOTO END

:END
net use x: /d

As you can see that can be quite large and that's without putting each and every patch that you'd need to add to the list, however if you are doing this once a month adding the patch names to this batch file is going to be allot easier than creating lists by OS and then lists by processor architecture.

So how could we improve on this? well how about having a dynamic list of patches that will get created every time the batch file runs, how this can work as long as you maintain a folder structure for the patches for example \\server\share\windows2012\x64 and all the x64 patches are under that folder.

We could use a dir /b *.exe command to grab all the exe files and run them like so.
chdir /d x:\windows2012\x64
dir /b *.exe >c:\install.txt
for /f %i in (c:\install.txt) do %i /quiet /norestart 
del c:\install.txt

The result of this would be four lines per option, however, you would not need to change the batch file only add the downloaded patches to the folders on the share.

No comments: