?
Solved

how to update particular value in the appdomain file through powershell

Posted on 2011-10-23
18
Medium Priority
?
265 Views
Last Modified: 2012-05-12
I have many server having appdomain, i want to update only one value on multiple servers.
eg:
<appdomai>
  <test>
    <test acc> ....</test acc>
     </test>
     <data storage sql server=' nameof sqlserver'/>
</appdomain>
i want to update name of sql server in the xml file on multiple server.
0
Comment
  • 9
  • 9
18 Comments
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37013656
Can you give me an exact copy of the XML document?

Replace any server names etc for security purposes if you want to.
0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37014421

<AppDomain Name="Name" Running="Enabled" LoggingStr="EventLog;AMDRoot\logs\AMD.log" Assembly="AMDRoot\AMDEngine\AMDAgent.exe" ReferencePath="AMDRoot\Name">

                <DataCollector CycleTime="60" CycleStartDelay="0" ThreadMaxStartDelay="evenly" EngineTimeout="50" ApplicationName="Name" SimulatorKind="DOTNET" SimulatorRunAt="Local" SimulatorAssembly="AMDRoot\Name.dll" SimulatorClassName="RelationshipManagement" SessionConfigFile="AMDRoot\Name\Personal.xml" SimulatorTraceFile="AMDRoot\logs\Name\NameTrace.txt" SimulatorLoginAccount="" SimulatorLoginDomain="" SimulatorLoginPassword="" ConnectionLimit="1" MaxServicePoints="" SessionStartBoundaryMinute="1" Debug="1">

                                <AccountDatabase Application="Name" Environment="Production" AccountType="Login" AMDEngine="ServerName" AccountGroup="" UserLoginNameWithDomain="False" ConnectStringEncrypt="False" ConnectString="Server=AMDCentral;Database=Test;Trusted_Connection=Yes;Connect Timeout=60"/>

                                <AccountGroup ScenarioID="Name" TestMode="PersonaTest" UserLoginName="" UserPassword="" Domain="Domainname" Timeout=""  PersonaURL="http://website" BatchAdminURL="http://website" URL="http://website" URL="http://website" PlatformURL="http://website" ErrorFileURL="\\AMDFILE\AMDRoot\logs\Name\Errors\" Trace="1">

                                                <Account TestDataId="Personal" UserAccountHost="Email" Transactions="Dummy_Trans_EA,CreateSync_EA,Lookup"/>
                                                <Account TestDataId="Personan" UserAccountHost="Email4" Transactions="Dummy_Trans_EA,CreateSync_EA,Lookup"/>
                                </AccountGroup>
                                <ShuffledParams></ShuffledParams>
                </DataCollector>
                <DataStorage Source="SQL" UpdateType="SQL" DataSaveMode="Own" CycleTime="" XmlSchemaFile="AMDRoot\Logs\Name\NameDataStorage.xsd" SaveDir="AMDRoot\Logs\Name" MaxLocalFileSize="" ConnectStringEncrypt="False" ConnectString="Server=sqlname;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000"/>
</AppDomain>


0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37014536
You can try this, however it kicks up an error with your XML saying that the "URL" attribute on Line 7 is a duplicate attribute name, and it's right it is. If I remove one of them it works just fine. Is this a problem in your real files or just the one you put here?

As normal I would highly recommend testing this against a copy of your original files, back stuff up etc before making changes in live! Can't stress this enough!

Assumptions:

I assume here we are updating the SQL server in the connection string, let me know if I've missed the mark.

Alternative Approaches

Some other approaches may include replacing the existing files with an updated copy you have, assuming all the appdomain files have the same content this may be preferable to file level modifications. Likewise if the connection string as a whole needs to be replaced it might be preferable to just update the lot instead of doing what i'm doing, which is trying to split the text out and find what needs to be replaced.

If you can't get the XML to validate in PowerShell then you can echo through the file as a normal file system object operation and replace the content anyway, but the XML method i've used should be more precise as it works against the nodes directly.

Running against multiple machines:

If you can test this against a single file, we can then worry about changing lots of files across your systems, in my experience though get the basics working first, we can use this as an inner code block for an outer query that loops through systems/files so no worries there.

