remote session returning local results

Hello All, first time poster here. I have a script that is driving me a little nuts. The intent is for me to provide it a list of computernames, it will pssession to each one and search c:\users recurse to find any .lnk. then, if the target of the link is a specific target it will log some info into a variable object and dump it into a csv file on a server. Each time i manually step through the code using a remote session, it works correctly; however when I feed it a list of computers it returns MY machine’s information for some reason. See code. Any help is appreciated . . .

$computers = get-content -path ‘somepath’
foreach ($computer in $computers){
enter-pssession $computer
invoke-command {
$mypwd = "" | convertto-securestring -key ()
$mycred = new-object system.management.automation.pscredential “somecred”,$mypwd
function GetShortcuts{
$shortcuts = get-childitem -recurse ‘c:\users’ -include *.lnk
$Shell = New-Object -ComObject WScript.Shell
$Link = @()
new-psdrive X -PSProvider FileSystem -root “somepath” -Credential $mycred
foreach ($shortcut in $shortcuts){
if($shell.createshortcut($shortcut).targetpath -eq ‘targetexe’){
$link += [pscustomobject]@{
CompName = $env:computername
IconName = $shortcut.name
Location = $shortcut.fullname
Target = $shell.createshortcut($shortcut).targetpath
}
$link | export-csv -path “X:\shortcuts.csv” -NoTypeInformation -Append -NoClobber
}

}
remove-psdrive -name X

return $link

}
$output = GetShortcuts
Exit-PSSession
}
}

 

It’s really tough to follow code when you don’t take a moment to format it - the instructions are right in the bulleted list above the posting box. When you don’t do that, you lose all the indentation, and it’s beastly to try and follow the logic.

I’m curious why you’re using Enter-PSSession, rather than just giving an array of computer names to Invoke-Command? This is an odd pattern.

I would ordinarily expect to see something like…

Invoke-Command -computername $computers -scriptblock {

# whatever you want run remotely

}

 

But bear in mind that if the remote computer is sending its output to a CSV file, that CSV file will appear on each remote computer, and you won’t get any other output back. It’s important to really think about “what’s running on my local computer, and what’s running remotely,” because the two can’t “see” each other, share variables, share files, etc.

 

@Paul, Adding to what Don has mentioned, you are trying to mix interactive and non interactive remoting.

Enter-PSSession is for interactive remoting and has to be used like ssh in unix environments.

For executing scripts remotely, you have to use Invoke-Command. You can even have a session object created and be used for subsequent remote calls. PowerShell remoting is very powerful and explaining the E2E use cases will not be possible via a Forum, hence I would ask to to take some time and go through the documentations., you can start from about_remote

