diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml index 0ffa79b9a..d95e267a8 100644 --- a/.github/workflows/release-workflow.yml +++ b/.github/workflows/release-workflow.yml @@ -44,32 +44,25 @@ jobs: Setup-Build-Dependancies: needs: ["Filter-Branch", "Check-PR-Labels"] - runs-on: ubuntu-latest + runs-on: windows-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - name: Setup PowerShell Module Cache id: cacher - uses: actions/cache@v3 + uses: actions/cache@v4 with: - path: "/home/runner/.local/share/powershell/Modules/" + path: 'C:\Users\runneradmin\Documents\PowerShell\Modules\' key: PS-Dependancies - - name: Install System Dependencies - if: steps.cacher.outputs.cache-hit != 'true' - shell: pwsh - run: | - Install-PackageProvider -Name:('NuGet') -Scope:('CurrentUser') -Force - name: Install dependencies if: steps.cacher.outputs.cache-hit != 'true' shell: pwsh run: | Set-PSRepository PSGallery -InstallationPolicy Trusted - If (!(Get-PackageProvider -Name:('NuGet') -ListAvailable -ErrorAction:('SilentlyContinue'))) { Write-Host ('[status]Installing package provider NuGet'); Install-PackageProvider -Name:('NuGet') -Scope:('CurrentUser') -Force } - $PSDependencies = @{ 'PowerShellGet' = @{Repository = 'PSGallery'; RequiredVersion = '3.0.12-beta' } 'PackageManagement' = @{Repository = 'PSGallery'; RequiredVersion = '1.4.8.1' } @@ -81,22 +74,25 @@ jobs: 'JumpCloud.SDK.V2' = @{Repository = 'PSGallery'; RequiredVersion = '0.0.39'} 'JumpCloud.SDK.DirectoryInsights' = @{Repository = 'PSGallery'; RequiredVersion = '0.0.23'} } - foreach ($RequiredModule in $PSDependencies.Keys) { If ([System.String]::IsNullOrEmpty((Get-InstalledModule | Where-Object { $_.Name -eq $RequiredModule }))) { Write-Host("[status]Installing module: '$RequiredModule'; version: $($PSDependencies[$RequiredModule].RequiredVersion) from $($PSDependencies[$RequiredModule].Repository)") - Install-Module -Name $RequiredModule -Repository:($($PSDependencies[$RequiredModule].Repository)) -RequiredVersion:($($PSDependencies[$RequiredModule].RequiredVersion)) -AllowPrerelease -Force + if ($($PSDependencies[$RequiredModule].RequiredVersion) -eq "latest"){ + Install-Module -Name $RequiredModule -Repository:($($PSDependencies[$RequiredModule].Repository)) -AllowPrerelease -Force + } else { + Install-Module -Name $RequiredModule -Repository:($($PSDependencies[$RequiredModule].Repository)) -RequiredVersion:($($PSDependencies[$RequiredModule].RequiredVersion)) -AllowPrerelease -Force -AllowClobber + } } } Build-Nuspec-Nupkg: needs: Setup-Build-Dependancies - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: - path: "/home/runner/.local/share/powershell/Modules/" + path: 'C:\Users\runneradmin\Documents\PowerShell\Modules\' key: PS-Dependancies - name: Build Nuspec shell: pwsh @@ -126,7 +122,7 @@ jobs: uses: ./.github/actions/upload-secure-artifact with: name: jumpcloud-module-nupkg - path: /home/runner/work/support/support/JumpCloud.*.nupkg + path: D:/a/support/support/JumpCloud.*.nupkg retention-days: 1 Manual-Approval-Release: @@ -156,7 +152,7 @@ jobs: Deploy-Nupkg: needs: [Manual-Approval-Release, Build-Nuspec-Nupkg] - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Download nupkg artifact uses: actions/download-artifact@v4 diff --git a/PowerShell/JumpCloud Module/Docs/Get-JCSystem.md b/PowerShell/JumpCloud Module/Docs/Get-JCSystem.md index d8c741a9c..47c6ad5cf 100644 --- a/PowerShell/JumpCloud Module/Docs/Get-JCSystem.md +++ b/PowerShell/JumpCloud Module/Docs/Get-JCSystem.md @@ -357,7 +357,7 @@ Valid properties that can be returned are: 'created', 'active', 'agentVersion', Type: System.String[] Parameter Sets: SearchFilter Aliases: -Accepted values: acknowledged, active, agentVersion, allowMultiFactorAuthentication, allowPublicKeyAuthentication, allowSshPasswordAuthentication, allowSshRootLogin, arch, azureAdJoined, connectionHistory, created, displayName, domainInfo, fde, fileSystem, hasServiceAccount, hostname, lastContact, mdm, modifySSHDConfig, networkInterfaces, organization, os, osFamily, provisionMetadata, remoteIP, serialNumber, serviceAccountState, sshdParams, systemInsights, systemTimezone, templateName, userMetrics, usernameHashes, version, hwVendor, secureLogin, displayManager, amazonInstanceID, archFamily, builtInCommands, description, osVersionDetail, policyStats, desktopCapable, sshRootEnabled, isPolicyBound +Accepted values: acknowledged, active, agentVersion, allowMultiFactorAuthentication, allowPublicKeyAuthentication, allowSshPasswordAuthentication, allowSshRootLogin, arch, azureAdJoined, connectionHistory, created, displayName, domainInfo, fde, fileSystem, hasServiceAccount, hostname, lastContact, mdm, modifySSHDConfig, networkInterfaces, organization, os, osFamily, primarySystemUser, provisionMetadata, remoteAssistAgentVersion, remoteIP, serialNumber, serviceAccountState, sshdParams, systemInsights, systemTimezone, templateName, userMetrics, usernameHashes, version, hwVendor, secureLogin, displayManager, amazonInstanceID, archFamily, builtInCommands, description, osVersionDetail, policyStats, desktopCapable, sshRootEnabled, isPolicyBound Required: False Position: Named diff --git a/PowerShell/JumpCloud Module/Docs/Get-JCUserGroupMember.md b/PowerShell/JumpCloud Module/Docs/Get-JCUserGroupMember.md index db82cbe0b..db9914378 100644 --- a/PowerShell/JumpCloud Module/Docs/Get-JCUserGroupMember.md +++ b/PowerShell/JumpCloud Module/Docs/Get-JCUserGroupMember.md @@ -56,7 +56,7 @@ If searching for a User Group using the GroupID populate the GroupID in the -ByI ```yaml Type: System.String Parameter Sets: ByID -Aliases: +Aliases: GroupID Required: True Position: Named diff --git a/PowerShell/JumpCloud Module/Docs/JumpCloud.md b/PowerShell/JumpCloud Module/Docs/JumpCloud.md index b28a8d9e2..d576f33ae 100644 --- a/PowerShell/JumpCloud Module/Docs/JumpCloud.md +++ b/PowerShell/JumpCloud Module/Docs/JumpCloud.md @@ -2,7 +2,7 @@ Module Name: JumpCloud Module Guid: 31c023d1-a901-48c4-90a3-082f91b31646 Download Help Link: https://github.com/TheJumpCloud/support/wiki -Help Version: 2.17.0 +Help Version: 2.18.0 Locale: en-Us --- diff --git a/PowerShell/JumpCloud Module/Docs/New-JCPolicy.md b/PowerShell/JumpCloud Module/Docs/New-JCPolicy.md index 47fe825c7..ceced17d8 100644 --- a/PowerShell/JumpCloud Module/Docs/New-JCPolicy.md +++ b/PowerShell/JumpCloud Module/Docs/New-JCPolicy.md @@ -82,6 +82,14 @@ PS C:\> New-JCPolicy -TemplateName windows_Advanced:_Custom_Registry_Keys -Name This command would create a new Windows Custom Registry Policy named "Windows - Imported Custom Registry Settings" and populate the values from a registry file. .Reg registry files can be passed into New-JCPolicy as long as the TemplateName is specified with the corresponding "windows_Advanced:\_Custom_Registry_Keys" template. .Reg files will be converted and uploaded to the JumpCloud policy as long as they contain "DWORD", "EXPAND_SZ", "MULTI_SZ", "SZ" or "QWORD" type data. +### Example 6 + +```PowerShell +PS C:\> New-JCPolicy -TemplateName custom_oma_uri_mdm_windows -Name "Windows - Custom OMA MDM Policy" -uriList '(@( @{format = "string"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage; value = "pathToImage" }, @{format = "int"; uri = "./Device/Vendor/MSFT/Policy/Config/DeviceLock/AccountLockoutPolicy"; value = "1" } ))' +``` + +This command creates a JumpCloud policy named "Windows - Custom OMA MDM Policy" using the custom_oma_uri_mdm_windows template. It defines two OMA-URI configurations: a string value for EnforceLockScreenAndLogonImage and an integer value for AccountLockoutPolicy. + ## PARAMETERS ### -Name diff --git a/PowerShell/JumpCloud Module/Docs/Set-JCPolicy.md b/PowerShell/JumpCloud Module/Docs/Set-JCPolicy.md index 2af62fd6e..9445a5cc9 100644 --- a/PowerShell/JumpCloud Module/Docs/Set-JCPolicy.md +++ b/PowerShell/JumpCloud Module/Docs/Set-JCPolicy.md @@ -90,6 +90,14 @@ PS C:\> Set-JCPolicy -PolicyName "Windows - Imported Custom Registry Settings" This command would overwrite the registry policy's existing values with the imported set of .Reg keys specified by the "RegistryFile" parameter. .Reg files will be converted and uploaded to the JumpCloud policy as long as they contain "DWORD", "EXPAND_SZ", "MULTI_SZ", "SZ" or "QWORD" type data. +### Example 7 + +```powershell +PS C:\> Set-JCPolicy -PolicyName "Windows - Custom OMA MDM Policy" -uriList '(@( @{format = "string"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage; value = "pathToImage" }, @{format = "int"; uri = "./Device/Vendor/MSFT/Policy/Config/DeviceLock/AccountLockoutPolicy"; value = "2" } ))' +``` + +This command modifies the existing JumpCloud policy named "Windows - Custom OMA MDM Policy". It updates the policy's OMA-URI settings using the -uriList parameter. The EnforceLockScreenAndLogonImage setting, a string, remains set to "pathToImage". The AccountLockoutPolicy setting, an integer, is updated from its previous value to "2", effectively changing the account lockout policy configuration. + ## PARAMETERS ### -NewName diff --git a/PowerShell/JumpCloud Module/Docs/Set-JCSettingsFile.md b/PowerShell/JumpCloud Module/Docs/Set-JCSettingsFile.md index 7f6b8fb85..1bb2c174f 100644 --- a/PowerShell/JumpCloud Module/Docs/Set-JCSettingsFile.md +++ b/PowerShell/JumpCloud Module/Docs/Set-JCSettingsFile.md @@ -14,8 +14,8 @@ Updates the JumpCloud Module Settings File ## SYNTAX ``` -Set-JCSettingsFile [-moduleBannerMessageCount ] - [-parallelOverride ] [] +Set-JCSettingsFile [-parallelOverride ] + [-moduleBannerMessageCount ] [] ``` ## DESCRIPTION diff --git a/PowerShell/JumpCloud Module/Docs/Set-JCSystem.md b/PowerShell/JumpCloud Module/Docs/Set-JCSystem.md index 52c1cb175..b51f30723 100644 --- a/PowerShell/JumpCloud Module/Docs/Set-JCSystem.md +++ b/PowerShell/JumpCloud Module/Docs/Set-JCSystem.md @@ -16,7 +16,8 @@ Updates an existing JumpCloud System Set-JCSystem [-SystemID] [-displayName ] [-description ] [-allowSshPasswordAuthentication ] [-allowSshRootLogin ] [-allowMultiFactorAuthentication ] [-allowPublicKeyAuthentication ] - [-systemInsights ] [] + [-systemInsights ] [-primarySystemUser ] + [] ``` ## DESCRIPTION @@ -133,6 +134,21 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` +### -primarySystemUser +A string value indicating a JumpCloud users email, username or userID. This will add the user to the device associations + +```yaml +Type: System.Object +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -SystemID The _id of the System which you want to remove from JumpCloud. The SystemID will be the 24 character string populated for the _id field. diff --git a/PowerShell/JumpCloud Module/JumpCloud.psd1 b/PowerShell/JumpCloud Module/JumpCloud.psd1 index cd1ebbf1b..bc95ae5c1 100644 --- a/PowerShell/JumpCloud Module/JumpCloud.psd1 +++ b/PowerShell/JumpCloud Module/JumpCloud.psd1 @@ -3,7 +3,7 @@ # # Generated by: JumpCloud Solutions Architect Team # -# Generated on: 1/3/2025 +# Generated on: 4/18/2025 # @{ @@ -12,7 +12,7 @@ RootModule = 'JumpCloud.psm1' # Version number of this module. -ModuleVersion = '2.17.0' +ModuleVersion = '2.18.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/PowerShell/JumpCloud Module/Private/NestedFunctions/Convert-JCUserToID.ps1 b/PowerShell/JumpCloud Module/Private/NestedFunctions/Convert-JCUserToID.ps1 new file mode 100644 index 000000000..61358ff69 --- /dev/null +++ b/PowerShell/JumpCloud Module/Private/NestedFunctions/Convert-JCUserToID.ps1 @@ -0,0 +1,78 @@ +function Convert-JCUserToID { + [CmdletBinding(DefaultParameterSetName = 'Default')] + Param( + [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0, HelpMessage = 'The username, id or email of a user')][ValidateNotNullOrEmpty()] + [System.String]$UserIdentifier + ) + process { + # First check if UserIdentifier returns valid user with id + # Regex match a userid + $regexPattern = [Regex]'^[a-z0-9]{24}$' + if (((Select-String -InputObject $UserIdentifier -Pattern $regexPattern).Matches.value)::IsNullOrEmpty) { + # if we have a 24 characterid, try to match the id using the search endpoint + $UserIdentifierSearch = @{ + filter = @{ + 'and' = @( + @{'_id' = @{'$eq' = "$($UserIdentifier)" } } + ) + } + fields = 'id' + } + $UserIdentifierResults = Search-JcSdkUser -Body:($UserIdentifierSearch) + # Set UserIdentifierValue; this is a validated user id + $UserIdentifierValue = $UserIdentifierResults.id + } else { + # Use class mailaddress to check if $_.value is email + try { + $null = [mailaddress]$UserIdentifier + Write-Debug "This is true" + # Search for UserIdentifier using email + $UserIdentifierSearch = @{ + filter = @{ + 'and' = @( + @{'email' = @{'$regex' = "(?i)(`^$($UserIdentifier)`$)" } } + ) + } + fields = 'email' + } + $UserIdentifierResults = Search-JcSdkUser -Body:($UserIdentifierSearch) + # Set UserIdentifierValue; this is a validated user id + $UserIdentifierValue = $UserIdentifierResults.id + # if no value was returned, then assume the case this is actually a username and search + if (!$UserIdentifierValue) { + $UserIdentifierSearch = @{ + filter = @{ + 'and' = @( + @{'username' = @{'$regex' = "(?i)(`^$($UserIdentifier)`$)" } } + ) + } + fields = 'username' + } + $UserIdentifierResults = Search-JcSdkUser -Body:($UserIdentifierSearch) + # Set UserIdentifierValue from the matched username + $UserIdentifierValue = $UserIdentifierResults.id + } + } catch { + # search the username in the search endpoint + $UserIdentifierSearch = @{ + filter = @{ + 'and' = @( + @{'username' = @{'$regex' = "(?i)(`^$($UserIdentifier)`$)" } } + ) + } + fields = 'username' + } + $UserIdentifierResults = Search-JcSdkUser -Body:($UserIdentifierSearch) + # Set UserIdentifierValue from the matched username + $UserIdentifierValue = $UserIdentifierResults.id + } + } + } + end { + if ($null -eq $UserIdentifierValue) { + throw "Could not validate $UserIdentifier. Please ensure the information was entered correctly." + } else { + return $UserIdentifierValue + } + } +} \ No newline at end of file diff --git a/PowerShell/JumpCloud Module/Private/Policies/Get-JCPolicyTemplateConfigField.ps1 b/PowerShell/JumpCloud Module/Private/Policies/Get-JCPolicyTemplateConfigField.ps1 index 7f1fb756e..5ec3640bc 100644 --- a/PowerShell/JumpCloud Module/Private/Policies/Get-JCPolicyTemplateConfigField.ps1 +++ b/PowerShell/JumpCloud Module/Private/Policies/Get-JCPolicyTemplateConfigField.ps1 @@ -22,6 +22,7 @@ function Get-JCPolicyTemplateConfigField { file = 'file' select = 'multi' number = 'int' + multiList = 'multilist' } } process { diff --git a/PowerShell/JumpCloud Module/Private/Policies/New-UriListItem.ps1 b/PowerShell/JumpCloud Module/Private/Policies/New-UriListItem.ps1 new file mode 100644 index 000000000..06af7b7f6 --- /dev/null +++ b/PowerShell/JumpCloud Module/Private/Policies/New-UriListItem.ps1 @@ -0,0 +1,169 @@ +function New-UriListItem { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [System.String]$uri, + + [Parameter(Mandatory = $false)] + [ValidateSet('int', 'string', 'chr', 'boolean', 'bool', 'float', 'xml', 'base64', 'b64')] + [System.String]$format, + + [Parameter(Mandatory = $false)] + [System.String]$value + ) + + process { + if (-not $uri -or -not $format -or -not $value) { + Write-Host "Please provide the URI, format, and value." + $uri = Read-Host "Enter URI" + + do { + $format = Read-Host "Enter format (int, string, boolean, float, xml, base64)" + if ($format -notin ('int', 'string', 'boolean', 'float', 'xml', 'base64')) { + Write-Warning "Invalid format. Please enter one of the following: int, string, boolean, float, xml, base64" + } + } while ($format -notin ('int', 'string', 'boolean', 'float', 'xml', 'base64')) + + $isValidValue = $false + do { + $value = Read-Host "Enter the value: (format: $format)" + + switch ($format) { + 'int' { + try { + $validateInt = [int]$value + $isValidValue = $true + } catch { + Write-Warning "Invalid integer value. Please enter a valid integer number." + } + + } + 'float' { + try { + $validateFloat = [float]$value + $isValidValue = $true + } catch { + Write-Warning "Invalid float value. Please enter a valid float number." + } + + } + 'boolean' { + try { + $validateBoolean = [System.Convert]::ToBoolean($value) + $isValidValue = $true + $format = 'bool' # API expects boolean to be passed as bool + } catch { + Write-Warning "Invalid boolean value. Please enter 'true' or 'false'." + } + } + 'string' { + $isValidValue = $true + # Convert the format string to chr since it is default for the API + $format = 'chr' # API expects a string value for chr, so we can just return the string as is. + } + 'xml' { + # Convert to XML + try { + $validateXml = [xml]$value + $isValidValue = $true + } catch { + Write-Warning "Invalid XML value. Please enter a valid XML string." + } + } + 'base64' { + try { + $validateBase64 = [void][Convert]::FromBase64String($value) + $isValidValue = $true + $format = 'b64' # API expects base64 to be passed as b64 + } catch { + Write-Warning "Invalid base64 value. Please enter a valid base64 string." + } + + } + default { + Write-Warning "Invalid format. Please enter int, string, float, xml, boolean, or base64." + $isValidValue = $false + } + } + + } while (!$isValidValue) + } else { + $isValidValue = $false; + try { + switch ($format) { + 'int' { + try { + [int]$value + $isValidValue = $true + } catch { + throw "Invalid integer value. Please enter a valid integer number." + } + + } + 'float' { + try { + [float]$value + $isValidValue = $true + } catch { + throw "Invalid float value. Please enter a valid float number." + } + + } + 'boolean' { + try { + [System.Convert]::ToBoolean($value) + $isValidValue = $true + $format = 'bool' # API expects boolean to be passed as bool + } catch { + throw "Invalid boolean value. Please enter 'true' or 'false'." + } + } + 'string' { + try { + $format = 'chr' # API expects a string value for chr, so we can just return the string as is. + $isValidValue = $true + } catch { + throw "Invalid string value. Please enter a valid string." + } + } + 'xml' { + try { + [xml]$value + $isValidValue = $true + } catch { + throw "Invalid XML value. Please enter a valid XML string." + } + } + 'base64' { + try { + $format = 'b64' # API expects base64 to be passed as b64 + [Convert]::FromBase64String($value) + $isValidValue = $true + } catch { + throw "Invalid base64 value. Please enter a valid base64 string." + } + } + default { + throw "Invalid format. Please enter int, string, float, xml, boolean, or base64." + } + } + } catch { + Write-Warning "Invalid value for format '$format'. Please check parameters." + } + if (!($isValidValue)) { + return @() + } + } + + } end { + # Create the object + # Return the object as a list item + $uriListItem = [PSCustomObject]@{ + format = $format + uri = $uri + value = $value + } + # Return the object + return $uriListItem + } +} \ No newline at end of file diff --git a/PowerShell/JumpCloud Module/Private/Policies/Set-JCPolicyConfigField.ps1 b/PowerShell/JumpCloud Module/Private/Policies/Set-JCPolicyConfigField.ps1 index 93eb0900f..01c4ac00e 100644 --- a/PowerShell/JumpCloud Module/Private/Policies/Set-JCPolicyConfigField.ps1 +++ b/PowerShell/JumpCloud Module/Private/Policies/Set-JCPolicyConfigField.ps1 @@ -260,6 +260,159 @@ function Set-JCPolicyConfigField { # finally update values $policyValues[$fieldIndex].value = $ValueObject } + 'multilist' { + # Test + # $policyValues[$fieldIndex].value = @( + # @{ format = "int"; uri = "a"; value = "2" }, + # @{ format = "string"; uri = "b"; value = "test" }, + # @{ format = "bool"; uri = "c"; value = "true" } + # ) + $Title = "JumpCloud Policy Field Editor" + $Message = "Select an Action:" + $Modify = New-Object System.Management.Automation.Host.ChoiceDescription "&Modify", "Modify - edit existing rows" + $Add = New-Object System.Management.Automation.Host.ChoiceDescription "&Add", "Add - add new table rows" + $Remove = New-Object System.Management.Automation.Host.ChoiceDescription "&Remove", "Remove - remove existing rows" + $Continue = New-Object System.Management.Automation.Host.ChoiceDescription "&Continue", "Continue - save/ update policy" + $Options = [System.Management.Automation.Host.ChoiceDescription[]]($Modify, $Add, $Remove, $Continue) + $multiListValues = New-Object System.Collections.ArrayList + $ValueObject = New-Object System.Collections.ArrayList + if ($policyValues[$fieldIndex].value) { + # Create a table to view + if ($ValueObject) { + $valueDisplay = New-Object System.Collections.ArrayList + for ($i = 0; $i -lt $ValueObject.Count; $i++) { + $valueDisplay.Add([PSCustomObject]@{ + row = $i + value = $ValueObject[$i] + }) | Out-Null + } + $valueDisplay | Format-Table row, @{Label = "format"; Expression = { $_.value | Select-Object -ExpandProperty format } }, @{Label = "uri"; Expression = { $_.value | Select-Object -ExpandProperty uri } }, @{Label = "value"; Expression = { $_.value | Select-Object -ExpandProperty value } } | Out-Host + } else { + # If values, populate value display + $ValueObject = New-Object System.Collections.ArrayList + $valueDisplay = New-Object System.Collections.ArrayList + for ($i = 0; $i -lt $policyValues[$fieldIndex].value.Count; $i++) { + $valueDisplay.Add([PSCustomObject]@{ + row = $i + value = $policyValues[$fieldIndex].value[$i] + }) | Out-Null + $ValueObject.Add($policyValues[$fieldIndex].value[$i]) | Out-Null + } + $valueDisplay | Format-Table row, @{Label = "format"; Expression = { $_.value | Select-Object -ExpandProperty format } }, @{Label = "uri"; Expression = { $_.value | Select-Object -ExpandProperty uri } }, @{Label = "value"; Expression = { $_.value | Select-Object -ExpandProperty value } } | Out-Host + $userChoice = $host.ui.PromptForChoice($title, $message, $options, 0) + } + + switch ($userChoice) { + 0 { + # Modify existing: + do { + $rowNum = (Read-Host "Please enter row number you wish to modify (0 - $($ValueObject.count - 1)) ") + } While (0..[int](($ValueObject).Count - 1) -notcontains $rownum -or '' -eq $rowNum) + # Get the row value + $multListRow = New-UriListItem + $ValueObject[$rowNum] = $multListRow + } + 1 { + # Add new row + $multiListValue = New-UriListItem + # Convert to a custom object + #$test = @( @{format = "int"; uri = "aasdadsdas"; value = "5" }, @{format = "string"; uri = "b"; value = "test" }, @{format = "bool"; uri = "c"; value = "true" } ) + $ValueObject.Add($multiListValue) | Out-Null + # Output the object + #$ValueObject | Format-Table + } + 2 { + # Remove existing: + [System.Collections.ARRAYLIST]$ValueObjectCopy = $ValueObject + do { + $rowNum = (Read-Host "Please enter row number you wish to remove (0 - $($ValueObject.count - 1)) ") + } While (0..[int](($ValueObject).Count - 1) -notcontains $rownum -or '' -eq $rowNum) + $ValueObjectCopy.RemoveAt($rowNum) | Out-Null + $ValueObject = $ValueObjectCopy + } + 3 { + break + } + } + } else { + do { + $validFormat = $false # Initialize to false for the while loop + + do { + Write-Host "Please enter the format and value for the new entry." + $format = Read-Host "Enter the format (int, string, float, xml, boolean, base64) for the value" + $value = Read-Host "Enter the value" + + # Validate format and value + switch ($format) { + 'int' { + try { + $value = [int]$value + $validFormat = $true + } catch { + Write-Warning "Invalid integer value. Please try again." + } + } + 'float' { + try { + $value = [double]$value + $validFormat = $true + } catch { + Write-Warning "Invalid float value. Please try again." + } + } + 'boolean' { + try { + $value = [System.Convert]::ToBoolean($value) # Attempt to convert to boolean + $validFormat = $true + $format = 'bool' # API expects boolean to be passed as bool + } catch { + Write-Warning "Invalid boolean value. Please enter 'true' or 'false'." + } + } + 'string' { + $validFormat = $true + $format = 'chr' + } # String always valid + 'xml' { + try { + $validateXml = [xml]$value #attempt xml conversion. + $validFormat = $true + } catch { + write-warning "Invalid xml. Please try again." + } + } + 'base64' { + try { + $testValue = [convert]::FromBase64String($value) + $validFormat = $true + $format = 'b64' # API expects base64 to be passed as b64 + } catch { + write-warning "Invalid base64 string. please try again." + } + + } + default { + Write-Warning "Invalid format. Please enter int, string, float, xml, boolean, or base64." + } + } + } while (!$validFormat) + + $uri = Read-Host "Enter the URI for the value" + $multiListValues = [PSCustomObject]@{ + uri = $uri + value = $value # This will be the validated value based on the format + format = $format + } + + $ValueObject.Add($multiListValues) | Out-Null + + $addMore = Read-Host "Add another value? (y/n)" + } while ($addMore -eq 'y') + } + + $policyValues[$fieldIndex].value = $ValueObject + } } } } diff --git a/PowerShell/JumpCloud Module/Private/Policies/Show-JCPolicyValues.ps1 b/PowerShell/JumpCloud Module/Private/Policies/Show-JCPolicyValues.ps1 index f41e3afca..695f76fbd 100644 --- a/PowerShell/JumpCloud Module/Private/Policies/Show-JCPolicyValues.ps1 +++ b/PowerShell/JumpCloud Module/Private/Policies/Show-JCPolicyValues.ps1 @@ -44,7 +44,6 @@ function Show-JCPolicyValues { $policyArray.Add($policyValue) | Out-Null $counter++ } - # If the policy is a registry policy, do not display value table if ($policyObject.configFieldName -notcontains "customRegTable") { # Display policy object array diff --git a/PowerShell/JumpCloud Module/Public/Groups/UserGroups/Get-JCUserGroupMember.ps1 b/PowerShell/JumpCloud Module/Public/Groups/UserGroups/Get-JCUserGroupMember.ps1 index 6d4d72ac2..a02a06324 100644 --- a/PowerShell/JumpCloud Module/Public/Groups/UserGroups/Get-JCUserGroupMember.ps1 +++ b/PowerShell/JumpCloud Module/Public/Groups/UserGroups/Get-JCUserGroupMember.ps1 @@ -6,13 +6,13 @@ Function Get-JCUserGroupMember () { [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'ByGroup', Position = 0, HelpMessage = 'The name of the JumpCloud User Group you want to return the members of.')] [Alias('name')][String]$GroupName, [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'ByID', HelpMessage = 'If searching for a User Group using the GroupID populate the GroupID in the -ByID field.')] - [String]$ByID + [Alias('GroupID')][String]$ByID ) begin { Write-Debug 'Verifying JCAPI Key' if ([System.String]::IsNullOrEmpty($JCAPIKEY)) { - Connect-JConline + Connect-JCOnline } $Parallel = $JCConfig.parallel.Calculated diff --git a/PowerShell/JumpCloud Module/Public/Policies/New-JCPolicy.ps1 b/PowerShell/JumpCloud Module/Public/Policies/New-JCPolicy.ps1 index 9f66bb074..0c580f579 100644 --- a/PowerShell/JumpCloud Module/Public/Policies/New-JCPolicy.ps1 +++ b/PowerShell/JumpCloud Module/Public/Policies/New-JCPolicy.ps1 @@ -87,6 +87,9 @@ function New-JCPolicy { 'exclude' { Continue } + 'multilist' { + $paramType = [system.object[]] + } Default { $paramType = 'string' } @@ -155,7 +158,6 @@ function New-JCPolicy { if ($templateObject.objectMap[$i].configFieldName -in $params.keys) { $keyName = $params.keys | Where-Object { $_ -eq $templateObject.objectMap[$i].configFieldName } $keyValue = $params.$KeyName - # write-host "Setting value from $($keyName) $($KeyValue)" switch ($templateObject.objectMap[$i].type) { 'multi' { $templateObject.objectMap[$i].value = $(($templateObject.objectMap[$i].validation | Where-Object { $_.Values -eq $keyValue }).keys) @@ -213,6 +215,89 @@ function New-JCPolicy { } $templateObject.objectMap[$i].value = $regRows } + 'multilist' { + if ($templateObject.objectMap[$i].configFieldName -eq "uriList") { + for ($j = 0; $j -lt $keyValue.Count; $j++) { + $item = $keyValue[$j] + # If uri, format, or value is null or empty, throw an error + if (!$item.uri -or !$item.format -or !$item.value) { + throw "Invalid value at index $j : uri, format, and value cannot be null or empty." + } else { + switch ($item.format) { + "base64" { + try { + $validateBase64 = [Convert]::FromBase64String($item.value) | Out-Null + $item.format = "b64" # API expects "b64" for base64 format + } catch { + throw "Invalid Base64 value at index $j : $($item.value)" + } + } + "b64" { + # Do nothing, already set to b64 + try { + $validateBase64 = [Convert]::FromBase64String($item.value) | Out-Null + } catch { + throw "Invalid Base64 value at index $j : $($item.value)" + } + } + "string" { + $item.format = "chr" # API expects "chr" for string format + } + "chr" { + # Do nothing, already set to chr + } + "boolean" { + try { + $validateBoolean = [System.Convert]::ToBoolean($item.value) | Out-Null + $item.format = "bool" # API expects "bool" for boolean format + } catch { + # Handle the case where the string is not a valid boolean + throw "Invalid boolean value at index $j : $($item.value). Please enter 'true' or 'false'." + } + } + "bool" { + # Do nothing, already set to bool + try { + $validateBoolean = [System.Convert]::ToBoolean($item.value) | Out-Null + } catch { + # Handle the case where the string is not a valid boolean + throw "Invalid boolean value at index $j : $($item.value). Please enter 'true' or 'false'." + } + } + "float" { + try { + $validateFloat = [float]$item.value + } catch { + throw "Invalid float value at index $j : $($item.value)" + } + } + "int" { + try { + $validateInt = [int]$item.value | Out-Null + } catch { + throw "Invalid int value at index $j : $($item.value)" + } + } + "xml" { + try { + $validateXml = [xml]$item.value + } catch { + throw "Invalid xml value at index $j : $($item.value)" + } + } + default { + throw "Unsupported format '$($item.format)' at index $j. No conversion performed." + } + } + } + $keyValue[$j] = $item + } + $templateObject.objectMap[$i].value = $keyValue + } else { + # For other multilist types, just pass the array + $templateObject.objectMap[$i].value = $keyValue + } + } Default { $templateObject.objectMap[$i].value = $($keyValue) } @@ -259,7 +344,6 @@ function New-JCPolicy { $updatedPolicyObject = $updatedPolicyObject | Select-Object configFieldID, configFieldName, value } } - # Validate PolicyObject if ($updatedPolicyObject) { $updatedPolicyObject | ForEach-Object { @@ -283,7 +367,6 @@ function New-JCPolicy { } | ConvertTo-Json -Depth 99 } - $headers = @{ 'x-api-key' = $env:JCApiKey 'x-org-id' = $env:JCOrgId diff --git a/PowerShell/JumpCloud Module/Public/Policies/Set-JCPolicy.ps1 b/PowerShell/JumpCloud Module/Public/Policies/Set-JCPolicy.ps1 index 81146301e..aea7b3322 100644 --- a/PowerShell/JumpCloud Module/Public/Policies/Set-JCPolicy.ps1 +++ b/PowerShell/JumpCloud Module/Public/Policies/Set-JCPolicy.ps1 @@ -91,6 +91,9 @@ function Set-JCPolicy { 'table' { $paramType = [system.object[]] } + 'multilist' { + $paramType = [system.object[]] + } 'exclude' { Continue } @@ -247,6 +250,106 @@ function Set-JCPolicy { } $templateObject.objectMap[$i].value = $regRows } + 'multilist' { + if ($templateObject.objectMap[$i].configFieldName -eq "uriList") { + $uriListProperties = $templateObject.objectMap[$i].defaultValue | Get-Member -MemberType NoteProperty + $ObjectProperties = if ($keyValue | Get-Member -MemberType NoteProperty) { + # for lists get note properties + ($keyValue | Get-Member -MemberType NoteProperty).Name + } else { + # for single objects, get keys + $keyValue.keys + } + $uriListProperties | ForEach-Object { + if ($_.Name -notin $ObjectProperties) { + Throw "Custom Windows MDM Policy require a `"$($_.Name)`" data string. The following data types were found: $($ObjectProperties)" + } + } + # uriList type validation + $validFormatTypes = @('int', 'string', 'chr', 'boolean', 'bool', 'float', 'xml', 'base64', 'b64' ) + $validFormat = $false + + $listRows = New-Object System.Collections.ArrayList + + # Loop through each item in the keyValue array + for ($j = 0; $j -lt $keyValue.Count; $j++) { + $item = $keyValue[$j] + # Validate if item.value is null or empty + # Ensure the item has a value and format and URI + if (!$item.uri -or !$item.format -or !$item.value) { + throw "Missing required fields 'uri', 'format', or 'value' at index $j in the uriList. Please ensure all items have these fields." + } else { + switch ($item.format) { + "base64" { + try { + $validateBase64 = [Convert]::FromBase64String($item.value) | Out-Null + $item.format = "b64" # API expects "b64" for base64 format + } catch { + throw "Invalid Base64 value at index $j : $($item.value)" + } + } + "b64" { + # Do nothing, already set to b64 + try { + $validateBase64 = [Convert]::FromBase64String($item.value) | Out-Null + } catch { + throw "Invalid Base64 value at index $j : $($item.value)" + } + } + "string" { + $item.format = "chr" # API expects "chr" for string format + } + "chr" { + # Do nothing, already set to chr + } + "boolean" { + try { + $validateBoolean = [System.Convert]::ToBoolean($item.value) | Out-Null + $item.format = "bool" # API expects "bool" for boolean format + } catch { + # Handle the case where the string is not a valid boolean + throw "Invalid boolean value at index $j : $($item.value). Please enter 'true' or 'false'." + } + } + "bool" { + # Do nothing, already set to bool + try { + $validateBoolean = [System.Convert]::ToBoolean($item.value) | Out-Null + } catch { + # Handle the case where the string is not a valid boolean + throw "Invalid boolean value at index $j : $($item.value). Please enter 'true' or 'false'." + } + } + "float" { + try { + $validateFloat = [float]$item.value + } catch { + throw "Invalid float value at index $j : $($item.value)" + } + } + "int" { + try { + $validateInt = [int]$item.value | Out-Null + } catch { + throw "Invalid int value at index $j : $($item.value)" + } + } + "xml" { + try { + $validateXml = [xml]$item.value + } catch { + throw "Invalid xml value at index $j : $($item.value)" + } + } + default { + throw "Unsupported format '$($item.format)' at index $j. No conversion performed." + } + } + } + } + $templateObject.objectMap[$i].value = $keyValue + } + } Default { $templateObject.objectMap[$i].value = $($keyValue) } @@ -328,6 +431,7 @@ function Set-JCPolicy { } } } + if ($updatedPolicyObject) { $body = [PSCustomObject]@{ name = $policyNameFromProcess diff --git a/PowerShell/JumpCloud Module/Public/Systems/Get-JCSystem.ps1 b/PowerShell/JumpCloud Module/Public/Systems/Get-JCSystem.ps1 index 1952f2b9f..a459133fa 100644 --- a/PowerShell/JumpCloud Module/Public/Systems/Get-JCSystem.ps1 +++ b/PowerShell/JumpCloud Module/Public/Systems/Get-JCSystem.ps1 @@ -153,7 +153,7 @@ Function Get-JCSystem () { ValueFromPipelineByPropertyName, ParameterSetName = 'SearchFilter', HelpMessage = 'Allows you to return select properties on JumpCloud system objects. Specifying what properties are returned can drastically increase the speed of the API call with a large data set. Valid properties that can be returned are: ''created'', ''active'', ''agentVersion'', ''allowMultiFactorAuthentication'', ''allowPublicKeyAuthentication'', ''allowSshPasswordAuthentication'', ''allowSshRootLogin'', ''arch'', ''created'', ''displayName'', ''hostname'', ''lastContact'', ''modifySSHDConfig'', ''organization'', ''os'', ''remoteIP'', ''serialNumber'', ''sshdParams'', ''systemTimezone'', ''templateName'', ''version'', ''hwVendor'',''secureLogin'',''displayManager'',''amazonInstanceID'',''archFamily'',''builtInCommands'',''description'',''osVersionDetail'',''policyStats'',''desktopCapable'', ''sshRootEnabled''')] - [ValidateSet('acknowledged', 'active', 'agentVersion', 'allowMultiFactorAuthentication', 'allowPublicKeyAuthentication', 'allowSshPasswordAuthentication', 'allowSshRootLogin', 'arch', 'azureAdJoined', 'connectionHistory', 'created', 'displayName', 'domainInfo', 'fde', 'fileSystem', 'hasServiceAccount', 'hostname', 'lastContact', 'mdm', 'modifySSHDConfig', 'networkInterfaces', 'organization', 'os', 'osFamily', 'provisionMetadata', 'remoteIP', 'serialNumber', 'serviceAccountState', 'sshdParams', 'systemInsights', 'systemTimezone', 'templateName', 'userMetrics', 'usernameHashes', 'version', 'hwVendor', 'secureLogin', 'displayManager', 'amazonInstanceID', 'archFamily', 'builtInCommands', 'description', 'osVersionDetail', 'policyStats', 'desktopCapable', 'sshRootEnabled', 'isPolicyBound')] + [ValidateSet('acknowledged', 'active', 'agentVersion', 'allowMultiFactorAuthentication', 'allowPublicKeyAuthentication', 'allowSshPasswordAuthentication', 'allowSshRootLogin', 'arch', 'azureAdJoined', 'connectionHistory', 'created', 'displayName', 'domainInfo', 'fde', 'fileSystem', 'hasServiceAccount', 'hostname', 'lastContact', 'mdm', 'modifySSHDConfig', 'networkInterfaces', 'organization', 'os', 'osFamily', 'primarySystemUser', 'provisionMetadata', 'remoteAssistAgentVersion', 'remoteIP', 'serialNumber', 'serviceAccountState', 'sshdParams', 'systemInsights', 'systemTimezone', 'templateName', 'userMetrics', 'usernameHashes', 'version', 'hwVendor', 'secureLogin', 'displayManager', 'amazonInstanceID', 'archFamily', 'builtInCommands', 'description', 'osVersionDetail', 'policyStats', 'desktopCapable', 'sshRootEnabled', 'isPolicyBound')] [String[]]$returnProperties ) diff --git a/PowerShell/JumpCloud Module/Public/Systems/Set-JCSystem.ps1 b/PowerShell/JumpCloud Module/Public/Systems/Set-JCSystem.ps1 index 1a2cf3cec..6c01205e1 100644 --- a/PowerShell/JumpCloud Module/Public/Systems/Set-JCSystem.ps1 +++ b/PowerShell/JumpCloud Module/Public/Systems/Set-JCSystem.ps1 @@ -35,14 +35,17 @@ Function Set-JCSystem () { [Parameter(ValueFromPipelineByPropertyName = $true, HelpMessage = 'Setting this value to $true will enable systemInsights and collect data for this system. Setting this value to $false will disable systemInsights and data collection for the system.')] [bool] - $systemInsights + $systemInsights, + + [Parameter(ValueFromPipelineByPropertyName = $false, HelpMessage = 'A value indicating a JumpCloud users email, username or userID. This will add the user to the device associations')] + $primarySystemUser ) begin { Write-Debug 'Verifying JCAPI Key' if ([System.String]::IsNullOrEmpty($JCAPIKEY)) { - Connect-JConline + Connect-JCOnline } $hdrs = @{ @@ -63,15 +66,12 @@ Function Set-JCSystem () { $body = @{ } foreach ($param in $PSBoundParameters.GetEnumerator()) { - if ([System.Management.Automation.PSCmdlet]::CommonParameters -contains $param.key) { continue } - if ($param.key -eq 'SystemID', 'JCAPIKey') { continue } - if ($param.key -eq 'systemInsights') { $state = switch ($systemInsights) { true { @@ -84,27 +84,33 @@ Function Set-JCSystem () { $body.add('systemInsights', @{'state' = $state }) continue } - + if ($param.key -eq "primarySystemUser") { + $userInfo = $param.value + if ($param.Value -eq $null -or $param.Value -eq "") { + $body.add("primarySystemUser.id", $null) + continue + } else { + try { + $primarySystemUserValue = Convert-JCUserToID -UserIdentifier $userInfo + $body.add("primarySystemUser.id", $primarySystemUserValue) + } catch { + Write-Warning "Could not validate $userinfo. Please ensure the user information is correct" + } + continue + } + } $body.add($param.Key, $param.Value) - } $jsonbody = $body | ConvertTo-Json - Write-Debug $jsonbody - $URL = "$JCUrlBasePath/api/systems/$SystemID" - Write-Debug $URL - $System = Invoke-RestMethod -Method PUT -Uri $URL -Body $jsonbody -Headers $hdrs -UserAgent:(Get-JCUserAgent) $UpdatedSystems += $System } - end { return $UpdatedSystems - } - -} +} \ No newline at end of file diff --git a/PowerShell/JumpCloud Module/Public/Users/New-JCUser.ps1 b/PowerShell/JumpCloud Module/Public/Users/New-JCUser.ps1 index 397bcf38b..d8ce331c7 100755 --- a/PowerShell/JumpCloud Module/Public/Users/New-JCUser.ps1 +++ b/PowerShell/JumpCloud Module/Public/Users/New-JCUser.ps1 @@ -187,7 +187,7 @@ Function New-JCUser () { begin { Write-Debug 'Verifying JCAPI Key' - if ([System.String]::IsNullOrEmpty($JCAPIKEY)) { Connect-JConline } + if ([System.String]::IsNullOrEmpty($JCAPIKEY)) { Connect-JCOnline } $hdrs = @{ @@ -298,79 +298,7 @@ Function New-JCUser () { # If manager field is null, skip continue } else { - # First check if manager returns valid user with id - # Regex match a userid - $regexPattern = [Regex]'^[a-z0-9]{24}$' - if (((Select-String -InputObject $param.Value -Pattern $regexPattern).Matches.value)::IsNullOrEmpty) { - # if we have a 24 characterid, try to match the id using the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'id' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'id' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } - # Use class mailaddress to check if $param.value is email - try { - $null = [mailaddress]$EmailAddress - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'email' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'email' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } catch { - # search the username in the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } + $managerValue = Convert-JCUserToID -UserIdentifier $param.Value if ($managerValue) { $body.add($param.Key, $managerValue) } else { diff --git a/PowerShell/JumpCloud Module/Public/Users/Set-JCUser.ps1 b/PowerShell/JumpCloud Module/Public/Users/Set-JCUser.ps1 index 56249f6a8..cdb28df47 100644 --- a/PowerShell/JumpCloud Module/Public/Users/Set-JCUser.ps1 +++ b/PowerShell/JumpCloud Module/Public/Users/Set-JCUser.ps1 @@ -561,83 +561,11 @@ UserID has an Alias of _id. This means you can leverage the PowerShell pipeline # Get the manager using manager username instead of userId if ("manager" -eq $param.Key) { - if ([System.String]::isNullOrEmpty($param.value)) { - $managerValue = $null + if ($param.Value -eq $null -or $param.Value -eq "") { + $body.add($param.Key, $null) + continue } else { - # First check if manager returns valid user with id - # Regex match a userid - $regexPattern = [Regex]'^[a-z0-9]{24}$' - if (((Select-String -InputObject $param.Value -Pattern $regexPattern).Matches.value)::IsNullOrEmpty) { - # if we have a 24 characterid, try to match the id using the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'id' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'id' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } - # Use class mailaddress to check if $param.value is email - try { - $null = [mailaddress]$EmailAddress - # Search for manager using email - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'email' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'email' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } catch { - # search the username in the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } + $managerValue = Convert-JCUserToID -UserIdentifier $param.Value if ($managerValue) { $body.add($param.Key, $managerValue) } else { @@ -732,83 +660,11 @@ UserID has an Alias of _id. This means you can leverage the PowerShell pipeline # Get the manager using manager username instead of userId if ("manager" -eq $param.Key) { - if ([System.String]::isNullOrEmpty($param.value)) { - $managerValue = $null + if ($param.Value -eq $null -or $param.Value -eq "") { + $body.add($param.Key, $null) + continue } else { - # First check if manager returns valid user with id - # Regex match a userid - $regexPattern = [Regex]'^[a-z0-9]{24}$' - if (((Select-String -InputObject $param.Value -Pattern $regexPattern).Matches.value)::IsNullOrEmpty) { - # if we have a 24 characterid, try to match the id using the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'id' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'id' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } - # Use class mailaddress to check if $param.value is email - try { - $null = [mailaddress]$EmailAddress - # Search for manager using email - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'email' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'email' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } catch { - # search the username in the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } + $managerValue = Convert-JCUserToID -UserIdentifier $param.Value if ($managerValue) { $body.add($param.Key, $managerValue) } else { @@ -972,84 +828,11 @@ UserID has an Alias of _id. This means you can leverage the PowerShell pipeline # Get the manager using manager username instead of userId if ("manager" -eq $param.Key) { - if ([System.String]::isNullOrEmpty($param.value)) { - $managerValue = $null + if ($param.Value -eq $null -or $param.Value -eq "") { + $body.add($param.Key, $null) + continue } else { - # First check if manager returns valid user with id - # Regex match a userid - $regexPattern = [Regex]'^[a-z0-9]{24}$' - if (((Select-String -InputObject $param.Value -Pattern $regexPattern).Matches.value)::IsNullOrEmpty) { - # if we have a 24 characterid, try to match the id using the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'id' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'id' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } - # Use class mailaddress to check if $param.value is email - try { - $null = [mailaddress]$EmailAddress - Write-Debug "This is true" - # Search for manager using email - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'email' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'email' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } catch { - # search the username in the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } + $managerValue = Convert-JCUserToID -UserIdentifier $param.Value if ($managerValue) { $body.add($param.Key, $managerValue) } else { @@ -1165,84 +948,11 @@ UserID has an Alias of _id. This means you can leverage the PowerShell pipeline # Get the manager using manager username instead of userId if ("manager" -eq $param.Key) { - if ([System.String]::isNullOrEmpty($param.value)) { - $managerValue = $null + if ($param.Value -eq $null -or $param.Value -eq "") { + $body.add($param.Key, $null) + continue } else { - # First check if manager returns valid user with id - # Regex match a userid - $regexPattern = [Regex]'^[a-z0-9]{24}$' - if (((Select-String -InputObject $param.Value -Pattern $regexPattern).Matches.value)::IsNullOrEmpty) { - # if we have a 24 characterid, try to match the id using the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'id' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'id' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } - # Use class mailaddress to check if $param.value is email - try { - $null = [mailaddress]$EmailAddress - Write-Debug "This is true" - # Search for manager using email - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'email' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'email' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue; this is a validated user id - $managerValue = $managerResults.id - # if no value was returned, then assume the case this is actually a username and search - if (!$managerValue) { - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } - } catch { - # search the username in the search endpoint - $managerSearch = @{ - filter = @{ - 'and' = @( - @{'username' = @{'$regex' = "(?i)(`^$($param.Value)`$)" } } - ) - } - fields = 'username' - } - $managerResults = Search-JcSdkUser -Body:($managerSearch) - # Set managerValue from the matched username - $managerValue = $managerResults.id - } + $managerValue = Convert-JCUserToID -UserIdentifier $param.Value if ($managerValue) { $body.add($param.Key, $managerValue) } else { diff --git a/PowerShell/JumpCloud Module/Public/Utilities/CSV_Import/New-JCDeviceUpdateTemplate.ps1 b/PowerShell/JumpCloud Module/Public/Utilities/CSV_Import/New-JCDeviceUpdateTemplate.ps1 index ea855d11b..501fefd55 100644 --- a/PowerShell/JumpCloud Module/Public/Utilities/CSV_Import/New-JCDeviceUpdateTemplate.ps1 +++ b/PowerShell/JumpCloud Module/Public/Utilities/CSV_Import/New-JCDeviceUpdateTemplate.ps1 @@ -75,6 +75,7 @@ Function New-JCDeviceUpdateTemplate { allowMultiFactorAuthentication = $null allowPublicKeyAuthentication = $null systemInsights = $null + primarySystemUser = $null } $fileName = 'JCDeviceUpdateImport_' + $date + '.csv' @@ -97,7 +98,7 @@ Function New-JCDeviceUpdateTemplate { $CSV = [ordered]@{ DeviceID = $null displayname = $null - hostname = $null + hostname = $null } Write-Host "`nWould you like to populate this update template with all of your existing systems?" @@ -198,6 +199,19 @@ Function New-JCDeviceUpdateTemplate { elseif ($ConfirmSystemInsights -eq 'N') { } + Write-Host "`nWould you like to set a primary system user?" + + while ($ConfirmPrimarySystemUser -ne 'Y' -and $ConfirmPrimarySystemUser -ne 'N') { + $ConfirmPrimarySystemUser = Read-Host "Enter Y for Yes or N for No" + } + + if ($ConfirmPrimarySystemUser -eq 'Y') { + $CSV.add('primarySystemUser', $null) + } + + elseif ($ConfirmPrimarySystemUser -eq 'N') { + } + $CSVheader = New-Object psobject -Property $Csv if ($systems) { diff --git a/PowerShell/JumpCloud Module/Tests/ModuleValidation/ReturnProperties.Tests.ps1 b/PowerShell/JumpCloud Module/Tests/ModuleValidation/ReturnProperties.Tests.ps1 index cfdf9b59b..93aeb496d 100644 --- a/PowerShell/JumpCloud Module/Tests/ModuleValidation/ReturnProperties.Tests.ps1 +++ b/PowerShell/JumpCloud Module/Tests/ModuleValidation/ReturnProperties.Tests.ps1 @@ -49,7 +49,7 @@ Describe -Tag:('ModuleValidation') 'Return Properties Checks' { $missing = $inSwaggerNotFunction | where-object { $_.InputObject -notin $functionHash[$item].ignoreList } # there should not be any missing items if ($missing.InputObject) { - Write-Warning "The folling properties are defined in swagger for the $item function but not the module, either add them to the function validate set or add them to the ignore list in this test" + Write-Warning "The following properties are defined in swagger for the $item function but not the module, either add them to the function validate set or add them to the ignore list in this test" Write-host $missing.InputObject } $missing.InputObject | should -BeNullOrEmpty diff --git a/PowerShell/JumpCloud Module/Tests/Private/NestedFunctions/Convert-JCUserToID.Tests.ps1 b/PowerShell/JumpCloud Module/Tests/Private/NestedFunctions/Convert-JCUserToID.Tests.ps1 new file mode 100644 index 000000000..e69de29bb diff --git a/PowerShell/JumpCloud Module/Tests/Private/Policies/New-UriList.Tests.ps1 b/PowerShell/JumpCloud Module/Tests/Private/Policies/New-UriList.Tests.ps1 new file mode 100644 index 000000000..e69de29bb diff --git a/PowerShell/JumpCloud Module/Tests/Private/Policies/New-UriListItem.Tests.ps1 b/PowerShell/JumpCloud Module/Tests/Private/Policies/New-UriListItem.Tests.ps1 new file mode 100644 index 000000000..e69de29bb diff --git a/PowerShell/JumpCloud Module/Tests/Public/Policies/New-JCPolicy.Tests.ps1 b/PowerShell/JumpCloud Module/Tests/Public/Policies/New-JCPolicy.Tests.ps1 index e53437490..231138381 100644 --- a/PowerShell/JumpCloud Module/Tests/Public/Policies/New-JCPolicy.Tests.ps1 +++ b/PowerShell/JumpCloud Module/Tests/Public/Policies/New-JCPolicy.Tests.ps1 @@ -92,6 +92,68 @@ Describe -Tag:('JCPolicy') 'New-JCPolicy' { ($multipleValPolicy.values | Where-Object { $_.configFieldName -eq "PreviewType" }).value | Should -Be 0 # 0 is the value for Always on the dropdown ($multipleValPolicy.values | Where-Object { $_.configFieldName -eq "BadgesEnabled" }).value | Should -Be $true } + + # URIList Test + It 'Creates a new policy that tests Custom Windows MDM OMA URIList' { + $policyTemplate = $policyTemplates | Where-Object { $_.name -eq "custom_oma_uri_mdm_windows" } + $templateId = $policyTemplate.id + $policyValueList = New-Object System.Collections.ArrayList + # Define list Values: + $policyValue = [pscustomobject]@{ + # Should look like this: (@( @{format = "string"; uri = "aasdadsdas"; value = "5" }, @{format = "string"; uri = "b"; value = "test" }, @{format = "boolean"; uri = "c"; value = "true" } )) + 'format' = 'int' + 'uri' = "./Device/Vendor/MSFT/Registry/HKLM/Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveTimeOut" + 'value' = '600' + } + $policyValue2 = [pscustomobject]@{ + 'format' = 'boolean' + 'uri' = "./Device/Vendor/MSFT/Registry/HKLM/Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveActive" + 'value' = "true" + } + $policyValue3 = [pscustomobject]@{ + 'format' = 'string' + 'uri' = "./Device/Vendor/MSFT/Registry/HKLM/Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveActive" + 'value' = "testString" + } + $policyValue4 = [pscustomobject]@{ + 'format' = 'float' + 'uri' = "./Device/Vendor/MSFT/Registry/HKLM/Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveActive" + 'value' = "2.5" + } + $policyValue5 = [pscustomobject]@{ + 'format' = 'xml' + 'uri' = "./Device/Vendor/MSFT/Registry/HKLM/Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveActive" + 'value' = "Test" + } + $policyValue6 = [pscustomobject]@{ + 'format' = 'base64' + 'uri' = "./Device/Vendor/MSFT/Registry/HKLM/Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveActive" + 'value' = "VGhpcyBpcyBhIHRlc3Q=" + } + # add values to list + $policyValueList.add($policyValue) | Out-Null # int type + $policyValueList.add($policyValue2) | Out-Null # boolean type + $policyValueList.Add($policyValue3) | Out-Null # string type + $policyValueList.Add($policyValue4) | Out-Null # float type + $policyValueList.Add($policyValue5) | Out-Null # xml type + $policyValueList.Add($policyValue6) | Out-Null # base64 type + + $uriListPolicy = New-JCPolicy -Name "Pester - URIList Test" -templateID $templateId -uriList $policyValueList + # Should not be null + $uriListPolicy.values.value.count | Should -Be 6 + $uriListPolicy.values.value[0].format | Should -Be "int" + $uriListPolicy.values.value[0].value | Should -Be "600" + $uriListPolicy.values.value[1].format | Should -Be "bool" + $uriListPolicy.values.value[1].value | Should -Be "true" + $uriListPolicy.values.value[2].format | Should -Be "chr" + $uriListPolicy.values.value[2].value | Should -Be "testString" + $uriListPolicy.values.value[3].format | Should -Be "float" + $uriListPolicy.values.value[3].value | Should -Be "2.5" + $uriListPolicy.values.value[4].format | Should -Be "xml" + $uriListPolicy.values.value[4].value | Should -Be "Test" + $uriListPolicy.values.value[5].format | Should -Be "b64" + $uriListPolicy.values.value[5].value | Should -Be "VGhpcyBpcyBhIHRlc3Q=" + } } Context 'Creates policies using the value parameters' { @@ -276,6 +338,128 @@ Describe -Tag:('JCPolicy') 'New-JCPolicy' { { New-JCPolicy -templateID $registryTemplate.id -customRegTable $policyValueList -Name "Pester - Registry Validation $(new-randomString -NumberOfChars 8)" } | Should -Throw } } + + # URIList Tests + Context 'New-JCPolicy should create a new policy using the URIList parameter' { + It 'New-JCPolicy creates a new policy using the URIList parameter successfully' { + $policyTemplate = $policyTemplates | Where-Object { $_.name -eq "custom_oma_uri_mdm_windows" } + $templateId = $policyTemplate.id + $uriList = @( + @{ format = "string"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage"; value = "Test" }, + @{ format = "int"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage"; value = "555" }, + @{ format = "boolean"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage"; value = "true" }, + @{ format = "float"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage"; value = "2.5" } + @{ format = "xml"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage"; value = "Test" }, + @{ format = "base64"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage"; value = "VGhpcyBpcyBhIHRlc3Q=" } + ) + $uriListPolicy = New-JCPolicy -Name "Pester - URIList1" -templateID $templateId -uriList $uriList + # Should not be null + $uriListPolicy.values.value.count | Should -Be 6 + $uriListPolicy.values.value[0].format | Should -Be "chr" + $uriListPolicy.values.value[0].value | Should -Be "Test" + $uriListPolicy.values.value[1].format | Should -Be "int" + $uriListPolicy.values.value[1].value | Should -Be "555" + $uriListPolicy.values.value[2].format | Should -Be "bool" + $uriListPolicy.values.value[2].value | Should -Be "true" + $uriListPolicy.values.value[3].format | Should -Be "float" + $uriListPolicy.values.value[3].value | Should -Be "2.5" + $uriListPolicy.values.value[4].format | Should -Be "xml" + $uriListPolicy.values.value[4].value | Should -Be "Test" + $uriListPolicy.values.value[5].format | Should -Be "b64" + $uriListPolicy.values.value[5].value | Should -Be "VGhpcyBpcyBhIHRlc3Q=" + + # Cleanup + $uriListPolicy = Get-JCPolicy | Where-Object { $_.Name -like "Pester - URIList*" } + $uriListPolicy | ForEach-Object { Remove-JcSdkPolicy -Id $_.id } + } + + It 'New-JCPolicy creates a new policy using the URIList parameter with invalid formats for each format' { + $policyTemplate = $policyTemplates | Where-Object { $_.name -eq "custom_oma_uri_mdm_windows" } + $templateId = $policyTemplate.id + + { New-JCPolicy -Name "Pester - URIList1" -templateID $templateId -uriList @(@{format = "string"; uri = "Test"; value = "" }) } | Should -Throw + { New-JCPolicy -Name "Pester - URIList2" -templateID $templateId -uriList @(@{format = "int"; uri = "Test"; value = "invalid" }) } | Should -Throw + { New-JCPolicy -Name "Pester - URIList3" -templateID $templateId -uriList @(@{format = "boolean"; uri = "Test"; value = "invalid" }) } | Should -Throw + { New-JCPolicy -Name "Pester - URIList4" -templateID $templateId -uriList @(@{format = "float"; uri = "Test"; value = "invalid" }) } | Should -Throw + { New-JCPolicy -Name "Pester - URIList5" -templateID $templateId -uriList @(@{format = "xml"; uri = "Test"; value = "invalid" }) } | Should -Throw + { New-JCPolicy -Name "Pester - URIList6" -templateID $templateId -uriList @(@{format = "base64"; uri = "Test"; value = "invalid" }) } | Should -Throw + # Cleanup + $uriListPolicy = Get-JCPolicy | Where-Object { $_.Name -like "Pester - URIList*" } + $uriListPolicy | ForEach-Object { Remove-JcSdkPolicy -Id $_.id } + + } + + It 'Handles invalid value - base64' { + $policyTemplate = $policyTemplates | Where-Object { $_.name -eq "custom_oma_uri_mdm_windows" } + $templateId = $policyTemplate.id + $invalidUriList = @( + @{ uri = "test"; format = "base64"; value = "invalid" } + ) + { New-JCPolicy -templateID $templateId -Name "Invalid Base64 Format Policy" -uriList $invalidUriList } | Should -Throw + } + + It 'Handles invalid value - xml' { + $policyTemplate = $policyTemplates | Where-Object { $_.name -eq "custom_oma_uri_mdm_windows" } + $templateId = $policyTemplate.id + $invalidUriList = @( + @{ uri = "test"; format = "xml"; value = "test data" + $setPolicy.values.value[5].value | Should -Be "SGVsbG8gV29ybGQh" + } + } + + Context 'Set-JCPolicy - Invalid Values' { + # Assuming $newPolicy is a valid policy object obtained from New-JCPolicy + BeforeEach { + $policyTemplate = $policyTemplates | Where-Object { $_.name -eq "custom_oma_uri_mdm_windows" } + $templateId = $policyTemplate.id + $uriList = @( + @{ uri = "a"; format = "int"; value = 2 } + ) + $newPolicy = New-JCPolicy -templateID $templateId -Name "Base Policy for Set Tests" -uriList $uriList + } + + It 'Handles invalid value in uriList - int' { + $invalidUriList = @( + @{ uri = "a"; format = "int"; value = "invalid" } + ) + { Set-JCPolicy -PolicyID $newPolicy.id -uriList $invalidUriList } | Should -Throw + } + + It 'Handles invalid value in uriList - string' { + $invalidUriList = @( + @{ uri = "a"; format = "string"; value = $null } #Null should be valid, so this test is changed. + ) + { Set-JCPolicy -PolicyID $newPolicy.id -uriList $invalidUriList } | Should -Throw + } + + It 'Handles invalid value in uriList - boolean' { + $invalidUriList = @( + @{ uri = "a"; format = "boolean"; value = "invalid" } + ) + { Set-JCPolicy -PolicyID $newPolicy.id -uriList $invalidUriList } | Should -Throw + } + + It 'Handles invalid value in uriList - float' { + $invalidUriList = @( + @{ uri = "a"; format = "float"; value = "invalid" } + ) + { Set-JCPolicy -PolicyID $newPolicy.id -uriList $invalidUriList } | Should -Throw + } + + It 'Handles invalid value in uriList - xml' { + $invalidUriList = @( + @{ uri = "a"; format = "xml"; value = " organization os osFamily + primarySystemUser provisionMetadata + remoteAssistAgentVersion remoteIP serialNumber serviceAccountState @@ -11000,7 +11002,7 @@ Get-JCUser -Username cClemons Get-JCUserGroupMember - + ByID If searching for a User Group using the GroupID populate the GroupID in the -ByID field. @@ -11032,7 +11034,7 @@ Get-JCUser -Username cClemons - + ByID If searching for a User Group using the GroupID populate the GroupID in the -ByID field. @@ -12736,6 +12738,13 @@ PS C:\> New-JCPolicy -TemplateName darwin_Login_Window_Text -Values $policyV This command would create a new Windows Custom Registry Policy named "Windows - Imported Custom Registry Settings" and populate the values from a registry file. .Reg registry files can be passed into New-JCPolicy as long as the TemplateName is specified with the corresponding "windows_Advanced:_Custom_Registry_Keys" template. .Reg files will be converted and uploaded to the JumpCloud policy as long as they contain "DWORD", "EXPAND_SZ", "MULTI_SZ", "SZ" or "QWORD" type data. + + -------------------------- Example 6 -------------------------- + PS C:\> New-JCPolicy -TemplateName custom_oma_uri_mdm_windows -Name "Windows - Custom OMA MDM Policy" -uriList '(@( @{format = "string"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage; value = "pathToImage" }, @{format = "int"; uri = "./Device/Vendor/MSFT/Policy/Config/DeviceLock/AccountLockoutPolicy"; value = "1" } ))' + + This command creates a JumpCloud policy named "Windows - Custom OMA MDM Policy" using the custom_oma_uri_mdm_windows template. It defines two OMA-URI configurations: a string value for EnforceLockScreenAndLogonImage and an integer value for AccountLockoutPolicy. + + @@ -19314,6 +19323,13 @@ PS C:\> Set-JCPolicy -PolicyName "macOS - Login Window Policy" -Values $poli This command would overwrite the registry policy's existing values with the imported set of .Reg keys specified by the "RegistryFile" parameter. .Reg files will be converted and uploaded to the JumpCloud policy as long as they contain "DWORD", "EXPAND_SZ", "MULTI_SZ", "SZ" or "QWORD" type data. + + -------------------------- Example 7 -------------------------- + PS C:\> Set-JCPolicy -PolicyName "Windows - Custom OMA MDM Policy" -uriList '(@( @{format = "string"; uri = "./Vendor/MSFT/Policy/Config/DeviceLock/EnforceLockScreenAndLogonImage; value = "pathToImage" }, @{format = "int"; uri = "./Device/Vendor/MSFT/Policy/Config/DeviceLock/AccountLockoutPolicy"; value = "2" } ))' + + This command modifies the existing JumpCloud policy named "Windows - Custom OMA MDM Policy". It updates the policy's OMA-URI settings using the -uriList parameter. The EnforceLockScreenAndLogonImage setting, a string, remains set to "pathToImage". The AccountLockoutPolicy setting, an integer, is updated from its previous value to "2", effectively changing the account lockout policy configuration. + + @@ -20489,6 +20505,18 @@ PS C:\> Set-JCPolicy -PolicyName "macOS - Login Window Policy" -Values $poli None + + primarySystemUser + + A string value indicating a JumpCloud users email, username or userID. This will add the user to the device associations + + System.Object + + System.Object + + + None + systemInsights @@ -20577,6 +20605,18 @@ PS C:\> Set-JCPolicy -PolicyName "macOS - Login Window Policy" -Values $poli None + + primarySystemUser + + A string value indicating a JumpCloud users email, username or userID. This will add the user to the device associations + + System.Object + + System.Object + + + None + SystemID diff --git a/PowerShell/ModuleChangelog.md b/PowerShell/ModuleChangelog.md index 6ba8e34d7..549c51843 100644 --- a/PowerShell/ModuleChangelog.md +++ b/PowerShell/ModuleChangelog.md @@ -1,6 +1,29 @@ +## 2.18.0 + +Release Date: April 18, 2025 + +#### RELEASE NOTES + +``` +This release adds support for Windows MDM OMA Custom policy (Custom MDM (OMA-URI)) with New/Set-JCPolicy +Introduces the primarySystemUser parameter to Set-JCSystem and Update-JCDeviceFromCSV functions. This parameter will allow you associate a user to the specified device + +``` + +#### FEATURES: +- Introduces support for passing list of objects (uriList) for Custom MDM (OMA-URI) policy with New/Set-JCPolicy + - Dynamic param added `-uriList` + - Menu for `Set-JCPolicy` to edit uriList - create/update/add/remove +* Added the primarySystemUser parameter to Set-JCSystem +* Update-JCDeviceFromCSV supports the primarySystemUser param that was added to Set-JCSystem + +#### BUG FIXES: + +* Added an Alias of GroupID to the ByID parameter for Get-JCUserGroupMember + ## 2.17.0 -Release Date: January 3, 2025 +Release Date: January 30, 2025 #### RELEASE NOTES