Solved

Upgrading normal.dotm in a mixed environment

Posted on 2011-03-24
17
2,772 Views
Last Modified: 2012-05-11
I am putt ing challenge out there.

Environment: 2K AD, XP and Windows 7

Problem: I would greatly appreciate it, if someone could assist me with creating a script to
copy the normal.dotm file from a network share, copy it to a temp directory on the users
local computer. The script would then need to look to see if the
normal.dotm file exists in either of these two locations :-

FOR XP
C:\Documents and Settings\UserName\Application Data\Microsoft\Templates

FOR WINDOWS 7
AppData\Roaming\Microsoft\Templates

If normal.dotm exists in either of those locations it would need to be renamed to normal.bak and then
copy the new file to either location. I was hoping to acheive this without using a login script. I was
hoping that That script would reference a text file with a list of the computers that the file has to
be copied too. The idea was to run it as a scheduled task and have the script log to either a
success.txt or failed.txt depending on the returned result. Could anyone please help me with this.

*** I can't use powershell as it doesn't exist within the domain***

Thanks very much ;)
0
Comment
Question by:MuddyOz
  • 8
  • 7
  • 2
17 Comments
 
LVL 5

Accepted Solution

by:
xylog earned 250 total points
ID: 35212373
for /f %%i in (list-of-computers.txt) do call goreplace %%i
goto :EOF

:goreplace
if exist "\\%1\c$\documents and settings" for /f  %%u in ('dir "\\%1\c$\documents and settings\" /ad /b') do if exist "\\%1\c$\Documents and Settings\%%u\Application Data\Microsoft\Templates\normal.dotm" ren "\\%1\c$\Documents and Settings\%%u\Application Data\Microsoft\Templates\normal.dotm" normal.bak && copy \\server\share\normal.dorm "\\%1\c$\Documents and Settings\%%u\Application Data\Microsoft\Templates\normal.dotm"

if exist "\\%1\c$\users" for /f "tokens=*" %%u in ('dir "\\%1\c$\users\" /ad  /b' ) do if exist "\\%1\c$\users\%%u\AppData\Roaming\Microsoft\Templates\normal.dotm" ren "\\%1\c$\users\%%u\AppData\Roaming\Microsoft\Templates\normal.dotm" normal.bak && copy \\server\share\normal.dorm "\\%1\c$\user\%%u\AppData\Roaming\Microsoft\Templates\normal.dotm"



0
 
LVL 65

Assisted Solution

by:RobSampson
RobSampson earned 250 total points
ID: 35212467
Hi, try this.  We use this to copy a new version of the Normal.dotm template if we change it later, based on the modified date of the file.  It does need to be run as a logon script through (or manually by each user), and it doesn't log anything.

Regards,

Rob.
Set objShell = CreateObject("WScript.Shell")
strSource = "\\server\share\newtemplate\normal.dotm"
strDestination = objShell.ExpandEnvironmentStrings("%APPDATA%") & "\Microsoft\Templates"

If Right(strDestination, 1) = "\" Then strDestination = Left(strDestination, Len(strDestination) - 1)
strOldTemplates = ""
bool2007TemplateExists = False
' This section renames any Word 2000 templates from .dot to .dot_bak
For Each objFile In objFSO.GetFolder(strDestination).Files
	If LCase(objFile.Name) = "normal.dotm" Then bool2007TemplateExists = True
	If Right(LCase(objFile.Name), 4) = ".dot" Then
		If strOldTemplates = "" Then
			strOldTemplates = objFile.Path
		Else
			strOldTemplates = strOldTemplates & ";" & objFile.Path
		End If
	End If
Next
arrOldTemplates = Split(strOldTemplates, ";")
For Each strTemplatePath In arrOldTemplates
	If objFSO.FileExists(strTemplatePath & "_bak") = True Then objFSO.DeleteFile strTemplatePath & "_bak"
	objFSO.MoveFile strTemplatePath, strTemplatePath & "_bak"
Next

' This section will copy the template if it doesn't exist in the destination
If bool2007TemplateExists = False Then
	If objFSO.FileExists(strSource) = True Then objFSO.CopyFile strSource, strDestination & "\", True