I apologize for the formatting, I will pay more attention next time. I originally started off with Invoke-Command -computername $computers -scriptblock {

however I had the machines all writing to a csv file on a network share to compile the data in one place and kept getting errors about the file in use. So i figured i’d hit them one by one so the file wouldn’t be locked by another machine at the time. I’ve only been using PowerShell for a couple weeks and am still fumbling around a lot!

Does this help with formatting?

$computers = get-content -path 'somepath'


foreach ($computer in $computers){
    enter-pssession $computer
    invoke-command  {
        $mypwd = "encryptedpwd" | convertto-securestring -key (encryptionkey)
        $mycred = new-object system.management.automation.pscredential "usercred",$mypwd
        function GetShortcuts{
            $shortcuts = get-childitem -recurse 'c:\users' -include *.lnk
            $Shell = New-Object -ComObject WScript.Shell
            $Link = @()
            new-psdrive X -PSProvider FileSystem -root "servershare" -Credential $mycred 
    
                 foreach ($shortcut in $shortcuts){
                    if($shell.createshortcut($shortcut).targetpath -eq 'target.exe'){
                    $link += [pscustomobject]@{
                        CompName = $env:computername
                        IconName = $shortcut.name
                        Location = $shortcut.fullname
                        Target = $shell.createshortcut($shortcut).targetpath
                        }
                    $link | export-csv -path "X:\shortcuts.csv" -NoTypeInformation -Append -NoClobber
                    }
             
                }
            remove-psdrive -name X
           
          }
      $output = GetShortcuts
   Exit-PSSession
    }  
    
  }

Yeah, so here’s the pattern:

Invoke-Command -comp $computers -script {

# whatever

} | Export-CSV output.csv

 

The idea is, you let the results of Invoke-Command come back to YOUR computer, and YOUR computer writes the results to a CSV. Only one computer nosing in the CSV. You rely on the PSComputerName add-on property, which Remoting will add, to tell which result came from where. So in your case, just “Write-Output $link” if that’s what you want in the CSV.

-Append and -NoClobber are mutually exclusive. You don’t need them both.

you can hit them one by one using Invoke-Command in foreach, please remove Enter-PSSession.
Since you used array of computers, everyone tried to write to the same file and file lock has happened, what you can do is

either, call Invoke-Command for each computer in computers
or, call it using array of computers and get the output as object from everyone to the source machine, the convert them to CSV and copy to the share location.

Would this be more appropriate? Nevermind you guys were quick, I will rework this a little and try again! thanks!

$computers = get-content -path 'computersonline.txt'
$c=new-pssession -computername $computers

icm -session $c{
        $mypwd = "encryptedpwd" | convertto-securestring -key (encryptionkey)
        $mycred = new-object system.management.automation.pscredential "cred",$mypwd
        function GetShortcuts{
            $shortcuts = get-childitem -recurse 'c:\users' -include *.lnk
            $Shell = New-Object -ComObject WScript.Shell
            $Link = @()
            new-psdrive X -PSProvider FileSystem -root "servershare" -Credential $mycred 
    
                 foreach ($shortcut in $shortcuts){
                    if($shell.createshortcut($shortcut).targetpath -eq 'target.exe'){
                    $link += [pscustomobject]@{
                        CompName = $env:computername
                        IconName = $shortcut.name
                        Location = $shortcut.fullname
                        Target = $shell.createshortcut($shortcut).targetpath
                        }
                    $link | export-csv -path "X:\shortcuts.csv" -NoTypeInformation -Append -NoClobber
                    }
             
                }
            remove-psdrive -name X
             #   return $link
          }
      $output = GetShortcuts
   
    }

Close.

$computers = get-content -path 'computersonline.txt'

$c=new-pssession -computername $computers

 

icm -session $c{

$mypwd = "encryptedpwd" | convertto-securestring -key (encryptionkey)

$mycred = new-object system.management.automation.pscredential "cred",$mypwd

function GetShortcuts{

$shortcuts = get-childitem -recurse 'c:\users' -include *.lnk

$Shell = New-Object -ComObject WScript.Shell

$Link = @()

new-psdrive X -PSProvider FileSystem -root "servershare" -Credential $mycred

 

foreach ($shortcut in $shortcuts){

if($shell.createshortcut($shortcut).targetpath -eq 'target.exe'){

$link = [pscustomobject]@{

CompName = $env:computername

IconName = $shortcut.name

Location = $shortcut.fullname

Target = $shell.createshortcut($shortcut).targetpath

}

Write-Output $link

}

 

}

remove-psdrive -name X

#   return $link

}

$output = GetShortcuts

 

} | export-csv -path "X:\shortcuts.csv" -NoTypeInformation

See, now the local computer is handling the CSV file. Notice that you don’t accumulate results in $link as you were doing; you create one object, and output it to the pipeline (Write-Output). What you were doing before was going to result in a lot of duplicate output anyway.

$computers = get-content -path 'c:\users\smip05\desktop\r5\computersonline.txt'
$c=new-pssession -computername $computers

icm -session $c{
        
        function GetShortcuts{
            $shortcuts = get-childitem -recurse 'c:\users' -include *.lnk
            $Shell = New-Object -ComObject WScript.Shell
            $Link = @()
                    foreach ($shortcut in $shortcuts){
                    if($shell.createshortcut($shortcut).targetpath -eq '\\mdcoap100850\r5client\r5apps.exe'){
                    $link += [pscustomobject]@{
                        CompName = $env:computername
                        IconName = $shortcut.name
                        Location = $shortcut.fullname
                        Target = $shell.createshortcut($shortcut).targetpath
                        }
                    write-output $link
                    }
             
                }
           
            }
      $output = GetShortcuts
   
    } |export-csv -path 'c:\output\shortcuts.csv' -NoTypeInformation -append

ok, so I’ve made the changes and this is where I am. It seems to run with no hitches however i’m getting a blank csv file. I have manually verified that at least 2 computers in the list i’m feeding it should be providing data, i.e. they have the shortcut specified. I removed all the creds and psdrive stuff because that was to make the machine able to talk back to mine which should be no longer needed as I am running the script as an elevated network account.

I’ve also found with the code above that if I enter-pssession and run it piece by piece it works and when it write-output $link it performs as expected. Would there be some reason that $link wouldn’t get returned from the invoke-command?

In addition, if I change write-output to write-host I get the results on my screen. It seems that the write-output is just not doing what i would hope and sending the result down the pipeline

 

I GOT IT!!! I had to remove the $output=getshortcuts, it was sending me $output down the pipeline, not $link. This is where I ended up:

 

$computers = get-content -path 'c:\users\smip05\desktop\r5\computersonline.txt'
$c=new-pssession -computername $computers

icm -session $c {
        
        function GetShortcuts{
            $shortcuts = get-childitem -recurse 'c:\users' -include *.lnk
            $Shell = New-Object -ComObject WScript.Shell
            $Link = @()
                    foreach ($shortcut in $shortcuts){
                    if($shell.createshortcut($shortcut).targetpath -eq '\\mdcoap100850\r5client\r5apps.exe'){
                    $link += [pscustomobject]@{
                        CompName = $env:COMPUTERNAME
                        IconName = $shortcut.name
                        Location = $shortcut.fullname
                        Target = $shell.createshortcut($shortcut).targetpath
                        }
                     write-output $link 
                    }
             
              }
          
        }
      GetShortcuts
      
   
    } |export-csv -path 'c:\output\shortcuts.csv' -NoTypeInformation

Thank you so much for your help!