Public/SyncRules/Set-JIMSyncRuleInitialPassword.ps1
|
# Copyright (c) Tetron Limited. All rights reserved. # Licensed under the Tetron Commercial License. See LICENSE file in the project root. function Set-JIMSyncRuleInitialPassword { <# .SYNOPSIS Configures the initial password a Synchronisation Rule sets on the accounts it provisions. .DESCRIPTION A newly provisioned account has no password and cannot be signed in to. Turning this on has JIM set one through the Connected System's password channel, straight after the account is created. By default JIM generates a different password for each account at the moment it is set, and stores none of them. -Source Static is the exception: it sets one password you choose on every account the rule provisions, so you can tell a new starter what it is. This option is not recommended: every account the rule provisions shares that password until each person changes it, so anybody who learns of this can sign in as any new starter who has not. Note: the password is stored encrypted and cannot be shown to you again, by this or any other surface, and it is the only password JIM stores. #1252 will deliver a generated password to somebody who should have it instead. Only the parameters provided are changed; everything else keeps its stored value. The exception is the generator settings, which are replaced as a set: supplying any of the -Style, -Length, -Minimum*, -Word*, -Appended*, -PermittedSymbols or -ExcludeAmbiguousCharacters parameters sends the whole policy, because those settings only make sense together. Read the current values with Get-JIMSyncRuleInitialPassword first if you are changing one of them in isolation. Turning this on requires an Export Synchronisation Rule that provisions to the Connected System: only an account JIM has just created has never had a password. Settings that cannot produce a password are refused here rather than parking every account they touch. .PARAMETER Id The unique identifier of the Synchronisation Rule. .PARAMETER InputObject Synchronisation Rule object to update (from pipeline). .PARAMETER Enable Sets an initial password on the accounts this Synchronisation Rule provisions. .PARAMETER Disable Stops setting an initial password. The settings are kept, so re-enabling restores them. .PARAMETER Source Where the password comes from. Valid values: - Discovered: generate one per account, deriving the settings from the password policy JIM discovered on the Connected System, and re-deriving whenever that policy is read again. - Custom: generate one per account using exactly the settings saved on this rule. - Static: set the one password supplied with -StaticPassword on every account. Not recommended; see the description. .PARAMETER StaticPassword The one password to set on every account this Synchronisation Rule provisions, used when -Source is Static. Supply it as a SecureString so it does not sit in the session's command history in clear text. Write-only: JIM encrypts it and never returns it. Omit it to leave the stored password as it is, which is what makes changing another setting safe. A password the Connected System would refuse is rejected here rather than parking every account the rule provisions. .PARAMETER Style How the password is composed. Valid values: RandomCharacters, Words, Pronounceable. .PARAMETER Length How many characters to produce. Ignored by the Words style, whose length follows from the words drawn. .PARAMETER MinimumUppercase The fewest uppercase letters a generated password must contain (RandomCharacters style). .PARAMETER MinimumLowercase The fewest lowercase letters a generated password must contain (RandomCharacters style). .PARAMETER MinimumDigits The fewest digits a generated password must contain (RandomCharacters style). .PARAMETER MinimumSymbols The fewest symbols a generated password must contain (RandomCharacters style). .PARAMETER PermittedSymbols The symbols JIM may use. Narrow this where something downstream cannot cope with a given character. .PARAMETER WordCount How many words to draw (Words style). .PARAMETER WordSeparator What goes between the words (Words style). Valid values: None, Hyphen, FullStop, Underscore, Digit, RandomSymbol. .PARAMETER WordCapitalisation How the words are capitalised (Words style). Valid values: Lowercase, EachWord, Uppercase, FirstWordOnly, RandomWord. .PARAMETER AppendedDigitCount How many digits to append (Words and Pronounceable styles). Usually how a passphrase reaches the three character categories a stock Active Directory domain requires. .PARAMETER AppendSymbol Whether to append one symbol (Words and Pronounceable styles). .PARAMETER ExcludeAmbiguousCharacters Whether to leave out characters that are easily confused when a password is read out or copied by hand. .PARAMETER ExpiryBehaviour What happens to the password once it is set. Valid values: RequireChangeAtNextSignIn, ExpiresAccordingToTargetPolicy, NeverExpires. A Connector that cannot honour the choice records what it applied instead, per account. .PARAMETER EnableAccount Whether the account is enabled once the password is set. Directories that refuse to enable an account without a compliant password need the password first, which is why this belongs here rather than in an Attribute Flow. .PARAMETER ChangeReason An optional reason for the change, recorded against this Synchronisation Rule's change history. .PARAMETER PassThru If specified, returns the updated initial password configuration. .OUTPUTS If -PassThru is specified, returns the updated initial password configuration. .EXAMPLE Set-JIMSyncRuleInitialPassword -Id 5 -Enable Sets an initial password on the accounts Synchronisation Rule 5 provisions, following the password policy JIM discovered on the Connected System. .EXAMPLE Set-JIMSyncRuleInitialPassword -Id 5 -Enable -Source Custom -Style Words -WordCount 4 -WordSeparator Hyphen -AppendedDigitCount 2 Uses a four-word passphrase with two appended digits, which is easier to read out to somebody over the telephone than a random string. .EXAMPLE $password = Read-Host -AsSecureString "Initial password for every new account" Set-JIMSyncRuleInitialPassword -Id 5 -Enable -Source Static -StaticPassword $password Sets one password on every account this rule provisions. Not recommended: every new starter shares it until each of them changes it. Leave -ExpiryBehaviour at its default so that first sign-in ends each account's share of it. .EXAMPLE $password = Read-Host -AsSecureString "New shared initial password" Set-JIMSyncRuleInitialPassword -Id 5 -StaticPassword $password -ChangeReason "Rotated after a leaver (CHG0043)" Rotates the shared password, leaving every other setting alone. Do this whenever somebody who knew it leaves; Get-JIMSyncRuleInitialPassword reports when it last changed. .EXAMPLE Set-JIMSyncRuleInitialPassword -Id 5 -Disable -ChangeReason "Accounts are now provisioned pre-enabled (CHG0042)" Stops setting an initial password, recording why against the rule's change history. .EXAMPLE Get-JIMSyncRule -Id 5 | Set-JIMSyncRuleInitialPassword -ExpiryBehaviour NeverExpires -PassThru Changes only the expiry behaviour, leaving every other setting as it was. .LINK Get-JIMSyncRuleInitialPassword Set-JIMSyncRule #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ById')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, ParameterSetName = 'ById', ValueFromPipelineByPropertyName)] [int]$Id, [Parameter(Mandatory, ParameterSetName = 'ByInputObject', ValueFromPipeline)] [PSCustomObject]$InputObject, [Parameter()] [switch]$Enable, [Parameter()] [switch]$Disable, [Parameter()] [ValidateSet('Discovered', 'Custom', 'Static')] [string]$Source, [Parameter()] [ValidateNotNull()] [securestring]$StaticPassword, [Parameter()] [ValidateSet('RandomCharacters', 'Words', 'Pronounceable')] [string]$Style, [Parameter()] [ValidateRange(1, 256)] [int]$Length, [Parameter()] [ValidateRange(0, 64)] [int]$MinimumUppercase, [Parameter()] [ValidateRange(0, 64)] [int]$MinimumLowercase, [Parameter()] [ValidateRange(0, 64)] [int]$MinimumDigits, [Parameter()] [ValidateRange(0, 64)] [int]$MinimumSymbols, [Parameter()] [ValidateNotNullOrEmpty()] [string]$PermittedSymbols, [Parameter()] [ValidateRange(1, 16)] [int]$WordCount, [Parameter()] [ValidateSet('None', 'Hyphen', 'FullStop', 'Underscore', 'Digit', 'RandomSymbol')] [string]$WordSeparator, [Parameter()] [ValidateSet('Lowercase', 'EachWord', 'Uppercase', 'FirstWordOnly', 'RandomWord')] [string]$WordCapitalisation, [Parameter()] [ValidateRange(0, 16)] [int]$AppendedDigitCount, [Parameter()] [bool]$AppendSymbol, [Parameter()] [bool]$ExcludeAmbiguousCharacters, [Parameter()] [ValidateSet('RequireChangeAtNextSignIn', 'ExpiresAccordingToTargetPolicy', 'NeverExpires')] [string]$ExpiryBehaviour, [Parameter()] [bool]$EnableAccount, [Parameter()] [ValidateNotNullOrEmpty()] [string]$ChangeReason, [switch]$PassThru ) process { if (-not $script:JIMConnection) { Write-Error "You are not connected to JIM. Run Connect-JIM -Url <your JIM URL> to authenticate, then try again." return } if ($Enable -and $Disable) { Write-Error "Specify either -Enable or -Disable, not both." return } $ruleId = if ($InputObject) { $InputObject.id } else { $Id } $body = @{} if ($Enable) { $body.enabled = $true } elseif ($Disable) { $body.enabled = $false } if ($PSBoundParameters.ContainsKey('Source')) { $body.source = $Source } if ($PSBoundParameters.ContainsKey('StaticPassword')) { # Unwrapped once, here, and sent over TLS for the API to encrypt. A SecureString on the parameter is # what keeps it out of the session's command history and any transcript of it. $body.staticPassword = ConvertFrom-SecureString -SecureString $StaticPassword -AsPlainText } if ($PSBoundParameters.ContainsKey('ExpiryBehaviour')) { $body.expiryBehaviour = $ExpiryBehaviour } if ($PSBoundParameters.ContainsKey('EnableAccount')) { $body.enableAccount = $EnableAccount } # The generator settings travel as one object because they only make sense together, so touching any of # them means reading the stored set and sending it back with the changes applied. Sending a partial # policy would silently reset the fields left out to the API's defaults. $policyParameters = @( 'Style', 'Length', 'MinimumUppercase', 'MinimumLowercase', 'MinimumDigits', 'MinimumSymbols', 'PermittedSymbols', 'WordCount', 'WordSeparator', 'WordCapitalisation', 'AppendedDigitCount', 'AppendSymbol', 'ExcludeAmbiguousCharacters') $changedPolicyParameters = @($policyParameters | Where-Object { $PSBoundParameters.ContainsKey($_) }) if ($changedPolicyParameters.Count -gt 0) { try { $current = Invoke-JIMApi -Endpoint "/api/v1/synchronisation/sync-rules/$ruleId/initial-password" -Method 'GET' } catch { Write-Error "Failed to read the current initial password settings before updating them: $_" return } # The stored names come back normalised to PascalCase by ConvertTo-JIMOutputObject, and the # parameter names are PascalCase too, so a changed setting overwrites the copied one rather than # sitting beside it under a differently-cased key. JSON binding is case-insensitive at the far end, # but a body carrying both spellings of the same setting is a trap for whoever reads it next. $policy = @{} foreach ($property in $current.CustomPolicy.PSObject.Properties) { $policy[$property.Name] = $property.Value } foreach ($parameter in $changedPolicyParameters) { $policy[$parameter] = $PSBoundParameters[$parameter] } $body.customPolicy = $policy } # A change reason alone is not an update; require at least one actual change first. if ($body.Count -eq 0) { Write-Warning "No updates specified." return } if ($PSBoundParameters.ContainsKey('ChangeReason')) { $body.changeReason = $ChangeReason } if ($PSCmdlet.ShouldProcess($ruleId, "Update Synchronisation Rule initial password configuration")) { Write-Verbose "Updating the initial password configuration of Synchronisation Rule: $ruleId" try { $result = Invoke-JIMApi -Endpoint "/api/v1/synchronisation/sync-rules/$ruleId/initial-password" -Method 'PUT' -Body $body if ($PassThru) { $result } } catch { Write-Error "Failed to update the initial password configuration: $_" } } } } |