Else
	' This can control the ability to copy a new version of the normal template to each users' templates folder.
	' Set boolCopyNewNormal to False to prevent copying a new version (based on modified date)
	boolCopyNewNormal = True
	If boolCopyNewNormal = True Then
		If objFSO.FileExists(strSource) = True Then
			If CDate(objFSO.GetFile(strSource).DateLastModified) > CDate(objFSO.GetFile(strDestination & "\Normal.dotm").DateLastModified) Then
				intBkpNum = 1
				While objFSO.FileExists(strDestination & "\Normal.dotm_bak" & intBkpNum) = True
					intBkpNum = intBkpNum + 1
				Wend
				objFSO.MoveFile strDestination & "\Normal.dotm", strDestination & "\Normal.dotm_bak" & intBkpNum
				objFSO.CopyFile strSource, strDestination & "\", True
			End If
		End If
	End If
End If

Open in new window

0
 

Author Comment

by:MuddyOz
ID: 35212724
Guys,

Thanks a bunch for your help. I am off work today but when I return I will test and report back. Thanks very much for the prompt reply.
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
LVL 5

Expert Comment

by:xylog
ID: 35215286
Missing a colon in the first line, should be:

for /f %%i in (list-of-computers.txt) do call :goreplace %%i

0
 

Author Comment

by:MuddyOz
ID: 35220447
xyloh and ROb,

How could we get a pass of fail result to a txt file when it runs? Could you please help?

Awesome job, Guys!

Muddy
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 35236574
In my code, to record pass and fail (only when actually trying to copy the file if a new one was detected), use this code.

Regards,

Rob.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objNetwork = CreateObject("WScript.Network")
strSource = "\\server\share\newtemplate\normal.dotm"
strSuccess = "\\server\share\newtemplate\success.txt"
strFail = "\\server\share\newtemplate\fail.txt"
strDestination = objShell.ExpandEnvironmentStrings("%APPDATA%") & "\Microsoft\Templates"

If Right(strDestination, 1) = "\" Then strDestination = Left(strDestination, Len(strDestination) - 1)
strOldTemplates = ""
bool2007TemplateExists = False
' This section renames any Word 2000 templates from .dot to .dot_bak
For Each objFile In objFSO.GetFolder(strDestination).Files
	If LCase(objFile.Name) = "normal.dotm" Then bool2007TemplateExists = True
	If Right(LCase(objFile.Name), 4) = ".dot" Then
		If strOldTemplates = "" Then
			strOldTemplates = objFile.Path
		Else
			strOldTemplates = strOldTemplates & ";" & objFile.Path
		End If
	End If
Next
arrOldTemplates = Split(strOldTemplates, ";")
For Each strTemplatePath In arrOldTemplates
	If objFSO.FileExists(strTemplatePath & "_bak") = True Then objFSO.DeleteFile strTemplatePath & "_bak"
	objFSO.MoveFile strTemplatePath, strTemplatePath & "_bak"
Next

' This section will copy the template if it doesn't exist in the destination
If bool2007TemplateExists = False Then
	If objFSO.FileExists(strSource) = True Then
		On Error Resume Next
		objFSO.CopyFile strSource, strDestination & "\", True
		If Err.Number = 0 Then
			strCopyError = ""
		Else
			strCopyError = "Error " & Err.Number & ": " & Err.Description
		End If
		Err.Clear
		On Error GoTo 0
	End If
Else
	' This can control the ability to copy a new version of the normal template to each users' templates folder.
	' Set boolCopyNewNormal to False to prevent copying a new version (based on modified date)
	boolCopyNewNormal = True
	If boolCopyNewNormal = True Then
		If objFSO.FileExists(strSource) = True Then
			If CDate(objFSO.GetFile(strSource).DateLastModified) > CDate(objFSO.GetFile(strDestination & "\Normal.dotm").DateLastModified) Then
				intBkpNum = 1
				While objFSO.FileExists(strDestination & "\Normal.dotm_bak" & intBkpNum) = True
					intBkpNum = intBkpNum + 1
				Wend
				On Error Resume Next
				objFSO.MoveFile strDestination & "\Normal.dotm", strDestination & "\Normal.dotm_bak" & intBkpNum
				objFSO.CopyFile strSource, strDestination & "\", True
				If Err.Number = 0 Then
					strCopyError = ""
				Else
					strCopyError = "Error " & Err.Number & ": " & Err.Description
				End If
				Err.Clear
				On Error GoTo 0
			End If
		End If
	End If
End If

If strCopyError = "" Then
	Set objResult = objFSO.OpenTextFile(strSuccess, 8, True)
	objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName
	objResult.Close
	Set objResult = Nothing
Else
	Set objResult = objFSO.OpenTextFile(strFail, 8, True)
	objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName & " - " & strCopyError
	objResult.Close
	Set objResult = Nothing
