Using POSH-SSH in a scheduled task

This topic contains 5 replies, has 4 voices, and was last updated by Profile photo of Mark Hammonds Mark Hammonds 1 year, 3 months ago.

  • Author
    Posts
  • #32701
    Profile photo of Mark MacLachlan
    Mark MacLachlan
    Participant

    I have a script that connects in to an SFTP site using stored credentials. It copies a file locally, then disconnects from the site and connects to a second SFTP site and uploads the file to that site.

    The code works perfectly when I execute it as myself logged into the server as a domain admin.

    I have the script setup to run as a scheduled task. When the task runs it starts the script. The problem I am experiencing is that the script seems to be unable to establish the remote server session via SFTP. I added code to the script to send me an email when it starts, and had it grab module information to verify that the POSH-SSH module was properly running and it checks out OK. So I added code to send me the session.host name. This comes back as blank, so it seems the issue is when running as a scheduled task the session cannot establish. Can anyone let me know if they see a problem in the code?

    $ErrorActionPreference = "SilenetlyContinue"
    #==========================================================================
    #
    # NAME: SFTPCopy.ps1
    #
    # AUTHOR: Mark D. MacLachlan, Element Payment Services
    # DATE : 11/30/2015 10:29:51
    #
    # This code is copyright (c) 2015 Element Payment Services.
    #
    # All rights reserved.
    #
    # THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
    # ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
    # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
    # PARTICULAR PURPOSE.
    #
    # IN NO EVENT SHALL ELEMENT PAYMENT SERVICES AND/OR ITS RESPECTIVE
    # SUPPLIERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
    # OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
    # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
    # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
    # OF THIS CODE OR INFORMATION.
    #
    # COMMENT:
    # This script requires the PowerShell SFTP Add on available free on GitHub.
    # To install the SFTP Add on run the following command within an elevated PowerShell command.
    # wget https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev | iex
    #
    #==========================================================================

    # Get the ID and security principal of the current user account
    $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
    $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)

    # Get the security principal for the Administrator role
    $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
    # Check to see if we are currently running "as Administrator"
    if ($myWindowsPrincipal.IsInRole($adminRole))
    {
    # We are running "as Administrator" - so change the title and background color to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
    $Host.UI.RawUI.BackgroundColor = "DarkBlue"
    clear-host
    }
    else
    {
    # We are not running "as Administrator" - so relaunch as administrator
    # Create a new process object that starts PowerShell
    $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
    # Specify the current script path and name as a parameter
    $newProcess.Arguments = $myInvocation.MyCommand.Definition;
    # Indicate that the process should be elevated
    $newProcess.Verb = "runas";
    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);
    # Exit from the current, unelevated, process
    exit
    }

    # Run your code that needs to be elevated here

    #Import the SFTP Module & CmdLets
    Set-Location "C:\Program Files\WindowsPowerShell\Modules\"
    Import-Module posh-ssh

    #Get our stored credentials
    $encryptedSource = Get-Content C:\PSScripts\EncryptedELPSSFTP.txt | ConvertTo-SecureString
    $CredSource = New-Object System.Management.Automation.PsCredential("ELPSSFTP", $encryptedSource)

    #Get yesterdays date for our file
    $FileDate = (Get-Date).AddDays(-1)
    $FileDate = $FileDate.ToString("yyyyMMdd")
    #Get date for our file 2 days ago
    $FileDate2 = (Get-Date).AddDays(-2)
    $FileDate2 = $FileDate2.ToString("yyyyMMdd")
    #Get date for our file 3 days ago
    $FileDate3 = (Get-Date).AddDays(-3)
    $FileDate3 = $FileDate3.ToString("yyyyMMdd")

    #Create a session to get the files
    $Session = New-SFTPSession -ComputerName "mmm.ftpsvr.com" -Credential $CredSource -AcceptKey

    #Send an email the process has started
    #Email the list
    $Body = "SFTP Script Started `r`n $Session.Host"
    $Subject = "SFTP Upload Started"
    $SMTP = "phx1util01.company.prod"
    $To = "mmaclachlan@company.com"
    $From = "SFTP@company.com"
    Send-MailMessage -To $To -From $From -SmtpServer $SMTP -BodyAsHTML $Body -Subject $Subject

    #Download the files
    Get-SFTPFile -SFTPSession $Session -RemoteFile "/Inbox/FOTO_P0BCD71D_$FileDate" -LocalPath "C:\Temp\SFTP\"
    Get-SFTPFile -SFTPSession $Session -RemoteFile "/Inbox/FOTO_P0BCD71D_$FileDate2" -LocalPath "C:\Temp\SFTP\"
    Get-SFTPFile -SFTPSession $Session -RemoteFile "/Inbox/FOTO_P0BCD71D_$FileDate3" -LocalPath "C:\Temp\SFTP\"

    #Remove the session
    Get-SFTPsession | Remove-SFTPSession

    #Create a session to put our file up
    $encryptedDest = Get-Content C:\PSScripts\EncryptedCoreCMS_SFTP.txt | ConvertTo-SecureString
    $CredDest = New-Object System.Management.Automation.PsCredential("corecms", $encryptedDest)
    $Session2 = New-SFTPSession -ComputerName phx1sftp01.company.prod -Credential $CredDest -AcceptKey -Port 2222

    #Specify the local files
    Set-Location "C:\Temp\SFTP\"
    $LocalFiles = Get-ChildItem "C:\Temp\SFTP\"

    #Now copy the files up
    ForEach ($LocalFile in $LocalFiles)
    {
    Set-SFTPFile -SessionId 0 -LocalFile "$LocalFile" -RemotePath "/1020380/"
    }

    #Create a list of uploaded files
    $Files = (Get-SFTPChildItem -SessionId 0 -Path /1020380) | Select FullName | Sort-Object FullName
    #Email the list
    $Body = $Files.FullName -Join "`r`n"
    $Subject = "$FileDate SFTP Upload Report"
    Send-MailMessage -To $To -From $From -SmtpServer $SMTP -BodyAsHTML $Body -Subject $Subject

    #Remove the session
    Get-SFTPsession | Remove-SFTPSession

    #Remove the local files
    ForEach ($LocalFile in $LocalFiles)
    {
    Remove-Item $LocalFile -Force
    }

  • #32702
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Well, it's probably not the script if it works fine when run interactively. Basic troubleshooting: you've more or less eliminated the script as a problem, since it works fine in one scenario.

    So what's different between the scenarios? Credentials. Is the scheduled task running as a domain admin? Because you're manually retrieving principles – something the System account, which Task Scheduler normally uses, isn't necessarily allowed to do.

  • #32704
    Profile photo of Christian Sandfeld
    Christian Sandfeld
    Participant

    My first thought goes to the encrypted password. Did you check that the RunAs account executing the script, can successfully decrypt it?

  • #32705
    Profile photo of Mark MacLachlan
    Mark MacLachlan
    Participant

    You may be on to something there. Going to check the rights to that folder. Thanks

  • #32706
    Profile photo of Mark MacLachlan
    Mark MacLachlan
    Participant

    Thanks guys you have both put me on the right track. I tested code to decode the encrypted password and I am able to do it as me, but the service account doesn't do it. I made sure the service account has rights to read the saved credential file and the folder they exist in, still no joy.

  • #32707
    Profile photo of Mark Hammonds
    Mark Hammonds
    Participant

    I think I read some were if you don't supply a key the encryption is tied to the account that encrypted it

    Try providing a key https://technet.microsoft.com/en-us/library/hh849818.aspx when you encrypt and decrypt it. I know I have done this before when I get to work tomorrow I will post what I have done.

    Article

    To recap my last blog, part 1 of Encrypting Credentials, when you use ConvertTo-SecureString and ConvertFrom-SecureString without a Key or SecureKey, Powershell will use Windows Data Protection API (DPAPI) to encrypt/decrypt your strings. This means that it will only work for the same user on the same computer.

You must be logged in to reply to this topic.