diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 04508b6..d987d38 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -12,11 +12,6 @@ name: "Code Analysis" on: - push: - branches: [ "master" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "master" ] schedule: - cron: '17 23 * * 3' diff --git a/.github/workflows/power-commander.yml b/.github/workflows/power-commander.yml new file mode 100644 index 0000000..f6e4aee --- /dev/null +++ b/.github/workflows/power-commander.yml @@ -0,0 +1,37 @@ +name: Publish PowerCommander + +on: [workflow_dispatch] + +jobs: + build: + runs-on: windows-latest + environment: prod + + steps: + - uses: actions/checkout@v2 + + - name: Load signing certificate + run: | + if (Test-Path -Path certificate.txt) { Remove-Item certificate.txt } + if (Test-Path -Path certificate.pfx) { Remove-Item certificate.pfx } + Set-Content -Path certificate.txt -Value '${{ secrets.PFX_CERT }}' + certutil -decode certificate.txt certificate.pfx + Remove-Item certificate.txt + shell: powershell + + - name: Sign PowerShell scripts + working-directory: ./PowerCommander + run: | + $certPassword = ConvertTo-SecureString -String "${{ secrets.PFX_PASS }}" -AsPlainText -Force + $certData = Get-PfxData -FilePath "..\certificate.pfx" -Password $certPassword + $cert = $certData.EndEntityCertificates[0] + Set-AuthenticodeSignature -FilePath *.ps1 -Certificate $cert + Set-AuthenticodeSignature -FilePath *.ps1xml -Certificate $cert + Set-AuthenticodeSignature -FilePath PowerCommander.psd1 -Certificate $cert + Set-AuthenticodeSignature -FilePath PowerCommander.psm1 -Certificate $cert + shell: powershell + + - name: Publish to PowerShell Gallery + run: | + Publish-Module -Path .\PowerCommander\ -NuGetApiKey "${{ secrets.POWERSHELL_PUBLISH_KEY }}" + shell: powershell diff --git a/PowerCommander/AuthCommands.ps1 b/PowerCommander/AuthCommands.ps1 index aea7b84..1944242 100644 --- a/PowerCommander/AuthCommands.ps1 +++ b/PowerCommander/AuthCommands.ps1 @@ -1,8 +1,8 @@ -#requires -Version 5.0 +#requires -Version 5.1 $expires = @( - [KeeperSecurity.Authentication.TwoFactorDuration]::EveryLogin, - [KeeperSecurity.Authentication.TwoFactorDuration]::Every30Days, + [KeeperSecurity.Authentication.TwoFactorDuration]::EveryLogin, + [KeeperSecurity.Authentication.TwoFactorDuration]::Every30Days, [KeeperSecurity.Authentication.TwoFactorDuration]::Forever) function twoFactorChannelToText ([KeeperSecurity.Authentication.TwoFactorChannel] $channel) { @@ -70,9 +70,6 @@ function getStepPrompt ([KeeperSecurity.Authentication.IAuthentication] $auth) { elseif ($auth.step -is [KeeperSecurity.Authentication.Sync.ReadyToLoginStep]) { $prompt = "`nLogin" } - elseif ($auth.step -is [KeeperSecurity.Authentication.Sync.HttpProxyStep]) { - $prompt = "`nHTTP Proxy Login" - } return $prompt } @@ -81,7 +78,7 @@ function printStepHelp ([KeeperSecurity.Authentication.IAuthentication] $auth) { $commands = @() if ($auth.step -is [KeeperSecurity.Authentication.Sync.DeviceApprovalStep]) { $channels = @() - foreach($ch in $auth.step.Channels) { + foreach ($ch in $auth.step.Channels) { $channels += deviceApprovalChannelToText $ch } if ($channels) { @@ -92,7 +89,7 @@ function printStepHelp ([KeeperSecurity.Authentication.IAuthentication] $auth) { } elseif ($auth.step -is [KeeperSecurity.Authentication.Sync.TwoFactorStep]) { $channels = @() - foreach($ch in $auth.step.Channels) { + foreach ($ch in $auth.step.Channels) { $channelText = twoFactorChannelToText $ch if ($channelText) { $channels += $channelText @@ -103,10 +100,10 @@ function printStepHelp ([KeeperSecurity.Authentication.IAuthentication] $auth) { } $channels = @() - foreach($ch in $auth.step.Channels) { + foreach ($ch in $auth.step.Channels) { $pushes = $auth.step.GetChannelPushActions($ch) if ($null -ne $pushes) { - foreach($push in $pushes) { + foreach ($push in $pushes) { $channels += [KeeperSecurity.Authentication.AuthUIExtensions]::GetPushActionText($push) } } @@ -116,7 +113,7 @@ function printStepHelp ([KeeperSecurity.Authentication.IAuthentication] $auth) { } $channels = @() - foreach($exp in $expires) { + foreach ($exp in $expires) { $channels += twoFactorDurationToExpire $exp } $commands += "expire=<$($channels -join ' | ')> to set 2fa expiration." @@ -136,7 +133,7 @@ function printStepHelp ([KeeperSecurity.Authentication.IAuthentication] $auth) { } elseif ($auth.step -is [KeeperSecurity.Authentication.Sync.SsoDataKeyStep]) { $channels = @() - foreach($ch in $auth.step.Channels) { + foreach ($ch in $auth.step.Channels) { $channels += [KeeperSecurity.Authentication.AuthUIExtensions]::SsoDataKeyShareChannelText($ch) } if ($channels) { @@ -149,11 +146,11 @@ function printStepHelp ([KeeperSecurity.Authentication.IAuthentication] $auth) { } if ($commands) { - Write-Host "`nAvailable Commands`n" + Write-Output "`nAvailable Commands`n" foreach ($command in $commands) { - Write-Host $command + Write-Output $command } - Write-Host ' to resume' + Write-Output ' to resume' } } @@ -169,13 +166,14 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut } elseif ($expire -eq '30_days') { $duration.Value = [KeeperSecurity.Authentication.TwoFactorDuration]::Every30Days - } else { + } + else { $duration.Value = [KeeperSecurity.Authentication.TwoFactorDuration]::EveryLogin } - + return $result } - + function tryTextToDeviceApprovalChannel ([string] $text, [ref] [KeeperSecurity.Authentication.DeviceApprovalChannel] $channel) { $result = $true if ($text -eq 'email') { @@ -186,14 +184,15 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut } elseif ($text -eq '2fa') { $channel.Value = [KeeperSecurity.Authentication.DeviceApprovalChannel]::TwoFactorAuth - } else { - Write-Host 'Unsupported device approval channel:', $text + } + else { + Write-Output 'Unsupported device approval channel:', $text $result = $false } - + return $result } - + function tryTextToTwoFactorChannel ([string] $text, [ref] [KeeperSecurity.Authentication.TwoFactorChannel] $channel) { $result = $true if ($text -eq 'authenticator') { @@ -210,17 +209,18 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut } elseif ($text -eq 'dna') { $channel.Value = [KeeperSecurity.Authentication.TwoFactorChannel]::KeeperDNA - } else { - Write-Host 'Unsupported 2FA channel:', $text + } + else { + Write-Output 'Unsupported 2FA channel:', $text $result = $false } return $result } - + if ($auth.step -is [KeeperSecurity.Authentication.Sync.DeviceApprovalStep]) { if ($action -eq 'push') { - $auth.step.SendPush($auth.step.DefaultChannel).GetAwaiter().GetResult() | Out-Null + $auth.step.SendPush($auth.step.DefaultChannel).GetAwaiter().GetResult() | Out-Null } elseif ($action -match 'channel\s*=\s*(.*)') { $ch = $Matches.1 @@ -228,15 +228,16 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut if (tryTextToDeviceApprovalChannel ($ch) ([ref]$cha)) { $auth.step.DefaultChannel = $cha } - } else { + } + else { Try { $auth.step.SendCode($auth.step.DefaultChannel, $action).GetAwaiter().GetResult() | Out-Null } - Catch [KeeperSecurity.Authentication.KeeperApiException]{ - Write-Host $_ -ForegroundColor Red + Catch [KeeperSecurity.Authentication.KeeperApiException] { + Write-Output $_ -ForegroundColor Red } Catch { - Write-Host $_ -ForegroundColor Red + Write-Output $_ -ForegroundColor Red } } } @@ -254,11 +255,12 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut if (tryExpireToTwoFactorDuration($exp) ([ref]$dur)) { $auth.step.Duration = $dur } - } else { - foreach($cha in $auth.step.Channels) { + } + else { + foreach ($cha in $auth.step.Channels) { $pushes = $auth.step.GetChannelPushActions($cha) if ($null -ne $pushes) { - foreach($push in $pushes) { + foreach ($push in $pushes) { if ($action -eq [KeeperSecurity.Authentication.AuthUIExtensions]::GetPushActionText($push)) { $auth.step.SendPush($push).GetAwaiter().GetResult() | Out-Null return @@ -269,7 +271,7 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut $auth.step.SendCode($auth.step.DefaultChannel, $action).GetAwaiter().GetResult() | Out-Null } Catch { - Write-Host $_ -ForegroundColor Red + Write-Output $_ -ForegroundColor Red } } } @@ -278,17 +280,18 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut Try { $auth.step.VerifyPassword($action).GetAwaiter().GetResult() | Out-Null } - Catch [KeeperSecurity.Authentication.KeeperAuthFailed]{ - Write-Host 'Invalid password' -ForegroundColor Red + Catch [KeeperSecurity.Authentication.KeeperAuthFailed] { + Write-Output 'Invalid password' -ForegroundColor Red } Catch { - Write-Host $_ -ForegroundColor Red + Write-Output $_ -ForegroundColor Red } } elseif ($auth.step -is [KeeperSecurity.Authentication.Sync.SsoTokenStep]) { if ($action -eq 'password') { $auth.step.LoginWithPassword().GetAwaiter().GetResult() | Out-Null - } else { + } + else { $auth.step.SetSsoToken($action).GetAwaiter().GetResult() | Out-Null } } @@ -308,22 +311,16 @@ function executeStepAction ([KeeperSecurity.Authentication.IAuthentication] $aut $auth.LoginSso($providerName).GetAwaiter().GetResult() | Out-Null } } - elseif ($auth.step -is [KeeperSecurity.Authentication.Sync.HttpProxyStep]) { - $args = Invoke-Expression ".{`$args} $action" - if ($args.Count -eq 3 -and $args[0] -eq 'login') { - $auth.step.SetProxyCredentials($args[1], $args[2]).GetAwaiter().GetResult() | Out-Null - } - } } function Connect-Keeper { -<# + <# .Synopsis Login to Keeper .Parameter Username User email - + .Parameter NewLogin Do not use Last Login information @@ -336,27 +333,28 @@ function Connect-Keeper { [CmdletBinding(DefaultParameterSetName = 'regular')] Param( [Parameter(Position = 0)][string] $Username, - [Parameter()] $Password, + [Parameter()] [SecureString]$Password, [Parameter()][switch] $NewLogin, - [Parameter(ParameterSetName='sso_password')][switch] $SsoPassword, - [Parameter(ParameterSetName='sso_provider')][switch] $SsoProvider, + [Parameter(ParameterSetName = 'sso_password')][switch] $SsoPassword, + [Parameter(ParameterSetName = 'sso_provider')][switch] $SsoProvider, [Parameter()][string] $Server ) Disconnect-Keeper -Resume | Out-Null - $storage = New-Object KeeperSecurity.Configuration.JsonConfigurationStorage + $storage = New-Object KeeperSecurity.Configuration.JsonConfigurationStorage if (-not $Server) { $Server = $storage.LastServer if ($Server) { Write-Information -MessageData "`nUsing Keeper Server: $Server`n" - } else { + } + else { Write-Information -MessageData "`nUsing Default Keeper Server: $([KeeperSecurity.Authentication.KeeperEndpoint]::DefaultKeeperServer)`n" } } - - $endpoint = New-Object KeeperSecurity.Authentication.KeeperEndpoint($Server, $storage.Servers) + + $endpoint = New-Object KeeperSecurity.Authentication.KeeperEndpoint($Server, $storage.Servers) $endpoint.DeviceName = 'PowerShell Commander' $endpoint.ClientVersion = 'c16.1.0' $authFlow = New-Object KeeperSecurity.Authentication.Sync.AuthSync($storage, $endpoint) @@ -376,15 +374,17 @@ function Connect-Keeper { } if ($Username) { - Write-Host "$(($namePrompt + ': ').PadLeft(21, ' ')) $Username" - } else { + Write-Output "$(($namePrompt + ': ').PadLeft(21, ' ')) $Username" + } + else { while (-not $Username) { $Username = Read-Host -Prompt $namePrompt.PadLeft(20, ' ') - } + } } if ($SsoProvider.IsPresent) { $authFlow.LoginSso($Username).GetAwaiter().GetResult() | Out-Null - } else { + } + else { $passwords = @() if ($Password) { if ($Password -is [SecureString]) { @@ -397,7 +397,7 @@ function Connect-Keeper { $authFlow.Login($Username, $passwords).GetAwaiter().GetResult() | Out-Null } Write-Output "" - while(-not $authFlow.IsCompleted) { + while (-not $authFlow.IsCompleted) { if ($lastStep -ne $authFlow.Step.State) { printStepHelp $authFlow $lastStep = $authFlow.Step.State @@ -406,19 +406,22 @@ function Connect-Keeper { $prompt = getStepPrompt $authFlow if ($authFlow.Step -is [KeeperSecurity.Authentication.Sync.PasswordStep]) { - $securedPassword = Read-Host -Prompt $prompt -AsSecureString + $securedPassword = Read-Host -Prompt $prompt -AsSecureString if ($securedPassword.Length -gt 0) { $action = [Net.NetworkCredential]::new('', $securedPassword).Password - } else { + } + else { $action = '' } - } else { + } + else { $action = Read-Host -Prompt $prompt } if ($action) { if ($action -eq '?') { - } else { + } + else { executeStepAction $authFlow $action } } @@ -426,7 +429,7 @@ function Connect-Keeper { if ($authFlow.Step.State -ne [KeeperSecurity.Authentication.Sync.AuthState]::Connected) { if ($authFlow.Step -is [KeeperSecurity.Authentication.Sync.ErrorStep]) { - Write-Host $authFlow.Step.Message -ForegroundColor Red + Write-Output $authFlow.Step.Message -ForegroundColor Red } return } @@ -456,13 +459,13 @@ $Keeper_ConfigServerCompleter = { $prefixes = @('', 'dev.', 'qa.') $suffixes = $('.com', '.eu') - $prefixes | % { $p = $_; $suffixes | % {$s = $_; "${p}keepersecurity${s}" }} | Where-Object {$_.StartsWith($wordToComplete)} + $prefixes | ForEach-Object { $p = $_; $suffixes | ForEach-Object { $s = $_; "${p}keepersecurity${s}" } } | Where-Object { $_.StartsWith($wordToComplete) } } Register-ArgumentCompleter -Command Connect-Keeper -ParameterName Server -ScriptBlock $Keeper_ConfigServerCompleter New-Alias -Name kc -Value Connect-Keeper function Disconnect-Keeper { -<# + <# .Synopsis Logout from Keeper #> @@ -496,7 +499,7 @@ function Disconnect-Keeper { New-Alias -Name kq -Value Disconnect-Keeper function Sync-Keeper { -<# + <# .Synopsis Sync down with Keeper #> @@ -506,7 +509,8 @@ function Sync-Keeper { if ($vault) { $task = $vault.SyncDown() $task.GetAwaiter().GetResult() | Out-Null - } else { + } + else { Write-Error -Message "Not connected" -ErrorAction Stop } } diff --git a/PowerCommander/Enterprise.format.ps1xml b/PowerCommander/Enterprise.format.ps1xml index ec6a833..9ccc85c 100644 --- a/PowerCommander/Enterprise.format.ps1xml +++ b/PowerCommander/Enterprise.format.ps1xml @@ -1,316 +1,316 @@ - - - KeeperSecurity.Enterprise.EnterpriseUser_TableView - - KeeperSecurity.Enterprise.EnterpriseUser - - - - - - - - - - - - - - - Id - - - DisplayName - - - Email - - - UserStatus - - - NodeName - - - - - - + + + KeeperSecurity.Enterprise.EnterpriseUser_TableView + + KeeperSecurity.Enterprise.EnterpriseUser + + + + + + + + + + + + + + + Id + + + DisplayName + + + Email + + + UserStatus + + + NodeName + + + + + + - - KeeperSecurity.Enterprise.EnterpriseUser_ListView - - KeeperSecurity.Enterprise.EnterpriseUser - - - - - - - Id - - - DisplayName - - - Email - - - UserStatus - - - ParentNodeId - - - NodeName - - - - - - + + KeeperSecurity.Enterprise.EnterpriseUser_ListView + + KeeperSecurity.Enterprise.EnterpriseUser + + + + + + + Id + + + DisplayName + + + Email + + + UserStatus + + + ParentNodeId + + + NodeName + + + + + + - - KeeperSecurity.Enterprise.EnterpriseNode_TableView - - KeeperSecurity.Enterprise.EnterpriseNode - - - - - - - - - - - - - - - Id - - - DisplayName - - - ParentNodeName - - - RestrictVisibility - - - Provisioning - - - - - - + + KeeperSecurity.Enterprise.EnterpriseNode_TableView + + KeeperSecurity.Enterprise.EnterpriseNode + + + + + + + + + + + + + + + Id + + + DisplayName + + + ParentNodeName + + + RestrictVisibility + + + Provisioning + + + + + + - - KeeperSecurity.Enterprise.EnterpriseNode_ListView - - KeeperSecurity.Enterprise.EnterpriseNode - - - - - - - Id - - - DisplayName - - - Email - - - ParentNodeId - - - ParentNodeName - - - RestrictVisibility - - - Provisioning - - - - - - + + KeeperSecurity.Enterprise.EnterpriseNode_ListView + + KeeperSecurity.Enterprise.EnterpriseNode + + + + + + + Id + + + DisplayName + + + Email + + + ParentNodeId + + + ParentNodeName + + + RestrictVisibility + + + Provisioning + + + + + + - - KeeperSecurity.Enterprise.EnterpriseTeam_TableView - - KeeperSecurity.Enterprise.EnterpriseTeam - - - - - - - - - - - - - - - - Uid - - - Name - - - RestrictSharing - - - RestrictEdit - - - RestrictView - - - NodeName - - - - - - + + KeeperSecurity.Enterprise.EnterpriseTeam_TableView + + KeeperSecurity.Enterprise.EnterpriseTeam + + + + + + + + + + + + + + + + Uid + + + Name + + + RestrictSharing + + + RestrictEdit + + + RestrictView + + + NodeName + + + + + + - - KeeperSecurity.Enterprise.EnterpriseTeam_ListView - - KeeperSecurity.Enterprise.EnterpriseTeam - - - - - - - Uid - - - Name - - - RestrictSharing - - - RestrictEdit - - - RestrictView - - - ParentNodeId - - - NodeName - - - - - - + + KeeperSecurity.Enterprise.EnterpriseTeam_ListView + + KeeperSecurity.Enterprise.EnterpriseTeam + + + + + + + Uid + + + Name + + + RestrictSharing + + + RestrictEdit + + + RestrictView + + + ParentNodeId + + + NodeName + + + + + + - - KeeperSecurity.Enterprise.EnterpriseManagedCompany_TableView - - KeeperSecurity.Enterprise.EnterpriseManagedCompany - - - - - - - - - - Right - - - Right - - - - - - - - CompanyId - - - CompanyName - - - PlanId - - - PlanName - - - FilePlanName - - - Allocated - - - Active - - - - - - + + KeeperSecurity.Enterprise.EnterpriseManagedCompany_TableView + + KeeperSecurity.Enterprise.EnterpriseManagedCompany + + + + + + + + + + Right + + + Right + + + + + + + + CompanyId + + + CompanyName + + + PlanId + + + PlanName + + + FilePlanName + + + Allocated + + + Active + + + + + + - - KeeperSecurity.Enterprise.EnterpriseManagedCompany_ListView - - KeeperSecurity.Enterprise.EnterpriseManagedCompany - - - - - - - CompanyId - - - CompanyName - - - PlanId - - - PlanName - - - Allocated - - - Active - - - ParentNodeId - - - ParentNodeName - - - - - - - + + KeeperSecurity.Enterprise.EnterpriseManagedCompany_ListView + + KeeperSecurity.Enterprise.EnterpriseManagedCompany + + + + + + + CompanyId + + + CompanyName + + + PlanId + + + PlanName + + + Allocated + + + Active + + + ParentNodeId + + + ParentNodeName + + + + + + + \ No newline at end of file diff --git a/PowerCommander/Enterprise.ps1 b/PowerCommander/Enterprise.ps1 index be075f2..0904f2d 100644 --- a/PowerCommander/Enterprise.ps1 +++ b/PowerCommander/Enterprise.ps1 @@ -1,455 +1,453 @@ function getEnterprise { - [KeeperSecurity.Authentication.IAuthentication] $auth = $Script:Context.Auth - if (-not $auth) { - Write-Error -Message "Not Connected" -ErrorAction Stop - } - if (-not $auth.AuthContext.IsEnterpriseAdmin) { - Write-Error -Message "Not an Enterprise Administrator" -ErrorAction Stop - } - $enterprise = $Script:Context.Enterprise - if (-not $enterprise) { - $enterprise = New-Object Enterprise - - $enterprise.enterpriseData = New-Object KeeperSecurity.Enterprise.EnterpriseData - $enterprise.roleData = New-Object KeeperSecurity.Enterprise.RoleData - $enterprise.mspData = New-Object KeeperSecurity.Enterprise.ManagedCompanyData - - [KeeperSecurity.Enterprise.EnterpriseDataPlugin[]] $plugins = $enterprise.enterpriseData, $enterprise.roleData, $enterprise.mspData - - $enterprise.loader = New-Object KeeperSecurity.Enterprise.EnterpriseLoader($auth, $plugins) - $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null - - $Script:Context.Enterprise = $enterprise - } - - return $enterprise + [KeeperSecurity.Authentication.IAuthentication] $auth = $Script:Context.Auth + if (-not $auth) { + Write-Error -Message "Not Connected" -ErrorAction Stop + } + if (-not $auth.AuthContext.IsEnterpriseAdmin) { + Write-Error -Message "Not an Enterprise Administrator" -ErrorAction Stop + } + $enterprise = $Script:Context.Enterprise + if (-not $enterprise) { + $enterprise = New-Object Enterprise + + $enterprise.enterpriseData = New-Object KeeperSecurity.Enterprise.EnterpriseData + $enterprise.roleData = New-Object KeeperSecurity.Enterprise.RoleData + $enterprise.mspData = New-Object KeeperSecurity.Enterprise.ManagedCompanyData + + [KeeperSecurity.Enterprise.EnterpriseDataPlugin[]] $plugins = $enterprise.enterpriseData, $enterprise.roleData, $enterprise.mspData + + $enterprise.loader = New-Object KeeperSecurity.Enterprise.EnterpriseLoader($auth, $plugins) + $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null + + $Script:Context.Enterprise = $enterprise + } + + return $enterprise } function Sync-KeeperEnterprise { - <# + <# .Synopsis Sync Keeper Enterprise Information #> - - [CmdletBinding()] - [Enterprise]$enterprise = getEnterprise - $task = $enterprise.loader.Load() - $task.GetAwaiter().GetResult() | Out-Null + + [CmdletBinding()] + [Enterprise]$enterprise = getEnterprise + $task = $enterprise.loader.Load() + $task.GetAwaiter().GetResult() | Out-Null } New-Alias -Name ked -Value Sync-KeeperEnterprise - -function Get-KeeperEnterpriseUsers { - <# + +function Get-KeeperEnterpriseUser { + <# .Synopsis Get a list of enterprise users #> - [CmdletBinding()] + [CmdletBinding()] - [Enterprise]$enterprise = getEnterprise - return $enterprise.enterpriseData.Users + [Enterprise]$enterprise = getEnterprise + return $enterprise.enterpriseData.Users } -New-Alias -Name keu -Value Get-KeeperEnterpriseUsers +New-Alias -Name keu -Value Get-KeeperEnterpriseUser -function Get-KeeperEnterpriseTeams { - <# +function Get-KeeperEnterpriseTeam { + <# .Synopsis Get a list of enterprise teams #> - [CmdletBinding()] + [CmdletBinding()] - [Enterprise]$enterprise = getEnterprise - return $enterprise.enterpriseData.Teams + [Enterprise]$enterprise = getEnterprise + return $enterprise.enterpriseData.Teams } -New-Alias -Name ket -Value Get-KeeperEnterpriseTeams +New-Alias -Name ket -Value Get-KeeperEnterpriseTeam $Keeper_TeamNameCompleter = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - - $result = @() - [Enterprise]$enterprise = $Script:Context.Enterprise - if (-not $enterprise) { - return $null - } - if ($wordToComplete) { - $to_complete = $wordToComplete + '*' - } - else { - $to_complete = '*' - } - foreach ($team in $enterprise.enterpriseData.Teams) { - if ($team.Name -like $to_complete) { - $teamName = $team.Name - if ($teamName -match '[\s'']') { - $teamName = $teamName -replace '''', '''''' - $teamName = "'${teamName}'" - } - - $result += $teamName - } - } - if ($result.Count -gt 0) { - return $result - } - else { - return $null - } + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + $result = @() + [Enterprise]$enterprise = $Script:Context.Enterprise + if (-not $enterprise) { + return $null + } + if ($wordToComplete) { + $to_complete = $wordToComplete + '*' + } + else { + $to_complete = '*' + } + foreach ($team in $enterprise.enterpriseData.Teams) { + if ($team.Name -like $to_complete) { + $teamName = $team.Name + if ($teamName -match '[\s'']') { + $teamName = $teamName -replace '''', '''''' + $teamName = "'${teamName}'" + } + + $result += $teamName + } + } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } -function Get-KeeperEnterpriseTeamUsers { - <# +function Get-KeeperEnterpriseTeamUser { + <# .Synopsis Get a list of enterprise users for team #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0, Mandatory = $true)]$Team - ) - - [Enterprise]$enterprise = getEnterprise - $enterpriseData = $enterprise.enterpriseData - $uid = $null - - if ($Team -is [String]) { - $uids = Get-KeeperEnterpriseTeams | Where-Object { $_.Uid -ceq $Team -or $_.Name -ieq $Team } | Select-Object -Property Uid - if ($uids.Length -gt 1) { - Write-Error -Message "Team name `"$Team`" is not unique. Use Team UID" -ErrorAction Stop - } - - if ($null -ne $uids.Uid) { - $uid = $uids.Uid - } - } - elseif ($null -ne $Team.Uid) { - $uid = $Team.Uid - } - if ($uid) { - $team = $null - if ($enterpriseData.TryGetTeam($uid, [ref]$team)) { - foreach ($userId in $enterpriseData.GetUsersForTeam($uid)) { - $user = $null - foreach ($userId in $enterpriseData.TryGetUserById($userId, [ref]$user)) { - $user + [CmdletBinding()] + Param ( + [Parameter(Position = 0, Mandatory = $true)]$Team + ) + + [Enterprise]$enterprise = getEnterprise + $enterpriseData = $enterprise.enterpriseData + $uid = $null + + if ($Team -is [String]) { + $uids = Get-KeeperEnterpriseTeam | Where-Object { $_.Uid -ceq $Team -or $_.Name -ieq $Team } | Select-Object -Property Uid + if ($uids.Length -gt 1) { + Write-Error -Message "Team name `"$Team`" is not unique. Use Team UID" -ErrorAction Stop + } + + if ($null -ne $uids.Uid) { + $uid = $uids.Uid + } + } + elseif ($null -ne $Team.Uid) { + $uid = $Team.Uid + } + if ($uid) { + $team = $null + if ($enterpriseData.TryGetTeam($uid, [ref]$team)) { + foreach ($userId in $enterpriseData.GetUsersForTeam($uid)) { + $user = $null + foreach ($userId in $enterpriseData.TryGetUserById($userId, [ref]$user)) { + $user + } + } + } + else { + Write-Error -Message "Team `"$uid`" not found" -ErrorAction Stop } - } } else { - Write-Error -Message "Team `"$uid`" not found" -ErrorAction Stop + Write-Error -Message "Team `"$Team`" not found" -ErrorAction Stop } - } - else { - Write-Error -Message "Team `"$Team`" not found" -ErrorAction Stop - } } -New-Alias -Name ketu -Value Get-KeeperEnterpriseTeamUsers -Register-ArgumentCompleter -CommandName Get-KeeperEnterpriseTeamUsers -ParameterName Team -ScriptBlock $Keeper_TeamNameCompleter +New-Alias -Name ketu -Value Get-KeeperEnterpriseTeamUser +Register-ArgumentCompleter -CommandName Get-KeeperEnterpriseTeamUser -ParameterName Team -ScriptBlock $Keeper_TeamNameCompleter $Keeper_ActiveUserCompleter = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - - $result = @() - [Enterprise]$enterprise = $Script:Context.Enterprise - if (-not $enterprise) { - return $null - } - if ($wordToComplete) { - $to_complete = '*' + $wordToComplete + '*' - } - else { - $to_complete = '*' - } - foreach ($user in $enterprise.enterpriseData.Users) { - if ($user.UserStatus -in @([KeeperSecurity.Enterprise.UserStatus]::Active, [KeeperSecurity.Enterprise.UserStatus]::Disabled, [KeeperSecurity.Enterprise.UserStatus]::Blocked)) { - if ($user.Email -like $to_complete) { - $result += $user.Email - } - } - } - if ($result.Count -gt 0) { - return $result - } - else { - return $null - } + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + $result = @() + [Enterprise]$enterprise = $Script:Context.Enterprise + if (-not $enterprise) { + return $null + } + if ($wordToComplete) { + $to_complete = '*' + $wordToComplete + '*' + } + else { + $to_complete = '*' + } + foreach ($user in $enterprise.enterpriseData.Users) { + if ($user.UserStatus -in @([KeeperSecurity.Enterprise.UserStatus]::Active, [KeeperSecurity.Enterprise.UserStatus]::Disabled, [KeeperSecurity.Enterprise.UserStatus]::Blocked)) { + if ($user.Email -like $to_complete) { + $result += $user.Email + } + } + } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } function Lock-KeeperEnterpriseUser { - <# + <# .Synopsis Locks Enterprise User - + .Parameter User User email, enterprise Id, or instance. #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0, Mandatory = $true)]$User - ) - - [Enterprise]$enterprise = getEnterprise - $userObject = resolveUser $enterprise.enterpriseData $User - if ($userObject) { - $saved = $enterprise.enterpriseData.SetUserLocked($userObject, $true).GetAwaiter().GetResult() - Write-Host "User `"$($saved.Email)`" was locked" - } + [CmdletBinding()] + Param ( + [Parameter(Position = 0, Mandatory = $true)]$User + ) + + [Enterprise]$enterprise = getEnterprise + $userObject = resolveUser $enterprise.enterpriseData $User + if ($userObject) { + $saved = $enterprise.enterpriseData.SetUserLocked($userObject, $true).GetAwaiter().GetResult() + Write-Output "User `"$($saved.Email)`" was locked" + } } Register-ArgumentCompleter -CommandName Lock-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_ActiveUserCompleter New-Alias -Name lock-user -Value Lock-KeeperEnterpriseUser $Keeper_LockedUserCompleter = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - - $result = @() - [Enterprise]$enterprise = $Script:Context.Enterprise - if (-not $enterprise) { - return $null - } - if ($wordToComplete) { - $to_complete = '*' + $wordToComplete + '*' - } - else { - $to_complete = '*' - } - foreach ($user in $enterprise.enterpriseData.Users) { - if ($user.UserStatus -eq [KeeperSecurity.Enterprise.UserStatus]::Locked) { - if ($user.Email -like $to_complete) { - $result += $user.Email - } - } - } - if ($result.Count -gt 0) { - return $result - } - else { - return $null - } + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + $result = @() + [Enterprise]$enterprise = $Script:Context.Enterprise + if (-not $enterprise) { + return $null + } + if ($wordToComplete) { + $to_complete = '*' + $wordToComplete + '*' + } + else { + $to_complete = '*' + } + foreach ($user in $enterprise.enterpriseData.Users) { + if ($user.UserStatus -eq [KeeperSecurity.Enterprise.UserStatus]::Locked) { + if ($user.Email -like $to_complete) { + $result += $user.Email + } + } + } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } function Unlock-KeeperEnterpriseUser { - <# + <# .Synopsis Unlocks Enterprise User - + .Parameter User User email, enterprise Id, or instance. #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0, Mandatory = $true)]$User - ) - - [Enterprise]$enterprise = getEnterprise - $userObject = resolveUser $enterprise.enterpriseData $User - if ($userObject) { - $saved = $enterprise.enterpriseData.SetUserLocked($userObject, $false).GetAwaiter().GetResult() - Write-Host "User `"$($saved.Email)`" was unlocked" - } + [CmdletBinding()] + Param ( + [Parameter(Position = 0, Mandatory = $true)]$User + ) + + [Enterprise]$enterprise = getEnterprise + $userObject = resolveUser $enterprise.enterpriseData $User + if ($userObject) { + $saved = $enterprise.enterpriseData.SetUserLocked($userObject, $false).GetAwaiter().GetResult() + Write-Output "User `"$($saved.Email)`" was unlocked" + } } Register-ArgumentCompleter -CommandName Unlock-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_LockedUserCompleter New-Alias -Name unlock-user -Value Unlock-KeeperEnterpriseUser $Keeper_EnterpriseUserCompleter = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - - $result = @() - [Enterprise]$enterprise = $Script:Context.Enterprise - if (-not $enterprise) { - return $null - } - if ($wordToComplete) { - $to_complete = '*' + $wordToComplete + '*' - } - else { - $to_complete = '*' - } - foreach ($user in $enterprise.enterpriseData.Users) { - if ($user.Email -like $to_complete) { - $result += $user.Email - } - } - if ($result.Count -gt 0) { - return $result - } - else { - return $null - } + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + $result = @() + [Enterprise]$enterprise = $Script:Context.Enterprise + if (-not $enterprise) { + return $null + } + if ($wordToComplete) { + $to_complete = '*' + $wordToComplete + '*' + } + else { + $to_complete = '*' + } + foreach ($user in $enterprise.enterpriseData.Users) { + if ($user.Email -like $to_complete) { + $result += $user.Email + } + } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } function Move-KeeperEnterpriseUser { - <# + <# .Synopsis Transfers enterprise user account to another user - + .Parameter FromUser email or user ID to transfer vault from user - + .Parameter TargetUser email or user ID to transfer vault to user #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0, Mandatory = $true)]$FromUser, - [Parameter(Position = 1, Mandatory = $true)]$TargetUser, - [Switch] $Force - ) - - [Enterprise]$enterprise = getEnterprise - - $fromUserObject = resolveUser $enterprise.enterpriseData $FromUser - if (-not $fromUserObject) { - return - } - $targetUserObject = resolveUser $enterprise.enterpriseData $TargetUser - if (-not $targetUserObject) { - return - } - if (-not $Force.IsPresent) { - Write-Host "This action cannot be undone.`n" - $answer = Read-Host -Prompt "Do you want to proceed with transferring $($fromUserObject.Email) account (Yes/No)? > " - if ($answer -ne 'yes' -and $answer -ne 'y') { - return - } - } - $transferResult = $enterprise.enterpriseData.TransferUserAccount($enterprise.roleData, $fromUserObject, $targetUserObject).GetAwaiter().GetResult() - if ($transferResult) { - Write-Information "Successfully Transfered:" - Write-Information " Records: $($transferResult.RecordsTransfered)" - Write-Information " Shared Folders: $($transferResult.SharedFoldersTransfered)" - Write-Information " Team: $($transferResult.TeamsTransfered)" - if ($transferResult.RecordsCorrupted -gt 0 -or $transferResult.SharedFoldersCorrupted -gt 0 -or $transferResult.TeamsCorrupted -gt 0) { - Write-Information "Failed to Transfer:" - if ($transferResult.RecordsCorrupted -gt 0) { - Write-Information " Records: $($transferResult.RecordsCorrupted)" - } - if ($transferResult.SharedFoldersCorrupted -gt 0) { - Write-Information " Shared Folders: $($transferResult.SharedFoldersCorrupted)" - } - if ($transferResult.TeamsCorrupted -gt 0) { - Write-Information " Team: $($transferResult.TeamsCorrupted)" - } - } - } + [CmdletBinding()] + Param ( + [Parameter(Position = 0, Mandatory = $true)]$FromUser, + [Parameter(Position = 1, Mandatory = $true)]$TargetUser, + [Switch] $Force + ) + + [Enterprise]$enterprise = getEnterprise + + $fromUserObject = resolveUser $enterprise.enterpriseData $FromUser + if (-not $fromUserObject) { + return + } + $targetUserObject = resolveUser $enterprise.enterpriseData $TargetUser + if (-not $targetUserObject) { + return + } + if (-not $Force.IsPresent) { + Write-Output "This action cannot be undone.`n" + $answer = Read-Host -Prompt "Do you want to proceed with transferring $($fromUserObject.Email) account (Yes/No)? > " + if ($answer -ne 'yes' -and $answer -ne 'y') { + return + } + } + $transferResult = $enterprise.enterpriseData.TransferUserAccount($enterprise.roleData, $fromUserObject, $targetUserObject).GetAwaiter().GetResult() + if ($transferResult) { + Write-Information "Successfully Transfered:" + Write-Information " Records: $($transferResult.RecordsTransfered)" + Write-Information " Shared Folders: $($transferResult.SharedFoldersTransfered)" + Write-Information " Team: $($transferResult.TeamsTransfered)" + if ($transferResult.RecordsCorrupted -gt 0 -or $transferResult.SharedFoldersCorrupted -gt 0 -or $transferResult.TeamsCorrupted -gt 0) { + Write-Information "Failed to Transfer:" + if ($transferResult.RecordsCorrupted -gt 0) { + Write-Information " Records: $($transferResult.RecordsCorrupted)" + } + if ($transferResult.SharedFoldersCorrupted -gt 0) { + Write-Information " Shared Folders: $($transferResult.SharedFoldersCorrupted)" + } + if ($transferResult.TeamsCorrupted -gt 0) { + Write-Information " Team: $($transferResult.TeamsCorrupted)" + } + } + } } Register-ArgumentCompleter -CommandName Move-KeeperEnterpriseUser -ParameterName FromUser -ScriptBlock $Keeper_LockedUserCompleter Register-ArgumentCompleter -CommandName Move-KeeperEnterpriseUser -ParameterName TargetUser -ScriptBlock $Keeper_ActiveUserCompleter New-Alias -Name transfer-user -Value Move-KeeperEnterpriseUser function Remove-KeeperEnterpriseUser { - <# + <# .Synopsis Removes Enterprise User - + .Parameter User User email, enterprise Id, or instance. #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0, Mandatory = $true)]$User, - [Switch] $Force - ) - - [Enterprise]$enterprise = getEnterprise - $userObject = resolveUser $enterprise.enterpriseData $User - if ($userObject) { - if (-not $Force.IsPresent) { - Write-Host "Deleting a user will also delete any records owned and shared by this user.`n" + - "Before you delete this user, we strongly recommend you lock their account`n" + - "and transfer any important records to other user.`n" + - "This action cannot be undone." - $answer = Read-Host -Prompt "Do you want to proceed with deleting $($userObject.Email) account (Yes/No)? > " - if ($answer -ne 'yes' -and $answer -ne 'y') { - return - } + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact = 'High')] + Param ( + [Parameter(Position = 0, Mandatory = $true)]$User, + [Switch] $Force + ) + + [Enterprise]$enterprise = getEnterprise + $userObject = resolveUser $enterprise.enterpriseData $User + if ($userObject) { + if (-not $Force.IsPresent) { + Write-Output "`nDeleting a user will also delete any records owned and shared by this user." + "Before you delete this user, we strongly recommend you lock their account" + "and transfer any important records to other user.`n" + "This action cannot be undone." + + if ($PSCmdlet.ShouldProcess($userObject.Email, "Removing Enterprise User")) { + $enterprise.enterpriseData.DeleteUser($userObject).GetAwaiter().GetResult() | Out-Null + Write-Output "User $($userObject.Email) has been deleted" + } + } } - - $enterprise.enterpriseData.DeleteUser($userObject).GetAwaiter().GetResult() | Out-Null - Write-Host "User $($userObject.Email) has been deleted" - } } Register-ArgumentCompleter -CommandName Remove-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_EnterpriseUserCompleter New-Alias -Name delete-user -Value Remove-KeeperEnterpriseUser function resolveUser { - Param ( - $enterpriseData, - $user - ) - [KeeperSecurity.Enterprise.EnterpriseUser] $u = $null - - if ($user -is [long]) { - if ($enterpriseData.TryGetUserById($user, [ref]$u)) { - return $u - } - } - elseif ($user -is [string]) { - if ($enterpriseData.TryGetUserByEmail($user, [ref]$u)) { - return $u - } - } - elseif ($user -is [KeeperSecurity.Enterprise.EnterpriseUser]) { - if ($enterpriseData.TryGetUserById($user.Id, [ref]$u)) { - return $u - } - } - Write-Host "`"${user}`" cannot be resolved as enterprise user" + Param ( + $enterpriseData, + $user + ) + [KeeperSecurity.Enterprise.EnterpriseUser] $u = $null + + if ($user -is [long]) { + if ($enterpriseData.TryGetUserById($user, [ref]$u)) { + return $u + } + } + elseif ($user -is [string]) { + if ($enterpriseData.TryGetUserByEmail($user, [ref]$u)) { + return $u + } + } + elseif ($user -is [KeeperSecurity.Enterprise.EnterpriseUser]) { + if ($enterpriseData.TryGetUserById($user.Id, [ref]$u)) { + return $u + } + } + Write-Output "`"${user}`" cannot be resolved as enterprise user" } -function Get-KeeperEnterpriseNodes { - <# +function Get-KeeperEnterpriseNode { + <# .Synopsis Get a list of enterprise nodes #> - [CmdletBinding()] + [CmdletBinding()] - [Enterprise]$enterprise = getEnterprise - return $enterprise.enterpriseData.Nodes + [Enterprise]$enterprise = getEnterprise + return $enterprise.enterpriseData.Nodes } -New-Alias -Name ken -Value Get-KeeperEnterpriseNodes +New-Alias -Name ken -Value Get-KeeperEnterpriseNode -function Get-KeeperManagedCompanies { - <# +function Get-KeeperManagedCompany { + <# .Synopsis Get a list of managed companies .Parameter Filter Managed Company ID or Name #> - [CmdletBinding()] - Param ( - [Parameter(Mandatory = $false)][string] $Filter - ) - - [Enterprise]$enterprise = getMspEnterprise - if ($Name) { - $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $Filter) -or ($_.EnterpriseName -like $Filter + '*') } - } - else { - $enterprise.mspData.ManagedCompanies - } + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $false)][string] $Filter + ) + + [Enterprise]$enterprise = getMspEnterprise + if ($Name) { + $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $Filter) -or ($_.EnterpriseName -like $Filter + '*') } + } + else { + $enterprise.mspData.ManagedCompanies + } } -New-Alias -Name kmc -Value Get-KeeperManagedCompanies +New-Alias -Name kmc -Value Get-KeeperManagedCompany $Keeper_MspAddonName = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - - $result = @() - $msp_addons = @('enterprise_breach_watch', 'compliance_report', 'enterprise_audit_and_reporting', 'msp_service_and_support', 'secrets_manager', 'connection_manager', 'chat') - - $toComplete = $wordToComplete += '*' - foreach ($addon in $msp_addons) { - if ($addon -like $toComplete) { - $result += $addon - } - } - if ($result.Count -gt 0) { - return $result - } - else { - return $null - } + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + $result = @() + $msp_addons = @('enterprise_breach_watch', 'compliance_report', 'enterprise_audit_and_reporting', 'msp_service_and_support', 'secrets_manager', 'connection_manager', 'chat') + + $toComplete = $wordToComplete += '*' + foreach ($addon in $msp_addons) { + if ($addon -like $toComplete) { + $result += $addon + } + } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } function New-KeeperManagedCompany { - <# + <# .Synopsis Adds new Managed Company .Parameter Name @@ -465,83 +463,88 @@ function New-KeeperManagedCompany { .Parameter Node Node Name or ID #> - [CmdletBinding()] - Param ( - [Parameter(Mandatory = $true, Position = 0)][string] $Name, - [Parameter(Mandatory = $true)][ValidateSet('business', 'businessPlus', 'enterprise', 'enterprisePlus')][string] $PlanId, - [Parameter(Mandatory = $true)][int] $MaximumSeats, - [Parameter(Mandatory = $false)][ValidateSet('100GB', '1TB', '10TB')][string] $Storage, - [Parameter(Mandatory = $false)][string[]] $Addons, - [Parameter(Mandatory = $false)][string] $Node - ) - - [Enterprise]$enterprise = getMspEnterprise - - $options = New-Object KeeperSecurity.Enterprise.ManagedCompanyOptions - $options.Name = $Name - $options.ProductId = $PlanId - $options.NumberOfSeats = $MaximumSeats - if ($Node) { - $n = findEnterpriseNode $Node - if ($n) { - $options.NodeId = $n.Id + [CmdletBinding(SupportsShouldProcess=$true)] + Param ( + [Parameter(Mandatory = $true, Position = 0)][string] $Name, + [Parameter(Mandatory = $true)][ValidateSet('business', 'businessPlus', 'enterprise', 'enterprisePlus')][string] $PlanId, + [Parameter(Mandatory = $true)][int] $MaximumSeats, + [Parameter(Mandatory = $false)][ValidateSet('100GB', '1TB', '10TB')][string] $Storage, + [Parameter(Mandatory = $false)][string[]] $Addons, + [Parameter(Mandatory = $false)][string] $Node + ) + + [Enterprise]$enterprise = getMspEnterprise + + $options = New-Object KeeperSecurity.Enterprise.ManagedCompanyOptions + $options.Name = $Name + $options.ProductId = $PlanId + $options.NumberOfSeats = $MaximumSeats + if ($Node) { + $n = findEnterpriseNode $Node + if ($n) { + $options.NodeId = $n.Id + } + else { + Write-Error -Message "Node ${Node} not found" -ErrorAction Stop + } } else { - Write-Error -Message "Node ${Node} not found" -ErrorAction Stop - } - } - else { - $options.NodeId = $enterprise.enterpriseData.RootNode.Id - } - switch ($Storage) { - '100GB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan100GB } - '1TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan1TB } - '10TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan10TB } - } - if ($Addons) { - $aons = @() - foreach ($addon in $Addons) { - $parts = $addon -split ':' - $addonOption = New-Object KeeperSecurity.Enterprise.ManagedCompanyAddonOptions - $addonOption.Addon = $parts[0] - if ($parts.Length -gt 1) { - $addonOption.NumberOfSeats = $parts[1] -as [int] - } - $aons += $addonOption - } - $options.Addons = $aons - } - - return $enterprise.mspData.CreateManagedCompany($options).GetAwaiter().GetResult() + $options.NodeId = $enterprise.enterpriseData.RootNode.Id + } + switch ($Storage) { + '100GB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan100GB } + '1TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan1TB } + '10TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan10TB } + } + if ($Addons) { + $aons = @() + foreach ($addon in $Addons) { + $parts = $addon -split ':' + $addonOption = New-Object KeeperSecurity.Enterprise.ManagedCompanyAddonOptions + $addonOption.Addon = $parts[0] + if ($parts.Length -gt 1) { + $addonOption.NumberOfSeats = $parts[1] -as [int] + } + $aons += $addonOption + } + $options.Addons = $aons + } + + + if ($PSCmdlet.ShouldProcess($Name, "Creating Managed Company")) { + return $enterprise.mspData.CreateManagedCompany($options).GetAwaiter().GetResult() + } } New-Alias -Name kamc -Value New-KeeperManagedCompany Register-ArgumentCompleter -CommandName New-KeeperManagedCompany -ParameterName Addons -ScriptBlock $Keeper_MspAddonName function Remove-KeeperManagedCompany { - <# + <# .Synopsis Removes Managed Company .Parameter Name Managed Company Id or Name #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0, Mandatory = $true)][string] $Name - ) - - [Enterprise]$enterprise = getMspEnterprise - $mc = findManagedCompany $Name - if (-not $mc) { - Write-Error -Message "Managed Company ${Name} not found" -ErrorAction Stop - } - - $enterprise.mspData.RemoveManagedCompany($mc.EnterpriseId).GetAwaiter().GetResult() | Out-Null - Write-Information "Removed Managed Company `"$($mc.EnterpriseName)`" ID: $($mc.EnterpriseId)" + [CmdletBinding(SupportsShouldProcess=$true)] + Param ( + [Parameter(Position = 0, Mandatory = $true)][string] $Name + ) + + [Enterprise]$enterprise = getMspEnterprise + $mc = findManagedCompany $Name + if (-not $mc) { + Write-Error -Message "Managed Company ${Name} not found" -ErrorAction Stop + } + + if ($PSCmdlet.ShouldProcess($mc.EnterpriseName, "Removing Managed Company")) { + $enterprise.mspData.RemoveManagedCompany($mc.EnterpriseId).GetAwaiter().GetResult() | Out-Null + Write-Information "Removed Managed Company `"$($mc.EnterpriseName)`" ID: $($mc.EnterpriseId)" + } } New-Alias -Name krmc -Value Remove-KeeperManagedCompany function Edit-KeeperManagedCompany { - <# + <# .Synopsis Removes Managed Company .Parameter Name @@ -559,83 +562,83 @@ function Edit-KeeperManagedCompany { .Parameter Id Managed Company Name or Id #> - [CmdletBinding()] - Param ( - [Parameter(Mandatory = $false)][string] $Name, - [Parameter(Mandatory = $false)][ValidateSet('business', 'businessPlus', 'enterprise', 'enterprisePlus')][string] $PlanId, - [Parameter(Mandatory = $false)][int] $MaximumSeats, - [Parameter(Mandatory = $false)][ValidateSet('100GB', '1TB', '10TB')][string] $Storage, - [Parameter(Mandatory = $false)][string[]] $Addons, - [Parameter(Mandatory = $false)][string] $Node, - [Parameter(Position = 0, Mandatory = $true)][string] $Id - ) - - [Enterprise]$enterprise = getMspEnterprise - $mc = findManagedCompany $Id - if (-not $mc) { - Write-Error -Message "Managed Company ${Id} not found" -ErrorAction Stop - } - - $options = New-Object KeeperSecurity.Enterprise.ManagedCompanyOptions - if ($Name) { - $options.Name = $Name - } - if ($PlanId) { - $options.ProductId = $PlanId - } - if ($MaximumSeats) { - $options.NumberOfSeats = $MaximumSeats - } - switch ($Storage) { - '100GB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan100GB } - '1TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan1TB } - '10TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan10TB } - } - if ($Addons) { - $aons = @() - foreach ($addon in $Addons) { - $parts = $addon -split ':' - $addonOption = New-Object KeeperSecurity.Enterprise.ManagedCompanyAddonOptions - $addonOption.Addon = $parts[0] - if ($parts.Length -gt 1) { - $addonOption.NumberOfSeats = $parts[1] -as [int] - } - $aons += $addonOption - } - $options.Addons = $aons - } - if ($Node) { - $n = findEnterpriseNode $Node - if ($n) { - $options.NodeId = $n.Id + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $false)][string] $Name, + [Parameter(Mandatory = $false)][ValidateSet('business', 'businessPlus', 'enterprise', 'enterprisePlus')][string] $PlanId, + [Parameter(Mandatory = $false)][int] $MaximumSeats, + [Parameter(Mandatory = $false)][ValidateSet('100GB', '1TB', '10TB')][string] $Storage, + [Parameter(Mandatory = $false)][string[]] $Addons, + [Parameter(Mandatory = $false)][string] $Node, + [Parameter(Position = 0, Mandatory = $true)][string] $Id + ) + + [Enterprise]$enterprise = getMspEnterprise + $mc = findManagedCompany $Id + if (-not $mc) { + Write-Error -Message "Managed Company ${Id} not found" -ErrorAction Stop + } + + $options = New-Object KeeperSecurity.Enterprise.ManagedCompanyOptions + if ($Name) { + $options.Name = $Name + } + if ($PlanId) { + $options.ProductId = $PlanId + } + if ($MaximumSeats) { + $options.NumberOfSeats = $MaximumSeats + } + switch ($Storage) { + '100GB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan100GB } + '1TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan1TB } + '10TB' { $options.FilePlanType = [KeeperSecurity.Enterprise.ManagedCompanyConstants]::StoragePlan10TB } + } + if ($Addons) { + $aons = @() + foreach ($addon in $Addons) { + $parts = $addon -split ':' + $addonOption = New-Object KeeperSecurity.Enterprise.ManagedCompanyAddonOptions + $addonOption.Addon = $parts[0] + if ($parts.Length -gt 1) { + $addonOption.NumberOfSeats = $parts[1] -as [int] + } + $aons += $addonOption + } + $options.Addons = $aons + } + if ($Node) { + $n = findEnterpriseNode $Node + if ($n) { + $options.NodeId = $n.Id + } + else { + Write-Error -Message "Node ${Node} not found" -ErrorAction Stop + } } else { - Write-Error -Message "Node ${Node} not found" -ErrorAction Stop + $options.NodeId = $enterprise.enterpriseData.RootNode.Id } - } - else { - $options.NodeId = $enterprise.enterpriseData.RootNode.Id - } - $enterprise.mspData.UpdateManagedCompany($mc.EnterpriseId, $options).GetAwaiter().GetResult() + $enterprise.mspData.UpdateManagedCompany($mc.EnterpriseId, $options).GetAwaiter().GetResult() } New-Alias -Name kemc -Value Edit-KeeperManagedCompany Register-ArgumentCompleter -CommandName Edit-KeeperManagedCompany -ParameterName Addons -ScriptBlock $Keeper_MspAddonName class MspDailySnapshotAddon { - [string]$Addon - [int]$Units + [string]$Addon + [int]$Units } class MspDailySnapshotRecord { - [System.DateTime]$Date - [int]$McEnterpriseId - [int]$LicenseCount - [string]$ProductPlan - [string]$FilePlan - [MspDailySnapshotAddon[]]$Addons + [System.DateTime]$Date + [int]$McEnterpriseId + [int]$LicenseCount + [string]$ProductPlan + [string]$FilePlan + [MspDailySnapshotAddon[]]$Addons } function Get-MspBillingReport { - <# + <# .Synopsis Runs MSP Billing Report .Parameter Month @@ -643,121 +646,121 @@ function Get-MspBillingReport { .Parameter Year Report Year 20xx #> - [CmdletBinding()] - Param ( - [Parameter(Mandatory = $false)][int] $Month, - [Parameter(Mandatory = $false)][int] $Year - ) - - $dt = Get-Date - if (0 -eq $Year) { - $Year = $dt.Year - } - if (0 -eq $Month) { - $Month = $dt.Month - 1 - if ($Month -le 0) { - $Year -= 1 - $Month = 12 - } - } - - $auth = [KeeperSecurity.Authentication.IAuthentication] $auth = $Script:Context.Auth - - $url = [KeeperSecurity.Authentication.AuthExtensions]::GetBiUrl($auth, 'mapping/addons') - $rq = New-Object BI.MappingAddonsRequest - $rs = $auth.ExecuteAuthRest($url, $rq, [BI.MappingAddonsResponse]).GetAwaiter().GetResult() - $filePlans = @{ - 4 = '100GB' - 7 = '1TB' - 8 = '10TB' - } - foreach ($fp in $rs.FilePlans) { - $filePlans[$fp.Id] = $fp.Name - } - $addons = @{} - foreach ($aon in $rs.Addons) { - $addons[$aon.Id] = $aon.Name - } - - $url = [KeeperSecurity.Authentication.AuthExtensions]::GetBiUrl($auth, 'reporting/daily_snapshot') - $rq = New-Object BI.ReportingDailySnapshotRequest - $rq.Month = $Month - $rq.Year = $Year - - $rs = $auth.ExecuteAuthRest($url, $rq, [BI.ReportingDailySnapshotResponse]).GetAwaiter().GetResult() - foreach ($rec in $rs.Records) { - $r = New-Object MspDailySnapshotRecord - $r.Date = [KeeperSecurity.Utils.DateTimeOffsetExtensions]::FromUnixTimeMilliseconds($rec.date).Date - $r.McEnterpriseId = $rec.mcEnterpriseId - $r.LicenseCount = $rec.maxLicenseCount - switch ($rec.MaxBasePlanId) { - 1 { $r.ProductPlan = 'business' } - 2 { $r.ProductPlan = 'businessPlus' } - 10 { $r.ProductPlan = 'enterprise' } - 11 { $r.ProductPlan = 'enterprisePlus' } - default { $r.ProductPlan = "Plan #$($r.rec)" } - } - if ($rec.maxFilePlanTypeId) { - $r.FilePlan = $filePlans[$rec.maxFilePlanTypeId] - if (-not $r.FilePlan) { - $r.FilePlan = "Storage Plan #$($rec.maxFilePlanTypeId)" - } - } - - foreach ($addon in $rec.addons) { - if ($addon.maxAddonId) { - $a = New-Object MspDailySnapshotAddon - $a.Addon = $addons[$addon.maxAddonId] - if (-not $a.Addon) { - $a.Addon = "Addon # $($addon.maxAddonId)" + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $false)][int] $Month, + [Parameter(Mandatory = $false)][int] $Year + ) + + $dt = Get-Date + if (0 -eq $Year) { + $Year = $dt.Year + } + if (0 -eq $Month) { + $Month = $dt.Month - 1 + if ($Month -le 0) { + $Year -= 1 + $Month = 12 } - $a.Units = $addon.units - $r.Addons += $a - } } - $r - } + + $auth = [KeeperSecurity.Authentication.IAuthentication] $auth = $Script:Context.Auth + + $url = [KeeperSecurity.Authentication.AuthExtensions]::GetBiUrl($auth, 'mapping/addons') + $rq = New-Object BI.MappingAddonsRequest + $rs = $auth.ExecuteAuthRest($url, $rq, [BI.MappingAddonsResponse]).GetAwaiter().GetResult() + $filePlans = @{ + 4 = '100GB' + 7 = '1TB' + 8 = '10TB' + } + foreach ($fp in $rs.FilePlans) { + $filePlans[$fp.Id] = $fp.Name + } + $addons = @{} + foreach ($aon in $rs.Addons) { + $addons[$aon.Id] = $aon.Name + } + + $url = [KeeperSecurity.Authentication.AuthExtensions]::GetBiUrl($auth, 'reporting/daily_snapshot') + $rq = New-Object BI.ReportingDailySnapshotRequest + $rq.Month = $Month + $rq.Year = $Year + + $rs = $auth.ExecuteAuthRest($url, $rq, [BI.ReportingDailySnapshotResponse]).GetAwaiter().GetResult() + foreach ($rec in $rs.Records) { + $r = New-Object MspDailySnapshotRecord + $r.Date = [KeeperSecurity.Utils.DateTimeOffsetExtensions]::FromUnixTimeMilliseconds($rec.date).Date + $r.McEnterpriseId = $rec.mcEnterpriseId + $r.LicenseCount = $rec.maxLicenseCount + switch ($rec.MaxBasePlanId) { + 1 { $r.ProductPlan = 'business' } + 2 { $r.ProductPlan = 'businessPlus' } + 10 { $r.ProductPlan = 'enterprise' } + 11 { $r.ProductPlan = 'enterprisePlus' } + default { $r.ProductPlan = "Plan #$($r.rec)" } + } + if ($rec.maxFilePlanTypeId) { + $r.FilePlan = $filePlans[$rec.maxFilePlanTypeId] + if (-not $r.FilePlan) { + $r.FilePlan = "Storage Plan #$($rec.maxFilePlanTypeId)" + } + } + + foreach ($addon in $rec.addons) { + if ($addon.maxAddonId) { + $a = New-Object MspDailySnapshotAddon + $a.Addon = $addons[$addon.maxAddonId] + if (-not $a.Addon) { + $a.Addon = "Addon # $($addon.maxAddonId)" + } + $a.Units = $addon.units + $r.Addons += $a + } + } + $r + } } function Script:Get-KeeperNodeName { - Param ( - [long]$nodeId - ) - $enterprise = getEnterprise - [KeeperSecurity.Enterprise.EnterpriseNode]$node = $null - if ($enterprise.enterpriseData.TryGetNode($nodeId, [ref]$node)) { - if ($node.ParentNodeId -gt 0) { - return $node.DisplayName - } - else { - return $enterprise.loader.EnterpriseName + Param ( + [long]$nodeId + ) + $enterprise = getEnterprise + [KeeperSecurity.Enterprise.EnterpriseNode]$node = $null + if ($enterprise.enterpriseData.TryGetNode($nodeId, [ref]$node)) { + if ($node.ParentNodeId -gt 0) { + return $node.DisplayName + } + else { + return $enterprise.loader.EnterpriseName + } } - } } function findManagedCompany { - Param ( - [string]$mc - ) - $enterprise = getMspEnterprise - $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $mc) -or ($_.EnterpriseName -eq $mc) } | Select-Object -First 1 + Param ( + [string]$mc + ) + $enterprise = getMspEnterprise + $enterprise.mspData.ManagedCompanies | Where-Object { ($_.EnterpriseId -eq $mc) -or ($_.EnterpriseName -eq $mc) } | Select-Object -First 1 } function findEnterpriseNode { - Param ( - [string]$node - ) - $enterprise = getEnterprise - if ($node -eq $enterprise.loader.EnterpriseName) { - return $enterprise.enterpriseData.RootNode - } - $enterprise.enterpriseData.Nodes | Where-Object { ($_.Id -eq $node) -or ($_.DisplayName -eq $node) } | Select-Object -First 1 + Param ( + [string]$node + ) + $enterprise = getEnterprise + if ($node -eq $enterprise.loader.EnterpriseName) { + return $enterprise.enterpriseData.RootNode + } + $enterprise.enterpriseData.Nodes | Where-Object { ($_.Id -eq $node) -or ($_.DisplayName -eq $node) } | Select-Object -First 1 } function getMspEnterprise { - [Enterprise]$enterprise = getEnterprise - if ($enterprise.enterpriseData.EnterpriseLicense -and $enterprise.enterpriseData.EnterpriseLicense.LicenseStatus -like "msp*") { - return $enterprise - } - Write-Error -Message "Not a MSP (Managed Service Provider)" -ErrorAction Stop + [Enterprise]$enterprise = getEnterprise + if ($enterprise.enterpriseData.EnterpriseLicense -and $enterprise.enterpriseData.EnterpriseLicense.LicenseStatus -like "msp*") { + return $enterprise + } + Write-Error -Message "Not a MSP (Managed Service Provider)" -ErrorAction Stop } diff --git a/PowerCommander/Enterprise.types.ps1xml b/PowerCommander/Enterprise.types.ps1xml index 0aca90e..3bf0b7b 100644 --- a/PowerCommander/Enterprise.types.ps1xml +++ b/PowerCommander/Enterprise.types.ps1xml @@ -1,111 +1,111 @@ - + - - KeeperSecurity.Enterprise.EnterpriseUser - - - NodeName - - Get-KeeperNodeName $this.ParentNodeId - - - - + + KeeperSecurity.Enterprise.EnterpriseUser + + + NodeName + + Get-KeeperNodeName $this.ParentNodeId + + + + - - KeeperSecurity.Enterprise.EnterpriseNode - - - ParentNodeName - - Get-KeeperNodeName $this.ParentNodeId - - - - Provisioning - - $provisioning = @() - if ($this.BridgeId -gt 0) { - $provisioning += "Bridge" - } - if ($this.ScimId -gt 0) { - $provisioning += "SCIM" - } - if ($this.SsoServiceProviderIds -and $this.SsoServiceProviderIds.Length -gt 0) { - $provisioning += "SSO" - } - $provisioning - - - - + + KeeperSecurity.Enterprise.EnterpriseNode + + + ParentNodeName + + Get-KeeperNodeName $this.ParentNodeId + + + + Provisioning + + $provisioning = @() + if ($this.BridgeId -gt 0) { + $provisioning += "Bridge" + } + if ($this.ScimId -gt 0) { + $provisioning += "SCIM" + } + if ($this.SsoServiceProviderIds -and $this.SsoServiceProviderIds.Length -gt 0) { + $provisioning += "SSO" + } + $provisioning + + + + - - KeeperSecurity.Enterprise.EnterpriseTeam - - - NodeName - - Get-KeeperNodeName $this.ParentNodeId - - - - + + KeeperSecurity.Enterprise.EnterpriseTeam + + + NodeName + + Get-KeeperNodeName $this.ParentNodeId + + + + - - KeeperSecurity.Enterprise.EnterpriseManagedCompany - - - PlanName - - Switch ($this.ProductId) { - "business" {"Business"} - "businessPlus" {"Business Plus"} - "enterprise" {"Enterprise"} - "enterprisePlus" {"Enterprise Plus"} - Default {$this.ProductId} - } - - + + KeeperSecurity.Enterprise.EnterpriseManagedCompany + + + PlanName + + Switch ($this.ProductId) { + "business" {"Business"} + "businessPlus" {"Business Plus"} + "enterprise" {"Enterprise"} + "enterprisePlus" {"Enterprise Plus"} + Default {$this.ProductId} + } + + - - FilePlanName - - Switch ($this.FilePlanType) { - "STORAGE_100GB" {"100GB"} - "STORAGE_1000GB" {"1TB"} - "STORAGE_10000GB" {"10TB"} - Default {$this.FilePlanType} - } - - + + FilePlanName + + Switch ($this.FilePlanType) { + "STORAGE_100GB" {"100GB"} + "STORAGE_1000GB" {"1TB"} + "STORAGE_10000GB" {"10TB"} + Default {$this.FilePlanType} + } + + - - ParentNodeName - - Get-KeeperNodeName $this.ParentNodeId - - - - PlanId - ProductId - - - CompanyId - EnterpriseId - - - CompanyName - EnterpriseName - - - Active - NumberOfUsers - - - Allocated - NumberOfSeats - - - + + ParentNodeName + + Get-KeeperNodeName $this.ParentNodeId + + + + PlanId + ProductId + + + CompanyId + EnterpriseId + + + CompanyName + EnterpriseName + + + Active + NumberOfUsers + + + Allocated + NumberOfSeats + + + \ No newline at end of file diff --git a/PowerCommander/FolderCommands.ps1 b/PowerCommander/FolderCommands.ps1 index d10a4b2..d6b01f0 100644 --- a/PowerCommander/FolderCommands.ps1 +++ b/PowerCommander/FolderCommands.ps1 @@ -1,7 +1,7 @@ -#requires -Version 5.0 +#requires -Version 5.1 function Add-KeeperFolder { -<# + <# .Synopsis Creates a Keeper folder. @@ -28,56 +28,56 @@ function Add-KeeperFolder { #> - [CmdletBinding(DefaultParameterSetName = 'Default')] - Param ( - [Parameter(Position = 0, Mandatory = $true)][string] $Name, - [Parameter()][string] $ParentFolderUid, - [Parameter()][switch] $Shared, - [Parameter()][switch] $CanEdit, - [Parameter()][switch] $CanShare, - [Parameter()][switch] $ManageUsers, - [Parameter()][switch] $ManageRecords - ) - - [KeeperSecurity.Vault.VaultOnline]$vault = getVault - - $objs = Get-KeeperChildItems -ObjectType Folder | Where-Object Name -eq $Name - if ($objs.Length -gt 0 ) { + [CmdletBinding(DefaultParameterSetName = 'Default')] + Param ( + [Parameter(Position = 0, Mandatory = $true)][string] $Name, + [Parameter()][string] $ParentFolderUid, + [Parameter()][switch] $Shared, + [Parameter()][switch] $CanEdit, + [Parameter()][switch] $CanShare, + [Parameter()][switch] $ManageUsers, + [Parameter()][switch] $ManageRecords + ) + + [KeeperSecurity.Vault.VaultOnline]$vault = getVault + + $objs = Get-KeeperChildItem -ObjectType Folder | Where-Object Name -eq $Name + if ($objs.Length -gt 0 ) { Write-Error -Message "Folder `"$Name`" already exists" -ErrorAction Stop - } - - $parentUid = $Script:CurrentFolder - if ($ParentFolderUid) { - [KeeperSecurity.Vault.FolderNode]$folder = $null - if (-not $vault.TryGetFolder($ParentFolderUid, [ref]$folder)) { - Write-Error -Message "Folder UID `"$ParentFolderUid`" does not exist" -ErrorAction Stop - } - $parentUid = $ParentFolderUid - } - - $options = $null - if ($Shared.IsPresent) { - $options = New-Object KeeperSecurity.Vault.SharedFolderOptions - if ($CanEdit.IsPresent) { - $options.CanEdit = $true - } - if ($CanShare.IsPresent) { - $options.CanShare = $true - } - if ($ManageUsers.IsPresent) { - $options.ManageUsers = $true - } - if ($ManageRecords.IsPresent) { - $options.ManageRecords = $true - } - - } - $vault.CreateFolder($Name, $parentUid, $options).GetAwaiter().GetResult() + } + + $parentUid = $Script:CurrentFolder + if ($ParentFolderUid) { + [KeeperSecurity.Vault.FolderNode]$folder = $null + if (-not $vault.TryGetFolder($ParentFolderUid, [ref]$folder)) { + Write-Error -Message "Folder UID `"$ParentFolderUid`" does not exist" -ErrorAction Stop + } + $parentUid = $ParentFolderUid + } + + $options = $null + if ($Shared.IsPresent) { + $options = New-Object KeeperSecurity.Vault.SharedFolderOptions + if ($CanEdit.IsPresent) { + $options.CanEdit = $true + } + if ($CanShare.IsPresent) { + $options.CanShare = $true + } + if ($ManageUsers.IsPresent) { + $options.ManageUsers = $true + } + if ($ManageRecords.IsPresent) { + $options.ManageRecords = $true + } + + } + $vault.CreateFolder($Name, $parentUid, $options).GetAwaiter().GetResult() } New-Alias -Name kmkdir -Value Add-KeeperFolder function Remove-KeeperFolder { -<# + <# .Synopsis Delete Keeper folder. @@ -85,29 +85,30 @@ function Remove-KeeperFolder { Folder name or Folder UID #> - [CmdletBinding(DefaultParameterSetName = 'Default')] - Param ( - [Parameter(Position = 0, Mandatory = $true)][string] $Name - ) - - [KeeperSecurity.Vault.VaultOnline]$vault = getVault - - $folderUid = $null - $folder = $null - if ($vault.TryGetFolder($Name, [ref]$folder)) { - $folderUid = $folder.FolderUid - } - if (-not $folderUid) { - $objs = Get-KeeperChildItems -ObjectType Folder | Where-Object Name -eq $Name - if (-not $objs) { - Write-Error -Message "Folder `"$Name`" does not exist" -ErrorAction Stop - } - if ($objs.Length -gt 1) { - Write-Error -Message "There are more than one folders with name `"$Name`". Use Folder UID do delete the correct one." -ErrorAction Stop - } - $folderUid = $objs[0].Uid - } - - $vault.DeleteFolder($folderUid).GetAwaiter().GetResult() | Out-Null + [CmdletBinding(DefaultParameterSetName = 'Default')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] + Param ( + [Parameter(Position = 0, Mandatory = $true)][string] $Name + ) + + [KeeperSecurity.Vault.VaultOnline]$vault = getVault + + $folderUid = $null + $folder = $null + if ($vault.TryGetFolder($Name, [ref]$folder)) { + $folderUid = $folder.FolderUid + } + if (-not $folderUid) { + $objs = Get-KeeperChildItem -ObjectType Folder | Where-Object Name -eq $Name + if (-not $objs) { + Write-Error -Message "Folder `"$Name`" does not exist" -ErrorAction Stop + } + if ($objs.Length -gt 1) { + Write-Error -Message "There are more than one folders with name `"$Name`". Use Folder UID do delete the correct one." -ErrorAction Stop + } + $folderUid = $objs[0].Uid + } + + $vault.DeleteFolder($folderUid).GetAwaiter().GetResult() | Out-Null } New-Alias -Name krmdir -Value Remove-KeeperFolder diff --git a/PowerCommander/LICENSE b/PowerCommander/LICENSE new file mode 100644 index 0000000..e9e07dd --- /dev/null +++ b/PowerCommander/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Keeper Security Inc. + +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. \ No newline at end of file diff --git a/PowerCommander/Library.format.ps1xml b/PowerCommander/Library.format.ps1xml index 17dc462..afaea02 100644 --- a/PowerCommander/Library.format.ps1xml +++ b/PowerCommander/Library.format.ps1xml @@ -1,529 +1,529 @@ - + - - - KeeperSecurity.Authentication.AuthCommon_TableView - - KeeperSecurity.Authentication.AuthCommon - - - - - - - - - - - - - - - - - - - Username - - - $_.AuthContext.IsEnterpriseAdmin - - - $_.Endpoint.Server - - - - - - - - - KeeperSecurity.Authentication.AuthCommon_ListView - - KeeperSecurity.Authentication.AuthCommon - - - - - - - Username - - - - $_.AuthContext.IsEnterpriseAdmin - - - - $_.Endpoint.Server - - - - ConfigurationInfo - - - - - - + + + KeeperSecurity.Authentication.AuthCommon_TableView + + KeeperSecurity.Authentication.AuthCommon + + + + + + + + + + + + + + + + + + + Username + + + $_.AuthContext.IsEnterpriseAdmin + + + $_.Endpoint.Server + + + + + + - - KeeperSecurity.Vault.VaultOnline_TableView - - KeeperSecurity.Vault.VaultOnline - - - - - - - - - Right - - - - Right - - - - Right - - - - - - - - $_.Auth.Username - - - RecordCount - - - SharedFolderCount - - - TeamCount - - - - - - + + KeeperSecurity.Authentication.AuthCommon_ListView + + KeeperSecurity.Authentication.AuthCommon + + + + + + + Username + + + + $_.AuthContext.IsEnterpriseAdmin + + + + $_.Endpoint.Server + + + + ConfigurationInfo + + + + + + - - KeeperSecurity.Vault.Vault_ListView - - KeeperSecurity.Vault.Vault - - - - - - - - $_.Auth.Username - - - - RecordCount - - - - SharedFolderCount - - - - TeamCount - - - - - - + + KeeperSecurity.Vault.VaultOnline_TableView + + KeeperSecurity.Vault.VaultOnline + + + + + + + + + Right + + + + Right + + + + Right + + + + + + + + $_.Auth.Username + + + RecordCount + + + SharedFolderCount + + + TeamCount + + + + + + - - KeeperSecurity.Vault.KeeperRecord_TableView - - KeeperSecurity.Vault.PasswordRecord - KeeperSecurity.Vault.TypedRecord - KeeperSecurity.Vault.FileRecord - - - - - - - - - 6 - - - - - - - - - - - Uid - - - TypeName - - - Title - - - PublicInformation - - - - - - + + KeeperSecurity.Vault.Vault_ListView + + KeeperSecurity.Vault.Vault + + + + + + + + $_.Auth.Username + + + + RecordCount + + + + SharedFolderCount + + + + TeamCount + + + + + + - - KeeperSecurity.Vault.KeeperRecord_ListView - - KeeperSecurity.Vault.FileRecord - KeeperSecurity.Vault.TypedRecord - KeeperSecurity.Vault.PasswordRecord - - - + + KeeperSecurity.Vault.KeeperRecord_TableView + + KeeperSecurity.Vault.PasswordRecord + KeeperSecurity.Vault.TypedRecord + KeeperSecurity.Vault.FileRecord + + + + + + + + + 6 + + + + + + + + + + + Uid + + + TypeName + + + Title + + + PublicInformation + + + + + + - - - - - Uid - - - - TypeName - - - Title - - - Notes - - - + + KeeperSecurity.Vault.KeeperRecord_ListView + + KeeperSecurity.Vault.FileRecord + KeeperSecurity.Vault.TypedRecord + KeeperSecurity.Vault.PasswordRecord + + + - - - KeeperSecurity.Vault.FileRecord - - - - - Uid - - - - TypeName - - - Title - - - Notes - - - Name - - - MimeType - - - FileSize - - - - - - KeeperSecurity.Vault.TypedRecord - - - - - Uid - - - - TypeName - - - Title - - - Notes - - - MainFields - - - CustomFields - - - - AttachmentsInfo - - - + + + + + Uid + + + + TypeName + + + Title + + + Notes + + + - - - KeeperSecurity.Vault.PasswordRecord - - - - - Uid - - - - TypeName - - - Title - - - Login - - - - DisplayedPassword - - - - Link - - - Notes - - - - CustomFields - - - - AttachmentsInfo - - - - - - + + + KeeperSecurity.Vault.FileRecord + + + + + Uid + + + + TypeName + + + Title + + + Notes + + + Name + + + MimeType + + + FileSize + + + + + + KeeperSecurity.Vault.TypedRecord + + + + + Uid + + + + TypeName + + + Title + + + Notes + + + MainFields + + + CustomFields + + + + AttachmentsInfo + + + - - KeeperSecurity.Vault.SharedFolder_TableView - - KeeperSecurity.Vault.SharedFolder - - - - - - - - - - - Right - - - Right - - - - - - - Uid - - - Name - - - DefaultManageRecords - - - DefaultManageUsers - - - DefaultCanEdit - - - DefaultCanShare - - - UserCount - - - RecordCount - - - - - - + + + KeeperSecurity.Vault.PasswordRecord + + + + + Uid + + + + TypeName + + + Title + + + Login + + + + DisplayedPassword + + + + Link + + + Notes + + + + CustomFields + + + + AttachmentsInfo + + + + + + - - KeeperSecurity.Vault.SharedFolder_ListView - - KeeperSecurity.Vault.SharedFolder - - - - - - - Uid - - - Name - - - DefaultManageRecords - - - DefaultManageUsers - - - DefaultCanEdit - - - DefaultCanShare - - - Users - - - RecordCount - - - - - - + + KeeperSecurity.Vault.SharedFolder_TableView + + KeeperSecurity.Vault.SharedFolder + + + + + + + + + + + Right + + + Right + + + + + + + Uid + + + Name + + + DefaultManageRecords + + + DefaultManageUsers + + + DefaultCanEdit + + + DefaultCanShare + + + UserCount + + + RecordCount + + + + + + - - KeeperSecurity.Vault.FolderNode_TableView - - KeeperSecurity.Vault.FolderNode - - - - - - - - - - - - - - - FolderUid - - - Name - - - FolderType - - - ParentUid - - - SubfolderCount - - - RecordCount - - - - - - + + KeeperSecurity.Vault.SharedFolder_ListView + + KeeperSecurity.Vault.SharedFolder + + + + + + + Uid + + + Name + + + DefaultManageRecords + + + DefaultManageUsers + + + DefaultCanEdit + + + DefaultCanShare + + + Users + + + RecordCount + + + + + + - - KeeperSecurity.Vault.RecordSharePermissions_TableView - - KeeperSecurity.Vault.RecordSharePermissions - - - - - - - - Right - - - Right - - - - - - - - RecordUid - - - RecordTitle - - - Owner - - - Users - - - Folders - - - - - - + + KeeperSecurity.Vault.FolderNode_TableView + + KeeperSecurity.Vault.FolderNode + + + + + + + + + + + + + + + FolderUid + + + Name + + + FolderType + + + ParentUid + + + SubfolderCount + + + RecordCount + + + + + + - - KeeperSecurity.Vault.RecordSharePermissions_ListView - - KeeperSecurity.Vault.RecordSharePermissions - - - - - - - RecordUid - - - RecordTitle - - - Owner - - - UserShares - - - FolderShares - - - - - - + + KeeperSecurity.Vault.RecordSharePermissions_TableView + + KeeperSecurity.Vault.RecordSharePermissions + + + + + + + + Right + + + Right + + + + + + + + RecordUid + + + RecordTitle + + + Owner + + + Users + + + Folders + + + + + + - + + KeeperSecurity.Vault.RecordSharePermissions_ListView + + KeeperSecurity.Vault.RecordSharePermissions + + + + + + + RecordUid + + + RecordTitle + + + Owner + + + UserShares + + + FolderShares + + + + + + + + \ No newline at end of file diff --git a/PowerCommander/Library.types.ps1xml b/PowerCommander/Library.types.ps1xml index e885709..071a50d 100644 --- a/PowerCommander/Library.types.ps1xml +++ b/PowerCommander/Library.types.ps1xml @@ -1,466 +1,473 @@ - + - - KeeperSecurity.Authentication.AuthCommon - - - ConfigurationInfo - - $conf = @() - if ($this.Storage -is [KeeperSecurity.Configuration.JsonConfigurationStorage]) { - if ($this.Storage.Cache.Loader -is [KeeperSecurity.Configuration.JsonConfigurationFileLoader]) { - $conf += $this.Storage.Cache.Loader.FilePath - } - } - $conf -join "`n" - - - - - - - KeeperSecurity.Vault.FileRecord - - - TypeName - file - - - PublicInformation - - [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($this) - - - - + + KeeperSecurity.Authentication.AuthCommon + + + ConfigurationInfo + + $conf = @() + if ($this.Storage -is [KeeperSecurity.Configuration.JsonConfigurationStorage]) { + if ($this.Storage.Cache.Loader -is + [KeeperSecurity.Configuration.JsonConfigurationFileLoader]) { + $conf += $this.Storage.Cache.Loader.FilePath + } + } + $conf -join "`n" + + + + - - KeeperSecurity.Vault.TypedRecord - - - PublicInformation - - [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($this) - - - - MainFields - - $values = @() - foreach ($f in $this.Fields) { - if ($f.FieldName -ne 'fileRef') { - $name = [KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldName($f) - if (Get-KeeperPasswordVisible) { - $value = "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldValues($f))" - } else { - $value = "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldInformation($f))" - } - $values += , @($name, $value) - } - } - $m = 16 - foreach ($p in $values) { - if ($p[0].Length -gt $m) { - $m = $p[0].Length - } - } - $ff = @() - $m = -$m - foreach ($p in $values) { - $ff += "{0, $m} | {1}" -f $p[0], $p[1] - } - $ff -join "`n" - - - - CustomFields - - $values = @() - foreach ($f in $this.Custom) { - if ($f.FieldName -ne 'fileRef') { - $name = [KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldName($f) - if (Get-KeeperPasswordVisible) { - $value = "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldValues($f))" - } else { - $value = "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldInformation($f))" - } - $values += , @($name, $value) - } - } - $m = 16 - foreach ($p in $values) { - if ($p[0].Length -gt $m) { - $m = $p[0].Length - } - } - $ff = @() - $m = -$m - foreach ($p in $values) { - $ff += "{0, $m} | {1}" -f $p[0], $p[1] - } - $ff -join "`n" - - - - AttachmentsInfo - - $private:vault = $Script:Vault - if ($vault) { - foreach ($a in $vault.RecordAttachments($this)) { - $af += "$($a.Id) | Name=$(if ($a.Title) {$a.Title} else {$a.Name}) ; Size=$($a.Size)" - } - } - $af -join "`n" - - - - + + KeeperSecurity.Vault.FileRecord + + + TypeName + file + + + PublicInformation + + [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($this) + + + + - - KeeperSecurity.Vault.PasswordRecord - - - TypeName - legacy - - - DisplayedPassword - - if (Get-KeeperPasswordVisible) { - $this.Password - } else { - if ($this.Password) { - "$([char]0x2022)$([char]0x2022)$([char]0x2022)$([char]0x2022)$([char]0x2022)$([char]0x2022)" - } - } - - - - CustomFields - - if ($this.Custom) { - $values = @() - foreach ($c in $this.Custom) { - $name = $c.Name - $value = $c.Value - $values += , @($name, $value) - } - $m = 16 - foreach ($p in $values) { - if ($p[0].Length -gt $m) { - $m = $p[0].Length - } - } - $ff = @() - $m = -$m - foreach ($p in $values) { - $ff += "{0, $m} | {1}" -f $p[0], $p[1] - } - $ff -join "`n" - } - - - - AttachmentsInfo - - if ($this.Attachments) { - $af = @() - foreach ($a in $this.Attachments) { - $af += "$($a.Id) | Name=$(if ($a.Title) {$a.Title} else {$a.Name}) ; Size=$($a.Size)" - } - $af -join "`r`n" - } - - - - + + KeeperSecurity.Vault.TypedRecord + + + PublicInformation + + [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($this) + + + + MainFields + + $values = @() + foreach ($f in $this.Fields) { + if ($f.FieldName -ne 'fileRef') { + $name = [KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldName($f) + if (Get-KeeperPasswordVisible) { + $value = "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldValues($f))" + } else { + $value = + "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldInformation($f))" + } + $values += , @($name, $value) + } + } + $m = 16 + foreach ($p in $values) { + if ($p[0].Length -gt $m) { + $m = $p[0].Length + } + } + $ff = @() + $m = -$m + foreach ($p in $values) { + $ff += "{0, $m} | {1}" -f $p[0], $p[1] + } + $ff -join "`n" + + + + CustomFields + + $values = @() + foreach ($f in $this.Custom) { + if ($f.FieldName -ne 'fileRef') { + $name = [KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldName($f) + if (Get-KeeperPasswordVisible) { + $value = "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldValues($f))" + } else { + $value = + "$([KeeperSecurity.Utils.RecordTypesUtils]::GetTypedFieldInformation($f))" + } + $values += , @($name, $value) + } + } + $m = 16 + foreach ($p in $values) { + if ($p[0].Length -gt $m) { + $m = $p[0].Length + } + } + $ff = @() + $m = -$m + foreach ($p in $values) { + $ff += "{0, $m} | {1}" -f $p[0], $p[1] + } + $ff -join "`n" + + + + AttachmentsInfo + + $private:vault = $Script:Vault + if ($vault) { + foreach ($a in $vault.RecordAttachments($this)) { + $af += "$($a.Id) | Name=$(if ($a.Title) {$a.Title} else {$a.Name}) ; + Size=$($a.Size)" + } + } + $af -join "`n" + + + + - - KeeperSecurity.Vault.SharedFolder - - - Users - - $ul = @() - foreach ($up in $this.UsersPermissions) { - $ul += "$($up.UserType): $($up.Name) ($($up.ShareStatus))" - } - $ul -join "`r`n" - - - - UserCount - $this.UsersPermissions.Count - - - RecordCount - $this.RecordPermissions.Count - - - + + KeeperSecurity.Vault.PasswordRecord + + + TypeName + legacy + + + DisplayedPassword + + if (Get-KeeperPasswordVisible) { + $this.Password + } else { + if ($this.Password) { + "$([char]0x2022)$([char]0x2022)$([char]0x2022)$([char]0x2022)$([char]0x2022)$([char]0x2022)" + } + } + + + + CustomFields + + if ($this.Custom) { + $values = @() + foreach ($c in $this.Custom) { + $name = $c.Name + $value = $c.Value + $values += , @($name, $value) + } + $m = 16 + foreach ($p in $values) { + if ($p[0].Length -gt $m) { + $m = $p[0].Length + } + } + $ff = @() + $m = -$m + foreach ($p in $values) { + $ff += "{0, $m} | {1}" -f $p[0], $p[1] + } + $ff -join "`n" + } + + + + AttachmentsInfo + + if ($this.Attachments) { + $af = @() + foreach ($a in $this.Attachments) { + $af += "$($a.Id) | Name=$(if ($a.Title) {$a.Title} else {$a.Name}) ; + Size=$($a.Size)" + } + $af -join "`r`n" + } + + + + - - KeeperSecurity.Vault.Team - - - PSStandardMembers + + KeeperSecurity.Vault.SharedFolder - - DefaultDisplayPropertySet - - TeamUid - Name - RestrictEdit - RestrictShare - RestrictView - - + + Users + + $ul = @() + foreach ($up in $this.UsersPermissions) { + $ul += "$($up.UserType): $($up.Name) ($($up.ShareStatus))" + } + $ul -join "`r`n" + + + + UserCount + $this.UsersPermissions.Count + + + RecordCount + $this.RecordPermissions.Count + - - - + - - KeeperSecurity.Vault.SharedFolderPermission - - - Name - - if ($this.UserType -eq [KeeperSecurity.Vault.UserType]::Team) { - Get-KeeperObject $this.UserId -ObjectType Team -PropertyName Name - } else { - $this.UserId - } - - - - ShareStatus - - if ($this.ManageRecords -and $this.ManageUsers) { - $status = "Can Manage Users & Records" - } elseif ($this.ManageRecords) { - $status = "Can Manage Records" - } elseif ($this.ManageUsers) { - $status = "Can Manage Users" - } else { - $status = "No User Permission" - } - $status - - + + KeeperSecurity.Vault.Team + + + PSStandardMembers + + + DefaultDisplayPropertySet + + TeamUid + Name + RestrictEdit + RestrictShare + RestrictView + + + + + + - - PSStandardMembers + + KeeperSecurity.Vault.SharedFolderPermission - - DefaultDisplayPropertySet - - UserType - Name - ManageRecords - ManageUsers - - + + Name + + if ($this.UserType -eq [KeeperSecurity.Vault.UserType]::Team) { + Get-KeeperObject $this.UserId -ObjectType Team -PropertyName Name + } else { + $this.UserId + } + + + + ShareStatus + + if ($this.ManageRecords -and $this.ManageUsers) { + $status = "Can Manage Users & Records" + } elseif ($this.ManageRecords) { + $status = "Can Manage Records" + } elseif ($this.ManageUsers) { + $status = "Can Manage Users" + } else { + $status = "No User Permission" + } + $status + + + + + PSStandardMembers + + + DefaultDisplayPropertySet + + UserType + Name + ManageRecords + ManageUsers + + + + - - - + - - KeeperSecurity.Vault.SharedFolderRecord - - - RecordTitle - - Get-KeeperObject $this.RecordUid -ObjectType Record -PropertyName Title - - - - PSStandardMembers + + KeeperSecurity.Vault.SharedFolderRecord - - DefaultDisplayPropertySet - - RecordUid - RecordTitle - CanShare - CanEdit - - + + RecordTitle + + Get-KeeperObject $this.RecordUid -ObjectType Record -PropertyName Title + + + + PSStandardMembers + + + DefaultDisplayPropertySet + + RecordUid + RecordTitle + CanShare + CanEdit + + + + - - - + - - KeeperSecurity.Vault.FolderNode - - - RecordCount - - $this.Records.Count - - - - SubfolderCount - - $this.Subfolders.Count - - - - PSStandardMembers + + KeeperSecurity.Vault.FolderNode - - DefaultDisplayPropertySet - - FolderUid - Name - FolderType - ParentUid - SharedFolderUid - Subfolders - Records - SubfolderCount - RecordCount - - + + RecordCount + + $this.Records.Count + + + + SubfolderCount + + $this.Subfolders.Count + + + + PSStandardMembers + + + DefaultDisplayPropertySet + + FolderUid + Name + FolderType + ParentUid + SharedFolderUid + Subfolders + Records + SubfolderCount + RecordCount + + + + - - - + - - KeeperSecurity.Vault.RecordSharePermissions - - - RecordTitle - - (Get-KeeperObject -Uid $this.RecordUid -ObjectType Record).Title - - - - + + KeeperSecurity.Vault.RecordSharePermissions + + + RecordTitle + + (Get-KeeperObject -Uid $this.RecordUid -ObjectType Record).Title + + + + - - KeeperSecurity.Vault.UserRecordPermissions - - - ShareStatus - - if ($this.Owner) { - "Owner" - } elseif ($this.AwaitingApproval) { - "Awaiting Approval" - } elseif ($this.CanShare -and $this.CanEdit) { - "Can Edit & Share" - } elseif ($this.CanShare) { - "Can Share" - } elseif ($this.CanEdit) { - "Can Edit" - } else { - "Read Only" - } - - - - PSStandardMembers + + KeeperSecurity.Vault.UserRecordPermissions - - DefaultDisplayPropertySet - - Username - ShareStatus - - + + ShareStatus + + if ($this.Owner) { + "Owner" + } elseif ($this.AwaitingApproval) { + "Awaiting Approval" + } elseif ($this.CanShare -and $this.CanEdit) { + "Can Edit & Share" + } elseif ($this.CanShare) { + "Can Share" + } elseif ($this.CanEdit) { + "Can Edit" + } else { + "Read Only" + } + + + + PSStandardMembers + + + DefaultDisplayPropertySet + + Username + ShareStatus + + + + - - - + - - KeeperSecurity.Vault.SharedFolderRecordPermissions - - - ShareStatus - - if ($this.CanShare -and $this.CanEdit) { - "Can Edit & Share" - } elseif ($this.CanShare) { - "Can Share" - } elseif ($this.CanEdit) { - "Can Edit" - } else { - "Read Only" - } - - - - SharedFolderName - - (Get-KeeperObject -Uid $this.SharedFolderUid -ObjectType SharedFolder).Name - - - - PSStandardMembers + + KeeperSecurity.Vault.SharedFolderRecordPermissions - - DefaultDisplayPropertySet - - SharedFolderUid - SharedFolderName - ShareStatus - - + + ShareStatus + + if ($this.CanShare -and $this.CanEdit) { + "Can Edit & Share" + } elseif ($this.CanShare) { + "Can Share" + } elseif ($this.CanEdit) { + "Can Edit" + } else { + "Read Only" + } + + + + SharedFolderName + + (Get-KeeperObject -Uid $this.SharedFolderUid -ObjectType SharedFolder).Name + + + + PSStandardMembers + + + DefaultDisplayPropertySet + + SharedFolderUid + SharedFolderName + ShareStatus + + + + - - - + - - KeeperSecurity.Vault.RecordSharePermissions - - - Owner - - $this.UserPermissions | Where-Object { $_.Owner } | Select-Object -ExpandProperty Username - - - - Users - - ($this.UserPermissions | Where-Object { -not $_.Owner }).Count - - - - Folders - - $this.SharedFolderPermissions.Count - - - - UserShares - - $shares = @() - foreach($up in $this.UserPermissions) { - if ($up.Owner) { - continue - } - $shares += "$($up.Username) ($($up.ShareStatus))" - } - $shares -join "`r`n" - - - - FolderShares - - $shares = @() - foreach($Sp in $this.SharedFolderPermissions) { - $shares += "$($sp.SharedFolderName)[$($sp.SharedFolderUid)] ($($sp.ShareStatus))" - } - $shares -join "`r`n" - - - - + + KeeperSecurity.Vault.RecordSharePermissions + + + Owner + + $this.UserPermissions | Where-Object { $_.Owner } | Select-Object + -ExpandProperty Username + + + + Users + + ($this.UserPermissions | Where-Object { -not $_.Owner }).Count + + + + Folders + + $this.SharedFolderPermissions.Count + + + + UserShares + + $shares = @() + foreach($up in $this.UserPermissions) { + if ($up.Owner) { + continue + } + $shares += "$($up.Username) ($($up.ShareStatus))" + } + $shares -join "`r`n" + + + + FolderShares + + $shares = @() + foreach($Sp in $this.SharedFolderPermissions) { + $shares += "$($sp.SharedFolderName)[$($sp.SharedFolderUid)] + ($($sp.ShareStatus))" + } + $shares -join "`r`n" + + + + \ No newline at end of file diff --git a/PowerCommander/PowerCommander.format.ps1xml b/PowerCommander/PowerCommander.format.ps1xml index f06d33f..4eb24c3 100644 --- a/PowerCommander/PowerCommander.format.ps1xml +++ b/PowerCommander/PowerCommander.format.ps1xml @@ -1,344 +1,344 @@ - - - KeeperEntries - - KeeperSecurity.Commander.FolderEntry - KeeperSecurity.Commander.RecordEntry - - - - FlatKeeperEntries - - KeeperSecurity.Commander.FolderEntryFlat - KeeperSecurity.Commander.RecordEntryFlat - - - + + + KeeperEntries + + KeeperSecurity.Commander.FolderEntry + KeeperSecurity.Commander.RecordEntry + + + + FlatKeeperEntries + + KeeperSecurity.Commander.FolderEntryFlat + KeeperSecurity.Commander.RecordEntryFlat + + + - - - KeeperEntries-GroupingFormat - - - - - - 4 - - Vault Folder: - - - $_.OwnerFolder - - - - - - - - - - - + + + KeeperEntries-GroupingFormat + + + + + + 4 + + Vault Folder: + + + $_.OwnerFolder + + + + + + + + + + + - - - KeeperSecurity.Commander.FolderInfo.Table - - KeeperSecurity.Commander.FolderInfo - - - - - - - - Path - - - - - - - - KeeperSecurity.Commander.FolderInfo.List - - KeeperSecurity.Commander.FolderInfo - - - - - - - Path - - - FolderType - - - Name - - - FolderUid - - - ParentUid - - - - - - - - - KeeperSecurity.Commander.Entries - - KeeperEntries - - - OwnerFolder - KeeperEntries-GroupingFormat - - - - - - 7 - - - - 24 - - - - - - - - Mode - - - Uid - - - Name - - - - - - - - - KeeperSecurity.Commander.Entries - - KeeperEntries - - - OwnerFolder - KeeperEntries-GroupingFormat - - - - - - KeeperSecurity.Commander.FolderEntry - - - - - FolderType - - - Name - - - Mode - - - - Uid - - - - - - KeeperSecurity.Commander.RecordEntry - - - - - 'Record' - - - - Name - - - Mode - - - Type - - - - PublicInformation - - - - Uid - - - - - - - + + + KeeperSecurity.Commander.FolderInfo.Table + + KeeperSecurity.Commander.FolderInfo + + + + + + + + Path + + + + + + + + KeeperSecurity.Commander.FolderInfo.List + + KeeperSecurity.Commander.FolderInfo + + + + + + + Path + + + FolderType + + + Name + + + FolderUid + + + ParentUid + + + + + + - - KeeperSecurity.Commander.FlatEntries - - FlatKeeperEntries - - - - - - 7 - - - - 24 - - - - - - - - Mode - - - Uid - - - Name - - - - - - + + KeeperSecurity.Commander.Entries + + KeeperEntries + + + OwnerFolder + KeeperEntries-GroupingFormat + + + + + + 7 + + + + 24 + + + + + + + + Mode + + + Uid + + + Name + + + + + + - - KeeperSecurity.Commander.FlatEntries - - FlatKeeperEntries - - - - - - KeeperSecurity.Commander.FolderEntryFlat - - - - - FolderType - - - Name - - - Mode - - - + + KeeperSecurity.Commander.Entries + + KeeperEntries + + OwnerFolder - - - - Uid - - - - - - KeeperSecurity.Commander.RecordEntryFlat - - - - - 'Record' - - - - Name - - - Mode - - - Login - - - - Link - - - - $_.OwnerFolder -join ', ' - - - - Uid - - - - - - - + KeeperEntries-GroupingFormat + + + + + + KeeperSecurity.Commander.FolderEntry + + + + + FolderType + + + Name + + + Mode + + + + Uid + + + + + + KeeperSecurity.Commander.RecordEntry + + + + + 'Record' + + + + Name + + + Mode + + + Type + + + + PublicInformation + + + + Uid + + + + + + + + + + KeeperSecurity.Commander.FlatEntries + + FlatKeeperEntries + + + + + + 7 + + + + 24 + + + + + + + + Mode + + + Uid + + + Name + + + + + + + + + KeeperSecurity.Commander.FlatEntries + + FlatKeeperEntries + + + + + + KeeperSecurity.Commander.FolderEntryFlat + + + + + FolderType + + + Name + + + Mode + + + + OwnerFolder + + + + Uid + + + + + + KeeperSecurity.Commander.RecordEntryFlat + + + + + 'Record' + + + + Name + + + Mode + + + Login + + + + Link + + + + $_.OwnerFolder -join ', ' + + + + Uid + + + + + + + - - TOTP.Codes - - TOTP.Codes - - - - - - - - - - - - - - - - - RecordTitle - - - TOTPCode - - - Elapsed - - - Left - - - - - - + + TOTP.Codes + + TOTP.Codes + + + + + + + + + + + + + + + + + RecordTitle + + + TOTPCode + + + Elapsed + + + Left + + + + + + - - + + \ No newline at end of file diff --git a/PowerCommander/PowerCommander.psd1 b/PowerCommander/PowerCommander.psd1 index 66c0c23..5b4dee9 100644 --- a/PowerCommander/PowerCommander.psd1 +++ b/PowerCommander/PowerCommander.psd1 @@ -7,109 +7,117 @@ # @{ + # Script module or binary module file associated with this manifest. + RootModule = 'PowerCommander.psm1' -# Script module or binary module file associated with this manifest. -RootModule = 'PowerCommander.psm1' + # Version number of this module. + ModuleVersion = '0.9.1' -# Version number of this module. -ModuleVersion = '1.0.0' + # Supported PSEditions + CompatiblePSEditions = @('Desktop') -# ID used to uniquely identify this module -GUID = 'aa8a313b-fdb6-41ea-9eed-b7441d7392a1' + # ID used to uniquely identify this module + GUID = 'aa8a313b-fdb6-41ea-9eed-b7441d7392a1' -# Author of this module -Author = 'Keeper Security Inc.' + # Author of this module + Author = 'Keeper Security Inc.' -# Company or vendor of this module -CompanyName = 'Keeper Security Inc.' + # Company or vendor of this module + CompanyName = 'Keeper Security Inc.' -# Copyright statement for this module -Copyright = '(c) 2022 Keeper Security Inc. All rights reserved.' + # Copyright statement for this module + Copyright = '(c) 2023 Keeper Security Inc. All rights reserved.' -# Description of the functionality provided by this module -# Description = '' + # Description of the functionality provided by this module + Description = 'PowerShell Commander' -# Minimum version of the Windows PowerShell engine required by this module -PowerShellVersion = '5.0' + # Minimum version of the Windows PowerShell engine required by this module + PowerShellVersion = '5.1' -# Name of the Windows PowerShell host required by this module -# PowerShellHostName = '' + # Name of the Windows PowerShell host required by this module + # PowerShellHostName = '' -# Minimum version of the Windows PowerShell host required by this module -# PowerShellHostVersion = '' + # Minimum version of the Windows PowerShell host required by this module + # PowerShellHostVersion = '' -# Minimum version of Microsoft .NET Framework required by this module -# DotNetFrameworkVersion = '' + # Minimum version of Microsoft .NET Framework required by this module + # DotNetFrameworkVersion = '' -# Minimum version of the common language runtime (CLR) required by this module -# CLRVersion = '' + # Minimum version of the common language runtime (CLR) required by this module + # CLRVersion = '' -# Processor architecture (None, X86, Amd64) required by this module -# ProcessorArchitecture = '' + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' -# Modules that must be imported into the global environment prior to importing this module -# RequiredModules = @() + # Modules that must be imported into the global environment prior to importing this module + # RequiredModules = @() -# Assemblies that must be loaded prior to importing this module -RequiredAssemblies = @('KeeperSdk.dll') + # Assemblies that must be loaded prior to importing this module + RequiredAssemblies = @('KeeperSdk.dll') -# Script files (.ps1) that are run in the caller's environment prior to importing this module. -# ScriptsToProcess = @() + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() -# Type files (.ps1xml) to be loaded when importing this module -TypesToProcess = @('PowerCommander.types.ps1xml', 'Library.types.ps1xml', 'Enterprise.types.ps1xml', - 'Record.types.ps1xml', 'SecretsManager.types.ps1xml') + # Type files (.ps1xml) to be loaded when importing this module + TypesToProcess = @('PowerCommander.types.ps1xml', 'Library.types.ps1xml', 'Enterprise.types.ps1xml', + 'Record.types.ps1xml', 'SecretsManager.types.ps1xml') -# Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = @('PowerCommander.format.ps1xml', 'Library.format.ps1xml', 'Enterprise.format.ps1xml', - 'Record.format.ps1xml', 'SecretsManager.format.ps1xml') + # Format files (.ps1xml) to be loaded when importing this module + FormatsToProcess = @('PowerCommander.format.ps1xml', 'Library.format.ps1xml', 'Enterprise.format.ps1xml', + 'Record.format.ps1xml', 'SecretsManager.format.ps1xml') -# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @('AuthCommands.ps1', 'VaultCommands.ps1', 'RecordCommands.ps1', 'SharedFolderCommands.ps1', - 'FolderCommands.ps1', 'Enterprise.ps1', 'Sharing.ps1', 'SecretsManager.ps1') + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + NestedModules = @('AuthCommands.ps1', 'VaultCommands.ps1', 'RecordCommands.ps1', 'SharedFolderCommands.ps1', + 'FolderCommands.ps1', 'Enterprise.ps1', 'Sharing.ps1', 'SecretsManager.ps1') -# Functions to export from this module -FunctionsToExport = @('Connect-Keeper', 'Sync-Keeper', 'Disconnect-Keeper', 'Get-KeeperLocation', 'Set-KeeperLocation', -'Get-KeeperChildItems', 'Get-KeeperObject', 'Get-KeeperRecords', 'Copy-KeeperToClipboard', 'Show-TwoFactorCode', -'Add-KeeperRecord', 'Remove-KeeperRecord', 'Move-RecordToFolder', 'Get-KeeperPasswordVisible', 'Set-KeeperPasswordVisible', -'Get-KeeperSharedFolders', 'Add-KeeperFolder', 'Remove-KeeperFolder', 'Get-KeeperRecordTypes', -'Get-KeeperEnterpriseUsers', 'Get-KeeperEnterpriseTeams', 'Sync-KeeperEnterprise', 'Get-KeeperEnterpriseNodes', 'Get-KeeperNodeName', -'Lock-KeeperEnterpriseUser', 'Unlock-KeeperEnterpriseUser', 'Move-KeeperEnterpriseUser', 'Remove-KeeperEnterpriseUser', -'Get-KeeperManagedCompanies', 'New-KeeperManagedCompany', 'Remove-KeeperManagedCompany','Edit-KeeperManagedCompany', 'Get-MspBillingReport', -'Get-KeeperEnterpriseTeamUsers', -# 'Test-Keeper', -'Show-KeeperRecordShares', 'Grant-KeeperRecordAccess', 'Revoke-KeeperRecordAccess', 'Grant-KeeperSharedFolderAccess', -'Revoke-KeeperSharedFolderAccess', 'Get-KeeperAvailableTeams', 'Get-KeeperSecretManagerApps', 'New-KeeperSecretManagerApp', -'Grant-KeeperSecretManagerFolderAccess', 'Revoke-KeeperSecretManagerFolderAccess', 'Add-KeeperSecretManagerClient', -'Remove-KeeperSecretManagerClient' -) + # Functions to export from this module + FunctionsToExport = @('Connect-Keeper', 'Sync-Keeper', 'Disconnect-Keeper', 'Get-KeeperLocation', 'Set-KeeperLocation', + 'Get-KeeperChildItem', 'Get-KeeperObject', 'Get-KeeperRecord', 'Copy-KeeperToClipboard', 'Show-TwoFactorCode', + 'Add-KeeperRecord', 'Remove-KeeperRecord', 'Move-RecordToFolder', 'Get-KeeperPasswordVisible', 'Set-KeeperPasswordVisible', + 'Get-KeeperSharedFolder', 'Add-KeeperFolder', 'Remove-KeeperFolder', 'Get-KeeperRecordType', + 'Get-KeeperEnterpriseUser', 'Get-KeeperEnterpriseTeam', 'Sync-KeeperEnterprise', 'Get-KeeperEnterpriseNode', 'Get-KeeperNodeName', + 'Lock-KeeperEnterpriseUser', 'Unlock-KeeperEnterpriseUser', 'Move-KeeperEnterpriseUser', 'Remove-KeeperEnterpriseUser', + 'Get-KeeperManagedCompany', 'New-KeeperManagedCompany', 'Remove-KeeperManagedCompany', 'Edit-KeeperManagedCompany', 'Get-MspBillingReport', + 'Get-KeeperEnterpriseTeamUser', + # 'Test-Keeper', + 'Show-KeeperRecordShare', 'Grant-KeeperRecordAccess', 'Revoke-KeeperRecordAccess', 'Grant-KeeperSharedFolderAccess', + 'Revoke-KeeperSharedFolderAccess', 'Get-KeeperAvailableTeam', 'Get-KeeperSecretManagerApp', 'Add-KeeperSecretManagerApp', + 'Grant-KeeperSecretManagerFolderAccess', 'Revoke-KeeperSecretManagerFolderAccess', 'Add-KeeperSecretManagerClient', + 'Remove-KeeperSecretManagerClient' + ) -# Cmdlets to export from this module -CmdletsToExport = @( ) + # Cmdlets to export from this module + CmdletsToExport = @( ) -# Variables to export from this module -# VariablesToExport = '*' + # Variables to export from this module + # VariablesToExport = '*' -# Aliases to export from this module -AliasesToExport = @('kc', 'ks', 'kq', 'kpwd', 'kcd', 'kdir', 'ko', 'kr', 'ksf', 'kcc', '2fa', 'kadd', 'kdel', 'kmv', 'kmkdir', 'krmdir', 'krti', - 'ked', 'keu', 'ken', 'ket', 'ketu', 'kmc', 'kamc', 'krmc', 'kemc', 'msp-license', 'lock-user', 'unlock-user', 'transfer-user', - 'delete-user', 'kshrsh', 'kshr', 'kushr', 'kshf', 'kushf', 'kat', - 'ksm', 'ksm-create', 'ksm-share', 'ksm-unshare', 'ksm-addclient', 'ksm-rmclient') + # Aliases to export from this module + AliasesToExport = @('kc', 'ks', 'kq', 'kpwd', 'kcd', 'kdir', 'ko', 'kr', 'ksf', 'kcc', '2fa', 'kadd', 'kdel', 'kmv', 'kmkdir', 'krmdir', 'krti', + 'ked', 'keu', 'ken', 'ket', 'ketu', 'kmc', 'kamc', 'krmc', 'kemc', 'msp-license', 'lock-user', 'unlock-user', 'transfer-user', + 'delete-user', 'kshrsh', 'kshr', 'kushr', 'kshf', 'kushf', 'kat', + 'ksm', 'ksm-create', 'ksm-share', 'ksm-unshare', 'ksm-addclient', 'ksm-rmclient') -# List of all modules packaged with this module -# ModuleList = @() + # List of all modules packaged with this module + # ModuleList = @() -# List of all files packaged with this module -# FileList = @() + # List of all files packaged with this module + # FileList = @() -# Private data to pass to the module specified in RootModule/ModuleToProcess -# PrivateData ='' + # Private data to pass to the module specified in RootModule/ModuleToProcess + PrivateData = @{ + PSData = @{ + Tags = @('PowerCommander','Keeper','Vault', 'PSEdition_Desktop') + LicenseUri = 'https://github.com/Keeper-Security/keeper-sdk-dotnet/blob/master/LICENSE' + ProjectUri = 'https://github.com/Keeper-Security/keeper-sdk-dotnet' + IconUri = 'https://keeper-email-images.s3.amazonaws.com/common/powershell.png' + ReleaseNotes = 'Initial PowerCommander release' + } + } -# HelpInfo URI of this module -# HelpInfoURI = '' - -# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. -# DefaultCommandPrefix = '' + # HelpInfo URI of this module + # HelpInfoURI = '' + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' } - diff --git a/PowerCommander/PowerCommander.psm1 b/PowerCommander/PowerCommander.psm1 index b11bbec..fbbba08 100644 --- a/PowerCommander/PowerCommander.psm1 +++ b/PowerCommander/PowerCommander.psm1 @@ -1,4 +1,4 @@ -#requires -Version 5.0 +#requires -Version 5.1 Class Enterprise { [KeeperSecurity.Enterprise.EnterpriseLoader] $loader @@ -8,10 +8,10 @@ Class Enterprise { } class KeeperContext { - [KeeperSecurity.Authentication.IAuth] $Auth = $null - [KeeperSecurity.Vault.VaultOnline] $Vault = $null - [string] $CurrentFolder = '' - [Enterprise] $Enterprise = $null + [KeeperSecurity.Authentication.IAuth] $Auth = $null + [KeeperSecurity.Vault.VaultOnline] $Vault = $null + [string] $CurrentFolder = '' + [Enterprise] $Enterprise = $null $AvailableTeams = $null $AvailableUsers = $null } @@ -21,37 +21,37 @@ New-Variable -Name Context -Option Constant -Scope 'Script' -Value (New-Object K Export-ModuleMember -Function Connect-Keeper, Sync-Keeper, Disconnect-Keeper Export-ModuleMember -Alias kc, ks, kq -Export-ModuleMember -Function Get-KeeperLocation, Set-KeeperLocation, Get-KeeperChildItems, - Get-KeeperObject +Export-ModuleMember -Function Get-KeeperLocation, Set-KeeperLocation, Get-KeeperChildItem, +Get-KeeperObject Export-ModuleMember -Alias kpwd, kcd, kdir, ko -Export-ModuleMember -Function Get-KeeperRecords, Copy-KeeperToClipboard, Show-TwoFactorCode, - Add-KeeperRecord, Remove-KeeperRecord, Move-RecordToFolder, - Get-KeeperPasswordVisible, Set-KeeperPasswordVisible, Get-KeeperRecordTypes +Export-ModuleMember -Function Get-KeeperRecord, Copy-KeeperToClipboard, Show-TwoFactorCode, +Add-KeeperRecord, Remove-KeeperRecord, Move-RecordToFolder, +Get-KeeperPasswordVisible, Set-KeeperPasswordVisible, Get-KeeperRecordType Export-ModuleMember -Alias kr, kcc, 2fa, kadd, kdel, kmv, krti -Export-ModuleMember -Function Get-KeeperSharedFolders +Export-ModuleMember -Function Get-KeeperSharedFolder Export-ModuleMember -Alias ksf Export-ModuleMember -Function Add-KeeperFolder, Remove-KeeperFolder Export-ModuleMember -Alias kmkdir, krmdir - -Export-ModuleMember -Function Sync-KeeperEnterprise, Get-KeeperEnterpriseUsers, Get-KeeperEnterpriseTeams, - Get-KeeperEnterpriseNodes, Get-KeeperNodeName, Lock-KeeperEnterpriseUser, - Unlock-KeeperEnterpriseUser, Move-KeeperEnterpriseUser, Remove-KeeperEnterpriseUser, - Get-KeeperEnterpriseTeamUsers + +Export-ModuleMember -Function Sync-KeeperEnterprise, Get-KeeperEnterpriseUser, Get-KeeperEnterpriseTeam, +Get-KeeperEnterpriseNode, Get-KeeperNodeName, Lock-KeeperEnterpriseUser, +Unlock-KeeperEnterpriseUser, Move-KeeperEnterpriseUser, Remove-KeeperEnterpriseUser, +Get-KeeperEnterpriseTeamUser Export-ModuleMember -Alias ked, keu, ket, ketu, ken, lock-user, unlock-user, transfer-user, delete-user -Export-ModuleMember -Function Get-KeeperManagedCompanies, New-KeeperManagedCompany, Remove-KeeperManagedCompany, - Edit-KeeperManagedCompany, Get-MspBillingReport +Export-ModuleMember -Function Get-KeeperManagedCompany, New-KeeperManagedCompany, Remove-KeeperManagedCompany, +Edit-KeeperManagedCompany, Get-MspBillingReport Export-ModuleMember -Alias kmc, kamc, krmc, kemc -Export-ModuleMember -Function Show-KeeperRecordShares, Grant-KeeperRecordAccess, Revoke-KeeperRecordAccess, - Grant-KeeperSharedFolderAccess, Revoke-KeeperSharedFolderAccess, Get-KeeperAvailableTeams +Export-ModuleMember -Function Show-KeeperRecordShare, Grant-KeeperRecordAccess, Revoke-KeeperRecordAccess, +Grant-KeeperSharedFolderAccess, Revoke-KeeperSharedFolderAccess, Get-KeeperAvailableTeam Export-ModuleMember -Alias kshrsh, kshr, kushr, kshf, kushf, kat -Export-ModuleMember -Function Get-KeeperSecretManagerApps, New-KeeperSecretManagerApp, Grant-KeeperSecretManagerFolderAccess, - Revoke-KeeperSecretManagerFolderAccess, Add-KeeperSecretManagerClient, Remove-KeeperSecretManagerClient +Export-ModuleMember -Function Get-KeeperSecretManagerApp, Add-KeeperSecretManagerApp, Grant-KeeperSecretManagerFolderAccess, +Revoke-KeeperSecretManagerFolderAccess, Add-KeeperSecretManagerClient, Remove-KeeperSecretManagerClient Export-ModuleMember -Alias ksm, ksm-create, ksm-share, ksm-unshare, ksm-addclient, ksm-rmclient # function Test-Keeper { diff --git a/PowerCommander/PowerCommander.tests.ps1 b/PowerCommander/PowerCommander.tests.ps1 index 322b28a..bc84f83 100644 --- a/PowerCommander/PowerCommander.tests.ps1 +++ b/PowerCommander/PowerCommander.tests.ps1 @@ -1,13 +1,13 @@ # # This is a PowerShell Unit Test file. -# You need a unit test framework such as Pester to run PowerShell Unit tests. +# You need a unit test framework such as Pester to run PowerShell Unit tests. # You can download Pester from https://go.microsoft.com/fwlink/?LinkID=534084 # Describe "Get-Function" { - Context "Function Exists" { - It "Should Return" { - - } - } + Context "Function Exists" { + It "Should Return" { + + } + } } \ No newline at end of file diff --git a/PowerCommander/PowerCommander.types.ps1xml b/PowerCommander/PowerCommander.types.ps1xml index 14551e1..967aaf7 100644 --- a/PowerCommander/PowerCommander.types.ps1xml +++ b/PowerCommander/PowerCommander.types.ps1xml @@ -1,48 +1,50 @@ - + - - KeeperSecurity.Commander.FolderEntry - - - Mode - - "f----$(if ($this.Shared) {'S'} else {'-'})" - - - - - - KeeperSecurity.Commander.RecordEntry - - - Mode - - "-r-$(if ($this.HasAttachments) {'A'} else {'-'})$(if ($this.Owner) {'O'} else {'-'})$(if ($this.Shared) {'S'} else {'-'})" - - - - + + KeeperSecurity.Commander.FolderEntry + + + Mode + + "f----$(if ($this.Shared) {'S'} else {'-'})" + + + + + + KeeperSecurity.Commander.RecordEntry + + + Mode + + "-r-$(if ($this.HasAttachments) {'A'} else {'-'})$(if ($this.Owner) {'O'} else + {'-'})$(if ($this.Shared) {'S'} else {'-'})" + + + + - - KeeperSecurity.Commander.FolderEntryFlat - - - Mode - - "f---$(if ($this.Shared) {'S'} else {'-'})-" - - - - - - KeeperSecurity.Commander.RecordEntryFlat - - - Mode - - "-r-$(if ($this.HasAttachments) {'A'} else {'-'})$(if ($this.Owner) {'O'} else {'-'})$(if ($this.Shared) {'S'} else {'-'})" - - - - + + KeeperSecurity.Commander.FolderEntryFlat + + + Mode + + "f---$(if ($this.Shared) {'S'} else {'-'})-" + + + + + + KeeperSecurity.Commander.RecordEntryFlat + + + Mode + + "-r-$(if ($this.HasAttachments) {'A'} else {'-'})$(if ($this.Owner) {'O'} else + {'-'})$(if ($this.Shared) {'S'} else {'-'})" + + + + \ No newline at end of file diff --git a/PowerCommander/README.md b/PowerCommander/README.md index c065ecd..c96fdd1 100644 --- a/PowerCommander/README.md +++ b/PowerCommander/README.md @@ -1,6 +1,10 @@ ### Reference Keeper Commander Powershell module +To install PowerCommander from PowerShell Gallery +``` +Install-Module PowerCommander +``` -To install the PowerCommander module copy PowerCommander\ directory to +To run the PowerCommander module from the source copy PowerCommander\ directory to * `%USERPROFILE%\Documents\WindowsPowerShell\Modules` Per User * `C:\Program Files\WindowsPowerShell\Modules` All users @@ -12,12 +16,12 @@ To install the PowerCommander module copy PowerCommander\ directory to | Disconnect-Keeper | | Logout and clear the data | Get-KeeperLocation | kpwd | Print current Keeper folder | Set-KeeperLocation | kcd | Change Keeper folder -| Get-KeeperChildItems | kdir | Display subfolder and record names in the current Keeper folder +| Get-KeeperChildItem | kdir | Display subfolder and record names in the current Keeper folder | Get-KeeperObject | ko | Get Keeper object by Uid -| Get-KeeperRecords | kr | Enumerate all records -| Get-KeeperSharedFolders | ksf | Enumerate all shared folders +| Get-KeeperRecord | kr | Enumerate all records +| Get-KeeperSharedFolder | ksf | Enumerate all shared folders | Add-KeeperRecord | kadd | Add/Modify Keeper record -| Get-KeeperRecordTypes | krti | Get Record Type Information +| Get-KeeperRecordType | krti | Get Record Type Information | Remove-KeeperRecord | kdel | Delete Keeper record | Move-RecordToFolder | kmv | Move records to Keeper folder | Add-KeeperFolder | kmkdir | Create Keeper folder @@ -28,41 +32,41 @@ To install the PowerCommander module copy PowerCommander\ directory to ### Sharing Cmdlets | Cmdlet name | Alias | Description |----------------------------------------|-------------|---------------------------- -| Show-KeeperRecordShares | kshrsh | Show a record sharing information +| Show-KeeperRecordShare | kshrsh | Show a record sharing information | Grant-KeeperRecordAccess | kshr | Share a record with user | Revoke-KeeperRecordAccess | kushr | Remove record share from user | Grant-KeeperSharedFolderAccess | kshf | Add a user or team to a shared foler | Revoke-KeeperSharedFolderAccess | kushf | Remove a user or team from a shared foler -| Get-KeeperAvailableTeams | kat | Get available teams +| Get-KeeperAvailableTeam | kat | Get available teams ### Enterprise Cmdlets | Cmdlet name | Alias | Description |----------------------------------------|-------------|---------------------------- | Sync-KeeperEnterprise | ked | Sync Keeper enterprise information -| Get-KeeperEnterpriseNodes | ken | Enumerate all enterprise nodes -| Get-KeeperEnterpriseUsers | keu | Enumerate all enterprise users -| Get-KeeperEnterpriseTeams | ket | Enumerate all enterprise teams -| Get-KeeperEnterpriseTeamUsers | ketu | Get a list of enterprise users for team +| Get-KeeperEnterpriseNode | ken | Enumerate all enterprise nodes +| Get-KeeperEnterpriseUser | keu | Enumerate all enterprise users +| Get-KeeperEnterpriseTeam | ket | Enumerate all enterprise teams +| Get-KeeperEnterpriseTeamUser | ketu | Get a list of enterprise users for team | Lock-KeeperEnterpriseUser | lock-user | Lock Enterprise User | Unlock-KeeperEnterpriseUser | unlock-user | Unlock Enterprise User | Move-KeeperEnterpriseUser |transfer-user| Transfer user account to another user | Remove-KeeperEnterpriseUser | delete-user | Delete Enterprise User | Get-KeeperMspLicenses | msp-license | Return MSP licenses -| Get-KeeperManagedCompanies | kmc | Enumerate all enterprise managed companies +| Get-KeeperManagedCompany | kmc | Enumerate all enterprise managed companies | New-KeeperManagedCompany | kamc | Create Managed Company | Remove-KeeperManagedCompany | krmc | Remove Managed Company | Edit-KeeperManagedCompany | kemc | Edit Managed Company -| Get-MspBillingReport | | Runs MSP Billing Report +| Get-MspBillingReport | | Run MSP Billing Report ### Secret Manager Cmdlets | Cmdlet name | Alias | Description |----------------------------------------|-------------|---------------------------- -| Get-KeeperSecretManagerApps | ksm | Enumerate all Keeper Secret Manager Applications -| New-KeeperSecretManagerApp | ksm-create | Create Keeper Secret Manager Application -| Grant-KeeperSecretManagerFolderAccess | ksm-share | Add shared folder to KSM Application -| Revoke-KeeperSecretManagerFolderAccess | ksm-unshare | Remove Shared Folder from KSM Application -| Add-KeeperSecretManagerClient |ksm-addclient| Adds client/device to KSM Application -| Remove-KeeperSecretManagerClient | ksm-rmclient| Removes client/device from KSM Application +| Get-KeeperSecretManagerApp | ksm | Enumerate all Keeper Secret Manager Applications +| Add-KeeperSecretManagerApp | ksm-create | Add a Keeper Secret Manager Application +| Grant-KeeperSecretManagerFolderAccess | ksm-share | Add a shared folder to KSM Application +| Revoke-KeeperSecretManagerFolderAccess | ksm-unshare | Remove a Shared Folder from KSM Application +| Add-KeeperSecretManagerClient |ksm-addclient| Add a client/device to KSM Application +| Remove-KeeperSecretManagerClient | ksm-rmclient| Remove a client/device from KSM Application #### Examples @@ -103,7 +107,7 @@ To install the PowerCommander module copy PowerCommander\ directory to PS > kr|2fa ``` where - * `kr` is alias for `Get-KeeperRecords` + * `kr` is alias for `Get-KeeperRecord` * `2fa` is alias for `Show-TwoFactorCode` 5. Copy record password to clipboard @@ -151,7 +155,7 @@ To install the PowerCommander module copy PowerCommander\ directory to 8. List all enterprise users ``` - PS > Get-KeeperEnterpriseUsers + PS > Get-KeeperEnterpriseUser ``` 9. Create a new Managed Company diff --git a/PowerCommander/Record.format.ps1xml b/PowerCommander/Record.format.ps1xml index 976e60f..45bd5df 100644 --- a/PowerCommander/Record.format.ps1xml +++ b/PowerCommander/Record.format.ps1xml @@ -1,125 +1,125 @@ - - - KeeperSecurity.Vault.RecordField_TableView - - KeeperSecurity.Vault.RecordField - - - - - - - - - - - - Name - - - TypeName - - - Multiple - - - - - - + + + KeeperSecurity.Vault.RecordField_TableView + + KeeperSecurity.Vault.RecordField + + + + + + + + + + + + Name + + + TypeName + + + Multiple + + + + + + - - KeeperSecurity.Vault.RecordTypeField_TableView - - KeeperSecurity.Vault.RecordTypeField - - - - - - - - - - - - FieldName - - - FieldLabel - - - TypeName - - - - - - + + KeeperSecurity.Vault.RecordTypeField_TableView + + KeeperSecurity.Vault.RecordTypeField + + + + + + + + + + + + FieldName + + + FieldLabel + + + TypeName + + + + + + - - KeeperSecurity.Vault.RecordType_TableView - - KeeperSecurity.Vault.RecordType - - - - - - - - - - - - - Name - - - Description - - - Scope - - - Fields - - - - - - + + KeeperSecurity.Vault.RecordType_TableView + + KeeperSecurity.Vault.RecordType + + + + + + + + + + + + + Name + + + Description + + + Scope + + + Fields + + + + + + - - KeeperSecurity.Vault.RecordField_ListView - - KeeperSecurity.Vault.RecordField - - - - - - - Name - - - - $_.Type.Name - - - - $_.Type.Description - - - Multiple - - - - - - + + KeeperSecurity.Vault.RecordField_ListView + + KeeperSecurity.Vault.RecordField + + + + + + + Name + + + + $_.Type.Name + + + + $_.Type.Description + + + Multiple + + + + + + - + \ No newline at end of file diff --git a/PowerCommander/Record.types.ps1xml b/PowerCommander/Record.types.ps1xml index c4f002c..3536599 100644 --- a/PowerCommander/Record.types.ps1xml +++ b/PowerCommander/Record.types.ps1xml @@ -1,25 +1,25 @@ - + - - KeeperSecurity.Vault.RecordField - - - TypeName - - $this.Type.Name - - - - - - KeeperSecurity.Vault.RecordTypeField - - - TypeName - - $this.RecordField.TypeName - - - - + + KeeperSecurity.Vault.RecordField + + + TypeName + + $this.Type.Name + + + + + + KeeperSecurity.Vault.RecordTypeField + + + TypeName + + $this.RecordField.TypeName + + + + \ No newline at end of file diff --git a/PowerCommander/RecordCommands.ps1 b/PowerCommander/RecordCommands.ps1 index c5f039d..99c2a54 100644 --- a/PowerCommander/RecordCommands.ps1 +++ b/PowerCommander/RecordCommands.ps1 @@ -1,6 +1,6 @@ -#requires -Version 5.0 +#requires -Version 5.1 -function Get-KeeperRecords { +function Get-KeeperRecord { <# .Synopsis Get Keeper Records @@ -12,7 +12,7 @@ function Get-KeeperRecords { Return matching records only #> [CmdletBinding()] - [OutputType([KeeperSecurity.Vault.KeeperRecord[]])] + [OutputType([KeeperSecurity.Vault.KeeperRecord[]])] Param ( [string] $Uid, [string] $Filter @@ -37,13 +37,13 @@ function Get-KeeperRecords { } } } -New-Alias -Name kr -Value Get-KeeperRecords +New-Alias -Name kr -Value Get-KeeperRecord function Copy-KeeperToClipboard { <# .Synopsis - Copy record password to clipboard or output + Copy record password to clipboard or output .Parameter Record Record UID or any object containing property Uid @@ -75,7 +75,7 @@ function Copy-KeeperToClipboard { $uid = $null if ($Record -is [String]) { $uid = $Record - } + } elseif ($null -ne $Record.Uid) { $uid = $Record.Uid } @@ -84,7 +84,7 @@ function Copy-KeeperToClipboard { if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { - $entries = Get-KeeperChildItems -Filter $uid -ObjectType Record + $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } @@ -110,7 +110,7 @@ function Copy-KeeperToClipboard { if ($fieldType) { $recordField = $rec.Fields | Where-Object FieldName -eq $fieldType | Select-Object -First 1 if (-not $recordField) { - $recordField = $rec.Custom | Where-Object FieldName -eq $fieldType | Select-Object -First 1 + $recordField = $rec.Custom | Where-Object FieldName -eq $fieldType | Select-Object -First 1 } if ($recordField) { $value = $recordField.ObjectValue @@ -123,22 +123,23 @@ function Copy-KeeperToClipboard { $value } else { - if ([System.Threading.Thread]::CurrentThread.GetApartmentState() -eq [System.Threading.ApartmentState]::MTA) { + if ([System.Threading.Thread]::CurrentThread.GetApartmentState() -eq [System.Threading.ApartmentState]::MTA) { powershell -sta "Set-Clipboard -Value '$value'" - } else { + } + else { Set-Clipboard -Value $value } - Write-Host "Copied to clipboard: $Field for $($rec.Title)" + Write-Output "Copied to clipboard: $Field for $($rec.Title)" } if ($Field -eq 'Password') { $vault.AuditLogRecordCopyPassword($rec.Uid) } } else { - Write-Host "Record $($rec.Title) has no $Field" + Write-Output "Record $($rec.Title) has no $Field" } } - } + } if (-not $found) { Write-Error -Message "Cannot find a Keeper record: $Record" } @@ -161,6 +162,7 @@ function Get-KeeperPasswordVisible { function Set-KeeperPasswordVisible { [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] Param ([switch] $Visible) $Script:PasswordVisible = $Visible.IsPresent } @@ -182,7 +184,7 @@ function Show-TwoFactorCode { if ($r -is [String]) { $uid = $r - } + } elseif ($null -ne $r.Uid) { $uid = $r.Uid } @@ -250,7 +252,7 @@ $Keeper_RecordTypeNameCompleter = { $result += $rt.Name } } - } + } if ($result.Count -gt 0) { return $result } @@ -265,11 +267,11 @@ function Add-KeeperRecord { .Synopsis Creates or Modifies a Keeper record in the current folder. - .Parameter Uid + .Parameter Uid Record UID. If provided the existing record to be updated. Otherwise record is added. .Parameter RecordType - Record Type (if account supports record types). + Record Type (if account supports record types). .Parameter Title Record Title. Mandatory field for added record. @@ -278,7 +280,7 @@ function Add-KeeperRecord { Record Notes. .Parameter GeneratePassword - Generate random password. + Generate random password. .Parameter Fields A list of record Fields. Record field format NAME=VALUE @@ -287,7 +289,7 @@ function Add-KeeperRecord { password Password url Web Address Any other name is added to Custom Fields - Example: login=username password=userpassword "Database Server=value1" + Example: login=username password=userpassword "Database Server=value1" #> [CmdletBinding(DefaultParameterSetName = 'add')] @@ -313,10 +315,12 @@ function Add-KeeperRecord { if ($var -match ':$') { $fieldName = $fieldName.Substring(0, $fieldName.Length - 1) } - } elseif ($null -ne $fieldName) { + } + elseif ($null -ne $fieldName) { $fields[$fieldName] = $var $fieldName = $null - } else { + } + else { if ($var -match '^([^=]+)=(.*)?') { $n = $Matches[1].Trim() $v = $Matches[2].Trim() @@ -331,7 +335,7 @@ function Add-KeeperRecord { Process { if ($Uid) { if (-not $vault.TryGetKeeperRecord($Uid, [ref]$record)) { - $objs = Get-KeeperChildItems -ObjectType Record | Where-Object Name -eq $Uid + $objs = Get-KeeperChildItem -ObjectType Record | Where-Object Name -eq $Uid if ($objs.Length -gt 1) { $vault.TryGetKeeperRecord($objs[0].Uid, [ref]$record) } @@ -387,7 +391,8 @@ function Add-KeeperRecord { if ($fieldLabel) { if ($fieldName -eq 'text') { $fieldName = $fieldLabel - } else { + } + else { $fieldName = "${fieldName}:${fieldLabel}" } } @@ -461,6 +466,7 @@ function Remove-KeeperRecord { Folder name or Folder UID #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding(DefaultParameterSetName = 'Default')] Param ( [Parameter(Position = 0, Mandatory = $true)][string] $Name @@ -483,7 +489,7 @@ function Remove-KeeperRecord { } } if (-not $recordUid) { - $objs = Get-KeeperChildItems -ObjectType Record | Where-Object Name -eq $Name + $objs = Get-KeeperChildItem -ObjectType Record | Where-Object Name -eq $Name if (-not $objs) { Write-Error -Message "Record `"$Name`" does not exist" return @@ -512,7 +518,7 @@ function Move-RecordToFolder { .Parameter Record Record UID, Path or any object containing property Uid. - .Parameter Folder + .Parameter Folder Folder Name, Path, or UID #> @@ -522,7 +528,7 @@ function Move-RecordToFolder { [Parameter(Position = 0, Mandatory = $true)][string]$Folder, [Parameter()][switch]$Link ) - + Begin { [KeeperSecurity.Vault.VaultOnline]$vault = getVault $folderNode = resolveFolderNode $vault $Folder @@ -562,7 +568,7 @@ function Move-RecordToFolder { if (-not $vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$fol)) { $fol = $vault.RootFolder } - + $comps = splitKeeperPath $r $folder, $rest = parseKeeperPath $comps $vault $fol if (-not $rest) { @@ -585,7 +591,7 @@ function Move-RecordToFolder { Write-Error "Record `"$r`" cannot be found" -ErrorAction Stop } - $rp = New-Object KeeperSecurity.Vault.RecordPath + $rp = New-Object KeeperSecurity.Vault.RecordPath $rp.RecordUid = $record.Uid $rp.FolderUid = $folder.FolderUid $sourceRecords += $rp @@ -603,7 +609,7 @@ New-Alias -Name kmv -Value Move-RecordToFolder Register-ArgumentCompleter -CommandName Move-RecordToFolder -ParameterName Folder -ScriptBlock $Keeper_FolderPathRecordCompleter -function Get-KeeperRecordTypes { +function Get-KeeperRecordType { <# .Synopsis Get Record Type Information @@ -611,7 +617,7 @@ function Get-KeeperRecordTypes { .Parameter Record Record UID, Path or any object containing property Uid. - .Parameter Folder + .Parameter Folder Folder Name, Path, or UID #> @@ -624,12 +630,13 @@ function Get-KeeperRecordTypes { [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($ShowFields.IsPresent) { - [KeeperSecurity.Vault.RecordTypesConstants]::RecordFields | Where-Object {-not $Name -or $_.Name -eq $Name} | Sort-Object Name - } else { - $vault.RecordTypes | Where-Object {-not $Name -or $_.Name -eq $Name} | Sort-Object Name + [KeeperSecurity.Vault.RecordTypesConstants]::RecordFields | Where-Object { -not $Name -or $_.Name -eq $Name } | Sort-Object Name + } + else { + $vault.RecordTypes | Where-Object { -not $Name -or $_.Name -eq $Name } | Sort-Object Name } } -New-Alias -Name krti -Value Get-KeeperRecordTypes +New-Alias -Name krti -Value Get-KeeperRecordType function resolveFolderNode { Param ([KeeperSecurity.Vault.VaultOnline]$vault, $path) @@ -639,9 +646,9 @@ function resolveFolderNode { if (-not $vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$folder)) { $folder = $vault.RootFolder } - + $comps = splitKeeperPath $path - $folder, $rest = parseKeeperPath $comps $vault $folder + $folder, $rest = parseKeeperPath $comps $vault $folder if ($rest) { Write-Error "Folder $path not found" -ErrorAction Stop } diff --git a/PowerCommander/SecretsManager.format.ps1xml b/PowerCommander/SecretsManager.format.ps1xml index b04a852..5740baf 100644 --- a/PowerCommander/SecretsManager.format.ps1xml +++ b/PowerCommander/SecretsManager.format.ps1xml @@ -1,196 +1,196 @@ - - - KeeperSecurity.Vault.ApplicationRecord_TableView - - KeeperSecurity.Vault.ApplicationRecord - - - - - - - - - - - Uid - - - Title - - - - - - + + + KeeperSecurity.Vault.ApplicationRecord_TableView + + KeeperSecurity.Vault.ApplicationRecord + + + + + + + + + + + Uid + + + Title + + + + + + - - KeeperSecurity.Vault.ApplicationRecord_ListView - - KeeperSecurity.Vault.ApplicationRecord - - - - - - - Uid - - - Title - - - - - - + + KeeperSecurity.Vault.ApplicationRecord_ListView + + KeeperSecurity.Vault.ApplicationRecord + + + + + + + Uid + + + Title + + + + + + - - KeeperSecurity.Vault.SecretsManagerApplication_TableView - - KeeperSecurity.Vault.SecretsManagerApplication - - - - - - - - - - - - - - Uid - - - Title - - - IsExternalShare - - - DeviceCount - - - ShareCount - - - - - - + + KeeperSecurity.Vault.SecretsManagerApplication_TableView + + KeeperSecurity.Vault.SecretsManagerApplication + + + + + + + + + + + + + + Uid + + + Title + + + IsExternalShare + + + DeviceCount + + + ShareCount + + + + + + - - KeeperSecurity.Vault.SecretsManagerApplication_ListView - - KeeperSecurity.Vault.SecretsManagerApplication - - - - - - - Uid - - - Title - - - IsExternalShare - - - Devices - - - Shares - - - - - - + + KeeperSecurity.Vault.SecretsManagerApplication_ListView + + KeeperSecurity.Vault.SecretsManagerApplication + + + + + + + Uid + + + Title + + + IsExternalShare + + + Devices + + + Shares + + + + + + - - KeeperSecurity.Vault.SecretsManagerDevice_TableView - - KeeperSecurity.Vault.SecretsManagerDevice - - - - - - - - - - - - - - - - Name - - - ShortDeviceId - - - UnlockIp - - - CreatedOn - - - LastAccess - - - AccessExpireOn - - - IpAddress - - - - - - + + KeeperSecurity.Vault.SecretsManagerDevice_TableView + + KeeperSecurity.Vault.SecretsManagerDevice + + + + + + + + + + + + + + + + Name + + + ShortDeviceId + + + UnlockIp + + + CreatedOn + + + LastAccess + + + AccessExpireOn + + + IpAddress + + + + + + - - KeeperSecurity.Vault.SecretManagerShare_TableView - - KeeperSecurity.Vault.SecretManagerShare - - - - - - - - - - - - - SecretUid - - - SecretType - - - Editable - - - CreatedOn - - - - - - + + KeeperSecurity.Vault.SecretManagerShare_TableView + + KeeperSecurity.Vault.SecretManagerShare + + + + + + + + + + + + + SecretUid + + + SecretType + + + Editable + + + CreatedOn + + + + + + - + \ No newline at end of file diff --git a/PowerCommander/SecretsManager.ps1 b/PowerCommander/SecretsManager.ps1 index bff5b8b..b292e40 100644 --- a/PowerCommander/SecretsManager.ps1 +++ b/PowerCommander/SecretsManager.ps1 @@ -1,4 +1,4 @@ -#requires -Version 5.0 +#requires -Version 5.1 $Keeper_KSMAppCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) @@ -42,14 +42,14 @@ $Keeper_KSMAppCompleter = { } } -function Get-KeeperSecretManagerApps { +function Get-KeeperSecretManagerApp { <# .Synopsis Get Keeper Secret Manager Applications - + .Parameter Uid Record UID - + .Parameter Filter Return matching applications only @@ -62,7 +62,7 @@ function Get-KeeperSecretManagerApps { [string] $Filter, [Switch] $Detail ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($Uid) { [KeeperSecurity.Vault.ApplicationRecord] $application = $null @@ -92,13 +92,13 @@ function Get-KeeperSecretManagerApps { } } } -New-Alias -Name ksm -Value Get-KeeperSecretManagerApps - -function New-KeeperSecretManagerApp { +New-Alias -Name ksm -Value Get-KeeperSecretManagerApp + +function Add-KeeperSecretManagerApp { <# .Synopsis Creates Keeper Secret Manager Application - + .Parameter Name Secret Manager Application #> @@ -106,17 +106,17 @@ function New-KeeperSecretManagerApp { Param ( [Parameter(Position = 0, Mandatory = $true)][string]$AppName ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault $vault.CreateSecretManagerApplication($AppName).GetAwaiter().GetResult() } -New-Alias -Name ksm-create -Value New-KeeperSecretManagerApp +New-Alias -Name ksm-create -Value Add-KeeperSecretManagerApp function Grant-KeeperSecretManagerFolderAccess { <# .Synopsis Adds shared folder to KSM Application - + .Parameter App KSM Application UID or Title @@ -133,21 +133,21 @@ function Grant-KeeperSecretManagerFolderAccess { [Parameter(Mandatory = $true)][string]$Secret, [Parameter()][switch]$CanEdit ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault - $apps = Get-KeeperSecretManagerApps -Filter $App + $apps = Get-KeeperSecretManagerApp -Filter $App if (-not $apps) { Write-Error -Message "Cannot find Secret Manager Application: $App" -ErrorAction Stop } [KeeperSecurity.Vault.ApplicationRecord]$application = $apps[0] [string]$uid = $null - $sfs = Get-KeeperSharedFolders -Filter $Secret + $sfs = Get-KeeperSharedFolder -Filter $Secret if ($sfs) { $uid = $sfs[0].Uid } else { - $recs = Get-KeeperRecords -Filter $Secret + $recs = Get-KeeperRecord -Filter $Secret if ($recs) { $uid = $recs[0].Uid } @@ -165,7 +165,7 @@ function Revoke-KeeperSecretManagerFolderAccess { <# .Synopsis Removes Shared Folder from KSM Application - + .Parameter App Secret Manager Application @@ -177,21 +177,21 @@ function Revoke-KeeperSecretManagerFolderAccess { [Parameter(Mandatory = $true)][string]$App, [Parameter(Mandatory = $true)][string]$Secret ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault - $apps = Get-KeeperSecretManagerApps -Filter $App + $apps = Get-KeeperSecretManagerApp -Filter $App if (-not $apps) { Write-Error -Message "Cannot find Secret Manager Application: $App" -ErrorAction Stop } [KeeperSecurity.Vault.ApplicationRecord]$application = $apps[0] [string]$uid = $null - $sfs = Get-KeeperSharedFolders -Filter $Secret + $sfs = Get-KeeperSharedFolder -Filter $Secret if ($sfs) { $uid = $sfs[0].Uid } else { - $recs = Get-KeeperRecords -Filter $Secret + $recs = Get-KeeperRecord -Filter $Secret if ($recs) { $uid = $recs[0].Uid } @@ -209,7 +209,7 @@ function Add-KeeperSecretManagerClient { <# .Synopsis Adds client/device to KSM Application - + .Parameter App KSM Application UID or Title @@ -225,9 +225,9 @@ function Add-KeeperSecretManagerClient { [Parameter()][string]$Name, [Parameter()][switch]$UnlockIP ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault - $apps = Get-KeeperSecretManagerApps -Filter $App + $apps = Get-KeeperSecretManagerApp -Filter $App if (-not $apps) { Write-Error -Message "Cannot find Secret Manager Application: $App" -ErrorAction Stop } @@ -243,7 +243,7 @@ function Remove-KeeperSecretManagerClient { <# .Synopsis Removes client/device from KSM Application - + .Parameter App KSM Application UID or Title @@ -251,14 +251,14 @@ function Remove-KeeperSecretManagerClient { Client Id or Device Name #> - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory = $true)][string]$App, [Parameter(Mandatory = $true)][string]$Name ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault - $apps = Get-KeeperSecretManagerApps -Filter $App -Detail + $apps = Get-KeeperSecretManagerApp -Filter $App -Detail if (-not $apps) { Write-Error -Message "Cannot find Secret Manager Application: $App" -ErrorAction Stop } @@ -269,9 +269,10 @@ function Remove-KeeperSecretManagerClient { Write-Error -Message "Cannot find Device: $Name" -ErrorAction Stop } - $vault.DeleteSecretManagerClient($application.Uid, $device.DeviceId).GetAwaiter().GetResult() | Out-Null - - Write-Information -MessageData "Device $($device.Name) has been deleted from KSM application `"$($application.Title)`"." + if ($PSCmdlet.ShouldProcess($application.Title, "Removing KSM Device '$($device.Name)'")) { + $vault.DeleteSecretManagerClient($application.Uid, $device.DeviceId).GetAwaiter().GetResult() | Out-Null + Write-Information -MessageData "Device $($device.Name) has been deleted from KSM application `"$($application.Title)`"." + } } Register-ArgumentCompleter -CommandName Remove-KeeperSecretManagerClient -ParameterName App -ScriptBlock $Keeper_KSMAppCompleter diff --git a/PowerCommander/SecretsManager.types.ps1xml b/PowerCommander/SecretsManager.types.ps1xml index ec6f48e..6f51fcd 100644 --- a/PowerCommander/SecretsManager.types.ps1xml +++ b/PowerCommander/SecretsManager.types.ps1xml @@ -1,31 +1,31 @@ - + - - KeeperSecurity.Vault.SecretsManagerApplication - - - DeviceCount - $this.Devices.Count - - - ShareCount - $this.Shares.Count - - - + + KeeperSecurity.Vault.SecretsManagerApplication + + + DeviceCount + $this.Devices.Count + + + ShareCount + $this.Shares.Count + + + - - KeeperSecurity.Vault.SecretsManagerDevice - - - ShortDeviceId - $this.DeviceId.Substring(0, 6) - - - UnlockIp - !$this.LockIp - - - + + KeeperSecurity.Vault.SecretsManagerDevice + + + ShortDeviceId + $this.DeviceId.Substring(0, 6) + + + UnlockIp + !$this.LockIp + + + - + \ No newline at end of file diff --git a/PowerCommander/SharedFolderCommands.ps1 b/PowerCommander/SharedFolderCommands.ps1 index dafa4ad..eefd431 100644 --- a/PowerCommander/SharedFolderCommands.ps1 +++ b/PowerCommander/SharedFolderCommands.ps1 @@ -1,7 +1,7 @@ -#requires -Version 5.0 +#requires -Version 5.1 -function Get-KeeperSharedFolders { -<# +function Get-KeeperSharedFolder { + <# .Synopsis Get Keeper Shared Folders @@ -11,71 +11,75 @@ function Get-KeeperSharedFolders { .Parameter Filter Return matching shared folders only #> - [CmdletBinding()] - [OutputType([KeeperSecurity.Vault.SharedFolder[]])] - Param ( - [string] $Uid, - [string] $Filter - ) + [CmdletBinding()] + [OutputType([KeeperSecurity.Vault.SharedFolder[]])] + Param ( + [string] $Uid, + [string] $Filter + ) - [KeeperSecurity.Vault.VaultOnline]$vault = getVault + [KeeperSecurity.Vault.VaultOnline]$vault = getVault - [KeeperSecurity.Vault.SharedFolder] $sharedFolder = $null - if ($Uid) { - if ($vault.TryGetSharedFolder($uid, [ref]$sharedFolder)) { - $sharedFolder - } - } else { - foreach ($sharedFolder in $vault.SharedFolders) { - if ($Filter) { - $match = $($sharedFolder.Uid, $sharedFolder.Name) | Select-String $Filter | Select-Object -First 1 - if (-not $match) { - continue - } - } - $sharedFolder - } - } + [KeeperSecurity.Vault.SharedFolder] $sharedFolder = $null + if ($Uid) { + if ($vault.TryGetSharedFolder($uid, [ref]$sharedFolder)) { + $sharedFolder + } + } + else { + foreach ($sharedFolder in $vault.SharedFolders) { + if ($Filter) { + $match = $($sharedFolder.Uid, $sharedFolder.Name) | Select-String $Filter | Select-Object -First 1 + if (-not $match) { + continue + } + } + $sharedFolder + } + } } -New-Alias -Name ksf -Value Get-KeeperSharedFolders +New-Alias -Name ksf -Value Get-KeeperSharedFolder +<# $Keeper_SharedFolderCompleter = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - $result = @() - [KeeperSecurity.Vault.VaultOnline]$private:vault = getVault - if (-not $vault) { - return $null - } + $result = @() + [KeeperSecurity.Vault.VaultOnline]$private:vault = getVault + if (-not $vault) { + return $null + } - $toComplete = $wordToComplete - if ($toComplete.Length -ge 1) { - if ($toComplete[0] -eq '''') { - $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) - $toComplete = $toComplete -replace '''''', '''' - } - if ($toComplete[0] -eq '"') { - $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) - $toComplete = $toComplete -replace '""', '"' - $toComplete = $toComplete -replace '`"', '"' - } - } + $toComplete = $wordToComplete + if ($toComplete.Length -ge 1) { + if ($toComplete[0] -eq '''') { + $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) + $toComplete = $toComplete -replace '''''', '''' + } + if ($toComplete[0] -eq '"') { + $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) + $toComplete = $toComplete -replace '""', '"' + $toComplete = $toComplete -replace '`"', '"' + } + } - $toComplete += '*' - foreach ($sf in $vault.SharedFolders) { - if ($sf.Name -like $toComplete) { - $name = $sf.Name - if ($name -match ' ') { - $name = $name -replace '''', '''''' - $name = '''' + $name + '''' - } - $result += $name - } - } + $toComplete += '*' + foreach ($sf in $vault.SharedFolders) { + if ($sf.Name -like $toComplete) { + $name = $sf.Name + if ($name -match ' ') { + $name = $name -replace '''', '''''' + $name = '''' + $name + '''' + } + $result += $name + } + } - if ($result.Count -gt 0) { - return $result - } else { - return $null - } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } +#> \ No newline at end of file diff --git a/PowerCommander/Sharing.ps1 b/PowerCommander/Sharing.ps1 index d47557f..c7871c6 100644 --- a/PowerCommander/Sharing.ps1 +++ b/PowerCommander/Sharing.ps1 @@ -1,7 +1,7 @@ -#requires -Version 5.0 +#requires -Version 5.1 -function Show-KeeperRecordShares { +function Show-KeeperRecordShare { <# .Synopsis Shows a record sharing information @@ -9,29 +9,29 @@ function Show-KeeperRecordShares { .Parameter Record Record UID or any object containing property Uid #> - + [CmdletBinding()] Param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true)]$Records ) Begin { [KeeperSecurity.Vault.VaultOnline]$vault = getVault - [string[]]$recordUids = @() - + [string[]]$recordUids = @() + } Process { foreach ($r in $Records) { $uid = $null if ($r -is [String]) { $uid = $r - } + } elseif ($null -ne $r.Uid) { $uid = $r.Uid } if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { - $entries = Get-KeeperChildItems -Filter $uid -ObjectType Record + $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } @@ -49,7 +49,7 @@ function Show-KeeperRecordShares { $vault.GetSharesForRecords($recordUids).GetAwaiter().GetResult() } } -New-Alias -Name kshrsh -Value Show-KeeperRecordShares +New-Alias -Name kshrsh -Value Show-KeeperRecordShare function Grant-KeeperRecordAccess { <# @@ -69,7 +69,7 @@ function Grant-KeeperRecordAccess { Grant re-share permission #> - + [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Record, @@ -77,7 +77,7 @@ function Grant-KeeperRecordAccess { [Parameter()][switch]$CanEdit, [Parameter()][switch]$CanShare ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($Record -is [Array]) { if ($Record.Count -ne 1) { @@ -88,7 +88,7 @@ function Grant-KeeperRecordAccess { $uid = $null if ($Record -is [String]) { $uid = $Record - } + } elseif ($null -ne $Record.Uid) { $uid = $Record.Uid } @@ -96,7 +96,7 @@ function Grant-KeeperRecordAccess { if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { - $entries = Get-KeeperChildItems -Filter $uid -ObjectType Record + $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } @@ -104,21 +104,21 @@ function Grant-KeeperRecordAccess { if ($rec) { try { $vault.ShareRecordWithUser($rec.Uid, $User, $CanShare.IsPresent, $CanEdit.IsPresent).GetAwaiter().GetResult() | Out-Null - Write-Host "Record `"$($rec.Title)`" was shared with $($User)" + Write-Output "Record `"$($rec.Title)`" was shared with $($User)" } catch [KeeperSecurity.Vault.NoActiveShareWithUserException] { - Write-Host $_ + Write-Output $_ $prompt = "Do you want to send share invitation request to `"$($User)`"? (Yes/No)" $answer = Read-Host -Prompt $prompt if ($answer -in 'yes', 'y') { $vault.SendShareInvitationRequest($User).GetAwaiter().GetResult() | Out-Null - Write-Host("Invitation has been sent to $($User)`nPlease repeat this command when your invitation is accepted."); + Write-Output("Invitation has been sent to $($User)`nPlease repeat this command when your invitation is accepted."); } } } else { Write-Error -Message "Cannot find a Keeper record: $Record" } - } + } } New-Alias -Name kshr -Value Grant-KeeperRecordAccess @@ -133,13 +133,13 @@ function Revoke-KeeperRecordAccess { .Parameter User User email #> - + [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Record, [Parameter(Mandatory = $true)]$User ) - + [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($Record -is [Array]) { if ($Record.Count -ne 1) { @@ -151,7 +151,7 @@ function Revoke-KeeperRecordAccess { $uid = $null if ($Record -is [String]) { $uid = $Record - } + } elseif ($null -ne $Record.Uid) { $uid = $Record.Uid } @@ -160,7 +160,7 @@ function Revoke-KeeperRecordAccess { if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { - $entries = Get-KeeperChildItems -Filter $uid -ObjectType Record + $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } @@ -168,9 +168,9 @@ function Revoke-KeeperRecordAccess { if ($rec) { $found = $true $vault.RevokeShareFromUser($rec.Uid, $User).GetAwaiter().GetResult() | Out-Null - Write-Host "Record `"$($rec.Title)`" share has been removed from $($username)" + Write-Output "Record `"$($rec.Title)`" share has been removed from $($username)" } - } + } if (-not $found) { Write-Error -Message "Cannot find a Keeper record: $Record" } @@ -191,7 +191,7 @@ function Grant-KeeperSharedFolderAccess { .Parameter Team Team Name or UID - + .Parameter ManageRecords Grant Manage Records permission @@ -199,7 +199,7 @@ function Grant-KeeperSharedFolderAccess { Grant Manage Users permission #> - + [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)]$SharedFolder, @@ -208,7 +208,7 @@ function Grant-KeeperSharedFolderAccess { [Parameter()][switch]$ManageRecords, [Parameter()][switch]$ManageUsers ) - + [KeeperSecurity.Vault.VaultOnline]$private:vault = getVault if ($SharedFolder -is [Array]) { @@ -221,7 +221,7 @@ function Grant-KeeperSharedFolderAccess { $uid = $null if ($SharedFolder -is [String]) { $uid = $SharedFolder - } + } elseif ($null -ne $Record.Uid) { $uid = $SharedFolder.Uid } @@ -245,7 +245,7 @@ function Grant-KeeperSharedFolderAccess { if (-not $userId) { return } - } + } elseif ($Team) { $userType = [KeeperSecurity.Vault.UserType]::Team [KeeperSecurity.Vault.TeamInfo]$teamInfo = $null @@ -278,15 +278,15 @@ function Grant-KeeperSharedFolderAccess { $options.ManageRecords = $ManageRecords.IsPresent $options.ManageUsers = $ManageUsers.IsPresent $vault.PutUserToSharedFolder($sf.Uid, $userId, $userType, $options).GetAwaiter().GetResult() | Out-Null - Write-Host "${userType} `"$($userName)`" has been added to shared folder `"$($sf.Name)`"" + Write-Output "${userType} `"$($userName)`" has been added to shared folder `"$($sf.Name)`"" } catch [KeeperSecurity.Vault.NoActiveShareWithUserException] { - Write-Host $_ + Write-Output $_ $prompt = "Do you want to send share invitation request to `"$($User)`"? (Yes/No)" $answer = Read-Host -Prompt $prompt if ($answer -in 'yes', 'y') { $vault.SendShareInvitationRequest($User).GetAwaiter().GetResult() | Out-Null - Write-Host("Invitation has been sent to `"$($User)`"`nPlease repeat this command when your invitation is accepted."); + Write-Output("Invitation has been sent to `"$($User)`"`nPlease repeat this command when your invitation is accepted."); } } @@ -305,16 +305,16 @@ function Revoke-KeeperSharedFolderAccess { .Parameter Team Team Name or UID - + #> - + [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)]$SharedFolder, [Parameter(Mandatory = $true, ParameterSetName='user')]$User, [Parameter(Mandatory = $true, ParameterSetName='team')]$Team ) - + [KeeperSecurity.Vault.VaultOnline]$private:vault = getVault if ($SharedFolder -is [Array]) { @@ -327,7 +327,7 @@ function Revoke-KeeperSharedFolderAccess { $uid = $null if ($SharedFolder -is [String]) { $uid = $SharedFolder - } + } elseif ($null -ne $Record.Uid) { $uid = $SharedFolder.Uid } @@ -351,7 +351,7 @@ function Revoke-KeeperSharedFolderAccess { if (-not $userId) { return } - } + } elseif ($Team) { $userType = [KeeperSecurity.Vault.UserType]::Team [KeeperSecurity.Vault.TeamInfo]$teamInfo = $null @@ -380,7 +380,7 @@ function Revoke-KeeperSharedFolderAccess { } $vault.RemoveUserFromSharedFolder($sf.Uid, $userId, $userType).GetAwaiter().GetResult() | Out-Null - Write-Host "${userType} `"$($userName)`" has been removed from shared folder `"$($sf.Name)`"" + Write-Output "${userType} `"$($userName)`" has been removed from shared folder `"$($sf.Name)`"" } function ensureAvalableLoaded { @@ -497,26 +497,26 @@ Register-ArgumentCompleter -CommandName Revoke-KeeperSharedFolderAccess -Paramet New-Alias -Name kushf -Value Revoke-KeeperSharedFolderAccess -function Get-KeeperAvailableTeams { +function Get-KeeperAvailableTeam { <# .Synopsis Get Keeper Available Teams - + .Parameter Uid Team UID - + .Parameter Filter Return matching teams only #> [CmdletBinding()] - [OutputType([KeeperSecurity.Vault.TeamInfo[]])] + [OutputType([KeeperSecurity.Vault.TeamInfo[]])] Param ( [string] $Uid, [string] $Filter ) - + ensureAvalableLoaded - $teams = $Script:Context.AvailableTeams + $teams = $Script:Context.AvailableTeams if ($Uid) { $teams | Where-Object { $_.TeamUid -ceq $Uid } | Select-Object -First 1 } else { @@ -531,5 +531,4 @@ function Get-KeeperAvailableTeams { } } } - New-Alias -Name kat -Value Get-KeeperAvailableTeams - \ No newline at end of file + New-Alias -Name kat -Value Get-KeeperAvailableTeam diff --git a/PowerCommander/VaultCommands.ps1 b/PowerCommander/VaultCommands.ps1 index 0d81244..0bacf93 100644 --- a/PowerCommander/VaultCommands.ps1 +++ b/PowerCommander/VaultCommands.ps1 @@ -1,4 +1,4 @@ -#requires -Version 5.0 +#requires -Version 5.1 $Script:PathDelimiter = [System.IO.Path]::DirectorySeparatorChar @@ -9,29 +9,30 @@ function getVault { if (-not $Script:Context.Vault) { Write-Error -Message "Not Connected" -ErrorAction Stop } - $Script:Context.Vault + $Script:Context.Vault } function Get-KeeperLocation { -<# + <# .Synopsis Get current Keeper folder #> - [CmdletBinding()] + [CmdletBinding()] - [KeeperSecurity.Vault.VaultOnline]$vault = getVault + [KeeperSecurity.Vault.VaultOnline]$vault = getVault - [string]$currentFolder = $Script:Context.CurrentFolder - [KeeperSecurity.Vault.FolderNode]$folder = $vault.RootFolder - if ($currentFolder) { - $vault.TryGetFolder($currentFolder, [ref]$folder) | Out-Null - } - exportKeeperNode $folder + [string]$currentFolder = $Script:Context.CurrentFolder + [KeeperSecurity.Vault.FolderNode]$folder = $vault.RootFolder + if ($currentFolder) { + $vault.TryGetFolder($currentFolder, [ref]$folder) | Out-Null + } + exportKeeperNode $folder } New-Alias -Name kpwd -Value Get-KeeperLocation + function Set-KeeperLocation { -<# + <# .Synopsis Change current Keeper folder @@ -39,116 +40,123 @@ function Set-KeeperLocation { New location #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0)][string] $Path - ) - [KeeperSecurity.Vault.VaultOnline]$vault = getVault - - if ($Path) { - [KeeperSecurity.Vault.FolderNode]$folder = $null - if (!$vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$folder)) { - $folder = $vault.RootFolder - } - - $components = splitKeeperPath $Path - $rs = parseKeeperPath $components $vault $folder - if ($rs -and !$rs[1]) { - $folder = $rs[0] - $uid = $folder.FolderUid - if ($vault.TryGetFolder($uid, [ref]$folder)) { - $Script:Context.CurrentFolder = $uid - } else { - $Script:Context.CurrentFolder = '' - } - } - } - getVaultFolderPath $vault $Script:Context.CurrentFolder + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] + [CmdletBinding()] + Param ( + [Parameter(Position = 0)][string] $Path + ) + [KeeperSecurity.Vault.VaultOnline]$vault = getVault + + if ($Path) { + [KeeperSecurity.Vault.FolderNode]$folder = $null + if (!$vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$folder)) { + $folder = $vault.RootFolder + } + + $components = splitKeeperPath $Path + $rs = parseKeeperPath $components $vault $folder + if ($rs -and !$rs[1]) { + $folder = $rs[0] + $uid = $folder.FolderUid + if ($vault.TryGetFolder($uid, [ref]$folder)) { + $Script:Context.CurrentFolder = $uid + } + else { + $Script:Context.CurrentFolder = '' + } + } + } + getVaultFolderPath $vault $Script:Context.CurrentFolder } $Keeper_FolderPathRecordCompleter = { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) - - $result = @() - [KeeperSecurity.Vault.VaultOnline]$vault = $Script:Context.Vault - if ($vault) { - [KeeperSecurity.Vault.FolderNode] $folder = $null - if (!$vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$folder)) { - $folder = $vault.RootFolder - } - - $pattern = '' - $toComplete = $wordToComplete - if ($toComplete.Length -ge 2) { - if ($toComplete[0] -eq '''' -and $toComplete[-1] -eq '''') { - $toComplete = $toComplete.Substring(1, $toComplete.Length - 2) - $toComplete = $toComplete -replace '''', '''' - } - } - if ($toComplete) { - $components = splitKeeperPath $toComplete - if ($components.Count -gt 1) { - if ($components[-1]) { - $pattern = $components[-1] - $components[-1] = '' - } - $rs = parseKeeperPath $components $vault $folder - if ($rs -and $rs.Count -eq 2) { - if (!$rs[1]) { - $folder = $rs[0] - } else { - $folder = $null - } - } - } else { - if ($components) { - $pattern = $components - $components = @('') - } else { - $folder = $vault.RootFolder - $pattern = '' - $components = @('') - } - } - } else { - $components = @('') - $pattern = $wordToComplete - } - - if ($folder) { - $pattern += '*' - foreach ($uid in $folder.Subfolders) { - $subfolder = $null - if ($vault.TryGetFolder($uid, [ref]$subfolder)) { - if ($subfolder.Name -like $pattern) { - $path = @() - $components | ForEach-Object { $path += $_ } - $path[-1] = $subfolder.Name - $expansion = ($path | ForEach-Object {$_ -replace '\\', '\\'}) -join $Script:PathDelimiter - if ($expansion -match '[\s'']') { - $expansion = $expansion -replace '''', '''''' - $expansion = "'${expansion}'" - } - $result += $expansion - } - } - } - } - } - if ($result.Count -gt 0) { - return $result - } else { - return $null - } + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + $result = @() + [KeeperSecurity.Vault.VaultOnline]$vault = $Script:Context.Vault + if ($vault) { + [KeeperSecurity.Vault.FolderNode] $folder = $null + if (!$vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$folder)) { + $folder = $vault.RootFolder + } + + $pattern = '' + $toComplete = $wordToComplete + if ($toComplete.Length -ge 2) { + if ($toComplete[0] -eq '''' -and $toComplete[-1] -eq '''') { + $toComplete = $toComplete.Substring(1, $toComplete.Length - 2) + $toComplete = $toComplete -replace '''', '''' + } + } + if ($toComplete) { + $components = splitKeeperPath $toComplete + if ($components.Count -gt 1) { + if ($components[-1]) { + $pattern = $components[-1] + $components[-1] = '' + } + $rs = parseKeeperPath $components $vault $folder + if ($rs -and $rs.Count -eq 2) { + if (!$rs[1]) { + $folder = $rs[0] + } + else { + $folder = $null + } + } + } + else { + if ($components) { + $pattern = $components + $components = @('') + } + else { + $folder = $vault.RootFolder + $pattern = '' + $components = @('') + } + } + } + else { + $components = @('') + $pattern = $wordToComplete + } + + if ($folder) { + $pattern += '*' + foreach ($uid in $folder.Subfolders) { + $subfolder = $null + if ($vault.TryGetFolder($uid, [ref]$subfolder)) { + if ($subfolder.Name -like $pattern) { + $path = @() + $components | ForEach-Object { $path += $_ } + $path[-1] = $subfolder.Name + $expansion = ($path | ForEach-Object { $_ -replace '\\', '\\' }) -join $Script:PathDelimiter + if ($expansion -match '[\s'']') { + $expansion = $expansion -replace '''', '''''' + $expansion = "'${expansion}'" + } + $result += $expansion + } + } + } + } + } + if ($result.Count -gt 0) { + return $result + } + else { + return $null + } } Register-ArgumentCompleter -CommandName Set-KeeperLocation -ParameterName Path -ScriptBlock $Keeper_FolderPathRecordCompleter New-Alias -Name kcd -Value Set-KeeperLocation -function Get-KeeperChildItems { -<# +function Get-KeeperChildItem { + <# .Synopsis - Get the content of Keeper folder. Output and parameters are similar to Get-ChildItems cmdlet + Get the content of Keeper folder. Output and parameters are similar to Get-ChildItem cmdlet .Parameter Path Keeper folder @@ -164,150 +172,153 @@ function Get-KeeperChildItems { .Parameter SkipGrouping Do not group result set by folder - + .Parameter ObjectType Limit result set to Folders or Records only #> - [CmdletBinding()] - Param ( - [Parameter(Position = 0)][string] $Path, - [string] $Filter, - [Switch] $Recursive, - [int] $Depth, - [Switch] $SkipGrouping, - [ValidateSet('Folder' ,'Record')][string] $ObjectType - ) - - $showFolder = $true - $showRecord = $true - if ($ObjectType) { - $showFolder = $ObjectType -eq 'Folder' - $showRecord = !$showFolder - } - - [KeeperSecurity.Vault.VaultOnline]$vault = getVault - - [KeeperSecurity.Vault.FolderNode] $baseDir = $null - if (!$vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$baseDir)) { - $baseDir = $vault.RootFolder - } - if ($Path) { - $components = splitKeeperPath $Path - $rs = parseKeeperPath $components $vault $baseDir - $baseDir = $rs[0] - } - [KeeperSecurity.Vault.FolderNode[]]$folders = @($baseDir) - if ($Recursive.IsPresent) { - $pos = 0 - $dep = 0 - while ($pos -lt $folders.Count) { - if ($Depth -gt 0) { - if ($dep -ge $Depth) { - break - } - } - $lastPos = $folders.Count - for ($i = $pos; $i -lt $lastPos; $i++) { - foreach($uid in $folders[$i].Subfolders) { - [KeeperSecurity.Vault.FolderNode] $sf = $null; - if ($vault.TryGetFolder($uid, [ref]$sf)) { - $folders += $sf - } - } - } - $pos = $lastPos - $dep++ - } - } - $entries = @() - $recordEntries = @{} - for ($i = 0; $i -lt $folders.Count; $i++) { - [KeeperSecurity.Vault.FolderNode]$f = $folders[$i] - $path = getVaultFolderPath $vault $f.FolderUid - if ($showFolder) { - foreach ($uid in $f.Subfolders) { - [KeeperSecurity.Vault.FolderNode]$sf = $null - if ($vault.TryGetFolder($uid, [ref]$sf)) { - $match = $true - if ($Filter) { - $match = @($sf.Name, $sf.FolderUid) | Select-String $Filter | Select-Object -First 1 - } - if ($match) { - $entry = [PSCustomObject]@{ - PSTypeName = "KeeperSecurity.Commander.FolderEntry$(if ($SkipGrouping.IsPresent) {'Flat'} else {''})" - Uid = $sf.FolderUid - Name = $sf.Name - OwnerFolder = $path - FolderType = $sf.FolderType - Shared = $sf.FolderType -ne [KeeperSecurity.Vault.FolderType]::UserFolder - SortGroup = 0 - } - $entries += $entry - } - } - } - } - if ($showRecord) { - foreach ($uid in $f.Records) { - [KeeperSecurity.Vault.KeeperRecord] $r = $null - if ($vault.TryGetKeeperRecord($uid, [ref]$r)) { - if ($r.Version -ne 2 -and $r.Version -ne 3) { - continue - } - $match = $true - if ($Filter) { - $match = @($r.Title, $r.Uid) | Select-String $Filter | Select-Object -First 1 - } - if ($match) { - if ($Flat.IsPresent -and $recordEntries.ContainsKey($uid)) { - $entry = $recordEntries[$uid] - $entry.OwnerFolder += $path - } else { - $type = [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordType($r) - $publicInfo = [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($r) - $entry = [PSCustomObject]@{ - PSTypeName = "KeeperSecurity.Commander.RecordEntry$(if ($SkipGrouping.IsPresent) {'Flat'} else {''})" - Uid = $r.Uid - Name = $r.Title - Shared = $r.Shared - Owner = $r.Owner - Type = $type - PublicInformation = $publicInfo - HasAttachments = ($vault.RecordAttachments($r).Count -gt 0) - SortGroup = 1 - } - if ($SkipGrouping.IsPresent) { - Add-Member -InputObject $entry -NotePropertyName OwnerFolder -NotePropertyValue @($path) - } else { - Add-Member -InputObject $entry -NotePropertyName OwnerFolder -NotePropertyValue $path - } - - $recordEntries[$uid] = $entry - $entry = $null - } - } - } - } - } - } - if ($recordEntries) { - $entries += $recordEntries.Values - } - if ($entries) { - if ($SkipGrouping.IsPresent) { - $entries | Sort-Object SortGroup, Name - } else { - $entries | Sort-Object OwnerFolder, SortGroup, Name - } - } + [CmdletBinding()] + Param ( + [Parameter(Position = 0)][string] $Path, + [string] $Filter, + [Switch] $Recursive, + [int] $Depth, + [Switch] $SkipGrouping, + [ValidateSet('Folder' , 'Record')][string] $ObjectType + ) + + $showFolder = $true + $showRecord = $true + if ($ObjectType) { + $showFolder = $ObjectType -eq 'Folder' + $showRecord = !$showFolder + } + + [KeeperSecurity.Vault.VaultOnline]$vault = getVault + + [KeeperSecurity.Vault.FolderNode] $baseDir = $null + if (!$vault.TryGetFolder($Script:Context.CurrentFolder, [ref]$baseDir)) { + $baseDir = $vault.RootFolder + } + if ($Path) { + $components = splitKeeperPath $Path + $rs = parseKeeperPath $components $vault $baseDir + $baseDir = $rs[0] + } + [KeeperSecurity.Vault.FolderNode[]]$folders = @($baseDir) + if ($Recursive.IsPresent) { + $pos = 0 + $dep = 0 + while ($pos -lt $folders.Count) { + if ($Depth -gt 0) { + if ($dep -ge $Depth) { + break + } + } + $lastPos = $folders.Count + for ($i = $pos; $i -lt $lastPos; $i++) { + foreach ($uid in $folders[$i].Subfolders) { + [KeeperSecurity.Vault.FolderNode] $sf = $null; + if ($vault.TryGetFolder($uid, [ref]$sf)) { + $folders += $sf + } + } + } + $pos = $lastPos + $dep++ + } + } + $entries = @() + $recordEntries = @{} + for ($i = 0; $i -lt $folders.Count; $i++) { + [KeeperSecurity.Vault.FolderNode]$f = $folders[$i] + $path = getVaultFolderPath $vault $f.FolderUid + if ($showFolder) { + foreach ($uid in $f.Subfolders) { + [KeeperSecurity.Vault.FolderNode]$sf = $null + if ($vault.TryGetFolder($uid, [ref]$sf)) { + $match = $true + if ($Filter) { + $match = @($sf.Name, $sf.FolderUid) | Select-String $Filter | Select-Object -First 1 + } + if ($match) { + $entry = [PSCustomObject]@{ + PSTypeName = "KeeperSecurity.Commander.FolderEntry$(if ($SkipGrouping.IsPresent) {'Flat'} else {''})" + Uid = $sf.FolderUid + Name = $sf.Name + OwnerFolder = $path + FolderType = $sf.FolderType + Shared = $sf.FolderType -ne [KeeperSecurity.Vault.FolderType]::UserFolder + SortGroup = 0 + } + $entries += $entry + } + } + } + } + if ($showRecord) { + foreach ($uid in $f.Records) { + [KeeperSecurity.Vault.KeeperRecord] $r = $null + if ($vault.TryGetKeeperRecord($uid, [ref]$r)) { + if ($r.Version -ne 2 -and $r.Version -ne 3) { + continue + } + $match = $true + if ($Filter) { + $match = @($r.Title, $r.Uid) | Select-String $Filter | Select-Object -First 1 + } + if ($match) { + if ($Flat.IsPresent -and $recordEntries.ContainsKey($uid)) { + $entry = $recordEntries[$uid] + $entry.OwnerFolder += $path + } + else { + $type = [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordType($r) + $publicInfo = [KeeperSecurity.Utils.RecordTypesUtils]::KeeperRecordPublicInformation($r) + $entry = [PSCustomObject]@{ + PSTypeName = "KeeperSecurity.Commander.RecordEntry$(if ($SkipGrouping.IsPresent) {'Flat'} else {''})" + Uid = $r.Uid + Name = $r.Title + Shared = $r.Shared + Owner = $r.Owner + Type = $type + PublicInformation = $publicInfo + HasAttachments = ($vault.RecordAttachments($r).Count -gt 0) + SortGroup = 1 + } + if ($SkipGrouping.IsPresent) { + Add-Member -InputObject $entry -NotePropertyName OwnerFolder -NotePropertyValue @($path) + } + else { + Add-Member -InputObject $entry -NotePropertyName OwnerFolder -NotePropertyValue $path + } + + $recordEntries[$uid] = $entry + $entry = $null + } + } + } + } + } + } + if ($recordEntries) { + $entries += $recordEntries.Values + } + if ($entries) { + if ($SkipGrouping.IsPresent) { + $entries | Sort-Object SortGroup, Name + } + else { + $entries | Sort-Object OwnerFolder, SortGroup, Name + } + } } -Register-ArgumentCompleter -CommandName Get-KeeperChildItems -ParameterName Path -ScriptBlock $Keeper_FolderPathRecordCompleter -New-Alias -Name kdir -Value Get-KeeperChildItems +Register-ArgumentCompleter -CommandName Get-KeeperChildItem -ParameterName Path -ScriptBlock $Keeper_FolderPathRecordCompleter +New-Alias -Name kdir -Value Get-KeeperChildItem function Get-KeeperObject { -<# + <# .Synopsis Get Keeper object by Uid @@ -316,229 +327,240 @@ function Get-KeeperObject { .Parameter ObjectType One of the following Record, SharedFolder, Folder, Team - + .Parameter PropertyName Return object property not the entire object #> - [CmdletBinding()] - Param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)][string[]] $Uid, - [string] [ValidateSet('Record' ,'SharedFolder', 'Folder', 'Team')] $ObjectType, - [string] $PropertyName - ) - - Begin { - [KeeperSecurity.Vault.VaultOnline]$vault = getVault - - $testRecord = if ($ObjectType) {$ObjectType -eq 'Record'} else {$true} - $testSharedFolder = if ($ObjectType) {$ObjectType -eq 'SharedFolder'} else {$true} - $testFolder = if ($ObjectType) {$ObjectType -eq 'Folder'} else {$true} - $testTeam = if ($ObjectType) {$ObjectType -eq 'Team'} else {$true} - } - Process { - ForEach($oid in $Uid) { - if ($testRecord) { - [KeeperSecurity.Vault.KeeperRecord] $record = $null - if ($vault.TryGetKeeperRecord($oid, [ref]$record)) { - if ($PropertyName) { - $mp = $record | Get-Member -MemberType Properties -Name $PropertyName - if ($mp) { - $record | Select-Object -ExpandProperty $PropertyName - } - } else { - $record - } - continue - } - } - if ($testSharedFolder) { - [KeeperSecurity.Vault.SharedFolder] $sf = $null - if ($vault.TryGetSharedFolder($oid, [ref]$sf)) { - if ($PropertyName) { - $mp = $sf | Get-Member -MemberType Properties -Name $PropertyName - if ($mp) { - $sf | Select-Object -ExpandProperty $PropertyName - } - } else { - $sf - } - continue - } - } - if ($testFolder) { - [KeeperSecurity.Vault.FolderNode] $f = $null - if ($vault.TryGetFolder($oid, [ref]$f)) { - if ($PropertyName) { - $mp = $f | Get-Member -MemberType Properties -Name $PropertyName - if ($mp) { - $f | Select-Object -ExpandProperty $PropertyName - } - } else { - $f - } - continue - } - } - if ($testTeam) { - [KeeperSecurity.Vault.Team] $t = $null - if ($vault.TryGetTeam($oid, [ref]$t)) { - if ($PropertyName) { - $mp = $t | Get-Member -MemberType Properties -Name $PropertyName - if ($mp) { - $t | Select-Object -ExpandProperty $PropertyName - } - } else { - $t - } - continue - } - ensureAvalableLoaded - [KeeperSecurity.Vault.TeamInfo] $teamInfo = $null - $teamInfo = $Script:Context.AvailableTeams | Where-Object { $_.TeamUid -ceq $oid } | Select-Object -First 1 - if ($teamInfo) { - if ($PropertyName) { - $mp = $teamInfo | Get-Member -MemberType Properties -Name $PropertyName - if ($mp) { - $teamInfo | Select-Object -ExpandProperty $PropertyName - } - } else { - $teamInfo - } - continue - } - } - } - } + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)][string[]] $Uid, + [string] [ValidateSet('Record' , 'SharedFolder', 'Folder', 'Team')] $ObjectType, + [string] $PropertyName + ) + + Begin { + [KeeperSecurity.Vault.VaultOnline]$vault = getVault + + $testRecord = if ($ObjectType) { $ObjectType -eq 'Record' } else { $true } + $testSharedFolder = if ($ObjectType) { $ObjectType -eq 'SharedFolder' } else { $true } + $testFolder = if ($ObjectType) { $ObjectType -eq 'Folder' } else { $true } + $testTeam = if ($ObjectType) { $ObjectType -eq 'Team' } else { $true } + } + Process { + ForEach ($oid in $Uid) { + if ($testRecord) { + [KeeperSecurity.Vault.KeeperRecord] $record = $null + if ($vault.TryGetKeeperRecord($oid, [ref]$record)) { + if ($PropertyName) { + $mp = $record | Get-Member -MemberType Properties -Name $PropertyName + if ($mp) { + $record | Select-Object -ExpandProperty $PropertyName + } + } + else { + $record + } + continue + } + } + if ($testSharedFolder) { + [KeeperSecurity.Vault.SharedFolder] $sf = $null + if ($vault.TryGetSharedFolder($oid, [ref]$sf)) { + if ($PropertyName) { + $mp = $sf | Get-Member -MemberType Properties -Name $PropertyName + if ($mp) { + $sf | Select-Object -ExpandProperty $PropertyName + } + } + else { + $sf + } + continue + } + } + if ($testFolder) { + [KeeperSecurity.Vault.FolderNode] $f = $null + if ($vault.TryGetFolder($oid, [ref]$f)) { + if ($PropertyName) { + $mp = $f | Get-Member -MemberType Properties -Name $PropertyName + if ($mp) { + $f | Select-Object -ExpandProperty $PropertyName + } + } + else { + $f + } + continue + } + } + if ($testTeam) { + [KeeperSecurity.Vault.Team] $t = $null + if ($vault.TryGetTeam($oid, [ref]$t)) { + if ($PropertyName) { + $mp = $t | Get-Member -MemberType Properties -Name $PropertyName + if ($mp) { + $t | Select-Object -ExpandProperty $PropertyName + } + } + else { + $t + } + continue + } + ensureAvalableLoaded + [KeeperSecurity.Vault.TeamInfo] $teamInfo = $null + $teamInfo = $Script:Context.AvailableTeams | Where-Object { $_.TeamUid -ceq $oid } | Select-Object -First 1 + if ($teamInfo) { + if ($PropertyName) { + $mp = $teamInfo | Get-Member -MemberType Properties -Name $PropertyName + if ($mp) { + $teamInfo | Select-Object -ExpandProperty $PropertyName + } + } + else { + $teamInfo + } + continue + } + } + } + } } New-Alias -Name ko -Value Get-KeeperObject function parseKeeperPath { - Param ( - [string[]]$components, - [KeeperSecurity.Vault.VaultOnline]$vault, - [KeeperSecurity.Vault.FolderNode]$folder - ) - if ($components) { - if (!$components[0]) { - $folder = $vault.RootFolder - $_, $components = $components - } - while ($components) { - $resume = $false - $component, $rest = $components - if ($component -eq '..') { - if ($folder.ParentUid) { - $resume = $vault.TryGetFolder($folder.ParentUid, [ref]$folder) - } else { - $folder = $vault.RootFolder - $resume = $true - } - } - elseif (!$component -or $component -eq '.') { - $resume = $true - } - else { - foreach ($x in $folder.Subfolders) { - [KeeperSecurity.Vault.FolderNode] $subfolder = $null - if ($vault.TryGetFolder($x, [ref]$subfolder)) { - if ($subfolder.Name -eq $component) { - $resume = $true - $folder = $subfolder - break - } - } - } - } - - if ($resume) { - $components = $rest - } else { - break - } - } - $folder - $components -join $Script:PathDelimiter - } else { - $folder - $path - } + Param ( + [string[]]$components, + [KeeperSecurity.Vault.VaultOnline]$vault, + [KeeperSecurity.Vault.FolderNode]$folder + ) + if ($components) { + if (!$components[0]) { + $folder = $vault.RootFolder + $_, $components = $components + } + while ($components) { + $resume = $false + $component, $rest = $components + if ($component -eq '..') { + if ($folder.ParentUid) { + $resume = $vault.TryGetFolder($folder.ParentUid, [ref]$folder) + } + else { + $folder = $vault.RootFolder + $resume = $true + } + } + elseif (!$component -or $component -eq '.') { + $resume = $true + } + else { + foreach ($x in $folder.Subfolders) { + [KeeperSecurity.Vault.FolderNode] $subfolder = $null + if ($vault.TryGetFolder($x, [ref]$subfolder)) { + if ($subfolder.Name -eq $component) { + $resume = $true + $folder = $subfolder + break + } + } + } + } + + if ($resume) { + $components = $rest + } + else { + break + } + } + $folder + $components -join $Script:PathDelimiter + } + else { + $folder + $path + } } function splitKeeperPath { - Param ([string] $path) - - [bool]$isDelimiter = $false - [string]$component = '' - foreach ($x in $path.ToCharArray()) { - if ($x -eq $Script:PathDelimiter) { - if ($isDelimiter) { - $component += $x - $isDelimiter = $false - } else { - $isDelimiter = $true - } - } else { - if ($isDelimiter) { - $component - $component = '' - $isDelimiter = $false - } - $component += $x - } - } - $component - if ($isDelimiter) { - '' - } + Param ([string] $path) + + [bool]$isDelimiter = $false + [string]$component = '' + foreach ($x in $path.ToCharArray()) { + if ($x -eq $Script:PathDelimiter) { + if ($isDelimiter) { + $component += $x + $isDelimiter = $false + } + else { + $isDelimiter = $true + } + } + else { + if ($isDelimiter) { + $component + $component = '' + $isDelimiter = $false + } + $component += $x + } + } + $component + if ($isDelimiter) { + '' + } } function exportKeeperNode { - Param ([KeeperSecurity.Vault.FolderNode] $folder) - [PSCustomObject]@{ - PSTypeName = 'KeeperSecurity.Commander.FolderInfo' - FolderUid = $folder.FolderUid - Path = getVaultFolderPath $vault $folder.FolderUid - Name = $folder.Name - ParentUid = $folder.ParentUid - FolderType = $folder.FolderType - } + Param ([KeeperSecurity.Vault.FolderNode] $folder) + [PSCustomObject]@{ + PSTypeName = 'KeeperSecurity.Commander.FolderInfo' + FolderUid = $folder.FolderUid + Path = getVaultFolderPath $vault $folder.FolderUid + Name = $folder.Name + ParentUid = $folder.ParentUid + FolderType = $folder.FolderType + } } function escapePathComponent { - Param ([string] $component) - - $component = $component -replace '\\', '\\' - $component = $component -replace '''', '''''' - if ($component -match '[\s'']') { - "'${component}'" - } else { - $component - } + Param ([string] $component) + + $component = $component -replace '\\', '\\' + $component = $component -replace '''', '''''' + if ($component -match '[\s'']') { + "'${component}'" + } + else { + $component + } } function getVaultFolderPath { - Param ( - [KeeperSecurity.Vault.VaultOnline]$vault, - [string] $folderUid - ) - - $comps = @() - traverseFolderToRoot $vault $folderUid ([ref]$comps) - $path = '' - if ($comps) { - [Array]::Reverse($comps) - $comps += '' - $path = ($comps | ForEach-Object {$_ -replace [Regex]::Escape($Script:PathDelimiter), "${Script:PathDelimiter}${Script:PathDelimiter}" }) -join $Script:PathDelimiter - } - "${Script:PathDelimiter}${path}" + Param ( + [KeeperSecurity.Vault.VaultOnline]$vault, + [string] $folderUid + ) + + $comps = @() + traverseFolderToRoot $vault $folderUid ([ref]$comps) + $path = '' + if ($comps) { + [Array]::Reverse($comps) + $comps += '' + $path = ($comps | ForEach-Object { $_ -replace [Regex]::Escape($Script:PathDelimiter), "${Script:PathDelimiter}${Script:PathDelimiter}" }) -join $Script:PathDelimiter + } + "${Script:PathDelimiter}${path}" } -function traverseFolderToRoot ([KeeperSecurity.Vault.VaultOnline]$vault, [string] $folderUid, [ref][string[]] $components) { - if ($folderUid) { - [KeeperSecurity.Vault.FolderNode]$folder = $null - if ($vault.TryGetFolder($folderUid, [ref]$folder)) { - $components.Value += $folder.Name - traverseFolderToRoot $vault $folder.ParentUid $components - } - } +function traverseFolderToRoot ([KeeperSecurity.Vault.VaultOnline]$vault, [string] $folderUid, [ref] $components) { + if ($folderUid) { + [KeeperSecurity.Vault.FolderNode]$folder = $null + if ($vault.TryGetFolder($folderUid, [ref]$folder)) { + $components.Value += $folder.Name + traverseFolderToRoot $vault $folder.ParentUid $components + } + } }