远程打开自定义远程PowerShell


1

我有2台电脑。在计算机A上,我有一个用C#编写的用于powershell 3.0的自定义模块,并通过MSI安装。我还有一个快捷方式,在已加载模块的情况下打开PowerShell。

我可以双击我的快捷方式,在这台计算机上运行我的命令Do-Something,没有任何问题,比如Exchange Server PowerShell。

但现在我想通过C#中的计算机B上的远程会话来完成它。

所以我的问题是,如何在我的模块已经加载并配置shell的情况下打开远程PowerShell会话到计算机A,这样我就可以运行我的命令并获得与在计算机A上运行它相同的结果?


你看过psexec了吗?

不,我没试过psexec你能举个例子吗?我可以打开一个远程PowerShell会话,而不是问题,它只是启动常规PowerShell。我更喜欢在我的模块已经加载的情况下启动powershell但是从远程会话中执行它可能会更加困难,因为此时我还不知道模块的安装路径。我看到了一些关于PSSessionConfiguration的信息,它允许启动脚本,但我不确定它是不是很好的方法。
Yann Lebel

Answers:


2

我终于找到了实现我所需要的方法。

首先,我创建了一个powershell脚本来导入我的模块和模块脚本文件

ShellInitScript

function Get-ScriptDirectory
{
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    Split-Path $Invocation.MyCommand.Path
}
$MyModuleDirectory = Get-ScriptDirectory
Set-Location $MyModuleDirectory 
Import-Module .\MyModule.psd1

MyModule.psd1

@{
GUID                = "[GENERATE A GUID HERE]" # Generate using $myGuid = [guid]::NewGuid() 

Author              = "Me"

CompanyName         = "My Company"

Copyright           = "© My Company. All rights reserved."

ModuleVersion       = "1.0.0.0"

ModuleToProcess     = "MyModule.psm1"
}

MyModule.psm1

Import-Module .\MyModuleCSharpAssembly.dll

function Enable-MyShellRemoting([switch]$Force)
{
    $proceed = 0

    if($Force -eq $false)
    {
        Write-Warning "Enable-MyShellRemoting restarts the WinRM service and all dependent services.`r`nAll WinRM sessions connected to Windows PowerShell session configurations are disconnected."

        $title = "Are you sure you want to perform this action?"
        $message = "Performing this operation will allow selected users to remotely run MyModule commands on this computer."

        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes"

        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No"

        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

        $proceed = $Host.UI.PromptForChoice($title, $message, $options, 0) 
    }

    if($proceed -eq 0)
    {
        Enable-PSRemoting -Force

        if((Get-WmiObject Win32_ComputerSystem).PartOfDomain -eq $false){
            Set-Item WSMan:\localhost\Client\TrustedHosts *
            Restart-Service WinRM
        }

        $path = Join-Path -Path $MyModuleDirectory  -ChildPath "ShellInitScript.ps1"
        Register-PSSessionConfiguration -Name "MyShellUri" -StartupScript $path -Force
    }
}
function Disable-MyShellRemoting([switch]$Force, [switch]$DisablePSRemoting)
{
    $proceed = 0

    if($Force -eq $false)
    {
        Write-Warning "Disable-MyShellRemoting restarts the WinRM service and all dependent services.`r`nAll WinRM sessions connected to Windows PowerShell session configurations are disconnected."

        $title = "Are you sure you want to perform this action?"
        $message = "Performing this operation will prevent all users to remotely run MyModule commands on this computer.`r`nUse the the -DisablePSRemoting switch to disable all PowerShell remoting features."

        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes"

        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No"

        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

        $proceed = $Host.UI.PromptForChoice($title, $message, $options, 0) 
    }

    if($proceed -eq 0)
    {
        if($DisablePSRemoting)
        {
            Disable-PSRemoting
        }

        if((Get-PSSessionConfiguration -Name "MyShellUri" -ErrorAction SilentlyContinue) -eq $null){
            Write-Host "The session configuration MyShellUri is already unregistered."
        }
        else {        
            Unregister-PSSessionConfiguration -Name "MyShellUri" -Force -ErrorAction Ignore
        }
    }
}

function Test-MyShellRemote()
{
    return "Test completed"
}

dll MyModuleCSharpAssembly.dll只是一个包含自定义Cmdlet的常规.Net程序集。

该问题的解决方案是在函数Enable-MyShellRemoting中,此方法启用powershell远程处理,并使用加载模块的statup脚本注册自定义Powershell会话配置。

然后在C#中我们必须这样做,就像这样在连接对象中指定ShellUri

WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.ComputerName = "MyComputer";
connectionInfo.ShellUri = "http://schemas.microsoft.com/powershell/MyShellUri";
using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
     remoteRunspace.Open();
     using (PowerShell shell = PowerShell.Create())
     {
          shell.Runspace = remoteRunspace;
          shell.AddCommand("Test-MyShellRemote");
          Collection<PSObject> results = shell.Invoke();
          //the results collection contains the string return by the command
     }
     remoteRunspace.Close();
 }

你可以使用[guid] :: NewGuid()然后复制粘贴生成的guid。对于您的模块,此guid应始终相同。
Yann Lebel

ShellInitScript可以包含在profile.ps1中,不是吗?
Kiquenet

是的,但是在这种情况下,模块将被加载到用户的所有PowerShell控制台中,但如果将它们分开,则可以创建一个更像Exchange Server Shell的独立shell。
Yann Lebel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.