5

Powershell and Machine.config help

I am very new to powershell and I need a quick hand if at all possible (I am sure this is a common sentence). I am writing a script that optimizes a server to become a webserver, I need to write to the machine.configs using powershell. I also have all of the Optimizations needed, I don't need help no that part.

I have been trying to figure it out for over a month, lots of googling as well, I cant really find a solution, so I figured to come to the experts. Hopefully i can get good in powershell too and contribute at some point.

I have gotten incredibly far so far and have already done all of the optimizations and most of the powershell but am stuck on 1 part in the script

  1. I need to get how many cpu cores the machine has, I have this line

    $property = "numberOfCores" Get-WmiObject -class win32_processor -Property $property | Select-Object -Propert $property

That tells me how many cores i have, which is exactly what I need but Once I have how many cores the machine has, I need to write to the machine.config some values.

Under system.web, it has these values

<system.web>
    <processModel autoConfig="true"/>

I would need to overwrite the already present value with this listed below

<system.web>
    <processModel maxWorkerThreads="370" maxIoThreads="370" minWorkerThreads="50" minIoThreads="50"/>
<httpRuntime minFreeThreads="90" minLocalRequestFreeThreads="80"/>

Aside from writing that line there (which I cant figure out how to do), I need to multiply the minfreethreads by the number of CPU cores and write that value in the place of the 90 and the same for minLocalRequestFreeThreads 80

So for example, if the computation sees 2 cores it would write the following lines

<processModel maxWorkerThreads="370" maxIoThreads="370" minWorkerThreads="50" minIoThreads="50"/>
<httpRuntime minFreeThreads="180" minLocalRequestFreeThreads="160"/>

after that, I need to add

<system.net>
<connectionManagement>
<add address = "*" maxconnection = "200" />
</connectionManagement>
</system.net>

As before, then replace the 200 with the multiplied values of the cpu cores and the 200. I hope that's not too much to ask, I don't know how to write to xml files, and then also multiply the cores and take that value and add it there?

so it would like this

<system.net>
<connectionManagement>
<add address = "*" maxconnection = "400" />
</connectionManagement>
</system.net>

Can anyone give me a hand?

Edit 1/4

This is the code i have so far, I am very far, I am working on it line by line so somethings may not work but I think I am on the right path

$xml = New-Object XML
$xml.Load("C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config")
$Path = "C:\Windows\Microsoft.Net\Framework\V2.0.50727\config"
$File = "machine.config"
$current_path = $path + "\" + $file
$text = (get-content ($current_path))
$xml = [XML] (get-content ($current_path))
$p.RemoveAttribute("autoConfig")
$p = $xml.configuration."system.web".processModel
$p.SetAttribute("maxWorkerThreads", "370")
$p.SetAttribute("maxIoThreads", "370")
$p.SetAttribute("minWorkerThreads", "50")
$p = $xml.configuration."system.web".httpRunTime
$p.SetAttribute("minFreeThreads", "90")
$p.SetAttribute("minLocalRequestFreeThreads", "80")
$processor = (Get-CimInstance Win32_processor -Property NumberOfLogicalProcessors | Select -ExpandProperty "NumberOfLogicalProcessors")
$minFT = $processor * 90
$minFT = [string]$minFT
$minFT * 2
$p.SetAttribute("minFreeThreads", [string]$minFT)

$xml_content = [xml]@'
  <system.net>
    <connectionManagement>
      <add address = "*" maxconnection = "200" />
    </connectionManagement>
  </system.net>
'@

Edit 1/11

Actually it failed, with the message

Method invocation failed because [System.Object[]] does not contain a method named 'op_Multiply'. At C:\Install\Pre4.ps1:124 char:1 + $httpRuntimexml.setAttribute("minFreeThreads",90 * $numberOfCores) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Multiply:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.Object[]] does not contain a method named 'op_Multiply'. At C:\Install\Pre4.ps1:125 char:1 + $httpRuntimexml.setAttribute("minLocalRequestFreeThreads",80 * $numberOfCores) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Multiply:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound

Method invocation failed because [System.Object[]] does not contain a method named 'op_Multiply'. At C:\Install\Pre4.ps1:130 char:45 + + ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Multiply:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound

----- script ------

$numberOfCores = Get-WmiObject -class win32_processor numberOfCores | Select-Object -ExpandProperty numberOfCores
$path = "c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config"
[xml]$machineConfig = Get-Content $path
$node = $machineConfig.SelectNodes("/configuration/system.web") 
$node.RemoveChild(($node.SelectSingleNode("processModel"))) | Out-Null
$processModelxml = $machineConfig.CreateElement("processModel")
$processModelxml.setAttribute("maxWorkerThreads",370)
$processModelxml.setAttribute("maxWorkerThreads",370)
$processModelxml.setAttribute("maxIoThreads",370)
$processModelxml.setAttribute("minWorkerThreads",50)
$processModelxml.setAttribute("minIoThreads",50)
$node.AppendChild($processModelxml) | Out-Null
$httpRuntimexml = $machineConfig.CreateElement("httpRuntime")
$httpRuntimexml.setAttribute("minFreeThreads",90 * $numberOfCores)
$httpRuntimexml.setAttribute("minLocalRequestFreeThreads",80 * $numberOfCores)
$node.AppendChild($httpRuntimexml) | Out-Null
[xml]$systemnetxml = @"
  <system.net>
    <connectionManagement>
      <add address = "*" maxconnection = "$(200 * $numberOfCores)" />
    </connectionManagement>
  </system.net>