Error Handling:

I included some basic error handling in this, i.e. if you don't provide a valid file path it won't process it, and if the file causes an exception when trying to parse the XML it won't proceed either, and finally any errors on the save will be picked up and return an Exception as well.

The code:

#Customise Vars

$FileName = "C:\TEMP\file1.xml"
$NewSQLServer = "NewSQLServer"

#Attempt to get XML Content

$XMLError = 0

if (Test-Path $FileName)
{
	Try
	{
		$FileContent = Get-Content $FileName
		$XMLFileContent = [xml]$FileContent
	}
	Catch [Exception]
	{
		$XMLError = 1
		Write-Host -ForeGroundColor "Red" -BackGroundColor "Black" "$($_.Exception)"
	}
}
else
{
	$XMLError = 1
	Write-Host "File not Found"
}

if ($XMLError -eq 0)
{
	#Get Current Connect String

	$ConnectString = $XMLFileContent.AppDomain.DataStorage.ConnectString

	#Get SQL Server from Connect String

	$SQLServer = $ConnectString.Substring(0, ($ConnectString.IndexOf(";")))
	$SQLServer = $SQLServer.SubString($SQLServer.IndexOf("=") + 1)

	#Replace SQL Server in Connect String

	$NewConnectString = $ConnectString.Replace($SQLServer, $NewSQLServer)
	$XMLFileContent.AppDomain.DataStorage.ConnectString = $NewConnectString

	#Save XML

	Try
	{
		$XMLFileContent.Save($FileName)
	}
	Catch [Exception]
	{
		Write-Host -ForeGroundColor "Red" -BackGroundColor "Black" "$($_.Exception)"
	}
}

Open in new window

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37017589
Yes it works. But when i run under mutiple server, nodes will be the same but content inside will varies.So want to confirm will not be affected.

And now how can we make chages to multiple servers?
0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37017740
Are the files always in the same locations on all the servers? or would you need to feed it a CSV with content like this?

Server   | Path
Server1 | C:\Folder\file.xml
Server2 | C:\Folder\SubFolder\file.xml
Server3 | C:\Folder\SubFolder\file2.xml

If the locations are always the same it's simpler to handle but I need your guidance on this really.
0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37018125
chrismerritt: First of all I like to appreciate your support and help,being so patient and understanding.
Your are quite different from others.


actually i have like below

server1|e:\amdroot\messenger\messengerlogappdomain.xml
server1|e:\amdroot\microsoftmicrosoftappdomain.xml
server2|e:\amdroot\yaoo\yahoochatappdomain.xml
server3|e:\amdroot\google\google1appdomain.xml

e:\amdroot\nameoftheapplication\there will be many subfiles.
But in the subfiles we will only one appdomain file.
similarity will be nameoftheapplication+appdomain


0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37018383
Are you able to easily formulate an import list of these in that CSV format? or would you prefer to check the e:\amdroot\ folder for any .xml files and attempt to modify them all automatically for each server?

Either way is good for me, I would just prefer not to make any assumptions on the way you would prefer to do this :)
0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37018988
would prefer to check the e:\amdroot\ folder\xmlfiles for any .xml files and attempt to modify them all automatically for each server

but there are many other xml files ,which shouldn't be disturbed.

For the information: other xml file will not have same set of nodes.
0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37019176
Will the name of the file always contains "appdomain"?
0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37022444
yes it will always contain appdomain.
 like nameoftheapplication+appdomain
0
 
LVL 9

Accepted Solution

by:
chrismerritt earned 2000 total points
ID: 37028236
Please try this one out. I have tested it locally but you will probably want to test it against a couple of servers first with some dummy data maybe.

Usage:

Change the variables under the Customise Vars section to fit your needs:

#Customise Vars
$ServerListFile = "C:\TEMP\servers.txt"
$XMLRootPath = "E:\amdroot"
$FileSearchName = "appdomain"
$Filter = "*.xml"
$NewSQLServer = "NewSQLServer"

Then you should be able to run the code OK :)

My Testing:

I created a dummy servers.txt file in C:\temp\servers.txt with the following content to mimic multiple servers:

