MyRemoteManager.psm1
# # Script module for module 'MyRemoteManager' # #Requires -Version 7.0 #Requires -PSEdition Core using namespace System.Management.Automation #region Enum enum Scopes { # Scopes in which a connection can be invoked Undefined = 1 Console = 2 External = 3 } #endregion Enums #region Classes class Item { # Name [ValidateLength(1, 50)] [ValidatePattern("^([a-zA-Z0-9_\-]+)$")] [string] $Name # Description [string] $Description [hashtable] Splat() { $Hashtable = [ordered] @{} foreach ($p in $this.PSObject.Properties) { $this.PSObject.Properties | ForEach-Object -Process { $Hashtable[$p.Name] = $p.Value } } return $Hashtable } } class Client : Item { # Executable [string] $Executable # Command template [string] $TokenizedArgs # Default port [UInt16] $DefaultPort # Default connection scope [Scopes] $DefaultScope # Does this client require a user [bool] $RequiresUser # Tokens static [string] $HostToken = "<host>" static [string] $PortToken = "<port>" static [string] $UserToken = "<user>" Client( [string] $Name, [string] $Executable, [string] $TokenizedArgs, [UInt16] $DefaultPort, [Scopes] $DefaultScope, [string] $Description ) { $this.Name = $Name $this.Executable = $Executable [Client]::ValidateTokenizedArgs($TokenizedArgs) $this.TokenizedArgs = $TokenizedArgs $this.DefaultPort = $DefaultPort $this.DefaultScope = $DefaultScope $this.RequiresUser = [Client]::UserTokenExists($TokenizedArgs) $this.Description = $Description } hidden static [void] ValidateTokenizedArgs( [string] $TokenizedArgs ) { @( [Client]::HostToken, [Client]::PortToken ) | ForEach-Object -Process { if ($TokenizedArgs -notmatch $_) { throw "The argument line does not contain the following token: {0}." -f $_ } } } hidden static [bool] UserTokenExists([string] $TokenizedArgs) { return $TokenizedArgs -match [Client]::UserToken } [string] GenerateArgs( [string] $Hostname, [UInt16] $Port ) { return $this.TokenizedArgs.Replace( [Client]::HostToken, $Hostname ).Replace( [Client]::PortToken, $Port ) } [string] GenerateArgs( [string] $Hostname, [UInt16] $Port, [string] $User ) { return $this.GenerateArgs($Hostname, $Port).Replace( [Client]::UserToken, $User ) } [string] ToString() { return "{0}, Description: `"{1}`", Scope: {2}, Command: `"{3} {4}`"" -f ( $this.Name, $this.Description, $this.DefaultScope, $this.Executable, $this.TokenizedArgs.Replace( "<port>", "<port:{0}>" -f $this.DefaultPort ) ) } } class Connection : Item { # Hostname [ValidatePattern("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$")] [string] $Hostname # Port [UInt16] $Port # Default client [string] $DefaultClient # Default user [string] $DefaultUser Connection( [String] $Name, [String] $Hostname, [UInt16] $Port, [string] $DefaultClient, [string] $DefaultUser, [string] $Description ) { $this.Name = $Name $this.Hostname = $Hostname.ToLower() $this.Port = $Port $this.DefaultClient = $DefaultClient $this.DefaultUser = $DefaultUser $this.Description = $Description } [bool] IsDefaultPort() { return $this.Port -eq 0 } [string] ToString() { return "{0}, Description `"{1}`", Default client {2}, Target {3}:{4}" -f ( $this.Name, $this.Description, $this.DefaultClient, $this.Hostname, $( if ($this.IsDefaultPort()) { "default" } else { $this.Port.ToString() } ) ) } } class Inventory { # Title for the inventory file [string] $Title = "MyRemoteManager inventory" # description for the inventory file [string] $Description = "MyRemoteManager inventory file where the connections and clients are stored" # Version of the inventory file [string] $Version = "0.1.0" # Path to the inventory file [string] $Path = [Inventory]::GetPath() # Collection of Clients [Client[]] $Clients # Collection of Connections [Connection[]] $Connections # Encoding for inventory file static [string] $Encoding = "utf-8" # Name of the environement variable to use a custom path to the inventory file static [string] $EnvVariable = "MY_RM_INVENTORY" static [string] GetPath() { foreach ($Target in @("Process", "User", "Machine")) { $Value = [System.Environment]::GetEnvironmentVariable( [Inventory]::EnvVariable, [System.EnvironmentVariableTarget]::"$Target" ) if ($Value) { return $Value } } return Join-Path -Path $env:USERPROFILE -ChildPath "MyRemoteManager.json" } [void] ReadFile() { $Items = Get-Content -Path $this.Path -Raw -Encoding ([Inventory]::Encoding) | ConvertFrom-Json -AsHashtable if ($Items.Version -ne $this.Version) { Write-Warning -Message ( "Version of the inventory file is not supported. Current version: `"{0}`", Expected version: `"{1}`"" -f ( $Items.Version, $this.Version ) ) throw "Version of the inventory file is not supported." } foreach ($c in $Items.Clients) { $this.Clients += New-Object -TypeName Client -ArgumentList @( $c.Name, $c.Executable, $c.TokenizedArgs, $c.DefaultPort, $c.DefaultScope, $c.Description ) } if ($this.ClientNameDuplicateExists()) { Write-Warning -Message ("Fix the inventory by renaming the duplicated client names in the inventory file: {0}" -f ( [Inventory]::GetPath() ) ) } foreach ($c in $Items.Connections) { $this.Connections += New-Object -TypeName Connection -ArgumentList @( $c.Name, $c.Hostname, $c.Port, $c.DefaultClient, $c.DefaultUser, $c.Description ) } if ($this.ConnectionNameDuplicateExists()) { Write-Warning -Message ( "Fix the inventory by renaming the duplicated connection names in the inventory file: {0}" -f ( [Inventory]::GetPath() ) ) } } [void] SaveFile() { $Items = [ordered] @{ Title = $this.Title Description = $this.Description Version = $this.Version Clients = @() Connections = @() } foreach ($c in $this.Clients) { $Items.Clients += $c.Splat() } foreach ($c in $this.Connections) { $Connection = $c.Splat() $Items.Connections += $Connection } $Json = ConvertTo-Json -InputObject $Items -Depth 3 $BackupPath = "{0}.backup" -f $this.Path if (Test-Path -Path $this.Path) { Copy-Item -Path $this.Path -Destination $BackupPath -Force } Set-Content -Path $this.Path -Value $Json -Encoding ([Inventory]::Encoding) -Force } hidden [bool] ClientNameDuplicateExists() { $Duplicates = $this.Clients | Group-Object -Property Name | Where-Object -Property Count -GT 1 if ($Duplicates) { $Duplicates | ForEach-Object -Process { Write-Warning -Message ("It exists more than one client named `"{0}`"." -f $_.Name) } return $true } return $false } hidden [bool] ConnectionNameDuplicateExists() { $Duplicates = $this.Connections | Group-Object -Property Name | Where-Object -Property Count -GT 1 if ($Duplicates) { $Duplicates | ForEach-Object -Process { Write-Warning -Message ("It exists more than one connection named `"{0}`"." -f $_.Name) } return $true } return $false } [Client] GetClient([string] $Name) { return $this.Clients | Where-Object -Property Name -EQ $Name } [Connection] GetConnection([string] $Name) { return $this.Connections | Where-Object -Property Name -EQ $Name } [bool] ClientExists([string] $Name) { return $this.GetClient($Name).Count -gt 0 } [bool] ConnectionExists([string] $Name) { return $this.GetConnection($Name).Count -gt 0 } [void] AddClient([Client] $Client) { if ($this.ClientExists($Client.Name)) { throw "Cannot add Client `"{0}`" as it already exists." -f $Client.Name } $this.Clients += $Client } [void] AddConnection([Connection] $Connection) { if ($this.ConnectionExists($Connection.Name)) { throw "Cannot add Connection `"{0}`" as it already exists." -f $Connection.Name } $this.Connections += $Connection } [void] RemoveClient([string] $Name) { $this.Clients = $this.Clients | Where-Object -Property Name -NE $Name } [void] RemoveConnection([string] $Name) { $this.Connections = $this.Connections | Where-Object -Property Name -NE $Name } } class ValidateClientName : IValidateSetValuesGenerator { [string[]] GetValidValues() { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() return $Inventory.Clients | ForEach-Object -Process { $_.Name } } } class ValidateConnectionName : IValidateSetValuesGenerator { [string[]] GetValidValues() { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() return $Inventory.Connections | ForEach-Object -Process { $_.Name } } } #endregion Classes #region Public functions function Add-MyRMClient { <# .SYNOPSIS Adds MyRemoteManager client. .DESCRIPTION Adds client entry to the MyRemoteManager inventory file. .PARAMETER Name Name of the client. .PARAMETER Executable Path to the executable program that the client uses. .PARAMETER Arguments String of Arguments to pass to the executable. The string should contain the required tokens. Please read the documentation of MyRemoteManager. .PARAMETER DefaultPort Network port to use if the connection has no defined port. .PARAMETER DefaultScope Default scope in which a connection will be invoked. .PARAMETER Description Short description for the client. .INPUTS None. You cannot pipe objects to Add-MyRMClient. .OUTPUTS System.Void. None. .EXAMPLE PS> Add-MyRMClient -Name SSH -Executable "ssh.exe" -Arguments "-l <user> -p <port> <host>" -DefaultPort 22 .EXAMPLE PS> Add-MyRMClient -Name MyCustomClient -Executable "client.exe" -Arguments "--hostname <host> --port <port>" -DefaultPort 666 -DefaultScope External -Description "My custom client" #> [OutputType([string])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( Mandatory = $true, HelpMessage = "Name of the client." )] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter( Mandatory = $true, HelpMessage = "Path to the executable to run as client." )] [ValidateNotNullOrEmpty()] [string] $Executable, [Parameter( Mandatory = $true, HelpMessage = "Arguments as a tokenized string. Please, read the documentation to get the list of tokens." )] [ValidateNotNullOrEmpty()] [string] $Arguments, [Parameter( Mandatory = $true, HelpMessage = "Default port to connect to on the remote host." )] [ValidateNotNullOrEmpty()] [UInt16] $DefaultPort, [Parameter( HelpMessage = "Default scope in which a connection will be invoked." )] [ValidateNotNullOrEmpty()] [Scopes] $DefaultScope = [Scopes]::Console, [Parameter( HelpMessage = "Short description of the client." )] [string] $Description ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { $Client = New-Object -TypeName Client -ArgumentList @( $Name, $Executable, $Arguments, $DefaultPort, $DefaultScope, $Description ) if ( $PSCmdlet.ShouldProcess( "Inventory file {0}" -f $Inventory.Path, "Add Client {0}" -f $Client.ToString() ) ) { $Inventory.AddClient($Client) $Inventory.SaveFile() Write-Verbose -Message ("Client `"{0}`" has been added to the inventory." -f $Name) } } } function Add-MyRMConnection { <# .SYNOPSIS Adds MyRemoteManager connection. .DESCRIPTION Adds connection entry to the MyRemoteManager inventory file. .PARAMETER Name Name of the connection. .PARAMETER Hostname Name of the remote host. .PARAMETER Port Port to connect to on the remote host. If not set, it will use the default port of the client. .PARAMETER DefaultClient Name of the default client. .PARAMETER DefaultUser Default client to use to connect to the remote host. .PARAMETER Description Short description for the connection. .INPUTS None. You cannot pipe objects to Add-MyRMConnection. .OUTPUTS System.Void. None. .EXAMPLE PS> Add-MyRMConnection -Name myconn -Hostname myhost -DefaultClient SSH .EXAMPLE PS> Add-MyRMConnection -Name myrdpconn -Hostname myhost -DefaultClient RDP -Description "My RDP connection" .EXAMPLE PS> Add-MyRMConnection -Name mysshconn -Hostname myhost -Port 2222 -DefaultClient SSH -DefaultUser myuser -Description "My SSH connection" #> [OutputType([string])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( Mandatory = $true, HelpMessage = "Name of the connection." )] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter( Mandatory = $true, HelpMessage = "Name of the remote host." )] [ValidateNotNullOrEmpty()] [string] $Hostname, [Parameter( HelpMessage = "Port to connect to on the remote host." )] [UInt16] $Port, [Parameter( Mandatory = $true, HelpMessage = "Default client to use to connect to the remote host." )] [ValidateSet([ValidateClientName])] [string] $DefaultClient, [Parameter( HelpMessage = "Default user to use to connect to the remote host." )] [string] $DefaultUser, [Parameter( HelpMessage = "Short description of the connection." )] [string] $Description ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { $Connection = New-Object -TypeName Connection -ArgumentList @( $Name, $Hostname, $Port, $DefaultClient, $DefaultUser, $Description ) if ($PSCmdlet.ShouldProcess( "Inventory file {0}" -f $Inventory.Path, "Add Connection {0}" -f $Connection.ToString() ) ) { $Inventory.AddConnection($Connection) $Inventory.SaveFile() Write-Verbose -Message ("Connection `"{0}`" has been added to the inventory." -f $Name) } } } function Get-MyRMClient { <# .SYNOPSIS Gets MyRemoteManager clients. .DESCRIPTION Gets available clients from the MyRemoteManager inventory file. Clients can be filtered by their name. .PARAMETER Name Filters clients by name. .INPUTS None. You cannot pipe objects to Get-MyRMClient. .OUTPUTS PSCustomObject. Get-MyRMClient returns objects with details of the available clients. .EXAMPLE PS> Get-MyRMClient (objects) .EXAMPLE PS> Get-MyRMClient -Name "custom_*" (filtered objects) #> [OutputType([PSCustomObject[]])] [CmdletBinding()] param ( [Parameter( HelpMessage = "Filter by client name." )] [ValidateNotNullOrEmpty()] [string] $Name = "*" ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { $Clients = @() foreach ($c in $Inventory.Clients) { $Clients += [PSCustomObject] @{ Name = $c.Name Command = "{0} {1}" -f $c.Executable, $c.TokenizedArgs DefaultPort = $c.DefaultPort DefaultScope = $c.DefaultScope Description = $c.Description } } } end { $Clients | Where-Object -Property Name -Like $Name | Sort-Object -Property Name } } function Get-MyRMConnection { <# .SYNOPSIS Gets MyRemoteManager connections. .DESCRIPTION Gets available connections from the MyRemoteManager inventory file. connections can be filtered by their name and/or client name. .PARAMETER Name Filters connections by name. .INPUTS None. You cannot pipe objects to Get-MyRMConnection. .OUTPUTS PSCustomObject. Get-MyRMConnection returns objects with details of the available connections. .EXAMPLE PS> Get-MyRMConnection (objects) .EXAMPLE PS> Get-MyRMConnection -Name "myproject_*" -Hostname "*.mydomain" -Client "*_myproject" (filtered objects) #> [OutputType([PSCustomObject[]])] [CmdletBinding()] param ( [Parameter( HelpMessage = "Filter by connection name." )] [ValidateNotNullOrEmpty()] [string] $Name = "*", [Parameter( HelpMessage = "Filter by hostname." )] [ValidateNotNullOrEmpty()] [string] $Hostname = "*", [Parameter( HelpMessage = "Filter by client name." )] [ValidateNotNullOrEmpty()] [string] $Client = "*" ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { $Connections = @() foreach ($c in $Inventory.Connections) { $Connections += [PSCustomObject] @{ Name = $c.Name Hostname = $c.Hostname Port = if ($c.IsDefaultPort) { $Inventory.GetClient($c.DefaultClient).DefaultPort } else { $c.Port } DefaultClient = $c.DefaultClient DefaultUser = $c.DefaultUser Description = $c.Description } } } end { $Connections | Where-Object -Property Name -Like $Name | Where-Object -Property Hostname -Like $Hostname | Where-Object -Property DefaultClient -Like $Client | Sort-Object -Property Name } } function Get-MyRMInventoryInfo { <# .SYNOPSIS Gets MyRemoteManager inventory information. .DESCRIPTION Gets detailed information about the MyRemoteManager inventory. .INPUTS None. You cannot pipe objects to Get-MyRMInventoryInfo. .OUTPUTS PSCustomObject. Get-MyRMInventoryInfo returns an object with detailed information. .EXAMPLE PS> Get-MyRMInventoryInfo (objects) #> [OutputType([PSCustomObject])] [CmdletBinding()] param () begin { $Inventory = New-Object -TypeName Inventory $FileExists = $false } process { if (Test-Path -Path $Inventory.Path -PathType Leaf) { $Inventory.ReadFile() $FileExists = $true } $InventoryInfo = [PSCustomObject] @{ Path = $Inventory.Path EnvVariable = [Inventory]::EnvVariable FileExists = $FileExists NumberOfClients = $Inventory.Clients.Count NumberOfConnections = $Inventory.Connections.Count } } end { $InventoryInfo } } function Invoke-MyRMConnection { <# .SYNOPSIS Invokes MyRemoteManager connection. .DESCRIPTION Invokes MyRemoteManager connection which is defined in the inventory. .PARAMETER Name Name of the connection. .PARAMETER Client Name of the client to use to initiate the connection. .PARAMETER User Name of the user to connect with. .PARAMETER Scope Scope in which the connection will be invoked. .INPUTS None. You cannot pipe objects to Invoke-MyRMConnection. .OUTPUTS System.Void. None. .EXAMPLE PS> Invoke-MyRMConnection myconn .EXAMPLE PS> Invoke-MyRMConnection -Name myconn -Client SSH -User root -Scope Console #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( Position = 0, Mandatory = $true, HelpMessage = "Name of the connection." )] [ValidateSet([ValidateConnectionName])] [string] $Name, [Parameter( HelpMessage = "Name of the client to use to initiate the connection." )] [ValidateSet([ValidateClientName])] [Alias("c")] [string] $Client, [Parameter( HelpMessage = "Name of the user to connect with." )] [Alias("u")] [string] $User, [Parameter( HelpMessage = "Scope in which the connection will be invoked." )] [Alias("x")] [Scopes] $Scope ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { $Invocation = @{} $Invocation.Connection = $Inventory.GetConnection($Name) Write-Debug -Message ("Invoke connection {0}" -f $Invocation.Connection.ToString()) $Invocation.Client = if ($Client) { $Inventory.GetClient($Client) } else { $Inventory.GetClient($Invocation.Connection.DefaultClient) } Write-Debug -Message ("Invoke connection with client {0}" -f $Invocation.Client.ToString()) $Invocation.Port = if ($Invocation.Connection.IsDefaultPort()) { $Invocation.Client.DefaultPort } else { $Invocation.Connection.Port } Write-Debug -Message ("Invoke connection on port {0}" -f $Invocation.Port) $Invocation.Executable = $Invocation.Client.Executable $Invocation.Arguments = if ($Invocation.Client.RequiresUser) { if ($User) { $Invocation.Client.GenerateArgs( $Invocation.Connection.Hostname, $Invocation.Port, $User ) } elseif ($Invocation.Connection.DefaultUser) { $Invocation.Client.GenerateArgs( $Invocation.Connection.Hostname, $Invocation.Port, $Invocation.Connection.DefaultUser ) } else { throw "Cannot invoke connection: A user must be specified." } } else { $Invocation.Client.GenerateArgs( $Invocation.Connection.Hostname, $Invocation.Port ) } $Invocation.Command = "{0} {1}" -f $Invocation.Executable, $Invocation.Arguments Write-Debug -Message ("Invoke connection with command `"{0}`"" -f $Invocation.Command) $Invocation.Scope = if ($Scope) { $Scope } else { $Invocation.Client.DefaultScope } Write-Debug -Message ("Invoke connection in scope `"{0}`"" -f $Invocation.Scope) if ($PSCmdlet.ShouldProcess($Invocation.Connection.ToString(), "Initiate connection")) { switch ($Invocation.Scope) { ([Scopes]::Console) { Invoke-Expression -Command $Invocation.Command } ([Scopes]::External) { Start-Process -FilePath $Invocation.Executable -ArgumentList $Invocation.Arguments } ([Scopes]::Undefined) { throw "Cannot invoke connection: Scope is undefined." } default { throw "Cannot invoke connection: Scope is unknown." } } } } } function New-MyRMInventory { <# .SYNOPSIS Creates MyRemoteManager inventory file. .DESCRIPTION Creates a new inventory file where MyRemoteManager saves items. .PARAMETER NoDefaultClients Does not add defaults clients to the new inventory. .PARAMETER Force Overwrites existing inventory file. .PARAMETER PassThru Indicates that the cmdlet sends items from the interactive window down the pipeline as input to other commands. .INPUTS None. You cannot pipe objects to New-MyRMInventory. .OUTPUTS System.Void. None. or if PassThru is set, System.String. New-MyRMInventory returns a string with the path to the created inventory. .EXAMPLE PS> New-MyRMInventory .EXAMPLE PS> New-MyRMInventory -NoDefaultClients .EXAMPLE PS> New-MyRMInventory -Force .EXAMPLE PS> New-MyRMInventory -PassThru C:\Users\MyUsername\MyRemoteManager.json .EXAMPLE PS> New-MyRMInventory -NoDefaultClients -Force -PassThru C:\Users\MyUsername\MyRemoteManager.json #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( HelpMessage = "Do not add defaults clients." )] [switch] $NoDefaultClients, [Parameter( HelpMessage = "Overwrite existing inventory file." )] [switch] $Force, [Parameter( HelpMessage = "Indicates that the cmdlet sends items from the interactive window down the pipeline as input to other commands." )] [switch] $PassThru ) begin { $Inventory = New-Object -TypeName Inventory } process { if ((Test-Path -Path $Inventory.Path -PathType Leaf) -and -not ($Force.IsPresent)) { Write-Error -ErrorAction Stop -Exception ( [System.IO.IOException] "Inventory file already exists. Use `"-Force`" to overwrite it." ) } if ($PSCmdlet.ShouldProcess($Inventory.Path, "Create inventory file")) { if (-not $NoDefaultClients.IsPresent) { $Inventory.AddClient( (New-Object -TypeName Client -ArgumentList @( "OpenSSH", "C:\Windows\System32\OpenSSH\ssh.exe", "-l <user> -p <port> <host>", 22, [Scopes]::Console, "OpenSSH (Microsoft Windows feature)" ) ) ) $Inventory.AddClient( (New-Object -TypeName Client -ArgumentList @( "PuTTY_SSH", "putty.exe", "-ssh -P <port> <user>@<host>", 22, [Scopes]::External, "PuTTY using SSH protocol" ) ) ) $Inventory.AddClient( (New-Object -TypeName Client -ArgumentList @( "RD", "C:\Windows\System32\mstsc.exe", "/v:<host>:<port> /fullscreen", 3389, [Scopes]::External, "Microsoft Remote Desktop" ) ) ) } $Inventory.SaveFile() Write-Verbose -Message ("Inventory file has been created: {0}" -f $Inventory.Path) } } end { if ($PassThru.IsPresent) { Resolve-Path $Inventory.Path | Select-Object -ExpandProperty Path } } } function Remove-MyRMClient { <# .SYNOPSIS Removes MyRemoteManager client. .DESCRIPTION Removes client entry from the MyRemoteManager inventory file. .PARAMETER Name Name of the client. .INPUTS None. You cannot pipe objects to Remove-MyRMClient. .OUTPUTS System.Void. None. .EXAMPLE PS> Remove-MyRMClient SSH .EXAMPLE PS> Remove-MyRMClient -Name SSH #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( Position = 0, Mandatory = $true, HelpMessage = "Name of the client." )] [ValidateNotNullOrEmpty()] [ValidateSet( [ValidateClientName] )] [string] $Name ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { if ( $PSCmdlet.ShouldProcess( "Inventory file {0}" -f $Inventory.Path, "Remove Client {0}" -f $Name ) ) { $Inventory.RemoveClient($Name) $Inventory.SaveFile() Write-Verbose -Message ("Client `"{0}`" has been removed from the inventory." -f $Name) } } } function Remove-MyRMConnection { <# .SYNOPSIS Removes MyRemoteManager connection. .DESCRIPTION Removes connection entry from the MyRemoteManager inventory file. .PARAMETER Name Name of the connection. .INPUTS None. You cannot pipe objects to Remove-MyRMConnection. .OUTPUTS System.Void. None. .EXAMPLE PS> Remove-MyRMConnection myconn .EXAMPLE PS> Remove-MyRMConnection -Name myconn #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( Position = 0, Mandatory = $true, HelpMessage = "Name of the connection." )] [ValidateNotNullOrEmpty()] [ValidateSet( [ValidateConnectionName] )] [string] $Name ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { if ( $PSCmdlet.ShouldProcess( "Inventory file {0}" -f $Inventory.Path, "Remove Connection {0}" -f $Name ) ) { $Inventory.RemoveConnection($Name) $Inventory.SaveFile() Write-Verbose -Message ("Connection `"{0}`" has been removed from the inventory." -f $Name) } } } function Set-MyRMInventoryPath { <# .SYNOPSIS Sets MyRemoteManager inventory path. .DESCRIPTION Sets the specific environment variable to overwrite default path to the MyRemoteManager inventory file. .PARAMETER Name Path to the inventory file. This path is set in a environment variable. Pass an empty string or null to reset to the default path. .PARAMETER Target Target scope where the environment variable will be saved. .INPUTS None. You cannot pipe objects to Set-MyRMInventoryPath. .OUTPUTS System.Void. None. .EXAMPLE PS> Set-MyRMInventoryPath C:\MyCustomInventory.json .EXAMPLE PS> Set-MyRMInventoryPath -Path C:\MyCustomInventory.json #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter( Position = 0, Mandatory = $true, HelpMessage = "Path to the inventory file." )] [AllowEmptyString()] [string] $Path, [Parameter( HelpMessage = "Target scope of the environment variable." )] [ValidateSet("Process", "User")] [string] $Target = "User" ) begin { $EnvVar = [Inventory]::EnvVariable } process { if ( $PSCmdlet.ShouldProcess( ("{0} environment variable {1}" -f $Target, $EnvVar), "Set value {0}" -f $Path ) ) { [System.Environment]::SetEnvironmentVariable( $EnvVar, $Path, [System.EnvironmentVariableTarget]::"$Target" ) Write-Verbose -Message ("{0} environment variable `"{1}`" has been set to `"{2}`"." -f $Target, $EnvVar, $Path) } } } function Test-MyRMConnection { <# .SYNOPSIS Tests MyRemoteManager connection. .DESCRIPTION Tests MyRemoteManager connection which is defined in the inventory. .PARAMETER Name Name of the connection. .INPUTS None. You cannot pipe objects to Test-MyRMConnection. .OUTPUTS System.Void. None. .EXAMPLE PS> Test-MyRMConnection myconn .EXAMPLE PS> Test-MyRMConnection -Name myconn #> [OutputType([void])] [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $true, HelpMessage = "Name of the connection." )] [ValidateNotNullOrEmpty()] [ValidateSet( [ValidateConnectionName] )] [string] $Name ) begin { $Inventory = New-Object -TypeName Inventory $Inventory.ReadFile() } process { $Connection = $Inventory.GetConnection($Name) $Port = if ($Connection.IsDefaultPort()) { $Inventory.GetClient($Connection.DefaultClient).DefaultPort } else { $Connection.Port } if (Test-Connection -TargetName $Connection.Hostname -TcpPort $Port -TimeoutSeconds 3) { Write-Information -MessageData ( "Connection {0} is up on port {1}." -f $Connection.ToString(), $Port ) } else { Write-Error -Exception ( [System.Exception] ("Connection: {0} is down on port {1}." -f $Connection.ToString(), $Port) ) } } } #endregion Public functions |