Dracoon.psm1
$script:ModuleRoot = $PSScriptRoot $script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\Dracoon.psd1").ModuleVersion # Detect whether at some level dotsourcing was enforced $script:doDotSource = Get-PSFConfigValue -FullName Dracoon.Import.DoDotSource -Fallback $false if ($Dracoon_dotsourcemodule) { $script:doDotSource = $true } <# Note on Resolve-Path: All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator. This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS. Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist. This is important when testing for paths. #> # Detect whether at some level loading individual module files, rather than the compiled module was enforced $importIndividualFiles = Get-PSFConfigValue -FullName Dracoon.Import.IndividualFiles -Fallback $false if ($Dracoon_importIndividualFiles) { $importIndividualFiles = $true } if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true } if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true } function Import-ModuleFile { <# .SYNOPSIS Loads files into the module on module import. .DESCRIPTION This helper function is used during module initialization. It should always be dotsourced itself, in order to proper function. This provides a central location to react to files being imported, if later desired .PARAMETER Path The path to the file to load .EXAMPLE PS C:\> . Import-ModuleFile -File $function.FullName Imports the file stored in $function according to import policy #> [CmdletBinding()] Param ( [string] $Path ) $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath if ($doDotSource) { . $resolvedPath } else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) } } #region Load individual files if ($importIndividualFiles) { # Execute Preimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\preimport.ps1")) { . Import-ModuleFile -Path $path } # Import all internal functions foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Import all public functions foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Execute Postimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\postimport.ps1")) { . Import-ModuleFile -Path $path } # End it here, do not load compiled code below return } #endregion Load individual files #region Load compiled code <# This file loads the strings documents from the respective language folders. This allows localizing messages and errors. Load psd1 language files for each language you wish to support. Partial translations are acceptable - when missing a current language message, it will fallback to English or another available language. #> Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'Dracoon' -Language 'en-US' import-module PSFramework Class Dracoon { hidden [string]$webServiceRoot [string]$serverRoot hidden static [string]$dateFormat = 'yyyy-MM-dd' hidden static [int]$maxRecursionLevelSSP = 50 hidden [int]$homeRoomParentId hidden [int]$projectsRoomParentId hidden [int]$openIDConfigId = 4 hidden [int]$adminGroupId#=6 hidden [String] $authToken [String] $authenticatedUser [switch] $verbose $oauthToken_Expires_in $headers = @{ } Dracoon ([PSCredential]$credentials, [string]$baseUrl) { # [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 Write-PSFMessage "Verbinde Dracoon $baseUrl mittels Credentials-Objekt" $this.serverRoot = Get-DracoonServerRoot $baseUrl $this.webServiceRoot = "$($this.serverRoot)/api" $this.Login($credentials) } Dracoon ([String]$AccessToken, [string]$baseUrl) { # [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 Write-PSFMessage "Verbinde Dracoon $baseUrl mittels AccessToken $AccessToken" -functionName "[Dracoon]::new(AccessToken, baseUrl)" $this.serverRoot = Get-DracoonServerRoot $baseUrl $this.webServiceRoot = "$($this.serverRoot)/api" $this.Login($AccessToken) } hidden Login([PSCredential]$credentials) { # [void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") # $this.jsonserial = New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer # $this.jsonserial.MaxJsonLength = 2147483647 $parameter = @{login = $credentials.UserName; password = $credentials.GetNetworkCredential().Password; language = "1"; authType = "sql" } $result = Invoke-DracoonAPI -connection $this -path "/v4/auth/login" -body $parameter -method Post -hideParameters $true Write-PSFMessage $result $this.authToken = $result.token $this.authenticatedUser = $credentials.UserName $this.headers.Add("X-Sds-Auth-Token", $this.authToken) Write-PSFMessage "This-Type: $($this.gettype())" } hidden Login([string]$AccessToken) { Write-PSFMessage "Login with AccessToken <$AccessToken>" -Level Debug if ($AccessToken){ $this.authToken = "Bearer $AccessToken" #$this.oauthToken_Expires_in = $tokenContent.expires_in $this.authenticatedUser = "OAuth" $this.headers.Add("Authorization", $this.authToken) }else{throw "AccessToken is null"} } # [PSCustomObject]GetGroups([string]$filter) { # $groups = $this.InvokeGet("/v4/groups?filter=$filter") # return $groups.items # } # [PSCustomObject]GetGroups() { # return $this.GetGroups("") # } # [PSCustomObject]GetGroupMembers([int]$groupId, [string]$filter) { # $groups = $this.InvokeGet("/v4/groups/$groupId/users?filter=$filter") # return $groups.items # } # [PSCustomObject]GetGroupMembers([int]$groupId) { # return $this.GetGroupMembers($groupId, "isMember:eq:true") # } # [PSCustomObject]AddGroupMembers([int]$groupId, [int[]]$userIdArray) { # $parameter = @{ids = $userIdArray } # $result = $this.InvokePost("/v4/groups/$groupId/users", $parameter) # return $result # } # [PSCustomObject]CreateGroup([string]$groupName) { # $parameter = @{name = "$groupName" } # $result = $this.InvokePost("/v4/groups", $parameter) # #if ($verbose) {Log-Message ("Authentication-Token: {0}" -f $result.token)} # Write-PSFMessage $result # return $result # } # [PSCustomObject]DeleteUser([int]$id) { # $result = $this.DeleteUser($id, $false) # return $result # } # [PSCustomObject]GetLastAdminRooms([int]$userId) { # $result = $this.InvokeGet("/v4/users/$userId/last_admin_rooms") # return $result.items # } # [PSCustomObject]GetUserDetails([int]$userId) { # $result = $this.InvokeGet("/v4/users/$userId") # return $result # } # [PSCustomObject]GetCurrentUserInfos() { # $result = $this.InvokeGet("/v4/user/account") # return $result # } # [PSCustomObject]UpdateUser([int]$userId, [Hashtable]$metaData) { # $result = $this.InvokePut("/v4/users/$userId", $metaData) # return $result # } # [PSCustomObject]SetUserAttributes([int]$userId, [Hashtable]$userAttributes) { # $result = $this.SetUserAttributes($userId, $userAttributes, $false) # return $result # } # [PSCustomObject]AddUserAttributes([int]$userId, [Hashtable]$userAttributes) { # $result = $this.SetUserAttributes($userId, $userAttributes, $true) # return $result # } # [Hashtable]GetUserAttributes([int]$userId) { # $attributes = @{ } # $userDetails = $this.GetUserDetails($userId) # foreach ($item in $userDetails.userAttributes.items) { # $attributes.add($item.key, $item.value) # } # return $attributes # } # [PSCustomObject]LockUser([int]$userId, [bool]$lock) { # return $this.UpdateUser($userId, @{isLocked = $lock }) # return $result # } # [PSCustomObject]CreateMailUser([string]$login, [string]$firstName, [string]$lastName, [string]$title, [string]$gender, [string]$eMail) { # return $this.CreateMailUser($login, $firstName, $lastName, $title, $gender, $eMail, $false) # } # [PSCustomObject]CreateMailUser([string]$login, [string]$password, [string]$firstName, [string]$lastName, [string]$title, [string]$gender, [string]$eMail, [bool]$notifyUser) { # return $this.CreateMailUser($login, $password, $firstName, $lastName, $title, $gender, $eMail, $notifyUser, $false) # } # [PSCustomObject]CreateMailUser([string]$login, [string]$password, [string]$firstName, [string]$lastName, [string]$title, [string]$gender, [string]$eMail, [bool]$notifyUser, [bool]$enableOpenID) { # $parameter = @{firstName = $firstName; lastName = $lastName; authMethods = @(@{authId = "sql"; isEnabled = "true" }); login = $login; title = $title; gender = $gender; expiration = @{enableExpiration = "false"; expireAt = "2018-01-01T00:00:00" }; receiverLanguage = "de-DE"; email = $eMail; notifyUser = "$notifyUser"; needsToChangePassword = "true"; password = $password } # if ($enableOpenID) { # $parameter["authMethods"] += (@{authId = "openid"; isEnabled = $true; options = @(@{key = "openid_config_id"; value = $this.openIDConfigId }; @{key = "username"; value = $eMail }) }) # } # $result = $this.InvokePost("/v4/users", $parameter) # return $result # } # [PSCustomObject]UploadFile([string]$fullFilePath, [int]$parentNodeId) { # return $this.UploadFile((get-item $fullFilePath), $parentNodeId) # } # [PSCustomObject]UploadFile([System.IO.FileSystemInfo]$fullFilePath, [int]$parentNodeId) { # $result = $null # Write-PSFMessage "Lade Datei hoch: $fullFilePath" # $parameter = @{"parentId" = $parentNodeId; "name" = $fullFilePath.Name; "classification" = 2; "size" = $fullFilePath.length; "expiration" = @{"enableExpiration" = $false; "expireAt" = "2018-01-01T00:00:00" }; "notes" = "" } # $initUpload = $this.InvokePost("/v4/nodes/files/uploads", $parameter) # try { # $result = Invoke-RestMethod $initUpload.uploadUrl -ContentType "application/octet-stream" -Method Post -Headers $this.headers -InFile $fullFilePath.FullName # Write-PSFMessage $result # $result = $this.Invoke(("/v4/uploads/{0}" -f $initUpload.token), $null, [Microsoft.Powershell.Commands.WebRequestMethod]::Put, $false) # } # catch { # Write-PSFMessage "Fehler $_" # $this.InvokeDelete(("/v4/uploads/{0}" -f $initUpload.token)) # throw $_ # } # return $result # } # # [PSCustomObject]GetEventLog([int]$limit, [int]$offset, [string]$filter) { # [PSCustomObject]GetEventLog([int]$limit, [int]$offset, [hashtable]$additionalParamater) { # $parameterTable = @{limit = $limit; offset = $offset } # $parameterTable += $additionalParamater # # $uri = "/v4/eventlog/events?type=6&limit=$limit&offset=$offset" # # if ($filter) { # # $uri += "&$filter" # # } # $events = $this.InvokeGet("/v4/eventlog/events", $parameterTable) # return $events # } # [PSCustomObject]GetNode([int]$nodeId) { # $node = $this.InvokeGet("/v4/nodes/$nodeId") # return $node # } # [PSCustomObject]GetNodeList([hashtable]$parameterTable) { # $nodes = $this.InvokeGet("/v4/nodes", $parameterTable) # return $nodes # } # [PSCustomObject]GetParents([int]$nodeId) { # $parents = $this.InvokeGet("/v4/nodes/$nodeId/parents") # return $parents # } # [PSCustomObject]SearchNode([int]$parentNode, [string]$searchString, [string]$filter, [string]$sort) { # $parameterTable = @{search_string = $searchString; filter = $filter; sort = $sort; parent_id = $parentNode } # $nodes = $this.InvokeGet("/v4/nodes/search", $parameterTable) # return $nodes # } # [PSCustomObject]MoveNodes([int]$targetNodeId, [int[]]$nodesToMove) { # Write-PSFMessage "Verschiebe nach $targetNodeId : $nodesToMove" # $parameter = @{resolutionStrategy = "overwrite"; keepShareLinks = $true; nodeIds = $nodesToMove } # $result = $this.InvokePost("/v4/nodes/$targetNodeId/move_to", $parameter) # return $result # } # [PSCustomObject]CopyNodes([int]$targetNodeId, [int[]]$nodesToMove) { # Write-PSFMessage "Kopiere nach $targetNodeId : $nodesToMove" # $parameter = @{resolutionStrategy = "overwrite"; keepShareLinks = $true; nodeIds = $nodesToMove } # $result = $this.InvokePost("/v4/nodes/$targetNodeId/copy_to", $parameter) # return $result # } # [PSCustomObject]CreateFolder([int]$parentNodeId, [string]$name, [string]$notes) { # Write-PSFMessage "Lege Ordner $name unter der Node $parentNodeId an, Comment=$notes" # $parameter = @{parentId = $parentNodeId; name = $name; notes = $notes } # $result = $this.InvokePost("/v4/nodes/folders", $parameter) # return $result # } } function Get-DracoonServerRoot { <# .SYNOPSIS Cleans a given URL to be used as a server-root. .DESCRIPTION Cleans a given URL to be used as a server-root. .PARAMETER Url A FQDN/URL or the server .EXAMPLE Get-DracoonServerRoot "my.server.de" Get-DracoonServerRoot "my.server.de/" Get-DracoonServerRoot "http://my.server.de" Get-DracoonServerRoot "http://my.server.de/" All versions return "https://my.server.de" .NOTES General notes #> param ( [parameter(mandatory = $true, Position=0)] [string]$Url ) Write-PSFMessage "Getting Dracoon Server-Root for $Url" # Strip leading / $serverRoot = $Url.Trim("/") # Strip Prefix protocoll $serverRoot = $serverRoot -replace "^.*:\/\/" $serverRoot="https://$serverRoot" Write-PSFMessage "Result: $serverRoot" $serverRoot } function Get-EncodedParameterString { <# .SYNOPSIS Converts a hashtable to GET Parameters .DESCRIPTION Converts a hashtable to GET Parameters. .PARAMETER parameter Hashtable with the GET Parameters .EXAMPLE Get-EncodedParameterString -parameter @{key1="value1";key2="value2"} Returns the string: key1=value1&key2=value2 .NOTES General notes #> param ( [parameter(Mandatory,Position=1)] [Hashtable]$parameter ) $getParameter = @() if ($parameter) { foreach ($key in $parameter.Keys) { $value = $parameter[$key] if ($value) { switch ($value.GetType()) { bool { $value = $value.ToString() } Default { } } $valueEncoded = [System.Web.HttpUtility]::UrlEncode($value) $getParameter += "$key=$valueEncoded" } } } return ($getParameter -join "&") } function New-DracoonRandomPassword { <# .SYNOPSIS Creates a new random password. .DESCRIPTION Creates a new random password with the following rules: -12 characters long -at least one lower case character -at least one upper case character -at least one number -at least one special character .EXAMPLE $newPassword=New-DracoonRandomPassword Creates a new password .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] param() process { [int]$PasswordLength = 12 # Specifies an array of strings containing charactergroups from which the password will be generated. # At least one char from each group (string) will be used. [String[]]$InputStrings = @('abcdefghijkmnpqrstuvwxyz', 'ABCEFGHJKLMNPQRSTUVWXYZ', '23456789', '!"#%&') $Password = @{ } # Create char arrays containing groups of possible chars [char[][]]$CharGroups = $InputStrings # Create char array containing all chars $AllChars = $CharGroups | ForEach-Object { [Char[]]$_ } # Randomize one char from each group Foreach ($Group in $CharGroups) { if ($Password.Count -lt $PasswordLength) { $Index = Get-DracoonSeed While ($Password.ContainsKey($Index)) { $Index = Get-DracoonSeed } $Password.Add($Index, $Group[((Get-DracoonSeed) % $Group.Count)]) } } # Fill out with chars from $AllChars for ($i = $Password.Count; $i -lt $PasswordLength; $i++) { $Index = Get-DracoonSeed While ($Password.ContainsKey($Index)) { $Index = GetSeed } $Password.Add($Index, $AllChars[((Get-DracoonSeed) % $AllChars.Count)]) } return $( -join ($Password.GetEnumerator() | Sort-Object -Property Name | Select-Object -ExpandProperty Value)) } } function Get-DracoonSeed { # Generate a seed for randomization $RandomBytes = New-Object -TypeName 'System.Byte[]' 4 $Random = New-Object -TypeName 'System.Security.Cryptography.RNGCryptoServiceProvider' $Random.GetBytes($RandomBytes) return [BitConverter]::ToUInt32($RandomBytes, 0) } function Remove-NullFromHashtable { <# .SYNOPSIS Funktion zum Entfernen von $null Werten aus HashTables. .DESCRIPTION Funktion zum Entfernen von $null Werten aus HashTables. Dazu wird die HashTable in einen json String umgewandelt und anschließend per RegEx alle null-Werte entfernt. Falls InputHashmap -eq $null dann wird nichts zurückgegeben. .PARAMETER InputHashmap Die Eingabe-HashTable .PARAMETER Json Wird der Parameter gesetzt, so wird anstatt einer neuen HashTable der modifizierte json String zurück geliefert .EXAMPLE $hash=@{ Name="Max" Surname="Mustermann" MiddleName=$null kids=@( @{ Name="Maxi" MiddleName=$null Surname="Mustermann" }, @{ Name="Maxine" MiddleName="Christine" Surname="Mustermann" } ) } $newHash=$hash | Remove-NullFromHashtable .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] param ( [Parameter(ValueFromPipeline)] [hashtable]$InputHashmap, [switch]$Json ) process { if ($InputHashmap) { $tempString = $InputHashmap | ConvertTo-Json -Depth 15 Write-PSFMessage -Level Debug "Entferne null Values aus $tempString" $tempString = $tempString -replace '"\w+?"\s*:\s*null,?' Write-PSFMessage -Level Debug "Ergebnis: $tempString" if ($Json) { $tempString }else { Write-PSFMessage -Level Debug "Erzeuge HashTable" $newHashmap = $tempString | ConvertFrom-Json $newHashmap } } } } function Add-DracoonUrl { <# .SYNOPSIS This function allows the addition of new Server-URLs for TAB Completion. Each function which requires a -Url parameter will provide a TAB completer with suggested URLs. .DESCRIPTION This function allows the addition of new Server-URLs for TAB Completion. Each function which requires a -Url parameter will provide a TAB completer with suggested URLs, e.g. Connect-Dracoon Different from Set-DracoonUrl this command does not overwrite but append to existing settings. .PARAMETER NewUrl The new URLs to be added .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE Add-DracoonUrl 'https://dxi.mydomain' Add a single Server to the list of suggested URLs (get-adforest -ErrorAction Stop).domains | ForEach-Object { Add-DracoonUrl "https://dataexchange.$($_)" } If you have an on prem Dracoon server in each of your Windows Domains with the address "https://dracoon.<yourdomain>" it will get added to the list of suggested URLs. .NOTES The URLs get saved at the PSF-Config "Dracoon.tepp.urls" #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'low')] param ( [parameter(mandatory = $true, Position = 0)] [string[]]$NewUrl ) Write-PSFMessage "Adding new Urls for the URL TEPP: $NewUrl" $oldUrl=Get-PSFConfigValue "Dracoon.tepp.urls" Write-PSFMessage "Existing Urls for the URL TEPP: $oldUrl" $combinedUrls=@() $combinedUrls+=$NewUrl if ($oldUrl) { $combinedUrls+=$oldUrl } # Adjusting format of URLs $combinedUrls = $combinedUrls | ForEach-Object { Get-DracoonServerRoot $_ } # Sorting and filtering unique $combinedUrls=$combinedUrls | Sort-Object | Select-Object -Unique Write-PSFMessage "combined Urls for the URL TEPP: $combinedUrls" Invoke-PSFProtectedCommand -Action "Saving new Urls for the URL TEPP" -Target "$NewUrl" -ScriptBlock { Set-PSFConfig -Module 'Dracoon' -Name 'tepp.urls' -Value $combinedUrls -PassThru | Register-PSFConfig } -PSCmdlet $PSCmdlet } function Connect-Dracoon { <# .SYNOPSIS Creates a new Connection Object to a Dracoon Server instance. .DESCRIPTION Creates a new Connection Object to a Dracoon Server instance. .PARAMETER Credential Credential-Object for direct login. .PARAMETER Url The server root URL. .PARAMETER RefreshToken Neccessary for OAuth Login: Refresh-Token. Can be created with Request-OAuthRefreshToken. .PARAMETER AccessToken Neccessary for OAuth Login: Access-Token. Can be created with Request-OAuthRefreshToken. .PARAMETER ClientID Neccessary for OAuth Login: The Id of the OAauth Client. .PARAMETER ClientSecret Neccessary for OAuth Login: The Secret of the OAauth Client. .PARAMETER EnableException Should Exceptions been thrown? .EXAMPLE # Connect Via OAuth access token ## Generate accesstoken $accessToken=Request-DracoonOAuthToken -ClientID $clientId -ClientSecret $clientSecret -Url $url -Credential $cred -TokenType access ## Login with created access token $connection=Connect-Dracoon -Url $url -AccessToken $accessToken .EXAMPLE # Connect Via OAuth refresh token ## Create a refresh token $refreshToken=Request-DracoonOAuthToken -ClientID $clientId -ClientSecret $clientSecret -Credential $cred -url $url -TokenType refresh ## Connect directly with the refresh token $connection=Connect-Dracoon -ClientID $clientId -ClientSecret $clientSecret -url $url -RefreshToken $refreshToken .EXAMPLE ## Second option: Create an access token from the refreh token and login with the access token. $accessToken=Request-DracoonOAuthToken -ClientID $clientId -ClientSecret $clientSecret -Url $url -RefreshToken $refreshToken $connection=Connect-Dracoon -Url $url -AccessToken $accessToken .EXAMPLE # Direct auth with /auth/login (**Deprecated**) ## If you are running an older version it maybe possible to login directly. But this option is deprecated and [will be removed in every installation in the future](https://blog.dracoon.com/en/goodbye-x-sds-auth-token-hello-oauth-2.0) $connection=Connect-Dracoon -Url $url -Credential $cred .NOTES As you have to authenticate with OAuth2.0 it is neccessary to create a client application within the admin web-page. For this * Go to _System Settings_ / _Apps_ in the navigation bar * Click on the _Add app_ button * Enter an application name (e.g. "Powershell Scripting") * enable all checkboxes (authorization code:implicit:password) * Copy the _Client ID_ and the _Client Secret_. Both will be referenced as `$ClientID` and `$ClientSecret`. Now it's time to open the powershell. Prepare the basic variables: $cred=Get-Credential -Message "Dracoon" $clientId="YOU JUST CREATED IT ;-)" $clientSecret="THIS ALSO" $url="dracoon.mydomain.com" #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] [CmdletBinding(DefaultParameterSetName = "AccessToken")] Param ( [parameter(mandatory = $true, ParameterSetName = "Credential")] [pscredential]$Credential, [parameter(mandatory = $true, ParameterSetName = "AccessToken")] [parameter(mandatory = $true, ParameterSetName = "RefreshToken")] [parameter(mandatory = $true, ParameterSetName = "Credential")] [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.url")] [string]$Url, [parameter(mandatory = $true, ParameterSetName = "RefreshToken")] [string]$RefreshToken, [parameter(mandatory = $true, ParameterSetName = "AccessToken")] [string]$AccessToken, [parameter(mandatory = $true, ParameterSetName = "RefreshToken")] [string]$ClientID, [parameter(mandatory = $true, ParameterSetName = "RefreshToken")] [string]$ClientSecret, [switch]$EnableException ) begin { Write-PSFMessage "Stelle Verbindung her zu $Url" -Target $Url if ($Credential) { # $connection = [Dracoon]::new($Credential, $Url) Invoke-PSFProtectedCommand -ActionString "Connect-Dracoon.Connecting" -ActionStringValues $Url -Target $Url -ScriptBlock { # $connection = [Dracoon]::new($Credential.username, $Credential.GetNetworkCredential().password, $Url) $connection = [Dracoon]::new($Credential, $Url) } -PSCmdlet $PSCmdlet -EnableException $EnableException } elseif ($RefreshToken) { # Invoke-PSFProtectedCommand -ActionString "Connect-Dracoon.Connecting" -ActionStringValues $Url -Target $Url -ScriptBlock { # } -PSCmdlet $PSCmdlet -EnableException $EnableException $AccessToken=Request-DracoonOAuthToken -Url $Url -ClientID $ClientID -ClientSecret $ClientSecret -RefreshToken $RefreshToken $connection = [Dracoon]::new($AccessToken,$Url) }else{ # Connection with an access token $connection = [Dracoon]::new($AccessToken,$Url) } } process { if (Test-PSFFunctionInterrupt) { return } Write-PSFMessage -string "Connect-Dracoon.Connected" $connection } } function Convert-DracoonGetSetRoomAcl { <# .SYNOPSIS Converts Information retrieved from Get-DracoonRoomAcl to be used for Set-DracoonRoomAcl. .DESCRIPTION Converts Information retrieved from Get-DracoonRoomAcl to be used for Set-DracoonRoomAcl. Get-DracoonRoomAcl returns an array in the following format: { "userInfo": { "id": 0, "userType": "internal", "avatarUuid": "string", "displayName": "string", "firstName": "string", "lastName": "string", "email": "string", "title": "string" }, "isGranted": true, "id": 0, "login": "string", "displayName": "string", "email": "john.doe@email.com", "permissions": { "manage": true, "read": true, "create": true, "change": true, "delete": true, "manageDownloadShare": true, "manageUploadShare": true, "readRecycleBin": true, "restoreRecycleBin": true, "deleteRecycleBin": true }, "publicKeyContainer": { "version": "A", "publicKey": "string" } } Set-DracoonRoomAcl needs only a sub-part as an array: { "id": 0, "permissions": { "manage": true, "read": true, "create": true, "change": true, "delete": true, "manageDownloadShare": true, "manageUploadShare": true, "readRecycleBin": true, "restoreRecycleBin": true, "deleteRecycleBin": true } } This function converts the different formats. .PARAMETER ExistingPermissions Array of the exisiting Permission Items. .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [array]$ExistingPermissions ) Write-PSFMessage "Converting Permissions " Write-PSFMessage "Current permissions: $($ExistingPermissions|convertto-json -depth 10)" $permissionList = @() foreach ($item in $ExistingPermissions) { $permissionList += @{id = $item.id; permissions = $item.permissions } } Write-PSFMessage "Neue Berechtigungen: $($permissionList|convertto-json -depth 10)" $permissionList } function Get-DracoonAuditDataroom { <# .SYNOPSIS Searches Datarooms by given filter. API-GET /v4/eventlog/audits/nodes .DESCRIPTION Retrieve a list of all nodes of type room, and the room assignment users with permissions. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Except for userName, userFirstName and userLastName - these are connected via logical disjunction (OR) Filter string syntax: FIELD_NAME:OPERATOR:VALUE[:VALUE...] userName:cn:searchString_1|userFirstName:cn:searchString_2|nodeId:eq:2 .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are NOT supported. Nodes are sorted by type first, then by sent sort string. Example: name:desc .PARAMETER HideSpecialRooms Filters any room which has a GUID as roomName oder Parent-Path .EXAMPLE Get-DracoonAuditDataroom -Connection $connection Lists all available Datarooms .NOTES Right "read audit log" required. #> param ( [parameter(Mandatory)] [Dracoon]$Connection, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [string]$Filter, [int]$Limit, [int]$Offset, [string]$Sort, [bool]$HideSpecialRooms=$true ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path = "/v4/eventlog/audits/nodes" EnablePaging = $true UrlParameter = @{ filter = $Filter limit = $Limit sort = $Sort offset = $offset } } $datarooms = Invoke-DracoonAPI @apiCallParameter if($HideSpecialRooms){ Write-PSFMessage "Entferne Datenräume, deren Parent einer GUID entsprechen" $regex = '[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?' return $datarooms | Where-Object {( $_.nodeParentPath -notmatch $regex) -and ( $_.nodeName -notmatch $regex)} }else{ return $datarooms } } function Get-DracoonAuthConfigAD{ <# .SYNOPSIS Retrieve a list of configured Active Directories. API-GET /v4/system/config/auth/ads .DESCRIPTION Retrieve a list of configured Active Directories. API-GET /v4/system/config/auth/ads Right “read global config” required. Role Config Manager of the Provider Customer. .PARAMETER Connection Parameter description .PARAMETER Alias Returns only the configuration whose "alias" attribute matches the parameter value .EXAMPLE To be added in the Future #> param ( [parameter(Mandatory)] [Dracoon]$Connection, [string]$Alias ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/system/config/auth/ads" } $result=Invoke-DracoonAPI @apiCallParameter if ($Alias){ $result.items|where-object {$_.Alias -eq $Alias} }else{ $result.items } } function Get-DracoonCurrentAccount { <# .SYNOPSIS Retrieves all information regarding the current user’s account. API-GET /v4/user/account .DESCRIPTION Retrieves all information regarding the current user’s account. API-GET /v4/user/account .PARAMETER Connection Parameter description .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$Connection ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/user/account" } Invoke-DracoonAPI @apiCallParameter } function Get-DracoonGroup { <# .SYNOPSIS Returns a list of user groups. API-GET /v4/groups .DESCRIPTION Returns a list of user groups. .PARAMETER Connection Parameter description .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Filter string syntax: FIELD_NAME:OPERATOR:VALUE Example: name:cn:searchString Filter by group name containing searchString. .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are supported. Example: name:asc|expireAt:desc Sort by name ascending AND by expireAt descending. Possible fields: name Group name createdAt Creation date expireAt Expiration date cntUsers Amount of users .PARAMETER EnablePaging Wenn die API mit Paging arbeitet, kann über diesn Parameter ein automatisches Handling aktivieren. Dann werden alle Pages abgehandelt und nur die items zurückgeliefert. .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$Connection, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [string]$Filter, [int]$Limit=500, [int]$Offset=0, [string]$Sort, [bool]$EnablePaging=$true ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/groups" EnablePaging = $EnablePaging UrlParameter = @{ filter=$Filter limit=$Limit sort=$Sort offset=$offset } } Invoke-DracoonAPI @apiCallParameter } # [PSCustomObject]GetLastAdminRooms([int]$userId) { # $result = $this.InvokeGet("/v4/users/$userId/last_admin_rooms") # return $result.items # } function Get-DracoonLastAdminRoom { <# .SYNOPSIS Get rooms where the user is last admin. API-GET /v4/users/$id/last_admin_rooms .DESCRIPTION Retrieve a list of all rooms where the user is last admin (except homeroom and its subordinary rooms). .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL. .PARAMETER Id ID of the user .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$Connection, [parameter(Mandatory)] [int]$Id ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path = "/v4/users/$Id/last_admin_rooms" } $result=Invoke-DracoonAPI @apiCallParameter $result.items } function Get-DracoonNode { <# .SYNOPSIS Provides a hierarchical list of file system nodes (rooms, folders or files) of a given parent that are *accessible* by the current user. .DESCRIPTION Provides a hierarchical list of file system nodes (rooms, folders or files) of a given parent that are accessible by the current user. GET /v4/nodes .PARAMETER connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Filter string syntax: FIELD_NAME:OPERATOR:VALUE[:VALUE...] Example: type:eq:room:folder|perm:eq:read .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are NOT supported. Nodes are sorted by type first, then by sent sort string. Example: name:desc .PARAMETER ParentID Parent node ID. Only rooms and folders can be parents. Parent ID 0 or empty is the root node. .PARAMETER RoomManager boolean. Show all rooms for management perspective. Only possible for Rooms Managers. For all other users, it will be ignored. .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$connection, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [string]$Filter, [int]$Limit=500, [int]$Offset=0, [string]$Sort, [int]$ParentID=0, $RoomManager ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/nodes" EnablePaging = $true UrlParameter = @{ filter=$Filter limit=$Limit sort=$Sort offset=$offset parent_id=$ParentID room_manager=$RoomManager } # EnablePaging=$true } $result = Invoke-DracoonAPI @apiCallParameter $result } # [PSCustomObject]GetRoomAcl([int]$roomId) { # $result = $this.InvokeGet("/v4/nodes/rooms/$roomId/users") # return $result # } function Get-DracoonRoomAcl { <# .SYNOPSIS Retrieve a list of users that are and / or can be granted to the room. API-GET /v4/nodes/rooms/$NodeId/users .DESCRIPTION Retrieve a list of users that are and / or can be granted to the room. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER NodeId ID of the room .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Filter string syntax: FIELD_NAME:OPERATOR:VALUE Example: permissionsManage:eq:true|user:cn:searchString Get all users that have manage permissions to this room AND whose (firstname OR lastname OR email) is like searchString. .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are NOT supported. Nodes are sorted by type first, then by sent sort string. Example: name:desc .PARAMETER EnablePaging Wenn die API mit Paging arbeitet, kann über diesn Parameter ein automatisches Handling aktivieren. Dann werden alle Pages abgehandelt und nur die items zurückgeliefert. .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$Connection, [parameter(Mandatory)] [int]$NodeId, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [string]$Filter, [int]$Limit = 500, [int]$Offset = 0, [bool]$EnablePaging = $true ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path = "/v4/nodes/rooms/$NodeId/users" EnablePaging = $EnablePaging UrlParameter = @{ filter = $Filter limit = $Limit offset = $offset } } Invoke-DracoonAPI @apiCallParameter } function Get-DracoonUser { <# .SYNOPSIS Query of all Users. API-GET /v4/users oder /v4/users/$Id .DESCRIPTION Function has two modes: Single or Multi-Users. If using in Multi-User Mode (without Id parameter) it returns an array of all users. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL. .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Except for login, firstName and lastName - these are connected via logical disjunction (OR) Filter string syntax: FIELD_NAME:OPERATOR:VALUE[:VALUE...] Example: login:cn:searchString_1|firstName:cn:searchString_2|lockStatus:eq:2 Filter users by login contains searchString_1 OR firstName contains searchString_2 AND those who are NOT locked. effectiveRoles Filter users with DIRECT or DIRECT AND EFFECTIVE roles false: DIRECT roles true: DIRECT AND EFFECTIVE roles DIRECT means: e.g. user gets role directly granted from someone with grant permission right. EFFECTIVE means: e.g. user gets role through group membership. .PARAMETER IncludeAttributes Parameter description .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are NOT supported. Nodes are sorted by type first, then by sent sort string. Example: name:desc .PARAMETER EnablePaging Wenn die API mit Paging arbeitet, kann über diesn Parameter ein automatisches Handling aktivieren. Dann werden alle Pages abgehandelt und nur die items zurückgeliefert. .PARAMETER Id Id of a specific user. .PARAMETER EffectiveRoles Filter users with DIRECT or DIRECT AND EFFECTIVE roles. false: DIRECT roles true: DIRECT AND EFFECTIVE roles DIRECT means: e.g. user gets role directly granted from someone with grant permission right. EFFECTIVE means: e.g. user gets role through group membership. .EXAMPLE To be added in the Future .NOTES General notes #> [CmdletBinding(DefaultParameterSetName = "SingleUser")] Param ( [parameter(Mandatory)] [Dracoon]$Connection, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [parameter(Mandatory = $false, ParameterSetName = "MultipleUsers")] [string]$Filter, [parameter(Mandatory = $false, ParameterSetName = "MultipleUsers")] [int]$Limit=500, [parameter(Mandatory = $false, ParameterSetName = "MultipleUsers")] [int]$Offset=0, [parameter(Mandatory = $false, ParameterSetName = "MultipleUsers")] [switch]$IncludeAttributes, [parameter(Mandatory = $false, ParameterSetName = "MultipleUsers")] [string]$Sort, [parameter(Mandatory = $false, ParameterSetName = "MultipleUsers")] [bool]$EnablePaging=$true, [parameter(Mandatory = $false, ParameterSetName = "SingleUser")] [int]$Id, [parameter(Mandatory = $false, ParameterSetName = "SingleUser")] [bool]$EffectiveRoles=$true ) if ($id -eq 0){ Write-PSFMessage "Ermittle mehrere User" $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/users" EnablePaging = $EnablePaging UrlParameter = @{ filter=$Filter include_attributes=$IncludeAttributes limit=$Limit sort=$Sort offset=$offset } } }else{ Write-PSFMessage "Requesting detailed user info for #$Id" $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/users/$Id" UrlParameter = @{ effective_roles = $EffectiveRoles } } } Invoke-DracoonAPI @apiCallParameter } function Get-DracoonUserAttribute { <# .SYNOPSIS Retrieve a list of user attributes. API-GET /v4/users/{user_id}/userAttributes .DESCRIPTION Retrieve a list of user attributes. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Id ID of the User. .PARAMETER ReturnHashTable If set to true (default), results are returned as a HashTable. Otherwise an array of PSCustomObjects is returned .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Filter string syntax: FIELD_NAME:OPERATOR:VALUE[:VALUE...] Example: key:cn:searchString_1|value:cn:searchString_2 Filter by attribute key contains searchString_1 AND attribute value contains searchString_2. .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are NOT supported. Nodes are sorted by type first, then by sent sort string. Example: name:desc .PARAMETER EnablePaging Wenn die API mit Paging arbeitet, kann über diesn Parameter ein automatisches Handling aktivieren. Dann werden alle Pages abgehandelt und nur die items zurückgeliefert. .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$connection, [parameter(Mandatory)] [int]$Id, [bool]$ReturnHashTable = $true, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [string]$Filter, [int]$Limit = 500, [int]$Offset = 0, [string]$Sort, [bool]$EnablePaging = $true ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path = "/v4/users/$Id/userAttributes" EnablePaging = $EnablePaging UrlParameter = @{ filter = $Filter limit = $Limit sort = $Sort offset = $offset } } Write-PSFMessage "Ermittele UserAttribute zu User $Id" $results = Invoke-DracoonAPI @apiCallParameter if ($EnablePaging) { $items = $results }else { $items = $results.items} if ($ReturnHashTable) { $attributes = @{} foreach ($item in $items ) { $attributes.add($item.key, $item.value) } $attributes } else { $items } } function Invoke-DracoonAPI { <# .SYNOPSIS Generic API Call to the Dracoon API. .DESCRIPTION Generic API Call to the Dracoon API. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Path API Path to the REST function .PARAMETER Body Parameter for the API call; Converted to the POST body .PARAMETER UrlParameter Parameter for the API call; Converted to the GET URL parameter set .PARAMETER Method HTTP Method .PARAMETER HideParameters If set to $true the password is hidden from logging .PARAMETER EnablePaging Wenn die API mit Paging arbeitet, kann über diesn Parameter ein automatisches Handling aktivieren. Dann werden alle Pages abgehandelt und nur die items zurückgeliefert. .EXAMPLE $result = Invoke-DracoonAPI -connection $this -path "/v4/auth/login" -method POST -body @{login = $credentials.UserName; password = $credentials.GetNetworkCredential().Password; language = "1"; authType = "sql" } -hideparameters $true Login to the service .NOTES General notes #> param ( [parameter(Mandatory)] $Connection, [parameter(Mandatory)] [string]$Path, [Hashtable] $Body, [Hashtable] $UrlParameter, [parameter(Mandatory)] [Microsoft.Powershell.Commands.WebRequestMethod]$Method, [bool] $HideParameters = $false, [switch]$EnablePaging ) $uri = $connection.webServiceRoot + $path if ($UrlParameter) { Write-PSFMessage "Wandle URL Parameter in String um und hänge diese an die URI" $parameterString = (Get-EncodedParameterString($UrlParameter)) $uri = $uri + '?' + $parameterString.trim("?") } $restAPIParameter = @{ Uri = $Uri method = $Method body = ($Body | Remove-NullFromHashtable -Json) Headers = $connection.headers ContentType = "application/json;charset=UTF-8" } Write-PSFMessage -Message "Rufe $uri auf" -Target $connection if ($method -ne [Microsoft.Powershell.Commands.WebRequestMethod]::Get) { $restAPIParameter.body = ($Body | Remove-NullFromHashtable -Json) } $tempBody = $body if ($hideParameters) { if ($tempBody.ContainsKey("password")) { $tempBody.set_Item("password", "*****") } } if ($tempBody) { Write-PSFMessage ("Rufe {0} mit {1} auf" -f $uri, ($tempBody | Remove-NullFromHashtable -Json)) } else { Write-PSFMessage ("Rufe {0} auf" -f $uri) } try { Write-PSFMessage -Level Debug "restAPIParameter= $($restAPIParameter|ConvertTo-Json -Depth 5)" $result = Invoke-RestMethod @restAPIParameter Write-PSFMessage -Level Debug "result= $($result|ConvertTo-Json -Depth 5)" if ($EnablePaging -and ($result -is [array])) { Write-PSFMessage "Paging enabled, aber keine Range zurückgeliefert" -Level Warning }elseif ($EnablePaging) { Write-PSFMessage "Paging enabled, starte Schleife, result.range=$($result.range)" $allItems = ($result.items) write-psfmessage "Anzahl ermittelter Items: $($allItems.count)" $UrlParameter.limit = $result.range.limit $UrlParameter.offset = $result.range.offset while ($result.range.total -gt $allItems.count) { Write-PSFMessage "result.range.total=$($result.range.total) -gt allItems.count=$($allItems.count)" $UrlParameter.offset = $allItems.count $nextParameter = @{ Connection = $Connection Path = $Path Body = $Body UrlParameter = $UrlParameter Method = $Method HideParameters = $HideParameters } write-psfmessage "Rufe API auf mit $($nextParameter|convertto-json -depth 10)" -Level Debug write-psfmessage "Rufe API auf mit URL Params auf $($UrlParameter|convertto-json -depth 10)" $result = Invoke-DracoonAPI @nextParameter $allItems += ($result.items) } return $allItems } } catch { $result = $_.errordetails Write-PSFMessage "$result" -Level Critical throw $_#$result.Message } #--------------------------------------------------------------------------------- # Ist das Objekt zu groß wird es als String und nicht als PSCustomObject # ausgegeben. Dieses wird dann mit dieser Methode in ein .DictionaryEntry-Object # umgewandelt, um damit arbeiten zu können. #--------------------------------------------------------------------------------- # if ($result.gettype().name -eq "String") { # $jsonresult = $connection.jsonserial.DeserializeObject($result) # return $jsonresult # } # else { return $result # } } function New-DracoonDataroom { <# .SYNOPSIS Creates a new room at the provided parent node. Creation of top level rooms provided. .DESCRIPTION API-POST /v4/nodes/rooms .PARAMETER connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER RoomName Name of the new room .PARAMETER ParentNodeId Node-ID of the parent-node, 0 for Creation of top level rooms .PARAMETER AdminUserId Array of user-ids of room admins .PARAMETER AdminGroupId Array of user-ids of room admin groups .PARAMETER RecycleBinRetentionPeriod How many days should files be kept in the recycle bin. .PARAMETER InheritPermissions Room inherits the permissions of the parent room .PARAMETER Notes Description notes for the room .PARAMETER NewGroupMemberAcceptance Do new admin group members have to be released? Default is "autoallow" .PARAMETER Quota Quota for the new room in bytes. 0 for no quota. .PARAMETER HasActivitiesLog Is the activity log enabled for the room? .PARAMETER Classification Nummerical classification. .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE To be added in the Future .NOTES Precondition: User has “manage” permissions in the parent room. #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [parameter(Mandatory)] [Dracoon]$Connection, [parameter(Mandatory)] [string]$RoomName, [int]$ParentNodeId, [parameter(Mandatory)] [array]$AdminUserId, [array]$AdminGroupId, [int]$RecycleBinRetentionPeriod = 14, [bool]$InheritPermissions = $false, [string]$Notes = "", [ValidateSet("autoallow", "pending")] [String]$NewGroupMemberAcceptance = "autoallow", [int]$Quota = 0, [bool]$HasActivitiesLog = $true, $Classification=2 ) Write-PSFMessage "Erzeuge Datenraum $RoomName" $apiCallParameter = @{ Connection = $Connection method = "Post" Path = "/v4/nodes/rooms" Body = @{ name = "$RoomName" recycleBinRetentionPeriod = $RecycleBinRetentionPeriod quota = $Quota inheritPermissions = $InheritPermissions adminIds = $AdminUserId adminGroupIds = $adminGroupId newGroupMemberAcceptance = $NewGroupMemberAcceptance notes = $Notes hasActivitiesLog = $HasActivitiesLog classification = $Classification hasRecycleBin = $true } # EnablePaging=$true } if ($parentNodeId -gt 0) { $apiCallParameter.body.parentId = $parentNodeId } Invoke-PSFProtectedCommand -Action "Creating new dataroom" -Target "$RoomName" -ScriptBlock { $result = Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "User erfolgreich angelegt" $result } -PSCmdlet $PSCmdlet } # [PSCustomObject]CreateADUser([string]$userPrincipalName, [string]$firstName, [string]$lastName, [string]$title, [string]$gender, [string]$domain, [string]$samAccountName) { # $randomPassword = [Dracoon]::GenerateRandomPassword() # $adConfigs = $this.getAuthConfigAD() # $adId = $adConfigs | Where-Object { $_.alias -ieq $domain } | Select-Object -ExpandProperty id # if (-not ($adId)) { # throw "Unbekannter AD-Alias $domain" # } # $parameter = @{firstName = $firstName; lastName = $lastName; authMethods = @(@{authId = "active_directory"; isEnabled = "true"; options = @(@{key = "ad_config_id"; value = $adId }; @{key = "username"; value = $samAccountName }) }); login = $userPrincipalName; title = $title; gender = $gender; expiration = @{enableExpiration = "false"; expireAt = "2018-01-01T00:00:00" }; receiverLanguage = "de-DE"; email = $userPrincipalName; notifyUser = "false"; needsToChangePassword = "false"; password = $randomPassword } # $result = $this.InvokePost("/v4/users", $parameter) # return $result # } # [PSCustomObject]CreateMailUser([string]$login, [string]$firstName, [string]$lastName, [string]$title, [string]$gender, [string]$eMail, [bool]$enableOpenID) { # $parameter = @{firstName = $firstName; lastName = $lastName; authMethods = @(@{authId = "sql"; isEnabled = "true" }); login = $login; title = $title; gender = $gender; expiration = @{enableExpiration = "false"; expireAt = "2018-01-01T00:00:00" }; receiverLanguage = "de-DE"; email = $eMail; notifyUser = "true"; needsToChangePassword = "true" } # if ($enableOpenID) { # $parameter["authMethods"] += (@{authId = "openid"; isEnabled = $true; options = @(@{key = "openid_config_id"; value = $this.openIDConfigId }; @{key = "username"; value = $eMail }) }) # } # $result = $this.InvokePost("/v4/users", $parameter) # return $result # } function New-DracoonUser { <# .SYNOPSIS Create a new user. .DESCRIPTION Create a new user. Two option sets are possible: Mail-User (internal authentication) or Active Directory based authentification. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Login Unique login for the user, UPN/MAIL format expected .PARAMETER FirstName First name of the user. .PARAMETER LastName Last name of the user. .PARAMETER Title Title of the user. .PARAMETER Gender Gender of the user. .PARAMETER Mail Mail address of the user. .PARAMETER Domain Only needed for Domain based Authentication. .PARAMETER SamAccountName Login Name Only needed for Domain based Authentication. .PARAMETER ExpirationDate Sets a date when the user will expire .PARAMETER NotifyUser If set to true the user is notified by mail. .PARAMETER NeedsToChangePassword If set to true the user has to change the password on first login. .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE To be added in the Future .NOTES General notes #> [CmdletBinding(DefaultParameterSetName = "Mailuser", SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [parameter(mandatory = $true, ParameterSetName = "Mailuser")] [parameter(mandatory = $true, ParameterSetName = "ADuser")] [Dracoon]$Connection, [parameter(mandatory = $true, ParameterSetName = "Mailuser")] [parameter(mandatory = $true, ParameterSetName = "ADuser")] [PSFValidateScript( { $_ -as [mailaddress] }, ErrorMessage = "{0} - is not a valid mail address")] [string]$Login, [parameter(mandatory = $true, ParameterSetName = "Mailuser")] [parameter(mandatory = $true, ParameterSetName = "ADuser")] [string]$FirstName, [parameter(mandatory = $true, ParameterSetName = "Mailuser")] [parameter(mandatory = $true, ParameterSetName = "ADuser")] [string]$LastName, [string]$Title = "", [ValidateSet('m', 'f', 'n')] [string]$Gender = 'n', [string]$Mail, [parameter(mandatory = $true, ParameterSetName = "ADuser")] [string]$Domain, [parameter(mandatory = $true, ParameterSetName = "ADuser")] [string]$SamAccountName, [parameter(mandatory = $false, ParameterSetName = "Mailuser")] [parameter(mandatory = $false, ParameterSetName = "ADuser")] [datetime]$ExpirationDate, [parameter(mandatory = $false, ParameterSetName = "Mailuser")] [bool]$NotifyUser = $false, [parameter(mandatory = $false, ParameterSetName = "Mailuser")] [bool]$NeedsToChangePassword = $false ) $apiCallParameter = @{ Connection = $Connection method = "Post" Path = "/v4/users" Body = @{ firstName = $FirstName lastName = $LastName authMethods = @() login = $Login title = $Title gender = $Gender expiration = @{ enableExpiration = "false" expireAt = "2018-01-01T00:00:00" } receiverLanguage = "de-DE" email = $Mail notifyUser = ("$NotifyUser").ToLower() needsToChangePassword = ("$NeedsToChangePassword").ToLower() password = New-DracoonRandomPassword } } if ($ExpirationDate) { $apiCallParameter.Body.expiration.enableExpiration = 'true' $apiCallParameter.Body.expiration.expireAt = $ExpirationDate.ToString('yyyy-MM-ddT00:00:00') } if ($Domain) { $adId = (Get-DracoonAuthConfigAD -Connection $Connection -Alias $Domain).id if (-not ($adId)) { throw "Unbekannter AD-Alias $domain" } Write-PSFMessage "Lege einen AD-User an ($Domain/$adId)" $apicallparameter.Body.authMethods += @{ authId = "active_directory" isEnabled = "true" options = @( @{ key = "ad_config_id" value = $adId } @{ key = "username" value = $samAccountName }) } } else { Write-PSFMessage "Lege einen SQL-User an ($Domain/$adId)" $apicallparameter.Body.authMethods += @{ authId = "sql" isEnabled = "true" } } write-psfmessage "($apiCallParameter|convertfrom-json -depth 10)" Invoke-PSFProtectedCommand -Action "Lege User an" -Target $Login -ScriptBlock { $result = Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "User erfolgreich angelegt" $result } -PSCmdlet $PSCmdlet -Confirm:$false -Verbose if (Test-PSFFunctionInterrupt) { return } } function Remove-DracoonNode { <# .SYNOPSIS Delete node (room, folder or file). API-DELETE /v4/nodes/{node_id} .DESCRIPTION Delete node (room, folder or file). Precondition: Authenticated user with “delete” permissions on: supplied nodes (for folders or files) superordinated node (for rooms) Effects: Node gets deleted. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER NodeId ID of the node which should be deleted. .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE $rooms = Get-DracoonAuditDataroom -connection $connection -filter "nodeName:cn:DEMO" $hubbaRooms| Remove-DracoonNode -connection $connection Queries all rooms with "DEMO" within the nodeName and deletes them. Remove-DracoonNode -connection $connection -NodeId 15 Deletes the node with ID 15. .NOTES General notes #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [parameter(Mandatory)] [Dracoon]$connection, [parameter(Mandatory, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias("ID")] [int]$NodeId ) process { $apiCallParameter = @{ Connection = $Connection method = "Delete" Path = "/v4/nodes/$NodeId" } Invoke-PSFProtectedCommand -Action "Removing Node" -Target "$Id" -ScriptBlock { $result = Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "Node removed" $result } -PSCmdlet $PSCmdlet } } # [PSCustomObject]DeleteUser([int]$id, [bool]$deleteLastAdminRooms) { # if ($deleteLastAdminRooms) { # $LastAdminRooms = $this.getLastAdminRooms($id) # if ($LastAdminRooms) { # Write-PSFMessage ("Lösche {0} LastAdminRooms" -f $LastAdminRooms.count) # $LastAdminRooms | Format-Table | Out-String | Write-PSFMessage # foreach ($room in $LastAdminRooms) { # $this.DeleteRoom($room.id) # } # } # } # $result = $this.InvokeDelete("/v4/users/$id") # return $result # } function Remove-DracoonUser { <# .SYNOPSIS Delete a user. API-DELETE /v4/users/{user_id} .DESCRIPTION Delete a user. API-DELETE /v4/users/{user_id} .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Id ID of the User which should be deleted. .PARAMETER DeleteLastAdminRooms If true, the function will check if the user is the last admin of any data room. If yes, the rooms will be removed first. .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE To be added in the Future .NOTES General notes #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [parameter(Mandatory)] [Dracoon]$connection, [parameter(Mandatory, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [int]$Id, [bool]$DeleteLastAdminRooms = $false ) process { $apiCallParameter = @{ Connection = $Connection method = "Delete" Path = "/v4/users/$Id" } Write-PSFMessage "Lösche User $Id" if ($DeleteLastAdminRooms) { Write-PSFMessage "Check if the user is last admin of some rooms" $lastAdminRooms = Get-DracoonLastAdminRoom -Connection $connection -id $id if ($lastAdminRooms) { Write-PSFMessage "Removing $($lastAdminRooms.count) rooms" $lastAdminRooms | Remove-DracoonNode -Connection $connection } } Invoke-PSFProtectedCommand -Action "Removing User" -Target "$Id" -ScriptBlock { $result = Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "User removed" $result } -PSCmdlet $PSCmdlet } } function Request-DracoonOAuthToken { <# .SYNOPSIS Helper-Function for creation of an OAuth Token. .DESCRIPTION The function uses OAuth for creating an refresh token which can be used for login to a dracoon instance. .PARAMETER Url Base-URL of the Dracoon Server .PARAMETER Credential Credential object used for login. .PARAMETER RefreshToken As an alternative a refresh token can be used instead of a credential Object .PARAMETER ClientID OAuth client ID .PARAMETER ClientSecret OAuth client secret .PARAMETER TokenType Defines the type of token to be returned. .EXAMPLE $authToken=Request-OAuthRefreshToken -Url $serverURL -Credential $credential -ClientID "0O6WWKpp0n***********xk8" -clientSecret "aySR8XB*********99Jj7DFgei" $connection = Connect-Dracoon -Url $serverURL -RefreshToken $authToken -ClientID "0O6WWKpp0n***********xk8" -clientSecret "aySR8XB*********99Jj7DFgei" .NOTES General notes #> param ( [parameter(mandatory = $true, ParameterSetName = "Refresh")] [parameter(mandatory = $true, ParameterSetName = "Access")] [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.url")] [string]$Url, [parameter(mandatory = $true, ParameterSetName = "Refresh")] [pscredential]$Credential, [parameter(mandatory = $true, ParameterSetName = "Access")] [string]$RefreshToken, [parameter(mandatory = $true, ParameterSetName = "Refresh")] [parameter(mandatory = $true, ParameterSetName = "Access")] [string]$ClientID, [parameter(mandatory = $true, ParameterSetName = "Refresh")] [parameter(mandatory = $true, ParameterSetName = "Access")] [string]$ClientSecret, [ValidateSet('refresh', 'access')] [System.String]$TokenType = 'access' ) $serverRoot = Get-DracoonServerRoot $Url $Base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $ClientID, $ClientSecret))) if ($Credential) { # Set Username and Password for first login, escape special characters since we use them in URI parameters Write-PSFMessage "OAuth-Anmeldung für User $($Credential.UserName) beim Server $serverRoot" $parameter = @{ "grant_type" = "password"; "username" = $Credential.UserName; "password" = $Credential.GetNetworkCredential().password } } elseif ($RefreshToken) { Write-PSFMessage "Create AccessToken from RefreshToken" write-psfmessage -Level Debug -Message "Login per refreshToken $RefreshToken, Client-ID/Secret: $($ClientId), $($ClientSecret)" $parameter = @{ "grant_type" = "refresh_token"; "refresh_token" = "$RefreshToken" } } $tokenResponse = Invoke-WebRequest -URI "$serverRoot/oauth/token" -Method Post -ContentType "application/x-www-form-urlencoded" -Body $parameter -Headers @{Authorization = ("Basic {0}" -f $Base64AuthInfo) } Write-PSFMessage $tokenResponse if (($TokenType -eq 'access') -or $RefreshToken) { $token = (ConvertFrom-Json $tokenResponse.Content).access_token } else { $token = (ConvertFrom-Json $tokenResponse.Content).refresh_token } return $token } function Search-DracoonNode { <# .SYNOPSIS Provides a flat list of file system nodes (rooms, folders or files) of a given parent that are accessible by the current user. API-GET /v4/nodes/search .DESCRIPTION Provides a flat list of file system nodes (rooms, folders or files) of a given parent that are accessible by the current user. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER Filter All filter fields are connected via logical conjunction (AND) Filter string syntax: FIELD_NAME:OPERATOR:VALUE[:VALUE...] Example: type:eq:file|createdAt:ge:2015-01-01 Get nodes where type equals file AND file creation date is >= 2015-01-01. .PARAMETER Limit Range limit. Maximum 500. For more results please use paging (offset + limit). .PARAMETER Offset Range offset .PARAMETER Sort Sort string syntax: FIELD_NAME:ORDER ORDER can be asc or desc. Multiple sort fields are NOT supported. Nodes are sorted by type first, then by sent sort string. Example: name:desc .PARAMETER ParentID Parent node ID. Only rooms and folders can be parents. Parent ID 0 or empty is the root node. .PARAMETER DepthLevel 0 - top level nodes only (default) -1 - full tree n (any positive number) - include n levels starting from the current node .PARAMETER SearchString String to be searched in the NodeName .EXAMPLE To be added in the Future .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$Connection, [PSFramework.TabExpansion.PsfArgumentCompleterAttribute("Dracoon.filter")] [string]$Filter, [int]$Limit=500, [int]$Offset=0, [string]$Sort, [int]$ParentID = 0, [int]$DepthLevel = 0, [parameter(Mandatory)] [string]$SearchString ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/nodes/search" EnablePaging = $true UrlParameter = @{ filter=$Filter limit=$Limit sort=$Sort offset=$offset depth_level=$DepthLevel parent_id=$ParentID room_manager=$RoomManager search_string = $SearchString } # EnablePaging=$true } $result = Invoke-DracoonAPI @apiCallParameter $result } function Set-DracoonRoomAcl { <# .SYNOPSIS Add or change room granted user(s). API-PUT /v4/nodes/rooms/$NodeId/users .DESCRIPTION Batch function. All existing user permissions will be overwritten. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER NodeId ID of the room .PARAMETER NewPermission Array of the new Permission Items. [ { "id": 0, "permissions": { "manage": true, "read": true, "create": true, "change": true, "delete": true, "manageDownloadShare": true, "manageUploadShare": true, "readRecycleBin": true, "restoreRecycleBin": true, "deleteRecycleBin": true } } ] .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE To be added in the Future .NOTES General notes #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [parameter(Mandatory)] [Dracoon]$Connection, [parameter(Mandatory)] [int]$NodeId, [array]$NewPermission ) $apiCallParameter = @{ Connection = $Connection method = "Put" Path = "/v4/nodes/rooms/$NodeId/users" Body=@{ items=@() } } $apiCallParameter.Body.items += $NewPermission Invoke-PSFProtectedCommand -Action "Setting permissions on node" -Target "$NodeId" -ScriptBlock { $result = Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "Permissions set" $result } -PSCmdlet $PSCmdlet } function Set-DracoonUrl { <# .SYNOPSIS This function allows to set new Server-URLs for TAB Completion. Each function which requires a -Url parameter will provide a TAB completer with suggested URLs. .DESCRIPTION This function allows to set new Server-URLs for TAB Completion. Each function which requires a -Url parameter will provide a TAB completer with suggested URLs, e.g. Connect-Dracoon Different from Add-DracoonUrl this command overwrites existing settings. .PARAMETER NewUrl The new URLs to be added .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE Add-DracoonUrl 'https://dxi.mydomain' Add a single Server to the list of suggested URLs (get-adforest -ErrorAction Stop).domains | ForEach-Object { Add-DracoonUrl "https://dataexchange.$($_)" } If you have an on prem Dracoon server in each of your Windows Domains with the address "https://dracoon.<yourdomain>" it will get added to the list of suggested URLs. .NOTES The URLs get saved at the PSF-Config "Dracoon.tepp.urls" #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'medium')] param ( [parameter(mandatory = $true, Position = 0)] [string[]]$NewUrl ) Write-PSFMessage "Saving new Urls for the URL TEPP: $NewUrl" # Adjusting format of URLs $NewUrl = $NewUrl | ForEach-Object { Get-DracoonServerRoot $_} Invoke-PSFProtectedCommand -Action "Saving new Urls for the URL TEPP" -Target "$NewUrl" -ScriptBlock { Set-PSFConfig -Module 'Dracoon' -Name 'tepp.urls' -Value $NewUrl -AllowDelete -PassThru | Register-PSFConfig } -PSCmdlet $PSCmdlet } # [PSCustomObject]SetUserAttributes([int]$userId, [Hashtable]$userAttributes, [bool]$keepExisting) { # $items = @() # foreach ($key in $userAttributes.Keys) { # $items += @{ key = $key ; value = $userAttributes[$key] } # } # $parameter = @{items = $items } # if ($keepExisting) { # $result = $this.InvokePut("/v4/users/$userId/userAttributes", $parameter) # } # else { # $result = $this.InvokePost("/v4/users/$userId/userAttributes", $parameter) # } # return $result # } function Set-DracoonUserAttribute { <# .SYNOPSIS Set custom user attributes. API-(POST/PUT) /v4/users/{user_id}/userAttributes .DESCRIPTION Set custom user attributes. Uses POST for overwriting the userAttributes or PUT for updating the userAttributes. .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .PARAMETER id ID of the user to be changed. .PARAMETER UserAttributes HashTable wit the UserAttributes. .PARAMETER Overwrite Shall all exisiting attributes be overwritten? Default False. .PARAMETER whatIf If enabled it does not execute the backend API call. .PARAMETER confirm If enabled the backend API Call has to be confirmed .EXAMPLE To be added in the Future .NOTES If the operation fails the function throws the exception #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [parameter(mandatory = $true)] [Dracoon]$Connection, [parameter(Mandatory)] [int]$Id, [Hashtable]$UserAttributes, [bool]$Overwrite = $false ) $itemArray = @() Write-PSFMessage "Setze User-Attribute für User $id auf $UserAttributes" foreach ($key in $UserAttributes.Keys) { $itemArray += @{ key = $key ; value = $userAttributes[$key] } } if ($Overwrite) { $method = "Post" }else { $method = "Put" } $apiCallParameter = @{ Connection = $Connection method = $method Path = "/v4/users/$Id/userAttributes" Body = @{items = $itemArray } } Invoke-PSFProtectedCommand -Action "Setting attributes on user" -Target "$Id" -ScriptBlock { $result = Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "Attribute set" $result } -PSCmdlet $PSCmdlet -EnableException $true } function Test-DracoonConnection { <# .SYNOPSIS Test connection to DRACOON Server. API-GET /v4/auth/ping .DESCRIPTION Test connection to DRACOON Server. API-GET /v4/auth/ping .PARAMETER Connection Object of Class [Dracoon], stores the authentication Token and the API Base-URL .EXAMPLE Test-DracoonConnection $connection Throws a [System.Net.NetworkInformation.PingException] if connection does not succeed, otherwise it returns $true .NOTES General notes #> param ( [parameter(Mandatory)] [Dracoon]$Connection ) $apiCallParameter = @{ Connection = $Connection method = "Get" Path ="/v4/auth/ping" } try { $result=Invoke-DracoonAPI @apiCallParameter Write-PSFMessage "Ping result: $result" if ($result -notmatch '^OK'){ throw [System.Net.NetworkInformation.PingException]::new("API not pingable, $($connection.serverRoot)/v4/auth/ping") } } catch { throw [System.Net.NetworkInformation.PingException]::new("API not pingable, $($connection.serverRoot)/v4/auth/ping") } $true } <# This is an example configuration file By default, it is enough to have a single one of them, however if you have enough configuration settings to justify having multiple copies of it, feel totally free to split them into multiple files. #> <# # Example Configuration Set-PSFConfig -Module 'Dracoon' -Name 'Example.Setting' -Value 10 -Initialize -Validation 'integer' -Handler { } -Description "Example configuration setting. Your module can then use the setting using 'Get-PSFConfigValue'" #> Set-PSFConfig -Module 'Dracoon' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging." Set-PSFConfig -Module 'Dracoon' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments." Set-PSFConfig -Module 'Dracoon' -Name 'tepp.urls' -Value "https://dracoon.team" -Initialize -Description "List of URLs for TabCompletion." <# Stored scriptblocks are available in [PsfValidateScript()] attributes. This makes it easier to centrally provide the same scriptblock multiple times, without having to maintain it in separate locations. It also prevents lengthy validation scriptblocks from making your parameter block hard to read. Set-PSFScriptblock -Name 'Dracoon.ScriptBlockName' -Scriptblock { } #> Register-PSFTeppScriptblock -Name "Dracoon.filter" -ScriptBlock { switch ($commandName) { 'Get-DracoonAuditDataroom' { 'nodeId:eq:[positive Integer]', 'nodeName:[cn, eq]:[search String]', 'nodeParentId:eq:[positive Integer]', 'Parent ID 0 is the root node.:[]:[]', 'userId:eq:[positive Integer]', 'userName:[cn, eq]:[search String]', 'userFirstName:[cn, eq]:[search String]', 'userLastName:[cn, eq]:[search String]', 'permissionsManage:eq:[true or false]', 'nodeIsEncrypted:eq:[true or false]', 'nodeHasActivitiesLog:eq:[true or false]' } 'Get-DracoonNode' { 'type:eq:[room[:folder:file]]', 'perm:eq:[manage[:read:change:create:delete:manageDownloadShare:manageUploadShare:canReadRecycleBin:canRestoreRecycleBin:canDeleteRecycleBin]]', 'childPerm:eq:[cf. perm]', 'name:[cn, eq]:[Node name contains / equals value.]', 'encrypted:eq:[true or false]', 'branchVersion:[ge, le]:[Branch version is greater / less equals than value.]' } 'Get-DracoonUser'{ 'login:cn:[search String]', 'firstName:cn:[search String]', 'lastName:cn:[search String]', 'isLocked:eq:[true or false]', 'effectiveRoles:eq:[true or false]' } 'Get-DracoonGroup' { 'name:cn:[search String]' } 'Get-DracoonUserAttribute' { 'key:[cn, eq, sw]:[Attribute key contains / equals / starts with value. ]', 'value:[cn, eq, sw]:[Attribute value contains / equals / starts with value. ]' } 'Get-DracoonRoomAcl' { 'user:cn:[search String]', 'userId:eq:[positive Integer]', 'isGranted:eq:[true/false/any]', 'permissionsManage:eq:[true or false]', 'effectivePerm:eq:[true or false]' } 'Search-DracoonNode' { 'type:[eq]:[room/folder/file]', 'fileType:[cn, eq]:[search String]', 'classification:[eq]:[1 - public, 2 - internal, 3 - confidential, 4 - strictly confidential]', 'createdBy:[cn, eq]:[search String]', 'createdAt:[ge, le]:[Date (yyyy-MM-dd)]', 'updatedBy:[cn, eq]:[search String]', 'updatedAt:[ge, le]:[Date (yyyy-MM-dd)]', 'expireAt:[ge, le]:[Date (yyyy-MM-dd)]', 'size:[ge, le]:[size in bytes]', 'isFavorite:[eq]:[true or false]', 'branchVersion:[ge, le]:[version number]', 'parentPath:[cn, eq]:[search String]' } Default {} } # $staticList=@( # 'https://murks.mydomain.com', # 'https://dataexchange.tkds.mydomain.com', # 'https://dataexchange.tkdo.mydomain.com', # 'https://dataexchange.tkbe.mydomain.com', # 'https://dataexchange.tkbr.mydomain.com', # 'https://dataexchange.tkme.mydomain.com', # 'https://dxi.mydomain.com' # ) # if (-not $env:USERDNSDOMAIN) { # return $staticList # } # try { # (get-adforest -ErrorAction Stop).domains | ForEach-Object { "https://dataexchange.$($_)" } # 'https://dxi.mydomain.com' # } # catch { # return $staticList # } } Register-PSFTeppScriptblock -Name "Dracoon.url" -ScriptBlock { $staticList=@('https://dracoon.team') try { $urlList=Get-PSFConfigValue "Dracoon.tepp.urls" -Fallback $staticList return $urlList } catch { return $staticList } } <# # Example: Register-PSFTeppScriptblock -Name "Dracoon.alcohol" -ScriptBlock { 'Beer','Mead','Whiskey','Wine','Vodka','Rum (3y)', 'Rum (5y)', 'Rum (7y)' } #> <# # Example: Register-PSFTeppArgumentCompleter -Command Get-Alcohol -Parameter Type -Name Dracoon.alcohol #> New-PSFLicense -Product 'Dracoon' -Manufacturer 'Sascha Spiekermann' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2020-09-21") -Text @" Copyright (c) 2020 Sascha Spiekermann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ Export-PSFModuleClass -ClassType ([Dracoon]) [System.Net.ServicePointManager]::SecurityProtocol = "Tls12" #endregion Load compiled code |