127.0.0.1
localhost

Then I ran my script against it and had the following results:

Server: 127.0.0.1
Network Path: \\127.0.0.1\E$\amdroot
Found File: \\127.0.0.1\E$\amdroot\Microsoft\microsoftmicrosoftappdomain.xml
Found File: \\127.0.0.1\E$\amdroot\Yahoo\yahoochatappdomain.xml
Found File: \\127.0.0.1\E$\amdroot\google1appdomain.xml
New Connection String: Server=NewSQLServer;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000
Saving XML to file: \\127.0.0.1\E$\amdroot\Microsoft\microsoftmicrosoftappdomain.xml
File saved successfully!
New Connection String: Server=NewSQLServer;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000
Saving XML to file: \\127.0.0.1\E$\amdroot\Yahoo\yahoochatappdomain.xml
File saved successfully!
New Connection String: Server=NewSQLServer;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000
Saving XML to file: \\127.0.0.1\E$\amdroot\google1appdomain.xml
File saved successfully!
Server: localhost
Network Path: \\localhost\E$\amdroot
Found File: \\localhost\E$\amdroot\Microsoft\microsoftmicrosoftappdomain.xml
Found File: \\localhost\E$\amdroot\Yahoo\yahoochatappdomain.xml
Found File: \\localhost\E$\amdroot\google1appdomain.xml
New Connection String: Server=NewSQLServer;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000
Saving XML to file: \\localhost\E$\amdroot\Microsoft\microsoftmicrosoftappdomain.xml
File saved successfully!
New Connection String: Server=NewSQLServer;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000
Saving XML to file: \\localhost\E$\amdroot\Yahoo\yahoochatappdomain.xml
File saved successfully!
New Connection String: Server=NewSQLServer;Database=databasename;Trusted_Connection=Yes;Connect Timeout=3000
Saving XML to file: \\localhost\E$\amdroot\google1appdomain.xml
File saved successfully!

The Code!

Function ChangeSQL-XML
{
	param
	(
		$FileName,
		$NewSQLServer
	)
	
	#Attempt to get XML Content
	$XMLError = 0

	if (Test-Path $FileName)
	{
		Try
		{
			$FileContent = Get-Content $FileName
			$XMLFileContent = [xml]$FileContent
		}
		Catch [Exception]
		{
			$XMLError = 1
			Write-Host -ForeGroundColor "Red" -BackGroundColor "Black" "$($_.Exception)"
		}
	}
	else
	{
		$XMLError = 1
		Write-Host "File not Found"
	}

	if ($XMLError -eq 0)
	{
		#Get Current Connect String
		$ConnectString = $XMLFileContent.AppDomain.DataStorage.ConnectString

		#Get SQL Server from Connect String
		$SQLServer = $ConnectString.Substring(0, ($ConnectString.IndexOf(";")))
		$SQLServer = $SQLServer.SubString($SQLServer.IndexOf("=") + 1)

		#Replace SQL Server in Connect String
		$NewConnectString = $ConnectString.Replace($SQLServer, $NewSQLServer)
		$XMLFileContent.AppDomain.DataStorage.ConnectString = $NewConnectString
		
		Write-Host -ForeGroundColor "Yellow" "New Connection String: $NewConnectString"

		#Save XML		
		$SaveXMLError = 0

		Try
		{
			$XMLFileContent.Save($FileName)
			Write-Host -ForeGroundColor "Yellow" "Saving XML to file: $FileName"
		}
		Catch [Exception]
		{
			$SaveXMLError = 1
			Write-Host -ForeGroundColor "Red" -BackGroundColor "Black" "$($_.Exception)"
		}
		Finally
		{
			if ($SaveXMLError -eq 0)
			{
				Write-Host -ForeGroundColor "Yellow" "File saved successfully!"
			}
		}
	}
}

Function ScanFor-XML
{
	param
	(
		$NetworkPath,
		$FileSearchName,
		$Filter
	)
	
	$FileArray = @()
	
	if (Test-Path $NetworkPath)
	{
		[array]$FileCollection = gci $NetworkPath -Include $Filter -recurse
		
		if ($FileCollection.Count -gt 0)
		{
			foreach ($File in $FileCollection)
			{
				if ($File.Name -match $FileSearchName)
				{
					Write-Host -ForeGroundColor "Yellow" "Found File: $($File.FullName)"
					$FileArray += $File
				}
			}
		}
	}
	
	return $FileArray
	
}

