2

I have two PowerShell scripts. One script invokes another PowerShell script using elevated credentials, using Start-Process.

But I am struggling with how to make the second script return the output value to the first script.

Here is script # 1, which is invoked with script1.psl "sender-ip=10.10.10.10"

function getUser($abc) {

    <#Previously created password file in C:\Script\cred.txt, read-host -assecurestring | convertfrom-securestring | out-file C:\Script\cred.txt#>

    $password = get-content C:\Script\cred.txt| convertto-securestring
    $credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist "DOMAIN\Username",$password
    $output = start-process powershell -Credential $credentials -ArgumentList '-noexit','-File', 'C:\script\script2.ps1', $abc
    return $output
}

[string]$abc = $args

getUser($abc)

Write-host Output is $output

When I execute the script, the output is

Output is

And here is script2, which outputs the desired value to a cmd window instead of returning the value to script 1:

$userID = $NULL
$line_array = @()
$multi_array = @()
[hashtable]$my_hash = @{}

foreach ($i in $args) {
   $line_array+= $i.split(" ")
}

foreach ($j in $line_array) {
    $multi_array += ,@($j.split("="))
}

foreach ($k in $multi_array) {
    $my_hash.add($k[0],$k[1])
}

$Sender_IP = $my_hash.Get_Item("sender-ip")


<# Courtesy of http://blogs.technet.com/b/heyscriptingguy/archive/2012/02/19/use-powershell-to-find-last-logon-times-for-virtual-workstations.aspx#>

<# Gather information on the computer corresponding to $Sender_IP #>
$Win32OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Sender_IP

<# Determine the build number #>
$Build = $Win32OS.BuildNumber


<# Running Windows Vista with SP1 and later, i.e. $Build is greater than or equal to 6001 #>
if ($Build -ge 6001) {
    $Win32User = Get-WmiObject -Class Win32_UserProfile -ComputerName $Sender_IP
    $Win32User = $Win32User | Sort-Object -Property LastUseTime -Descending
    $LastUser = $Win32User | Select-Object -First 1
    $UserSID = New-Object System.Security.Principal.SecurityIdentifier($LastUser.SID)
    $userId = $UserSID.Translate([System.Security.Principal.NTAccount])
    $userId = $userId.Value
}

<# Running Windows Vista without SP1 and earlier, i.e $Build is less than or equal to 6000 #>
elseif ($Build -le 6000) {
    $SysDrv = $Win32OS.SystemDrive
    $SysDrv = $SysDrv.Replace(":","$")
    $ProfDrv = "\\" + $Sender_IP + "\" + $SysDrv
    $ProfLoc = Join-Path -Path $ProfDrv -ChildPath "Documents and Settings"
    $Profiles = Get-ChildItem -Path $ProfLoc
    $LastProf = $Profiles | ForEach-Object -Process {$_.GetFiles("ntuser.dat.LOG")}
    $LastProf = $LastProf | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1
    $userId = $LastProf.DirectoryName.Replace("$ProfLoc","").Trim("\").ToUpper()
}

else{
    $userId = "Unknown/UserID"
}


# Logic block to return the correct value
if ($userId -ne $NULL) {
    return "userId=" + $userId
}
elseif ($userID -eq $NULL)
{
    return "userId=" + $userId
}

I am willing to use other functions and cmdlets, but it is absolutely necessary that the script automatically runs in elevated mode because a third party program is calling script 1, which calls script 2, so script 2 needs to send value back to script 1, which goes to third party program.

(I posted updated question in a question, ProcessStartInfo and Process in PowerShell - Authentication Error).

Community
  • 1
  • 1
Glowie
  • 2,271
  • 21
  • 60
  • 104

1 Answers1

3

You could make use of ProcessStartInfo and Process which would allow you to read the StandardOutput.

Here's an example of what you might do:

$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = "C:\script\script2.ps1"

$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
$startInfo.Username = "DOMAIN\Username"
$startInfo.Password = $password

$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$standardOut = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()

# $standardOut should contain the results of "C:\script\script2.ps1"
$standardOut
David Martin
  • 11,764
  • 1
  • 61
  • 74
  • @ David Martin This code is quite helpful, but I am still having trouble. I edited my original question with the updated code. – Glowie Aug 30 '13 at 18:38
  • 1
    @ David Martin Tiny thing in the code you put the password in the Username property – Bostwick Sep 03 '14 at 17:12
  • You're kidding me! So, to return value from script2 to script1, I really need to go through all this, with credential passing and all? Yak! I'd rather get to work converting the script into a function. – Ifedi Okonkwo Nov 19 '14 at 14:38
  • 1
    @IfediOkonkwo The specific problem was that the second script (which couldn't be changed) was running in a different security context, hence all the hoops to jump through. – David Martin Nov 19 '14 at 14:41
  • Okay, I see. So would it be much simpler if both scripts were both of one context. How could the script look? Sorry if I'm branching off the OPs situation, but the thread title (which brought me here from Google) was deceptively silent about the "elevated credentials" bit ;) – Ifedi Okonkwo Nov 19 '14 at 19:51
  • 1
    @IfediOkonkwo You can just pipe the results of your second script into your first or assign the results to a variable. e.g. $newvariable = .\2.ps1 If you have a specific question, you should post a new question, I'm sure you'll get many responses. – David Martin Nov 20 '14 at 08:22
  • 1
    Hmmm. I like this `$newvariable = .\2.ps1` idea. I'm going to study it. Thanks for the trouble. – Ifedi Okonkwo Nov 20 '14 at 08:44