End If

Open in new window

0
 

Author Comment

by:MuddyOz
ID: 35339396
Hey Rob,

That script works perfectly mate Well done. Is there anyway that we can get it to do this to a list of computers supplied in a text file? The problem is that I am having is that, there are terminal servers (old 2k) that the application data folder doesn't exist and hence pops an error box up at the user.

Thanksmate.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 35339405
Is it easier to specify computers that it *shouldn't* run on?  Or, is it easier to just do nothing if the strDestination folder doesn't exist, like so:

Rob.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objNetwork = CreateObject("WScript.Network")
strSource = "\\server\share\newtemplate\normal.dotm"
strSuccess = "\\server\share\newtemplate\success.txt"
strFail = "\\server\share\newtemplate\fail.txt"
strDestination = objShell.ExpandEnvironmentStrings("%APPDATA%") & "\Microsoft\Templates"

If objFSO.FolderExists(strDestination) = True Then
	If Right(strDestination, 1) = "\" Then strDestination = Left(strDestination, Len(strDestination) - 1)
	strOldTemplates = ""
	bool2007TemplateExists = False
	' This section renames any Word 2000 templates from .dot to .dot_bak
	For Each objFile In objFSO.GetFolder(strDestination).Files
		If LCase(objFile.Name) = "normal.dotm" Then bool2007TemplateExists = True
		If Right(LCase(objFile.Name), 4) = ".dot" Then
			If strOldTemplates = "" Then
				strOldTemplates = objFile.Path
			Else
				strOldTemplates = strOldTemplates & ";" & objFile.Path
			End If
		End If
	Next
	arrOldTemplates = Split(strOldTemplates, ";")
	For Each strTemplatePath In arrOldTemplates
		If objFSO.FileExists(strTemplatePath & "_bak") = True Then objFSO.DeleteFile strTemplatePath & "_bak"
		objFSO.MoveFile strTemplatePath, strTemplatePath & "_bak"
	Next
	
	' This section will copy the template if it doesn't exist in the destination
	If bool2007TemplateExists = False Then
		If objFSO.FileExists(strSource) = True Then
			On Error Resume Next
			objFSO.CopyFile strSource, strDestination & "\", True
			If Err.Number = 0 Then
				strCopyError = ""
			Else
				strCopyError = "Error " & Err.Number & ": " & Err.Description
			End If
			Err.Clear
			On Error GoTo 0
		End If
	Else
		' This can control the ability to copy a new version of the normal template to each users' templates folder.
		' Set boolCopyNewNormal to False to prevent copying a new version (based on modified date)
		boolCopyNewNormal = True
		If boolCopyNewNormal = True Then
			If objFSO.FileExists(strSource) = True Then
				If CDate(objFSO.GetFile(strSource).DateLastModified) > CDate(objFSO.GetFile(strDestination & "\Normal.dotm").DateLastModified) Then
					intBkpNum = 1
					While objFSO.FileExists(strDestination & "\Normal.dotm_bak" & intBkpNum) = True
						intBkpNum = intBkpNum + 1
					Wend
					On Error Resume Next
					objFSO.MoveFile strDestination & "\Normal.dotm", strDestination & "\Normal.dotm_bak" & intBkpNum
					objFSO.CopyFile strSource, strDestination & "\", True
					If Err.Number = 0 Then
						strCopyError = ""
					Else
						strCopyError = "Error " & Err.Number & ": " & Err.Description
					End If
					Err.Clear
					On Error GoTo 0
				End If
			End If
		End If
	End If
	
	If strCopyError = "" Then
		Set objResult = objFSO.OpenTextFile(strSuccess, 8, True)
		objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName
		objResult.Close
		Set objResult = Nothing
	Else
		Set objResult = objFSO.OpenTextFile(strFail, 8, True)
		objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName & " - " & strCopyError
		objResult.Close
		Set objResult = Nothing
	End If
End If

Open in new window

0
 

Author Comment

by:MuddyOz
ID: 35339415
Hey Rob,


Well it would be easier to supply a list NOT to run on. The reason for this is that there are only say 6 servers (assets) that don't need this. Is the above script suitable to use for this?

Scott.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 35339437
No, I didn't provide the list in the above, but I can....probably just in an array in the script itself....that way you don't have a separate text file.