"@
$machineConfig.configuration.AppendChild($machineConfig.ImportNode($systemnetxml."system.net",$true)) | Out-Null
$machineConfig.Save("c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config")
Cœur
  • 37,241
  • 25
  • 195
  • 267
Iggy Castillo
  • 75
  • 1
  • 9
  • Is there anything you tried so far that we can help build on? – Matt Dec 31 '15 at 15:50
  • yes, though it may not be in 100% working order, I have gotten much further, but not perfect – Iggy Castillo Jan 04 '16 at 18:38
  • 1
    Add that into the question and we can build on it :) – Matt Jan 04 '16 at 18:40
  • oh it messed it all up, how do I fix it, sorry thats not how it looks like in my code – Iggy Castillo Jan 04 '16 at 18:42
  • Also, trying to figure out how to save the file, little fish big pond here it looks like – Iggy Castillo Jan 04 '16 at 18:53
  • Thanks Matt, please let me know if this helps, it is now part of the question, added as an Edit – Iggy Castillo Jan 04 '16 at 19:04
  • Matt, is this something you could help me with? – Iggy Castillo Jan 06 '16 at 15:26
  • Yes, If no one else has had a crack at it I can see about looking at it sometime today. – Matt Jan 06 '16 at 15:52
  • Where does system.net portion need to go? Under the configuration element? – Matt Jan 06 '16 at 21:05
  • system.net I usually put at the very end before and – Iggy Castillo Jan 06 '16 at 22:12
  • Hello Matt, actually it failed, I posted above the message and the script I used, at least that portion – Iggy Castillo Jan 11 '16 at 22:05
  • I guess in your case they need a subexpression. Didn't for me. See my update. Need to figure out how to address the last error. it's odd because it is a number and not an object..... You tagged two ps versions. Which one are you using when it fails? – Matt Jan 12 '16 at 01:25
  • Other thing I could think to do is remove the calculation from inside the set attribute and move it out into a variable. – Matt Jan 12 '16 at 11:30
  • the PS versions is me saving the file when I make changes, sorry didnt mean to confuse – Iggy Castillo Jan 12 '16 at 13:29
  • I dont know if it will help, but this is the output of the error 1 Modifying Machine.config's to optimize adapter performace Updating Framework64 - v4.0.30319 Method invocation failed because [System.Object[]] does not contain a method named 'op_Multiply'. At C:\Install\Pre4.ps1:124 char:1 + $httpRuntimexml.setAttribute("minFreeThreads",(90 * $numberOfCores)) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Multiply:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound – Iggy Castillo Jan 12 '16 at 13:45
  • It's shows system object in the error which is odd since it is multiplying an integer. Unless number of cores is the problem. Check the value of that in case it is not an integer – Matt Jan 12 '16 at 13:46
  • Matt, would it help if I sent you the PS file? – Iggy Castillo Jan 12 '16 at 13:49
  • Possibly. Could link pastebin. I won't be able to look at it until this evening at the earliest as I am flying – Matt Jan 12 '16 at 14:42
  • Thanks Matt, I hope you have safe travels. Please let me know if you can read this pastebin http://pastebin.com/6LRefqh8 – Iggy Castillo Jan 12 '16 at 15:46
  • Hey Matt, you know what, I put it on a fresh machine and it worked fine. what was going on is that in my script, I am copying the original machine.config to machine.org, then modifying the machine.conf, problem is when you run the script too many times it copies the edited machine.config and overwrites the machine.orig I created and then appends to that, messing everything up like we saw. How would you recommend I correct that? So to be clear, everything you have recommended worked, worked flawlessly, now the issue process on my side. – Iggy Castillo Jan 12 '16 at 17:29
  • Not sure what you mean by _appends to that_ since there is nothing appending here. But if you make an orig file then when the script is run I would just check if an orig file already exists and _assume_ that it is safe to proceed. `if(-not Test-Path(c:\pathtoorig)){#make a backup}` – Matt Jan 12 '16 at 21:09

1 Answers1

2

Havent played with XML and PowerShell much but this seems to work for what you want. Load the file as an XML. Remove the two elements in question so that we can build them as we want. Lastly we add the element and corresponding details under the configuration element.

In the case of values being multiplied before committed you will see several instances of multiplication that cover that. In your example you were performation multiplication on a string which would have simply duplicated it. Consider the two following examples.

PS C:\Users\mcameron> "200" * 2
200200

PS C:\Users\mcameron> 200 * 2
400

