Running Local On Remote

on Friday, August 1, 2014

A lot of PowerShell functions/Cmdlets are written in a way that they can only be run on a localhost. But, sometimes you need to run them remotely.

PSSession will let you run a command on a remote host (One Hop). If you need to connect to more hosts than that, you’ll to need setup CredSSP in your environment.

One Hop Scripts

This function is a template for running a local command on a remote host:

Function Verb-Noun {
[CmdletBinding()]
[OutputType(If you can set this, that's awesome)]
Param (
    [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "A")]
    [PSObject] $A
    [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "A")]
    [string] $AZ,
    [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "B")]
    [string] $B,
    [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
    [string] $ServerName = $env:COMPUTERNAME,
    [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
    [System.Management.Automation.Runspaces.PSSession] $Session = $null
)

    $scriptBlock = {
        Import-Module WebAdministration
        Import-Module ABC

        if($args) {
   Merge-AllParams -Arguments $args[0];
  }

        ... code goes here ...

        return $XYZ
    }

    # handle calling with sessions
    $sessInfo = Test-CreateNewSession -Session $Session -ServerName $ServerName
    $Session = $sessInfo.Session

    try {
     if($session -and -not (Test-IsLocalSession $session)) {
            # copy all variables to pass across with Invoke-Command
         $allParams = Get-AllParams -Command $MyInvocation.MyCommand -Local (Get-Variable -Scope Local)

      # if a session is avaliable, run it in the session; unless its the local sysem
      $XYZ = Invoke-Command -Session $Session -ArgumentList $allParams -ScriptBlock $scriptblock;
     } else {
      # if it's a local session or if no session is avaliable, then run the script block inline
      $XYZ = (. $scriptblock);
     }
    } finally {
        if($sessInfo.CreatedSession) { Remove-PSSession $Session }
    }

    return $XYZ
}

The function relies on Get-AllParams, Merge-AllParams, and Test-CreateNewSession.

<#
.SYNOPSIS
 Will retrieve all arguments passed into a function. This can help ease passing those values
 to an Invoke-Command cmdlet.

.EXAMPLE
 Get-AllParams -Command $MyInvocation.MyCommand -Locals (Get-Variable -Scope Local);
#>
Function Get-AllParams {
[CmdletBinding()]
Param(
 [Parameter(Mandatory = $true)]
 [System.Management.Automation.FunctionInfo]$Command,
 [Parameter(Mandatory = $true)]
 [Array]$Locals
)

 $allParams = @{};
 $Command.Parameters.Keys| foreach {
   $i = $_;
   $allParams[$i] = ($Locals |? { $_.Name -eq $i; }).Value;
  }
 return $allParams;
}

<#
.SYNOPSIS
 Will load all parameters passed in into the Script scope. This can be used in conjuction with
 Get-AllParams to pass variables into an Invoke-Command block.

.EXAMPLE
 Merge-AllParams -Arguments $args[0];
#>
Function Merge-AllParams {
[CmdletBinding()]
Param (
 [Hashtable]$Arguments
)

 $Arguments.GetEnumerator() |% { Set-Variable -Name $_.key -Value  $_.value -Scope Global; }
}

<#
.SYNOPSIS
    Sets up a Session object if needed. It also returns a flag if a session object was created.

.DESCRIPTION
    Sets up a Session object if needed. It also returns a flag if a session object was created.

    When functions sometimes need to run remotely (through a Session) or sometime locally, the
    code can be written to use a script block and logic can be added to call the code with a Session.
    The logic can become redundant when determing if and how to call the Session. This helper
    function helps with the process.

.PARAMETER Session
    The current Session variable passed into the calling function

.PARAMETER ServerName
    The current ServerName variable available in the calling function

.EXAMPLE
    $sessInfo = Test-CreateNewSession -Session $Session -ServerName $ServerName
    $Session = $sessInfo.Session

    try {
        ... determine if the session needs to be called or a local execution should be used ...
    } finally {
        if($sessInfo.CreatedSession) { Remove-PSSession $sessInfo.Session }
    }
#>
Function Test-CreateNewSession {
[CmdletBinding()]
Param (
    [System.Management.Automation.Runspaces.PSSession] $Session = $null,   
    [string] $ServerName = ""
)

    $createdSession = $false
    if($Session -eq $null -and $ServerName -ne "") {
        if(-not (Test-IsLocalComputerName $ServerName)) {
            $Session = New-PSSession $ServerName
            $createdSession = $true
        }
    }

    $sessInfo = New-PsType "CoreUcsb.PSSessionCreate" @{
                    Session = $Session
                    CreatedSession = $createdSession
                }

    return $sessInfo
}

0 comments:

Post a Comment


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.