#Customise Vars
$ServerListFile = "C:\TEMP\servers.txt"
$XMLRootPath = "E:\amdroot"
$FileSearchName = "appdomain"
$Filter = "*.xml"
$NewSQLServer = "NewSQLServer"

[array]$ServerList = Get-Content $ServerListFile

#Check if ServerList contains any entries
if ($ServerList.Count -gt 0)
{
	foreach ($Server in $ServerList)
	{
		Write-Host -ForeGroundColor "Magenta" "Server: $Server"
		
		$XMLNetworkPath = $XMLRootPath.Replace(":","$")
		$NetworkPath = "\\" + $Server + "\" + $XMLNetworkPath
		
		Write-Host -ForeGroundColor "Yellow" "Network Path: $NetworkPath"
		
		[array]$XMLNetworkFiles = ScanFor-XML $NetworkPath $FileSearchName $Filter
		
		if ($XMLNetworkFiles.Count -gt 0)
		{
			foreach ($XMLNetworkFile in $XMLNetworkFiles)
			{
				ChangeSQL-XML $XMLNetworkFile $NewSQLServer
			}
		}
	}
}

Open in new window

0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37063282
$XMLRootPath = "E:\amdroot"
$NewSQLServer = "NewSQLServer"


for this two variable,i like to pass the value through text file.
I tried using
$XMLRootPath = gci c:\temp\path.txt
$NewSQLServer =  gci c:\temp\value.txt

It's giving exception error. how to achieve the above requirement.
0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37064392
You need to use gc instead of gci
0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37064557
yes, i tried get-content as well but it was giving me the same error
0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37064651
I created a file called C:\TEMP\path.txt and put the following in it:

E:\amdroot

Then I ran this in PowerShell:

PS C:\Users\Chris> $XMLRootPath = gc "C:\TEMP\path.txt"
PS C:\Users\Chris> $XMLRootPath | Out-Host
E:\amdroot
PS C:\Users\Chris>

So it appears to work fine via text file.

If you're trying to pass multiple values in those text files it won't work, as you would need a looping logic to handle multiple values.

What is the exception you get?
0
 
LVL 5

Author Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37068011
the below code i have used. and i getting following error

PS C:\Users\vivek\Desktop\sql> & '.\Changing SQL Server name in the appdomain.ps1'
Get-Content : Cannot find path 'C:\Users\vivek\Desktop\sql\servername' becaus
e it does not exist.
At C:\Users\vivek\Desktop\sql\Changing SQL Server name in the appdomain.ps1:1
08 char:33
+ [array]$ServerList = Get-Content <<<<  $ServerListFile
    + CategoryInfo          : ObjectNotFound: (C:\Users\vivek\Desktop\sql\servername:String) [Get-Content], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetCo
   ntentCommand

in the error i have replaced the my hostname with the servername for security reason.
Function ChangeSQL-XML
{
	param
	(
		$FileName,
		$NewSQLServer
	)
	
	#Attempt to get XML Content
	$XMLError = 0

	if (Test-Path $FileName)
	{
		Try
		{
			$FileContent = Get-Content $FileName
			$XMLFileContent = [xml]$FileContent
		}
		Catch [Exception]
		{
			$XMLError = 1
			Write-Host -ForeGroundColor "Red" -BackGroundColor "Black" "$($_.Exception)"
		}
	}
	else
	{
		$XMLError = 1
		Write-Host "File not Found"
	}

	if ($XMLError -eq 0)
	{
		#Get Current Connect String
		$ConnectString = $XMLFileContent.AppDomain.DataStorage.ConnectString

		#Get SQL Server from Connect String
		$SQLServer = $ConnectString.Substring(0, ($ConnectString.IndexOf(";")))
		$SQLServer = $SQLServer.SubString($SQLServer.IndexOf("=") + 1)

		#Replace SQL Server in Connect String
		$NewConnectString = $ConnectString.Replace($SQLServer, $NewSQLServer)
		$XMLFileContent.AppDomain.DataStorage.ConnectString = $NewConnectString
		
		Write-Host -ForeGroundColor "Yellow" "New Connection String: $NewConnectString"

		#Save XML		
		$SaveXMLError = 0

		Try
		{
			$XMLFileContent.Save($FileName)
			Write-Host -ForeGroundColor "Yellow" "Saving XML to file: $FileName"
		}
		Catch [Exception]
		{
			$SaveXMLError = 1
			Write-Host -ForeGroundColor "Red" -BackGroundColor "Black" "$($_.Exception)"
		}
		Finally
		{
			if ($SaveXMLError -eq 0)
			{
				Write-Host -ForeGroundColor "Yellow" "File saved successfully!"
			}
		}
	}
}

