VIVEKANANDHAN_PERIASAMY
asked on
how to update particular value in the appdomain file through powershell
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.
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.
ASKER
<AppDomain Name="Name" Running="Enabled" LoggingStr="EventLog;AMDRo
<DataCollector CycleTime="60" CycleStartDelay="0" ThreadMaxStartDelay="evenl
<AccountDatabase Application="Name" Environment="Production" AccountType="Login" AMDEngine="ServerName" AccountGroup="" UserLoginNameWithDomain="F
<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\AM
<Account TestDataId="Personal" UserAccountHost="Email" Transactions="Dummy_Trans_
<Account TestDataId="Personan" UserAccountHost="Email4" Transactions="Dummy_Trans_
</AccountGroup>
<ShuffledParams></Shuffled
</DataCollector>
<DataStorage Source="SQL" UpdateType="SQL" DataSaveMode="Own" CycleTime="" XmlSchemaFile="AMDRoot\Log
</AppDomain>
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:
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)"
}
}
ASKER
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?
And now how can we make chages to multiple servers?
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.x ml
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.
Server | Path
Server1 | C:\Folder\file.xml
Server2 | C:\Folder\SubFolder\file.x
Server3 | C:\Folder\SubFolder\file2.
If the locations are always the same it's simpler to handle but I need your guidance on this really.
ASKER
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\messeng er\messeng erlogappdo main.xml
server1|e:\amdroot\microso ftmicrosof tappdomain .xml
server2|e:\amdroot\yaoo\ya hoochatapp domain.xml
server3|e:\amdroot\google\ google1app domain.xml
e:\amdroot\nameoftheapplic ation\ther e will be many subfiles.
But in the subfiles we will only one appdomain file.
similarity will be nameoftheapplication+appdo main
Your are quite different from others.
actually i have like below
server1|e:\amdroot\messeng
server1|e:\amdroot\microso
server2|e:\amdroot\yaoo\ya
server3|e:\amdroot\google\
e:\amdroot\nameoftheapplic
But in the subfiles we will only one appdomain file.
similarity will be nameoftheapplication+appdo
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 :)
Either way is good for me, I would just prefer not to make any assumptions on the way you would prefer to do this :)
ASKER
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.
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.
Will the name of the file always contains "appdomain"?
ASKER
yes it will always contain appdomain.
like nameoftheapplication+appdo main
like nameoftheapplication+appdo
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
$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.
$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.
You need to use gc instead of gci
ASKER
yes, i tried get-content as well but it was giving me the same error
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?
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?
ASKER
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\sq l\serverna me' 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\sq l\serverna me:String) [Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.Pow erShell.Co mmands.Get Co
ntentCommand
in the error i have replaced the my hostname with the servername for security reason.
PS C:\Users\vivek\Desktop\sql
Get-Content : Cannot find path 'C:\Users\vivek\Desktop\sq
e it does not exist.
At C:\Users\vivek\Desktop\sql
08 char:33
+ [array]$ServerList = Get-Content <<<< $ServerListFile
+ CategoryInfo : ObjectNotFound: (C:\Users\vivek\Desktop\sq
+ FullyQualifiedErrorId : PathNotFound,Microsoft.Pow
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
}
}
}
}
Problem is as far as I can see is that you've said:
$ServerListFile = gc C:\Users\vivek\Desktop\sql \servers.t xt
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\sq l\servers. txt"
[array]$ServerList = Get-Content $ServerListFile
That should work.
$ServerListFile = gc C:\Users\vivek\Desktop\sql
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\sq
[array]$ServerList = Get-Content $ServerListFile
That should work.
ASKER
Experts was really very good to work with, i really appreciate his work.
I like award him more points to him.
I like award him more points to him.
Replace any server names etc for security purposes if you want to.