Trouble setting the Visibility property on Cmdlets, etc. in a constrained endpt

This topic contains 4 replies, has 3 voices, and was last updated by Profile photo of Marty Wiedmeyer Marty Wiedmeyer 2 years, 1 month ago.

  • Author
    Posts
  • #20226

    Boe wrote a great series of articles on constrained endpoints as a guest on the Hey Scripting Guy blog which inspired me.

    I decided to try the approach of using a startup script to secure commands in the constrained endpoint.

    Unfortunately my customer is typing adverse and I had to resort to making my solution menu driven to minimize typing.

    I am attempting to break their grip on the mouse by keeping all activity in the PowerShell host. i.e. no popup graphical elements, in the hope that some of braver souls may actually try typing a few cmdlets.

    (Yes, a switch statement would be better for the "Are You sure" cases below, but this is a work in progress 🙂 )

    Unfortunately, when my constrained endpoint's start up script gets to the $_.Visibility = 'Private' sections, my screen bleeds over and over errors similar to:
    The property 'Visibility' cannot be found on this object. Verify that the property exists and can be set.
    At D:\scripts\Constrained_startup.ps1:264 char:9
    + $Command.Visibility = 'Private'
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

    I must be missing something.

    Tips and feedback are more than welcome!

    Marty Wiedmeyer
    =============================
    Here's what the script looks like:

    $PVER = "ScheduledTasksProfile 1.01 - 20141023 - 14:32 Central"
    
    # *** Variables *** 
    New-Variable -name temp -value $([io.path]::gettemppath())
    Set-Variable -Name PSEmailServer -Value smtp-out.us.Nuex.com 
    #Set-Variable -Name PSSessionConfigurationName -value WithProfile
    New-Variable -Name VIMPATH -Value "D:\Nuex\apps\vim\vim74\vim.exe"
    New-Variable -Name WD -Value "D:\Nuex\Work\"
    
    # *** Update the PATH to include our scripts directory for the current user only, in their current sesson ***
    $env:PATH += ";D:\Nuex\Scripts;D:\Nuex\Apps;D:\Nuex\Apps\vim\vim74"
    
    # Add the custom formatting files to the session, placing them at the beginning of the path
    Update-FormatData -PrependPath D:\Nuex\Modules\Nuex.format.ps1xml
    
    # Add the shared Module pdir to the $PSModulePath
    $env:PSModulePath = $env:PSModulePath + ";D:\Nuex\Modules"
    
    # Change the Path permantly for the entire machine
    #[Environment]::SetEnvironmentVariable("PATH", "D:\Nuex\Scripts;" + $env:Path, 'Machine')
    
    # *** Alias ***
    
    New-Alias -name lst -value List-ScheduledTask 
    New-Alias -name m -value Show-NuexTaskCommands
    New-Alias -name stast -value Start-ScheduledTask 
    New-Alias -name stost -value Stop-ScheduledTask 
    New-Alias -name cst -value Control-ScheduledTask 
    New-Alias -name raie -value Restart-AIE
    New-Alias -name rap -value Restart-ARPlugin
    New-Alias -name rar -value Restart-ARrecond 
    
    $NuexTaskCommands = @" 
    =========================
    Scheduled Task Management
    =========================
    Control-Scheduledtask [cst] -Control Nuexv3 Scheduled Tasks
    
    ==============================
    Process and Service Management
    ==============================
    Restart-AIE [raie] -Restart AIE
    Restart-ARPlugin [rap] -Restart arplugin
    Restart-ARrecond [rar] -Restart arrecond
    
    "@
    
    #Define Custom Proxy functions
    Function Set-Nuexlog
      {
        $Script:GetTime = get-date -Format "HH:mm"
        $Script:Today = get-date -Format "yyyyMMdd"
        $Script:LogFile = "D:\Nuex\work\logs\$Today.txt"
      }  # End function Set-NuexLog
    
    Function Write-NuexLog
      {
    
      Set-NuexLog
      $ServerName = $env:COMPUTERNAME
      $RemoteConnection=$PSSenderInfo|select -expandProperty ConnectionString
      $RemoteUser=$PSSenderInfo|select -expandProperty ConnectedUser
      
      Write-Output "$ServerName,$MenuItem,$env:UserName,$Script:GetTime,$Script:Today,$Script:CmdArgs,$RemoteUser,$RemoteConnection"|Out-File $Script:LogFile -append
      
      $Script:CmdArgs = $null
      } # End Function Write-NuexLog
    
    function Prompt 
        {
        if ([System.IntPtr]::Size -eq 8) {$size = '64 bit'}
        else {$size = '32 bit'}  
        
        $CurrentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
        $SecPrin = New-Object Security.Principal.WindowsPrincipal $CurrentUser
        
        if
        ($SecPrin.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
        {$Admin = 'Administrator'}
        else {$Admin = 'non-Administrator'}
        
        if ($Host.Name -eq "ServerRemoteHost")
           {$Remote = "[REMOTE SESSION]"
            $MachineName = $null
           }
        else {$Remote = $null
              $MachineName = "$env:COMPUTERNAME"
             }
    
        $host.ui.RawUI.WindowTitle = "$Reminder   $Admin    $Size    $Remote"
        #"$MachineName :: $(get-location) 
        "$MachineName :: m for the menu
    PS>"
    
         } # End function Prompt
    
    Function Restart-AIE
        {
          $PlugAns = Read-Host "You are about to restart the AIE Service"
          stop-Service -DisplayName *AIE* -Confirm
          $MenuItem = "Restart-AIE"
          Write-NuexLog
        } # end function Restart-AIE
    
    
    Function Restart-ARPlugin
        {
          $PlugAns = Read-Host "You are about to restart arplugin"
          stop-process -Name arplugin -Confirm
          $MenuItem = "Restart-ARPlugin"
          Write-NuexLog
        } # end function Restart-ARPlugin
    
    Function Restart-ARrecond
        {
          $PlugAns = Read-Host "You are about to restart ARrecond"
          stop-process -Name ARrecond -Confirm
          $MenuItem = "Restart-ARrecond"
          Write-NuexLog
        } # end function Restart-ARrecond
    
    Function Show-NuexTaskCommands
        {
          $NuexTaskCommands
          $MenuItem = "Show-NuexTaskCommands"
          Write-NuexLog
        } # end function Show-NuexTaskCommands
    
    Function List-ScheduledTask
      {
       get-scheduledtask "*Remedyload*"
      }
    
    Function Control-ScheduledTask
        {
        $Script:CmdArgs=$null
        $TodaysDate = Get-date -format yyyyMMdd-hhmm
        $ANS= $Null
    
            $Target = $Env:COMPUTERNAME
    
            Write-Output "Nuexv3 Tasks on $Target :"
            get-scheduledtask "*Remedyload*" | select TaskName, State|format-table -AutoSize
    
    
        $TargetTask = Read-Host "Enter (copy/paste or type) the name of the task to affect"
        
        $Action = Read-Host "St(A)rt, St(O)p, (E)nable or (D)isable $TargetTask"
          
          switch ($Action)
            {
              A
                {
                 Start-Scheduledtask $TargetTask
                }
              e
                {
                  Enable-Scheduledtask $TargetTask
                }
              d
                {
                  Write-Output "You are about to Disable $TargetTask -Are you sure? Ctrl-C to exit"
                  pause
                  Disable-Scheduledtask $TargetTask
                }
              o
                {
                  Write-Output "You are about to Stop $TargetTask  -Are you sure? Ctrl-C to exit"
                  pause
                  Stop-Scheduledtask $TargetTask
                }
            default
                {
                  Write-Output "Please make a valid entry A, O, E or D. Exiting...`n" 
                  break
                }
            }
                
    
            
    
        $Script:CmdArgs=$Target
        $MenuItem = "Update-ScheduledTask"
         Write-NuexLog
    
          } #End Function Control-ScheduledTask
    
    Function Control-ScheduledTaskRemote
        {
        $Script:CmdArgs=$null
        $TodaysDate = Get-date -format yyyyMMdd-hhmm
        $ANS= $Null
        $ANS = Read-Host "Control a Scheduled Task in (D)ev or (S)IT"
    
        switch ($ANS)
          {
            D
              {
                $Target = "NUVDWITSM3AP21"
              }
            S
              {
                $Target = "NUVSWITSM3AP21"
              }
            }
    
            Write-Output "Nuexv3 Tasks on $Target :"
            invoke-command -comp $Target -scriptblock {get-scheduledtask "*Remedyload*"}
    
    
        $TargetTask = "Enter the name of the Task to affect"
    
        $Action = Read-Host "St(A)rt or St(O)p The Service"
          
          switch ($Action)
            {
              A
                {
                 invoke-command -comp $Target -scriptblock {Start-Scheduledtask $TargetTask}
                }
              o
                {
                  invoke-command -comp $Target -scriptblock {Stop-Scheduledtask $TargetTask}
                }
            }
    
            
    
        $Script:CmdArgs=$Target
        $MenuItem = "Update-ScheduledTaskRemote"
         Write-NuexLog
    
          } #End Function Control-ScheduledTaskRemote
    
    
    #Proxy functions
    
    [string[]]$proxyFunction = 'Update-ScheduledTask','Show-NuexTaskCommands','Get-Command','Restart-AIE','Restart-ARPlugin','Restart-ARrecond','List-ScheduledTask','Control-ScheduledTask','Prompt','Write-NuexLog','Set-NuexLog'
    
    #Variables
    
    Get-Variable | ForEach {   
    
        $_.Visibility = 'Private'
    
    }
    
    #Aliases
    
    Get-Alias | ForEach {   
    
        $_.Visibility = 'Private'
    
    }
    
    #Cmdlets
    
    ForEach ($Command in (Get-Command|Select-String "Measure-Object" -notmatch)) {
    
        If (($proxyFunction -notcontains $Command.Name)) {
    
            $Command.Visibility = 'Private'
    
        }
    
    }
    
    $ExecutionContext.SessionState.Applications.Clear()
    
    $ExecutionContext.SessionState.Scripts.Clear()
    
    $ExecutionContext.SessionState.LanguageMode = "NoLanguage"
    
    
    $NuexTaskCommands
    
  • #20369
    Profile photo of Boe Prox
    Boe Prox
    Member

    This line:

    ForEach [$Command in [Get-Command|Select-String "Measure-Object" -notmatch]] {

    Is returning back an object of Microsoft.PowerShell.Commands.MatchInfo which is not exactly the System.Management.Automation.CmdletInfo object that you actually need in order to set the visibility to private.
    I'm not sure what is happening here with the measure-object and select-string stuff, but if you remove all of that and just leave the Get-Command call, it should work properly.

    ForEach [$Command in [Get-Command] {
        If [[$proxyFunction -notcontains $Command.Name]] {
            $Command.Visibility = 'Private'
        }
    }

    It sounds like you are still in the dev phase of this startup script, but just wanted to make sure that you know to filter out your aliases and variables that should not be hidden (basically anything that you have created in the script) so the rest of the endpoint works properly.

  • #20390
    Profile photo of Warren Frame
    Warren Frame
    Participant

    What Boe said.

    Marty – are you trying to allow interactive access to that endpoint? That's the only thing that stands out about measure-object to me, although you would need proxies for the following functions as well:

    $iss = [Management.Automation.Runspaces.InitialSessionState]::CreateRestricted("RemoteServer")
    $iss.Commands | where { $_.Visibility -eq "Public" } | Select Name
    
  • #20432

    Hi CM and Boe,

    Yes, I want the endpoint to be used interactively.

    I'll pull the measure-object and select-string stuff out at your suggestion.

    It makes sense that the object type returned would be different.

    Also, I'll try adding the $iss lines as well, CM.

    Thank you both for the replies!

    I'll let you know how it goes.

    Marty

  • #20433

    Hi Guys,

    Your suggestions really helped out.

    My constrained endpoint is working like a champ!

    Thanks for your help.

    Marty

You must be logged in to reply to this topic.