Function ScanFor-XML
{
	param
	(
		$NetworkPath,
		$FileSearchName,
		$Filter
	)
	
	$FileArray = @()
	
	if (Test-Path $NetworkPath)
	{
		[array]$FileCollection = gci $NetworkPath -Include $Filter -recurse
		
		if ($FileCollection.Count -gt 0)
		{
			foreach ($File in $FileCollection)
			{
				if ($File.Name -match $FileSearchName)
				{
					Write-Host -ForeGroundColor "Yellow" "Found File: $($File.FullName)"
					$FileArray += $File
				}
			}
		}
	}
	
	return $FileArray
	
}

#Customise Vars
$ServerListFile = gc C:\Users\vivek\Desktop\sql\servers.txt
$XMLRootPath = gc "C:\Users\vivek\Desktop\sql\amdpath.txt"
$FileSearchName = "appdomain"
$Filter = "*.xml"
$NewSQLServer = gc "C:\Users\vivek\Desktop\sql\sqlservername.txt"

[array]$ServerList = Get-Content $ServerListFile

#Check if ServerList contains any entries
if ($ServerList.Count -gt 0)
{
	foreach ($Server in $ServerList)
	{
		Write-Host -ForeGroundColor "Magenta" "Server: $Server"
		
		$XMLNetworkPath = $XMLRootPath.Replace(":","$")
		$NetworkPath = "\\" + $Server + "\" + $XMLNetworkPath
		
		Write-Host -ForeGroundColor "Yellow" "Network Path: $NetworkPath"
		
		[array]$XMLNetworkFiles = ScanFor-XML $NetworkPath $FileSearchName $Filter
		
		if ($XMLNetworkFiles.Count -gt 0)
		{
			foreach ($XMLNetworkFile in $XMLNetworkFiles)
			{
				ChangeSQL-XML $XMLNetworkFile $NewSQLServer
			}
		}
	}
}

Open in new window

0
 
LVL 9

Expert Comment

by:chrismerritt
ID: 37068140
Problem is as far as I can see is that you've said:

$ServerListFile = gc C:\Users\vivek\Desktop\sql\servers.txt

Then:

[array]$ServerList = Get-Content $ServerListFile

Basically you're getting the content of the file, then getting the content of the content of the file?

Try this:

$ServerListFile = "C:\Users\vivek\Desktop\sql\servers.txt"

[array]$ServerList = Get-Content $ServerListFile

That should work.
0
 
LVL 5

Author Closing Comment

by:VIVEKANANDHAN_PERIASAMY
ID: 37075714
Experts was really very good to work with, i really appreciate his work.
I like award him more points to him.
0

Featured Post

 The Evil-ution of Network Security Threats

What are the hacks that forever changed the security industry? To answer that question, we created an exciting new eBook that takes you on a trip through hacking history. It explores the top hacks from the 80s to 2010s, why they mattered, and how the security industry responded.

Question has a verified solution.

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

Auditing domain password hashes is a commonly overlooked but critical requirement to ensuring secure passwords practices are followed. Methods exist to extract hashes directly for a live domain however this article describes a process to extract u…
Measuring Server's processing rate with a simple powershell command. The differences in processing rate also was recorded in different use-cases, when a server in free and busy states.
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…
Loops Section Overview

829 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