Public/Reset-VMConnectConfig.ps1

#.ExternalHelp VMConnectConfig-help.xml
function Reset-VMConnectConfig
{
    [CmdletBinding(ConfirmImpact = 'Medium', DefaultParameterSetName = 'Name', HelpURI='https://thegraffix.github.io/VMConnectConfig/reset-vmconnectconfig.html', SupportsShouldProcess)]
    [Alias('rsvmc')]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param (
        [Parameter(Mandatory, ParameterSetName = 'Id', Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('VMId')]
        [ValidateNotNullOrEmpty()]
        [System.Guid[]]$Id,

        [Parameter(Mandatory, ParameterSetName = 'InputObject', Position = 0, ValueFromPipeline)]
        [System.Management.Automation.PSTypeName('VMConnectConfig')]$InputObject,

        [Parameter(Mandatory, ParameterSetName = 'LiteralPath', ValueFromPipelineByPropertyName)]
        [Alias('FullName')]
        [ValidateNotNullOrEmpty()]
        [System.String[]]$LiteralPath,

        [Parameter(Mandatory, ParameterSetName = 'Name', Position = 0, ValueFromPipeline)]
        [SupportsWildcards()]
        [ValidateNotNullOrEmpty()]
        [System.String[]]$Name,

        [switch]$PassThru,

        [Parameter(Mandatory, ParameterSetName = 'Path')]
        [SupportsWildcards()]
        [ValidateNotNullOrEmpty()]
        [System.String[]]$Path
    )

    begin
    {
        # This is a workaround for a bug where advanced functions can output an error if "-ErrorAction/-WarningAction Ignore" are used.
        if ($ErrorActionPreference -eq 'Ignore') {$ErrorActionPreference = 'Ignore'}
        if ($WarningPreference -eq 'Ignore') {$WarningPreference = 'Ignore'}

        [System.String[]]$configFilePathList = @()
    } #begin

    process
    {
        if ($PSCmdlet.ParameterSetName -notlike '*Path')
        {
            $null = Test-VMConfigFolder
            $allConfigFiles = Get-AllConfigFiles
        }

        switch ($PSCmdlet.ParameterSetName)
        {
            'Id'
            {
                foreach ($vmGuid in $Id)
                {
                    $files = @()
                    $files = [System.String[]](($allConfigFiles | Where-Object {$_.Name -match "vmconnect\.rdp\.$vmGuid.*\.config"}).FullName)

                    if (($files.Count -eq 0) -or ([System.String]::IsNullOrEmpty($files)))
                    {
                        $errMsg = ($MsgTable.ConfigFileNotFoundIdError -f $VMConfigFolder, $vmGuid)

                        $errParams = @{
                            Category = $ErrorCatObjectNotFound
                            Exception = New-Object -TypeName 'System.ArgumentException' -ArgumentList $errMsg
                            Message = $errMsg
                        }

                        Write-Error @errParams
                    } #if no .config file(s) found.
                    else
                    {
                        foreach ($file in $files)
                        {
                            $configFilePathList += $file
                        }
                    }
                } #foreach $vmGuid

                break
            } # -Id

            'InputObject'
            {
                foreach ($file in $InputObject.Path)
                {
                    $configFilePathList += $file
                }

                break
            } # -InputObject

            'LiteralPath'
            {
                foreach ($literalItem in $LiteralPath)
                {
                    $literalPathError = $null
                    $resolvedLiteralPaths = @()
                    $resolvedLiteralPaths = [System.String[]]((Resolve-Path -LiteralPath $literalItem -ErrorVariable 'literalPathError').Path | Where-Object {[System.IO.File]::Exists($_)})

                    if ((($resolvedLiteralPaths.Count -eq 0) -or ([System.String]::IsNullOrEmpty($resolvedLiteralPaths))) -and [System.String]::IsNullOrEmpty($literalPathError))
                    {
                        # Output an error message when Resolve-Path returns 0 items and doesn't output an error message.
                        $resolvedLiteralItemPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($literalItem)
                        $errMsg = ($MsgTable.ConfigFileNotFoundPathError -f $resolvedLiteralItemPath)

                        $errParams = @{
                            Category = $ErrorCatObjectNotFound
                            Exception = New-Object -TypeName 'System.IO.FileNotFoundException' -ArgumentList $errMsg, $resolvedLiteralItemPath
                            Message = $errMsg
                            TargetObject = $resolvedLiteralItemPath
                        }

                        Write-Error @errParams
                    } #if no .config file(s) found.
                    else
                    {
                        foreach ($resolvedLiteralPath in $resolvedLiteralPaths)
                        {
                            $configFilePathList += $resolvedLiteralPath
                        }
                    }
                } #foreach $literalItem

                break
            } # -LiteralPath

            'Name'
            {
                foreach ($vmName in $Name)
                {
                    $files = @()

                    try
                    {
                        $files = [System.String[]]((Select-Xml -Path $allConfigFiles.FullName -XPath $VMNameXPath | Where-Object {$_.Node.Value -like $vmName}).Path)
                    } #try
                    catch
                    {
                        # Do nothing. This is to fully suppress terminating errors from the Select-Xml cmdlet when the 1.0 directory exists but is empty.
                    } #catch

                    if (($files.Count -eq 0) -or ([System.String]::IsNullOrEmpty($files)))
                    {
                        $errMsg = ($MsgTable.ConfigFileNotFoundNameError -f $VMConfigFolder, $vmName)

                        $errParams = @{
                            Category = $ErrorCatObjectNotFound
                            Exception = New-Object -TypeName 'System.ArgumentException' -ArgumentList $errMsg
                            Message = $errMsg
                        }

                        Write-Error @errParams
                    } #if no .config file(s) found.
                    else
                    {
                        foreach ($file in $files)
                        {
                            $configFilePathList += $file
                        }
                    }
                } #foreach $vmName

                break
            } # -Name

            'Path'
            {
                foreach ($item in $Path)
                {
                    $pathError = $null
                    $resolvedPaths = @()
                    $resolvedPaths = [System.String[]]((Resolve-Path -Path $item -ErrorVariable 'pathError').Path | Where-Object {[System.IO.File]::Exists($_)})

                    if ((($resolvedPaths.Count -eq 0) -or ([System.String]::IsNullOrEmpty($resolvedPaths))) -and ([System.String]::IsNullOrEmpty($pathError)))
                    {
                        # Output an error message when Resolve-Path returns 0 items and doesn't output an error message.
                        $resolvedItemPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($item)
                        $errMsg = ($MsgTable.ConfigFileNotFoundPathError -f $resolvedItemPath)

                        $errParams = @{
                            Category = $ErrorCatObjectNotFound
                            Exception = New-Object -TypeName 'System.IO.FileNotFoundException' -ArgumentList $errMsg, $resolvedItemPath
                            Message = $errMsg
                            TargetObject = $resolvedItemPath
                        }

                        Write-Error @errParams
                    } #if no .config file(s) found.
                    else
                    {
                        foreach ($resolvedPath in $resolvedPaths)
                        {
                            $configFilePathList += $resolvedPath
                        }
                    }
                } #foreach $item

                break
            } # -Path
        } #switch ($PSCmdlet.ParameterSetName)
    } #process

    end
    {
        $configFilePathList = $configFilePathList | Select-Object -Unique
        [System.String[]]$passThruList = @()

        foreach ($configFile in $configFilePathList)
        {
            if ((Test-VMConnectConfig -LiteralPath $configFile -ErrorAction SilentlyContinue) -eq $false)
            {
                $errMsg = ($MsgTable.InvalidConfigFileError -f $configFile)

                $errParams = @{
                    Category = $ErrorCatInvalidArgument
                    Exception = New-Object -TypeName 'System.ArgumentException' -ArgumentList $errMsg
                    Message = $errMsg
                    TargetObject = $configFile
                }

                Write-Error @errParams
                continue
            }

            try
            {
                $xmlFile = New-Object -TypeName 'System.Xml.XmlDocument'
                $xmlFile.Load($configFile)

                switch ($xmlFile.SelectNodes($XPath).Count)
                {
                    15 {$configFileType = 'Legacy'; break}
                    16 {$configFileType = 'Modern'; break}
                    17 {$configFileType = 'WebAuthn'; break}
                }

                $vmId = $null
                $vmId = ($configFile | Select-String -Pattern $GuidRegexPattern).Matches.Value
                [System.String]$vmName = $xmlFile.SelectSingleNode($VMNameXPath).value
                [System.String]$vmServerName = $xmlFile.SelectSingleNode($VMServerNameXPath).value
            } #try
            catch
            {
                $PSCmdlet.WriteError($_)
                continue
            } #catch

            # Prevent $vmId from being part of the $actionString if $vmId is $null or an empty string.
            $actionVmId = $null

            if ([System.String]::IsNullOrEmpty($vmId) -eq $false)
            {
                $actionVmId = " ($vmid)"
            }

            $actionString = ($MsgTable.ActionMsgResetVmConfigFile -f $vmName, $actionVmId)

            if ($PSCmdlet.ShouldProcess($configFile, $actionString))
            {
                $newVmConfigProps = @{
                    Name = $vmName
                    Path = $configFile
                    VMServerName = $vmServerName
                    ConfigFileType = $configFileType
                    Force = $true
                    Verbose = $false
                    Confirm = $false
                    PassThru = $false
                }

                try
                {
                    Write-VMVerbose -FunctionName Reset-VMConnectConfig -Category Writing -Message ($MsgTable.ResetVmConfigFileMsg -f $configFile)
                    $null = New-VMConnectConfig @newVmConfigProps

                    if ($PassThru)
                    {
                        $passThruList += $configFile
                    } #if -PassThru
                } #try
                catch
                {
                    $PSCmdlet.WriteError($_)
                    continue
                } #catch
            } #ShouldProcess
        } #foreach $configFile

        if ($passThruList.Count -gt 0)
        {
            Get-VMConnectConfig -LiteralPath $passThruList
        }

        # Perform garbage collection.
        [System.GC]::Collect()
        [System.GC]::WaitForPendingFinalizers()
    } #end
} #function Reset-VMConnectConfig