Rob.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objNetwork = CreateObject("WScript.Network")
strSource = "\\server\share\newtemplate\normal.dotm"
strSuccess = "\\server\share\newtemplate\success.txt"
strFail = "\\server\share\newtemplate\fail.txt"
strDestination = objShell.ExpandEnvironmentStrings("%APPDATA%") & "\Microsoft\Templates"
arrServersToSkip = Array("Server1", "Server2", "Server3", "Server4", "Server5", "Server6")

blnSkip = False
For Each strServer In strServersToSkip
	If UCase(strServer) = UCase(objNetwork.Hostname) Then blnSkip = True
Next

If blnSkip = False Then
	If objFSO.FolderExists(strDestination) = True Then
		If Right(strDestination, 1) = "\" Then strDestination = Left(strDestination, Len(strDestination) - 1)
		strOldTemplates = ""
		bool2007TemplateExists = False
		' This section renames any Word 2000 templates from .dot to .dot_bak
		For Each objFile In objFSO.GetFolder(strDestination).Files
			If LCase(objFile.Name) = "normal.dotm" Then bool2007TemplateExists = True
			If Right(LCase(objFile.Name), 4) = ".dot" Then
				If strOldTemplates = "" Then
					strOldTemplates = objFile.Path
				Else
					strOldTemplates = strOldTemplates & ";" & objFile.Path
				End If
			End If
		Next
		arrOldTemplates = Split(strOldTemplates, ";")
		For Each strTemplatePath In arrOldTemplates
			If objFSO.FileExists(strTemplatePath & "_bak") = True Then objFSO.DeleteFile strTemplatePath & "_bak"
			objFSO.MoveFile strTemplatePath, strTemplatePath & "_bak"
		Next
		
		' This section will copy the template if it doesn't exist in the destination
		If bool2007TemplateExists = False Then
			If objFSO.FileExists(strSource) = True Then
				On Error Resume Next
				objFSO.CopyFile strSource, strDestination & "\", True
				If Err.Number = 0 Then
					strCopyError = ""
				Else
					strCopyError = "Error " & Err.Number & ": " & Err.Description
				End If
				Err.Clear
				On Error GoTo 0
			End If
		Else
			' This can control the ability to copy a new version of the normal template to each users' templates folder.
			' Set boolCopyNewNormal to False to prevent copying a new version (based on modified date)
			boolCopyNewNormal = True
			If boolCopyNewNormal = True Then
				If objFSO.FileExists(strSource) = True Then
					If CDate(objFSO.GetFile(strSource).DateLastModified) > CDate(objFSO.GetFile(strDestination & "\Normal.dotm").DateLastModified) Then
						intBkpNum = 1
						While objFSO.FileExists(strDestination & "\Normal.dotm_bak" & intBkpNum) = True
							intBkpNum = intBkpNum + 1
						Wend
						On Error Resume Next
						objFSO.MoveFile strDestination & "\Normal.dotm", strDestination & "\Normal.dotm_bak" & intBkpNum
						objFSO.CopyFile strSource, strDestination & "\", True
						If Err.Number = 0 Then
							strCopyError = ""
						Else
							strCopyError = "Error " & Err.Number & ": " & Err.Description
						End If
						Err.Clear
						On Error GoTo 0
					End If
				End If
			End If
		End If
		
		If strCopyError = "" Then
			Set objResult = objFSO.OpenTextFile(strSuccess, 8, True)
			objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName
			objResult.Close
			Set objResult = Nothing
		Else
			Set objResult = objFSO.OpenTextFile(strFail, 8, True)
			objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName & " - " & strCopyError
			objResult.Close
			Set objResult = Nothing
		End If
	End If
End If

Open in new window

0
 

Author Comment

by:MuddyOz
ID: 35339448
Oh ok. How would I specify the comuter and or servers that I don't want this file copied too?
0
 

Author Comment

by:MuddyOz
ID: 35339453
Rob,

I'm an idoit, I should of read the script first. Please excuse my stupidity :)

thank you so much!
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 35339454
In the code above, see this line:
arrServersToSkip = Array("Server1", "Server2", "Server3", "Server4", "Server5", "Server6")

Just specify as many servers as you need, and if the current computer is one of those, nothing will happen.

Regards,

Rob.
0
 

Author Comment

by:MuddyOz
ID: 35347421
Hey Rob,

Using that script with specifing the servers I get the following error -

Error Line 11
Char: 1
Object not a collection

Line 11 in my code is the follwoing -

For Each arrServersToskip In strServersToSkip

Where is the string for the servers? Thats what it seems to be complaining about.

Thanks mate

Scott.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 35347446
Argh! That's embarrassing!  Change that to
For Each strServer In arrServersToSkip

