New-NpsRadiusClientWithTemplate.ps1
#requires -Version 2.0 <#PSScriptInfo .VERSION 0.1 .GUID 59c4a6c3-5bd5-43cd-913b-f4e533f6ef73 .AUTHOR Chris Masters .COMPANYNAME Chris Masters .COPYRIGHT (c) 2019 Chris Masters. All rights reserved. .TAGS NPS RADIUS SecretKey SharedSecret .LICENSEURI .PROJECTURI https://www.powershellgallery.com/profiles/masters274/ .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Initial release, with very little testing. I know it works for adding. And when you check the GUI, it shows the device as using the template. However, I have not gone so far as to setup a dev env so I could change the keys we use for our various SharedSecretTemplates. Some notes on the process (observed only, not research)... The IAS (Network Policy Server) service stores its files in $env:SystemRoot\System32\IAS\ When you edit data, it gets entered into ias_converted.xml and ias.xml. I'm not sure of the process or reason for the two different files, as they're identical (SHA256 hashed). Maybe the changes are entered into the converted files, checked for proper formatting, then copied to ias.xml...? Either way, I don't think it would be a good idea to edit these files directly, because stuff happens. PROCESS: - First the script creates a session with your NPS server. - Creates a new NPS radius client - Exports the configuration (messy, I know. Yet will be worth it when you need to change the key later) - Changes the GUID for the template used on that client - Then imports the changed config - And optionaly restarts the service. I've noticed that it doesn't take affect until a service restart when editing via the command line. Also of note.... it wasn't 3am when I wrote this, so not my best work... but it was pretty late, so maybe it's not so bad. .PRIVATEDATA #> <# .Synopsis Adds a new NPS RADIUS client, and applies an authentication template to the client .DESCRIPTION Why Microsoft doesn't give you the ability to apply a template when creating a new client puzzles me. This script aims to solve this problem, as many organizations have a lot of devices, and a password policy that requires changing RADIUS secrets. You don't want to have to update all the clients, just the template. That why we use them...! This may not be the best way to solve this problem, however it does work. .EXAMPLE Example of how to use this cmdlet .EXAMPLE Another example of how to use this cmdlet .NOTES I would suggest that you add default parameter values into your profile. You don't want to put in values that don't change often, every time. $PSDefaultParameterValues = @{ ComputerName = 'myNpsServer.domain.name' AuthenticationTemplate = 'Cisco_Template' Vendor = 'Cisco' } #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$true, position=0, HelpMessage='Client name', ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [String] $ClientName, [Parameter(Mandatory=$true, position=1, HelpMessage='Client IP', ValueFromPipelineByPropertyName=$true)] [IPAddress] $IPAddress, [Parameter(Mandatory=$true, HelpMessage='Name of computer to manage', ValueFromPipelineByPropertyName=$true)] [String] $AuthenticationTemplate, [Parameter(Mandatory=$false, HelpMessage='Radius client vendor name. i.e cisco', ValueFromPipelineByPropertyName=$true)] [String] $Vendor = 'RADIUS Standard', [Parameter(Mandatory=$true, HelpMessage='Name of NPS server(s)')] [String[]] $ComputerName, [Switch] $Restart, # The service needs to be restarted before the settings take effect [Parameter(Mandatory=$false, HelpMessage='Credentials for administering NPS')] [System.Management.Automation.Credential()] [PSCredential] $Credential, [ValidateSet('Default','Basic','CredSSP','Digest','Kerberos','Negotiate','NegotiateWithImplicitCredential')] [String] $Authentication = 'Kerberos' ) Begin { # If you don't want ur stuff to work, don't restart If (!$Restart) { Write-Warning -Message 'You need to restart before settings take affect' } # Constants $Params = @{ ComputerName = $ComputerName Authentication = $Authentication } If ($Credential) { $Params += @{ Credential = $Credential } } # We only need to make our connection once $s = New-PSSession @Params } Process { # Variables [ScriptBlock] $sbCommand = { Param ( $ClientName, $IPAddress, $AuthenticationTemplate, $Vendor, $Restart ) Try { # IAS templates are stored in a file on the NPS server. [String] $strIASFile = $env:SystemRoot + '\System32\ias\iastemplates.xml' [xml] $objIAS = Get-Content -Path $strIASFile [String] $strTemplateGuid = $objIAS.GetElementsByTagName($AuthenticationTemplate).Properties.Template_Guid.InnerText [String] $strSharedSecret = $objIAS.GetElementsByTagName($AuthenticationTemplate).Properties.RADIUS_Shared_Secret.InnerText # We need to make the object firt, then we'll apply the auth template New-NpsRadiusClient -Name $ClientName -Address ($IPAddress.ToString()) -AuthAttributeRequired $False -VendorName $Vendor -SharedSecret $strSharedSecret # we now need to export the config, update the affected object, then re-import $strTempExportFile = [System.IO.Path]::GetTempPath() + [Guid]::NewGuid().guid + '.xml' $strTempImportFile = [System.IO.Path]::GetTempPath() + [Guid]::NewGuid().guid + '.xml' Export-NpsConfiguration -Path $strTempExportFile [xml] $objNPSExport = Get-Content $strTempExportFile } Catch { "Error was $_" $line = $_.InvocationInfo.ScriptLineNumber "Error was in Line $line" } Try { $cleanedClientName = $ClientName -replace '\s|\-','_' $objNPSExport.GetElementsByTagName($cleanedClientName).properties.Client_Secret_Template_Guid.'#text' = $strTemplateGuid } Catch { # No need to keep it, if we can't find it later. Remove-NpsRadiusClient -Name $ClientName -ErrorAction SilentlyContinue # clean up the temp file Remove-Item -Path $strTempExportFile Write-Error -Message 'Unable to find your object. Please only use uderscores "_", instead of spaces or dashes "-"' # exiting return } $objNPSExport.Save($strTempImportFile) Import-NpsConfiguration -Path $strTempImportFile # Clean up remove-item -Path $strTempExportFile -ErrorAction SilentlyContinue Remove-Item -Path $strTempImportFile -ErrorAction SilentlyContinue # when making changes to clients, the service has to be restarted. If ($Restart) { Restart-Service -Name IAS } } Invoke-Command -Session $s -ScriptBlock $sbCommand -ArgumentList $ClientName, $IPAddress, $AuthenticationTemplate, $Vendor, $Restart } End { Remove-PSSession -Session $s } |