Starting .ps1 Script from PowerShell with Parameters and Credentials and getting output using variable

前端 未结 4 1827
无人共我
无人共我 2020-12-19 01:58

Hello Stack Community :)

I have a simple goal. I\'d like to start some PowerShell Script from an another Powershell Script, but there are 3 conditions:

    <
4条回答
  •  执念已碎
    2020-12-19 02:53

    Start-Process would be my last resort choice for invoking PowerShell from PowerShell - especially because all I/O becomes strings and not (deserialized) objects.

    Two alternatives:

    1. If the user is a local admin and PSRemoting is configured

    If a remote session against the local machine (unfortunately restricted to local admins) is a option, I'd definitely go with Invoke-Command:

    $strings = Invoke-Command -FilePath C:\...\script1.ps1 -ComputerName localhost -Credential $credential
    

    $strings will contain the results.


    2. If the user is not an admin on the target system

    You can write your own "local-only Invoke-Command" by spinning up an out-of-process runspace by:

    1. Creating a PowerShellProcessInstance, under a different login
    2. Creating a runspace in said process
    3. Execute your code in said out-of-process runspace

    I put together such a function below, see inline comments for a walk-through:

    function Invoke-RunAs
    {
        [CmdletBinding()]
        param(
            [Alias('PSPath')]
            [ValidateScript({Test-Path $_ -PathType Leaf})]
            [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
            [string]
            ${FilePath},
    
            [Parameter(Mandatory = $true)]
            [pscredential]
            [System.Management.Automation.CredentialAttribute()]
            ${Credential},
    
            [Alias('Args')]
            [Parameter(ValueFromRemainingArguments = $true)]
            [System.Object[]]
            ${ArgumentList},
    
            [Parameter(Position = 1)]
            [System.Collections.IDictionary]
            $NamedArguments
        )
    
        begin
        {
            # First we set up a separate managed powershell process
            Write-Verbose "Creating PowerShellProcessInstance and runspace"
            $ProcessInstance = [System.Management.Automation.Runspaces.PowerShellProcessInstance]::new($PSVersionTable.PSVersion, $Credential, $null, $false)
    
            # And then we create a new runspace in said process
            $Runspace = [runspacefactory]::CreateOutOfProcessRunspace($null, $ProcessInstance)
            $Runspace.Open()
            Write-Verbose "Runspace state is $($Runspace.RunspaceStateInfo)"
        }
    
        process
        {
            foreach($path in $FilePath){
                Write-Verbose "In process block, Path:'$path'"
                try{
                    # Add script file to the code we'll be running
                    $powershell = [powershell]::Create([initialsessionstate]::CreateDefault2()).AddCommand((Resolve-Path $path).ProviderPath, $true)
    
                    # Add named param args, if any
                    if($PSBoundParameters.ContainsKey('NamedArguments')){
                        Write-Verbose "Adding named arguments to script"
                        $powershell = $powershell.AddParameters($NamedArguments)
                    }
    
                    # Add argument list values if present
                    if($PSBoundParameters.ContainsKey('ArgumentList')){
                        Write-Verbose "Adding unnamed arguments to script"
                        foreach($arg in $ArgumentList){
                            $powershell = $powershell.AddArgument($arg)
                        }
                    }
    
                    # Attach to out-of-process runspace
                    $powershell.Runspace = $Runspace
    
                    # Invoke, let output bubble up to caller
                    $powershell.Invoke()
    
                    if($powershell.HadErrors){
                        foreach($e in $powershell.Streams.Error){
                            Write-Error $e
                        }
                    }
                }
                finally{
                    # clean up
                    if($powershell -is [IDisposable]){
                        $powershell.Dispose()
                    }
                }
            }
        }
    
        end
        {
            foreach($target in $ProcessInstance,$Runspace){
                # clean up
                if($target -is [IDisposable]){
                    $target.Dispose()
                }
            }
        }
    }
    

    Then use like so:

    $output = Invoke-RunAs -FilePath C:\path\to\script1.ps1 -Credential $targetUser -NamedArguments @{ClientDevice = "ClientName"}
    

提交回复
热议问题