Regards,

Rob.
0
 

Author Comment

by:MuddyOz
ID: 35347571
Hey Rob,

I get a new error saying that 'objNetwork.Hostname' do you know how I can fix this error Rob?

Scott.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 35347630
Oh, sorry again...I must have been tired....that should be objNetwork.ComputerName

Regards,

Rob.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objNetwork = CreateObject("WScript.Network")
strSource = "\\server\share\newtemplate\normal.dotm"
strSuccess = "\\server\share\newtemplate\success.txt"
strFail = "\\server\share\newtemplate\fail.txt"
strDestination = objShell.ExpandEnvironmentStrings("%APPDATA%") & "\Microsoft\Templates"
arrServersToSkip = Array("Server1", "Server2", "Server3", "Server4", "Server5", "Server6")

blnSkip = False
For Each strServer In arrServersToSkip
	If UCase(strServer) = UCase(objNetwork.ComputerName) Then blnSkip = True
Next

If blnSkip = False Then
	If objFSO.FolderExists(strDestination) = True Then
		If Right(strDestination, 1) = "\" Then strDestination = Left(strDestination, Len(strDestination) - 1)
		strOldTemplates = ""
		bool2007TemplateExists = False
		' This section renames any Word 2000 templates from .dot to .dot_bak
		For Each objFile In objFSO.GetFolder(strDestination).Files
			If LCase(objFile.Name) = "normal.dotm" Then bool2007TemplateExists = True
			If Right(LCase(objFile.Name), 4) = ".dot" Then
				If strOldTemplates = "" Then
					strOldTemplates = objFile.Path
				Else
					strOldTemplates = strOldTemplates & ";" & objFile.Path
				End If
			End If
		Next
		arrOldTemplates = Split(strOldTemplates, ";")
		For Each strTemplatePath In arrOldTemplates
			If objFSO.FileExists(strTemplatePath & "_bak") = True Then objFSO.DeleteFile strTemplatePath & "_bak"
			objFSO.MoveFile strTemplatePath, strTemplatePath & "_bak"
		Next
		
		' This section will copy the template if it doesn't exist in the destination
		If bool2007TemplateExists = False Then
			If objFSO.FileExists(strSource) = True Then
				On Error Resume Next
				objFSO.CopyFile strSource, strDestination & "\", True
				If Err.Number = 0 Then
					strCopyError = ""
				Else
					strCopyError = "Error " & Err.Number & ": " & Err.Description
				End If
				Err.Clear
				On Error GoTo 0
			End If
		Else
			' This can control the ability to copy a new version of the normal template to each users' templates folder.
			' Set boolCopyNewNormal to False to prevent copying a new version (based on modified date)
			boolCopyNewNormal = True
			If boolCopyNewNormal = True Then
				If objFSO.FileExists(strSource) = True Then
					If CDate(objFSO.GetFile(strSource).DateLastModified) > CDate(objFSO.GetFile(strDestination & "\Normal.dotm").DateLastModified) Then
						intBkpNum = 1
						While objFSO.FileExists(strDestination & "\Normal.dotm_bak" & intBkpNum) = True
							intBkpNum = intBkpNum + 1
						Wend
						On Error Resume Next
						objFSO.MoveFile strDestination & "\Normal.dotm", strDestination & "\Normal.dotm_bak" & intBkpNum
						objFSO.CopyFile strSource, strDestination & "\", True
						If Err.Number = 0 Then
							strCopyError = ""
						Else
							strCopyError = "Error " & Err.Number & ": " & Err.Description
						End If
						Err.Clear
						On Error GoTo 0
					End If
				End If
			End If
		End If
		
		If strCopyError = "" Then
			Set objResult = objFSO.OpenTextFile(strSuccess, 8, True)
			objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName
			objResult.Close
			Set objResult = Nothing
		Else
			Set objResult = objFSO.OpenTextFile(strFail, 8, True)
			objResult.WriteLine Now & " - " & objNetwork.ComputerName & ": " & objNetwork.UserName & " - " & strCopyError
			objResult.Close
			Set objResult = Nothing
		End If
	End If
End If

Open in new window

0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article is the result of a quest to better understand Task Scheduler 2.0 and all the newer objects available in vbscript in this version over  the limited options we had scripting in Task Scheduler 1.0.  As I started my journey of knowledge I f…
You may have already been in the need to update a whole folder stucture using a script. Robocopy does it well and even provides a list of non-updated files in a log (if asked to). Generally those files that were locked by a user or a process by the …
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

776 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question