Change your paths as you see fit. You will see at the end I write to a temporary location. I urge you to do the same for testing.

$numberOfCores = Get-WmiObject -class win32_processor numberOfCores | Select-Object -ExpandProperty numberOfCores


$path = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machineTest.config"
[xml]$machineConfig = Get-Content $path

# Remove the elements we are going to be replacing
$node = $machineConfig.SelectNodes("/configuration/system.web") 
$node.RemoveChild(($node.SelectSingleNode("processModel"))) | Out-Null

# Create the element processModel and set attributes
$processModelxml = $machineConfig.CreateElement("processModel")
$processModelxml.setAttribute("maxWorkerThreads",370)
$processModelxml.setAttribute("maxWorkerThreads",370)
$processModelxml.setAttribute("maxIoThreads",370)
$processModelxml.setAttribute("minWorkerThreads",50)
$processModelxml.setAttribute("minIoThreads",50)
$node.AppendChild($processModelxml) | Out-Null

# Create the element httpRuntime and set attributes. Adjust values based on number of cores
$httpRuntimexml = $machineConfig.CreateElement("httpRuntime")
$httpRuntimexml.setAttribute("minFreeThreads",(90 * $numberOfCores))
$httpRuntimexml.setAttribute("minLocalRequestFreeThreads",(80 * $numberOfCores))
$node.AppendChild($httpRuntimexml) | Out-Null

# Build the <system.net> section
[xml]$systemnetxml = @"
  <system.net>
    <connectionManagement>
      <add address = "*" maxconnection = "$(200 * $numberOfCores)" />
    </connectionManagement>
  </system.net>
"@

# Import into config
$machineConfig.configuration.AppendChild($machineConfig.ImportNode($systemnetxml."system.net",$true)) | Out-Null

# Save changes
$machineConfig.Save("c:\temp\testing.xml")
# Change back to $path to write back to original file.

You will also see Out-Null which is there to suppress the output of the elements being created. It does not change what happens to the file.

Matt
  • 45,022
  • 8
  • 78
  • 119
  • thank you Matt, I will test this soon and let you know as soon as possible. – Iggy Castillo Jan 07 '16 at 13:13
  • Pre-editted code removed a node it was not supposed to. Just had a similar and I didn't pick up on it. I removed the offending line. – Matt Jan 08 '16 at 02:51
  • thank you Matt, trying to work on this while taking care of my work, so its taking me sometime. Thank you for staying on it. – Iggy Castillo Jan 08 '16 at 19:09
  • by the way, I cannot do $numberOfCores = Get-WmiObject -class win32_processor numberOfCores | Select-Object -ExpandProperty numberOfCores because that gives me the total amount of cores for the host, I need the amount of cores for the guest, since this will be run on VM's, which is why I run this $processor = (Get-CimInstance Win32_processor -Property NumberOfLogicalProcessors | Select -ExpandProperty "NumberOfLogicalProcessors") does that sound right? – Iggy Castillo Jan 08 '16 at 19:35
  • @IggyCastillo I didn't really read into how this would be run and against what machine. But yes that is what you would be doing. – Matt Jan 08 '16 at 19:36
  • Hey Matt, this line is passing an error "[xml]$systemnetxml = @" – Iggy Castillo Jan 08 '16 at 19:54
  • PS H:\> [xml]$systemnetxml = @ At line:1 char:22 + [xml]$systemnetxml = @ + ~ Unrecognized token in source text. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : UnrecognizedToken – Iggy Castillo Jan 08 '16 at 22:08
  • Do you have a double quote following that at sign? – Matt Jan 08 '16 at 23:44
  • Actually, please cancel that, seems to be working. 1 small request, the line we added for processmodel and httpruntime, I would like to add it directly under a subhheading of which is under , how can I get it there? – Iggy Castillo Jan 11 '16 at 16:45
  • Actually no, thats it, it works. You are the best, thank you sooooooo much. I will say, out of all of the forums I have placed this questions on (2 others) you have been the only one to answer me correctly, actually even the only one who has been able to give me specific examples, instead of "Look at this link", "Look at this kba" you have been able to answer me 100% which helps me learn how to do this for myself. Thank you again so much for all of your help, you rock. – Iggy Castillo Jan 11 '16 at 16:49
  • Hey Matt, I am sorry I have been gone for so long, i lost this site, it is bookmarked now so it wont happen again. The script works perfect, thank you SOOOOO much for your help, but I do need a little more, I dont know if I should start a new thread or continue from here. I need for it to be able to catch errors, for example "Installing CGI" Install-WindowsFeature Web-CGI II run that, but how do I know that it installed it without looking? A little more, but ran out of space – Iggy Castillo Mar 09 '16 at 22:20
  • In this line Copy-Item -Path c:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config -Destination c:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.orig How can I make it so that if machine.orig exists, it deletes the current machine.config, then renames the machine.orig back to machine.config to edit it again? – Iggy Castillo Mar 09 '16 at 22:20