Public/New-NSPFortiGateUserConversionCli.ps1
|
function New-NSPFortiGateUserConversionCli { <# .SYNOPSIS Converts FortiGate local users to RADIUS or LDAP authentication: the FortiGate CLI, plus a PowerShell snippet that adds the same users to AD groups. .DESCRIPTION Returns an object with: FGT 'config user local' setting each user's type and server; with -GroupName, a 'config user group' block too. 'set member' replaces a group's whole member list, so -ExistingGroupMembers (the group's current members) are kept and the converted users are appended, without duplicates (case-insensitive). With -Vdom the whole thing is wrapped in 'config vdom' / 'edit <Vdom>' ... 'end'. AD PowerShell that adds each user to every -ADGroups group, one user at a time so a user missing from AD doesn't stop the rest; $FailedUsers lists the ones that failed, ready to pass back as -DisabledUsernames. Lines end in CRLF. .PARAMETER Usernames The local users to convert. .PARAMETER TargetType radius or ldap. .PARAMETER ServerName The RADIUS or LDAP server object on the FortiGate. .PARAMETER ADGroups AD groups for the AD snippet. .PARAMETER DisabledUsernames Users that also get 'set status disable' (for example, people who have left). Case-insensitive. .PARAMETER GroupName FortiGate user group to add the converted users to. .PARAMETER ExistingGroupMembers The group's current members. Ignored without -GroupName. .PARAMETER Vdom The VDOM, on a multi-VDOM FortiGate. .EXAMPLE $inv = Get-NSPFortiGateUserInventory -Path .\FGT-backup.conf $users = @($inv.Users | Where-Object Type -eq 'password' | ForEach-Object Username) $out = New-NSPFortiGateUserConversionCli -Usernames $users -TargetType radius -ServerName 'NPS01' -ADGroups 'VPN_Staff' $out.FGT | Set-Clipboard #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Returns CLI text; changes nothing.')] [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)][string[]]$Usernames, [Parameter(Mandatory)][ValidateSet('radius', 'ldap')][string]$TargetType, [Parameter(Mandatory)][string]$ServerName, [string[]]$ADGroups = @(), [string[]]$DisabledUsernames = @(), [string]$GroupName, [string[]]$ExistingGroupMembers = @(), [string]$Vdom ) $disabledSet = [Collections.Generic.HashSet[string]]::new([string[]]@($DisabledUsernames | Where-Object { $_ }), [StringComparer]::OrdinalIgnoreCase) $fgtLines = [Collections.Generic.List[string]]::new() $fgtLines.Add('config user local') foreach ($u in $Usernames) { $fgtLines.Add(" edit `"$u`"") if ($disabledSet.Contains($u)) { $fgtLines.Add(' set status disable') } $fgtLines.Add(" set type $TargetType") $fgtLines.Add(" set $TargetType-server `"$ServerName`"") $fgtLines.Add(' next') } $fgtLines.Add('end') $fgtText = $fgtLines -join "`r`n" if ($GroupName) { $seen = [Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) $members = [Collections.Generic.List[string]]::new() foreach ($m in @($ExistingGroupMembers) + @($Usernames)) { if ($m -and $seen.Add($m)) { $members.Add($m) } } $quoted = (@($members | ForEach-Object { "`"$_`"" }) -join ' ') $fgtText += "`r`n`r`nconfig user group`r`n edit `"$GroupName`"`r`n set member $quoted`r`n next`r`nend" } if ($Vdom) { $indented = ($fgtText -split "`r`n" | ForEach-Object { if ($_) { " $_" } else { $_ } }) -join "`r`n" $fgtText = "config vdom`r`n edit `"$Vdom`"`r`n$indented`r`nend" } # One Add-ADGroupMember per user: a call with several members fails as a whole when one of # them doesn't resolve, adding nobody. $quotedMembers = (@($Usernames | ForEach-Object { "`"$_`"" }) -join ', ') $quotedGroups = (@($ADGroups | ForEach-Object { "`"$_`"" }) -join ', ') $adLines = @( "`$Members = @($quotedMembers)" "`$ADGroups = @($quotedGroups)" '' '$Success = @()' '$FailedUsers = @()' '' 'foreach ($user in $Members) {' ' try {' ' foreach ($group in $ADGroups) { Add-ADGroupMember -Identity $group -Members @($user) }' ' $Success += $user' ' } catch {' ' $FailedUsers += $user' ' }' '}' '' '$Success.Count' '$FailedUsers.Count' '$FailedUsers' ) [pscustomobject]@{ PSTypeName = 'NSP.FortiGate.UserConversion' FGT = $fgtText AD = $adLines -join "`r`n" } } |