1

I have this function I found online which updates an IIS web.config XML file based on values I am feeding it from CSV files. I would like to prevent the output of every XML entry modification from being printed when the function is executed. I have tried numerous times to place to utilize Out-Null but I cannot seem to locate which portion of this XML update function is causing the output.

I would like to remove all XML update output like shown below after the line "Setting web.config appSettings for D:\Inetpub\WWWRoot\test". The output seems to be the key/value pair the function is reading from the CSV file and updating the web.config file with.

Setting web.config appSettings for D:\Inetpub\WWWRoot\test #text ----- allowFrame TRUE

authenticationType SSO

cacheProviderType Shared

Here is the function I am utilizing:

function Set-Webconfig-AppSettings
{
    param (
        # Physical path for the IIS Endpoint on the machine without the "web.config" part.
        # Example: 'D:\inetpub\wwwroot\cmweb510\'
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String] $path,
 
        # web.config key that you want to create or change
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String] $key,
 
        # Value of the key you want to create or change
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String] $value
    )
 
   Write-Host "Setting web.config appSettings for $path" -ForegroundColor DarkCyan
 
    $webconfig = Join-Path $path "web.config"
    [bool] $found = $false
 
    if (Test-Path $webconfig)
    {
        $xml = [xml](get-content $webconfig);
        $root = $xml.get_DocumentElement();
 
        foreach ($item in $root.appSettings.add)
        {
            if ($item.key -eq $key)
            {
                $item.value = $value;
                $found = $true;
            }
        }
 
        if (-not $found)
        {
            
            $newElement = $xml.CreateElement("add");
            $nameAtt1 = $xml.CreateAttribute("key")
            $nameAtt1.psbase.value = $key;
            $newElement.SetAttributeNode($nameAtt1);
 
            $nameAtt2 = $xml.CreateAttribute("value");
            $nameAtt2.psbase.value = $value;
            $newElement.SetAttributeNode($nameAtt2);
 
            $xml.configuration["appSettings"].AppendChild($newElement);
        }
        
        $xml.Save($webconfig)
    }
    else
    {
        Write-Error -Message "Error: File not found '$webconfig'"
    }
}

2 Answers2

2

Both SetAttributeNode and AppendChild output information so we just need to $null or [void] those out

function Set-Webconfig-AppSettings
{
    param (
        # Physical path for the IIS Endpoint on the machine without the "web.config" part.
        # Example: 'D:\inetpub\wwwroot\cmweb510\'
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String] $path,

        # web.config key that you want to create or change
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String] $key,

        # Value of the key you want to create or change
        [parameter(mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String] $value
    )

   Write-Host "Setting web.config appSettings for $path" -ForegroundColor DarkCyan

    $webconfig = Join-Path $path "web.config"
    [bool] $found = $false

    if (Test-Path $webconfig)
    {
        $xml = [xml](get-content $webconfig);
        $root = $xml.get_DocumentElement();

        foreach ($item in $root.appSettings.add)
        {
            if ($item.key -eq $key)
            {
                $item.value = $value;
                $found = $true;
            }
        }

        if (-not $found)
        {
        
            $newElement = $xml.CreateElement("add");
            $nameAtt1 = $xml.CreateAttribute("key")
            $nameAtt1.psbase.value = $key;
            $null = $newElement.SetAttributeNode($nameAtt1);

            $nameAtt2 = $xml.CreateAttribute("value");
            $nameAtt2.psbase.value = $value;
            $null = $newElement.SetAttributeNode($nameAtt2);

            $null = $xml.configuration["appSettings"].AppendChild($newElement);
        }
    
        $xml.Save($webconfig)
    }
    else
    {
        Write-Error -Message "Error: File not found '$webconfig'"
    }
}
Doug Maurer
  • 8,090
  • 3
  • 12
  • 13
2

In PowerShell, return values from .NET methods (in general, all output) that are neither assigned to a variable, nor sent through the pipeline to another command, nor redirected to a file are implicitly output ("returned") from functions - even without an explicit output command such as Write-Output or a return statement.
See the bottom section of this answer for the rationale behind this implicit-output feature.

It follows that, in PowerShell:

  • When you call .NET methods, you need to be aware of whether or not they return a value (technically, not returning a value is indicated by a return type of void).
  • If they do and if you don't need this return value, you must explicitly discard (suppress) it, so that it doesn't accidentally become part of the function's output.

In your case, it is the calls to the System.Xml.XmlElement.SetAttributeNode and System.Xml.XmlElement.AppendChild methods that cause your problems, because they have return values that you're not suppressing.

Doug Maurer's helpful answer shows how you to discard these return values by assigning the method calls to $null ($null = ...).

While two other methods for suppressing output exist as well - casting to [void] and piping to Out-Null - $null = ... is the best overall choice, as discussed in this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775