functions/Set-WUGDeviceGroup.ps1
|
<#
.SYNOPSIS Updates device group settings in WhatsUp Gold - the write counterpart to Get-WUGDeviceGroup. .DESCRIPTION The Set-WUGDeviceGroup function modifies one or more device groups via the REST API. It supports updating group definitions (name, description, parent), assigning roles (brand, OS, primary, sub-role), triggering poll-now or discovery refresh, and retrieving a deduplicated list of device IDs across selected groups. Accepts an array of GroupIds and automatically cycles through each one. Pipeline input is supported for easy chaining with Get-WUGDeviceGroup. Parameter sets: Properties PUT /device-groups/{id}/definition (rename, reparent, update description) Role PUT /device-groups/{id}/roles/{type} (assign brand, os, primary, or sub-role) PollNow PUT /device-groups/{id}/poll-now (trigger polling for all devices) Refresh PUT /device-groups/{id}/refresh (trigger discovery refresh) ListDeviceIds GET /device-groups/{id}/devices/- (deduplicated device list) .PARAMETER GroupId One or more device group IDs to update. Accepts pipeline input. .PARAMETER Name New name for the device group. (Properties set) .PARAMETER Description New description for the device group. (Properties set) .PARAMETER NewParentGroupId Move the group under a different parent group. Leave blank to keep current parent. (Properties set) .PARAMETER Role Switch to assign a role to devices in the group. Requires -RoleType and -Body. (Role set) .PARAMETER RoleType The type of role to assign. Valid values: brand, os, primary, sub-role. .PARAMETER PollNow Switch to request the polling service to poll all devices in the group immediately. .PARAMETER Refresh Switch to request the discovery service to refresh all devices in the group immediately. .PARAMETER RefreshOptions Array of refresh options. Valid values: brand, os, inventory, history, credentials, allAttributes. Controls what data is reset using newly collected info. Default: empty (disabled). .PARAMETER DropDataOlderThanHours Remove data discovered prior to x hours ago. Min value 1, less than 0 ignored, 0 uses system default. Default: -1. .PARAMETER RefreshLimit Number of devices to refresh. Zero or empty gives the server maximum. Default: 0. .PARAMETER ListDeviceIds Switch to collect and return a deduplicated list of device IDs across all specified groups. .PARAMETER Body A raw JSON string for custom payloads (Role and Properties sets). .EXAMPLE # Rename a device group Set-WUGDeviceGroup -GroupId 101 -Name "Production Servers" .EXAMPLE # Update name and description across multiple groups Set-WUGDeviceGroup -GroupId 101, 102 -Description "Managed by automation" .EXAMPLE # Move a group under a new parent Set-WUGDeviceGroup -GroupId 101 -NewParentGroupId 50 .EXAMPLE # Assign a primary role to devices in a group $body = @{ roleId = "role-abc-123" } | ConvertTo-Json Set-WUGDeviceGroup -GroupId 101 -Role -RoleType primary -Body $body .EXAMPLE # Assign a brand role to devices across multiple groups $body = @{ roleId = "brand-xyz" } | ConvertTo-Json Set-WUGDeviceGroup -GroupId 101, 102, 103 -Role -RoleType brand -Body $body .EXAMPLE # Poll all devices in a group immediately Set-WUGDeviceGroup -GroupId 101 -PollNow .EXAMPLE # Trigger discovery refresh for multiple groups Set-WUGDeviceGroup -GroupId 101, 102 -Refresh .EXAMPLE # Get a deduplicated list of device IDs across groups (useful for piping) $deviceIds = Set-WUGDeviceGroup -GroupId 101, 102, 103 -ListDeviceIds .EXAMPLE # Pipeline: rename all groups matching a search Get-WUGDeviceGroup -SearchValue "Old" | Set-WUGDeviceGroup -Name "Updated" .NOTES Author: Jason Alberino (jason@wug.ninja) Reference: https://docs.ipswitch.com/NM/WhatsUpGold2024/02_Guides/rest_api/index.html#tag/DeviceGroup #> function Set-WUGDeviceGroup { [CmdletBinding(DefaultParameterSetName = 'Properties', SupportsShouldProcess = $true)] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('id', 'ConfigGroupId')] [int[]]$GroupId, # -- Properties set (definition) -- [Parameter(ParameterSetName = 'Properties')] [string]$Name, [Parameter(ParameterSetName = 'Properties')] [string]$Description, [Parameter(ParameterSetName = 'Properties')] [string]$NewParentGroupId, # -- Role set -- [Parameter(Mandatory = $true, ParameterSetName = 'Role')] [switch]$Role, [Parameter(Mandatory = $true, ParameterSetName = 'Role')] [ValidateSet('brand', 'os', 'primary', 'sub-role')] [string]$RoleType, [Parameter(Mandatory = $true, ParameterSetName = 'Role')] [string]$Body, # -- PollNow set -- [Parameter(Mandatory = $true, ParameterSetName = 'PollNow')] [switch]$PollNow, [Parameter(ParameterSetName = 'PollNow')] [int]$PollNowLimit, # -- PollNow / Refresh shared params -- [Parameter(ParameterSetName = 'PollNow')] [Parameter(ParameterSetName = 'Refresh')] [switch]$ImmediateChildren, [Parameter(ParameterSetName = 'PollNow')] [Parameter(ParameterSetName = 'Refresh')] [string]$Search, # -- Refresh set -- [Parameter(Mandatory = $true, ParameterSetName = 'Refresh')] [switch]$Refresh, [Parameter(ParameterSetName = 'Refresh')] [switch]$UpdateNamesForInterfaceActiveMonitor, [Parameter(ParameterSetName = 'Refresh')] [ValidateSet('brand', 'os', 'inventory', 'history', 'credentials', 'allAttributes')] [string[]]$RefreshOptions, [Parameter(ParameterSetName = 'Refresh')] [int]$DropDataOlderThanHours, [Parameter(ParameterSetName = 'Refresh')] [int]$RefreshLimit, # -- ListDeviceIds set -- [Parameter(Mandatory = $true, ParameterSetName = 'ListDeviceIds')] [switch]$ListDeviceIds ) begin { Write-Debug "Starting Set-WUGDeviceGroup [$($PSCmdlet.ParameterSetName)]" $baseUri = "${global:WhatsUpServerBaseURI}/api/v1/device-groups" $allGroupIds = [System.Collections.Generic.List[int]]::new() $finalOutput = [System.Collections.Generic.List[object]]::new() } process { foreach ($gid in $GroupId) { $allGroupIds.Add($gid) } } end { # Validate Properties set has at least one property to change if ($PSCmdlet.ParameterSetName -eq 'Properties') { if (-not $PSBoundParameters.ContainsKey('Name') -and -not $PSBoundParameters.ContainsKey('Description') -and -not $PSBoundParameters.ContainsKey('NewParentGroupId')) { Write-Error "Specify at least one of -Name, -Description, or -NewParentGroupId." return } } $total = $allGroupIds.Count $current = 0 # -- ListDeviceIds: collect and deduplicate device IDs across groups -- if ($PSCmdlet.ParameterSetName -eq 'ListDeviceIds') { $deviceIdSet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($gid in $allGroupIds) { $current++ Write-Progress -Activity 'Collecting device IDs' -Status "Group $gid ($current of $total)" -PercentComplete (($current / $total) * 100) try { $uri = "${baseUri}/${gid}/devices/-" $result = Get-WUGAPIResponse -Uri $uri -Method 'GET' $devices = if ($result.data.devices) { $result.data.devices } elseif ($result.data) { $result.data } else { @() } foreach ($d in $devices) { $did = if ($d.id) { "$($d.id)" } else { "$d" } [void]$deviceIdSet.Add($did) } } catch { Write-Error "Error fetching devices for group ${gid}: $_" } } Write-Progress -Activity 'Collecting device IDs' -Completed Write-Verbose "Resolved $($deviceIdSet.Count) unique device(s) across $total group(s)." return @($deviceIdSet) } # -- Write operations: loop through groups -- foreach ($gid in $allGroupIds) { $current++ $pct = [Math]::Round(($current / $total) * 100) switch ($PSCmdlet.ParameterSetName) { 'Properties' { $uri = "${baseUri}/${gid}/definition" $method = 'PUT' $action = 'Update group definition' $bodyHash = @{} if ($PSBoundParameters.ContainsKey('Name')) { $bodyHash.name = $Name } if ($PSBoundParameters.ContainsKey('Description')) { $bodyHash.description = $Description } if ($PSBoundParameters.ContainsKey('NewParentGroupId')) { $bodyHash.parentGroupId = "$NewParentGroupId" } $requestBody = $bodyHash | ConvertTo-Json -Depth 5 } 'Role' { $uri = "${baseUri}/${gid}/roles/${RoleType}" $method = 'PUT' $action = "Assign role ($RoleType)" $requestBody = $Body } 'PollNow' { $pollQueryParams = @() if ($ImmediateChildren) { $pollQueryParams += "immediateChildren=true" } if ($Search) { $pollQueryParams += "search=$([uri]::EscapeDataString($Search))" } if ($PSBoundParameters.ContainsKey('PollNowLimit')) { $pollQueryParams += "limit=$PollNowLimit" } $pollQs = if ($pollQueryParams.Count) { '?' + ($pollQueryParams -join '&') } else { '' } $uri = "${baseUri}/${gid}/poll-now${pollQs}" $method = 'PUT' $action = 'Poll now' $requestBody = $null } 'Refresh' { $refreshQueryParams = @() if ($ImmediateChildren) { $refreshQueryParams += "immediateChildren=true" } if ($Search) { $refreshQueryParams += "search=$([uri]::EscapeDataString($Search))" } if ($UpdateNamesForInterfaceActiveMonitor) { $refreshQueryParams += "updateNamesForInterfaceActiveMonitor=true" } if ($PSBoundParameters.ContainsKey('RefreshOptions')) { foreach ($opt in $RefreshOptions) { $refreshQueryParams += "options=$opt" } } if ($PSBoundParameters.ContainsKey('DropDataOlderThanHours')) { $refreshQueryParams += "dropDataOlderThanHours=$DropDataOlderThanHours" } if ($PSBoundParameters.ContainsKey('RefreshLimit')) { $refreshQueryParams += "limit=$RefreshLimit" } $refreshQs = if ($refreshQueryParams.Count) { '?' + ($refreshQueryParams -join '&') } else { '' } $uri = "${baseUri}/${gid}/refresh${refreshQs}" $method = 'PUT' $action = 'Discovery refresh' $requestBody = $null } } Write-Debug "${action} on group ${gid}. URI: $uri" Write-Progress -Activity $action -Status "Group $gid ($current of $total)" -PercentComplete $pct if (-not $PSCmdlet.ShouldProcess("Group $gid", $action)) { continue } try { if ($requestBody) { $result = Get-WUGAPIResponse -Uri $uri -Method $method -Body $requestBody } else { $result = Get-WUGAPIResponse -Uri $uri -Method $method } $data = if ($result.data) { $result.data } else { $result } $finalOutput.Add($data) } catch { Write-Error "Error in Set-WUGDeviceGroup (${action}) for group ${gid}: $_" } } Write-Progress -Activity 'Set-WUGDeviceGroup' -Completed Write-Debug "Completed Set-WUGDeviceGroup. Results: $($finalOutput.Count)" return $finalOutput } } # SIG # Begin signature block # MIIVlwYJKoZIhvcNAQcCoIIViDCCFYQCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBtbZnikwsGxqEs # xWpFkqvhPDnks8EQYKGg5ITbQy2yoaCCEdMwggVvMIIEV6ADAgECAhBI/JO0YFWU # jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI # DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM # EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy # dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG # EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv # IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s # hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD # J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7 # P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme # me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz # T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q # RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz # mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc # QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T # OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/ # AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID # AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD # VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV # HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE # VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v # ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE # KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI # hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF # OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC # J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ # pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl # d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH # +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M # UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD # VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv # ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5 # NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp # BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G # CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI # ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV # DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3 # 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw # mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm # +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe # dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4 # 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM # dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY # MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU # pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV # HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG # A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1 # YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG # AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl # U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0 # aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh # w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd # OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj # cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc # WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO # hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs # zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7 # 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J # KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH # j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2 # Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/ # L9Uo2bC5a4CH2RwwggY+MIIEpqADAgECAhAHnODk0RR/hc05c892LTfrMA0GCSqG # SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 # ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw # HhcNMjYwMjA5MDAwMDAwWhcNMjkwNDIxMjM1OTU5WjBVMQswCQYDVQQGEwJVUzEU # MBIGA1UECAwLQ29ubmVjdGljdXQxFzAVBgNVBAoMDkphc29uIEFsYmVyaW5vMRcw # FQYDVQQDDA5KYXNvbiBBbGJlcmlubzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBAPN6aN4B1yYWkI5b5TBj3I0VV/peETrHb6EY4BHGxt8Ap+eT+WpEpJyE # tRYPxEmNJL3A38Bkg7mwzPE3/1NK570ZBCuBjSAn4mSDIgIuXZnvyBO9W1OQs5d6 # 7MlJLUAEufl18tOr3ST1DeO9gSjQSAE5Nql0QDxPnm93OZBon+Fz3CmE+z3MwAe2 # h4KdtRAnCqwM+/V7iBdbw+JOxolpx+7RVjGyProTENIG3pe/hKvPb501lf8uBAAD # LdjZr5ip8vIWbf857Yw1Bu10nVI7HW3eE8Cl5//d1ribHlzTzQLfttW+k+DaFsKZ # BBL56l4YAlIVRsrOiE1kdHYYx6IGrEA809R7+TZA9DzGqyFiv9qmJAbL4fDwetDe # yIq+Oztz1LvEdy8Rcd0JBY+J4S0eDEFIA3X0N8VcLeAwabKb9AjulKXwUeqCJLvN # 79CJ90UTZb2+I+tamj0dn+IKMEsJ4v4Ggx72sxFr9+6XziodtTg5Luf2xd6+Phha # mOxF2px9LObhBLLEMyRsCHZIzVZOFKu9BpHQH7ufGB+Sa80Tli0/6LEyn9+bMYWi # 2ttn6lLOPThXMiQaooRUq6q2u3+F4SaPlxVFLI7OJVMhar6nW6joBvELTJPmANSM # jDSRFDfHRCdGbZsL/keELJNy+jZctF6VvxQEjFM8/bazu6qYhrA7AgMBAAGjggGJ # MIIBhTAfBgNVHSMEGDAWgBQPKssghyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQU # 6YF0o0D5AVhKHbVocr8GaSIBibAwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQC # MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIB # AwIwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EM # AQQBMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2Vj # dGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBE # BggrBgEFBQcwAoY4aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGlj # Q29kZVNpZ25pbmdDQVIzNi5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNl # Y3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4IBgQAEIsm4xnOd/tZMVrKwi3doAXvC # wOA/RYQnFJD7R/bSQRu3wXEK4o9SIefye18B/q4fhBkhNAJuEvTQAGfqbbpxow03 # J5PrDTp1WPCWbXKX8Oz9vGWJFyJxRGftkdzZ57JE00synEMS8XCwLO9P32MyR9Z9 # URrpiLPJ9rQjfHMb1BUdvaNayomm7aWLAnD+X7jm6o8sNT5An1cwEAob7obWDM6s # X93wphwJNBJAstH9Ozs6LwISOX6sKS7CKm9N3Kp8hOUue0ZHAtZdFl6o5u12wy+z # zieGEI50fKnN77FfNKFOWKlS6OJwlArcbFegB5K89LcE5iNSmaM3VMB2ADV1FEcj # GSHw4lTg1Wx+WMAMdl/7nbvfFxJ9uu5tNiT54B0s+lZO/HztwXYQUczdsFon3pjs # Nrsk9ZlalBi5SHkIu+F6g7tWiEv3rtVApmJRnLkUr2Xq2a4nbslUCt4jKs5UX4V1 # nSX8OM++AXoyVGO+iTj7z+pl6XE9Gw/Td6WKKKsxggMaMIIDFgIBATBoMFQxCzAJ # BgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNl # Y3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYCEAec4OTRFH+FzTlzz3Yt # N+swDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZ # BgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYB # BAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgKLIY8lDvcEQirRM4vJSwyHs/CJ+Q4xDL # GK+wo+bVrQgwDQYJKoZIhvcNAQEBBQAEggIASc0EQYqtAYo69FsNyoxelq2eewpb # lkbJy18ARha+DYuHuDtMvaLN1G2SMts98onY4Pe81HzH4Gs//Ghjvk41sDl3rTyf # sGRWYgLWe3jgl6RJboDAGk3QqUvx4Y8X3UclQqv0Gt5NBxxYB+g+488hZ/Ix60l+ # J1Zqs9VNGGg6DXGSYxNN3rcSDP9e5X6QDxwU/sib4PrDTzebe5nhhn92qqQeHEu5 # L2aBHoC/bLL7aJOr3EsAmbW8qczZPyzZWqK/fS70KhYREtFtV3wWxGZbRxGfIlgx # qgxaX3i9BDzwygAR2LjklcQ2E6rfqL7v2N4gY83nvj8lJeYtDegVU9bLJYr4tX5x # BQVV+KmK6pfqmLNl6KvjzekXo8hX+c1//atA4KnkB3Zek37ZNkZ1lzirGHiVjA04 # FTuyqSWTmt1gXLnfIp1c/R9KF/BUSksPBBoWhGUDVzVx4qras6zwj1DfApNlAU4V # sLnmiSauXkoCR6DAyKmKVlVGS01F58gdu6fhxIfY0SD6nXvnXEcDzIHhVYjJ4KbH # /LIPdW+gM3HO7GN9oFMpTPRTIFcxnfynG85V8yD/wCm42+Uh9hPm133iM0qtHMHn # OVY7NsYFk7HhLVcTFlC3NVf0nFgaDkYU0xJgqHh4aWORxM87K7dnmur79EclT2Df # gMy4aBQ0oM0/w9I= # SIG # End signature block |