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 Changes a Synchronisation Rule's initial password settings. .DESCRIPTION A newly provisioned Connected System Object 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 it is created. By default JIM generates a different password for each, at the moment it is set, and stores none of them. -Source Static is the exception: it sets one password you choose on every Connected System Object the rule provisions, so you can tell a new starter what it is. It is not recommended: they all share that password until each person changes it, so anybody who learns it can sign in as any new starter who has not. The password is stored encrypted, cannot be shown again on any surface, and is the only password JIM stores. Only the parameters you give change; everything else keeps its stored value. The exception is the generator settings, which are replaced as a set: giving any of -Style, -Length, -Minimum*, -Word*, -Appended*, -PermittedSymbols or -ExcludeAmbiguousCharacters sends the whole policy, because those settings only make sense together. Read the current values with Get-JIMSyncRuleInitialPassword first when changing one of them on its own. Turning this on needs an export Synchronisation Rule that provisions to the Connected System: only a Connected System Object JIM has just created has never had a password. Settings that cannot produce a password are refused here, rather than parking every Connected System Object they touch. .PARAMETER Id The ID of the Synchronisation Rule. .PARAMETER InputObject A Synchronisation Rule from Get-JIMSyncRule, through the 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. Discovered generates one per Connected System Object from the password policy JIM discovered on the Connected System, re-deriving the settings whenever the policy is read again. Custom generates one per Connected System Object from the settings saved on this rule. Static sets the one password given with -StaticPassword on every Connected System Object; it is not recommended. .PARAMETER StaticPassword The one password to set on every Connected System Object this Synchronisation Rule provisions, used when -Source is Static. Give 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 Connected System Object the rule provisions. .PARAMETER Style How the password is composed. .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). .PARAMETER WordCapitalisation How the words are capitalised (Words style). .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. A Connector that cannot honour the choice records what it applied instead, for each Connected System Object. On Active Directory and Samba AD, Password never expires follows this only where no export has written the account's userAccountControl by the time the password is delivered; where one has, the Attribute Flow decides it. Requiring a change at the next sign-in always applies. .PARAMETER EnableAccount Whether the Connected System Object is enabled once the password is set. It applies only where no export has written the object's enabled state (such as userAccountControl) by the time the password is delivered; where one has, the Attribute Flow decides. $false leaves it as it was created. It also applies, with whether the password never expires, when a password change already waiting for the person is delivered as the object's first password instead of the Initial Password. .PARAMETER ChangeReason An optional reason for the change, recorded against this Synchronisation Rule's change history. .PARAMETER PassThru Returns the settings as changed. .OUTPUTS With -PassThru, the settings as changed; otherwise nothing. .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('JIM.SyncRuleInitialPasswordResponse')] 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: $_" } } } } |