locked
The term 'Get-Sftp' is not recognized as the name of a cmdlet, function, script file, or operable program RRS feed

  • Question

  • I have a script that is called via Scheduled Task that uses a PowerShell Function called 'Get-Sftp' , which is part of a Module, it's been working successfully for several months with no problems. Suddenly it's now throwing an error: "The term 'Get-Sftp'  is not recognized as the name of a cmdlet, function, script file, or operable program".  When I run Process Monitor I can see an error that shows , i think, that the process is not seeing the command as calling a function but rather a command line tool. The script has an import-module step for the module containing this function, and if I run the process using 'runas' and the same credentials the scheduled task uses, it runs ok.  

    

    Why is this occurring and what can I do to resolve the issue? Thanks.

    II do not understand why the person below is saying my post is inappropriate. I think I'm doing what all the other millions of posts are doing. Looking for ideas and suggestions from others.
    • Edited by Firmbyte Saturday, January 5, 2019 5:22 PM jrv criticising my post.
    Saturday, January 5, 2019 4:00 PM

All replies

  • Sorry but this is not a Microsoft support forum.  We cannot troubleshoot you system for you. You will need to contact a trained tech to troubleshoot this issue.

    As you have noted the script has always worked so it is not a script issue.


    \_(ツ)_/

    Saturday, January 5, 2019 4:31 PM
  • ok, that response has just thrown me totally,,,,,this forum is packed full of questions about issues reacted to Microsoft products, same as I've done. Why are you saying it's not a support forum? Why is all the other questions in here: https://social.technet.microsoft.com/Forums/en-US/home?forum=en-US ok but mine isn't ? I'm simply looking for suggestions as to what to try next or where to look. 
    Saturday, January 5, 2019 5:18 PM
  • This is a community support forum. No one here is a Microsoft employee.  The forum is for questions about a script you have written or are writing.  It is not a tech support forum for system troubleshooting.

    YOU have already told us that your script has been working but now some system issue is causing it to fail.  YOu need to use standard troubleshooting methods to find the cause of the problem. If you do not know how to troubleshoot then you will need to contact someone who can help you with this. e cannot teach you how to troubleshoot Windows systems issues.

    Please carefully review the following links to set your expectation for posting in  technical forums.

    This Forum is for Scripting Questions Rather than script requests


    \_(ツ)_/

    Saturday, January 5, 2019 5:34 PM
  • Dude it's community support i'm looking for, in the PowerShell forum, ideas on what I could do next, where I can look, etc.

    Exactly the same as all the other millions of posts on here.

    In your response there, you even quote "The purpose of this forum is to get answers to scripting questions" and "The forum is for questions about a script you have written".






    • Edited by Firmbyte Saturday, January 5, 2019 5:44 PM
    Saturday, January 5, 2019 5:36 PM
  • Next use troubleshooting techniques that you would use with any system problem.  Start with the scheduler log files. Check the PowerShell logs.  Until you understand what is happening there is no way to guess at what is causing this.

    We cannot see your system so you have to do the work.  Clearly something in your system has changed.  It is up to you to detect what has changed or what has broken.

    You also need to be sure your script is catching and reporting all errors.   If it is not then a previous error might tell you what is causing your problems.


    \_(ツ)_/

    Saturday, January 5, 2019 5:41 PM
  • I should also note that there is no such PowerShell command as "Get-Sftp". It must be from a module you have downloaded or installed.  You might try posting to the author of the module for assistance..


    \_(ツ)_/

    Saturday, January 5, 2019 5:50 PM
  • Scheduler log files, show no errors, as the scheduler ran as expected.

    The log created by the script, trapping errors returned by "$_.Exception.Message" shows the error provide: The term 'Get-Sftp' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

    I've also ran process monitor and got that error that I posted.

    I had thought perhaps some one had seen similar before and would shout out.

    Or maybe suggest a way to get more info that I'm getting from $_ 

    Saturday, January 5, 2019 5:56 PM
  • We have no way of knowing if your script is actually trapping all errors.  If it is not written correctly then many errors may just be bypassed until one either aborts the script or causes an error to be saved.

    What is in the PowerShell Event log?

    Have you tried running a transcript file?


    \_(ツ)_/

    Saturday, January 5, 2019 6:00 PM
  • Good point.

    The Function uses "WinSCPnet.dll" which is from WinSCP

    Info here: https://winscp.net/eng/docs/library_install

    The path to the dll is in the script: $WinSCP = "X:\Scripts\WinSCPnet.dll"

    And passed to the function by cmd line: 

    $Files += Get-Sftp -HostName $HostName -remotepath $remotepath -localPath $localPath -username $UserName -Password $Password -WinSCP $WinSCP -ErrorAction Stop

    Function Get-Sftp
    {
        param (
        $HostName ,
        $remotepath ,
        $localPath  ,
        $UserName  ,
        $Password 
        )
     
        try
        {
            # Load WinSCP .NET assembly
            Add-Type -Path $WinSCP
     
         $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
                        Protocol = [WinSCP.Protocol]::Sftp
                        GiveUpSecurityAndAcceptAnySshHostKey = $true
                        HostName = $HostName 
                        UserName = $UserName
                        Password = $Password
                    }
            $session = New-Object WinSCP.Session
     
            try
            {
                # Connect
                $session.Open($sessionOptions)
     
                # Get list of files in the directory
                $directoryInfo = $session.ListDirectory($remotePath)
     
                # Select the most recent file
                $latest =
                    $directoryInfo.Files |
                    Where-Object { -Not $_.IsDirectory } |
                    Sort-Object LastWriteTime -Descending |
                    Select-Object -First 10
     
                # Any file at all?
                if ($latest -eq $Null)
                {
                    Write-Host "No file found"
                    exit 1
                }
     
                # Download the selected file
                foreach($file in $latest) { 
                $file 
                $session.GetFiles(
                    [WinSCP.RemotePath]::EscapeFileMask($remotePath + $file.Name), $localPath).Check()
                    }
            }
            finally
            {
                # Disconnect, clean up
                $session.Dispose()
            }
     
        }
        catch
        {
            Write-Host "Error: $($_.Exception.Message)"
        }
    
    }


    • Edited by Firmbyte Saturday, January 5, 2019 6:04 PM
    Saturday, January 5, 2019 6:01 PM
  • In the process monitor trace, select Tools, File Summary. Verify that your scripts/modules are being pulled from the correct folders.

    Has the PATH environment variable been changed?  In the trace you should see Powershell searching every directory in your PATH for get-sftp.

    Add this command to your script to verify that all of your custom functions are being recognized.
     

        Get-ChildItem function:\

    From https://stackoverflow.com/questions/15694338/how-to-get-a-list-of-custom-powershell-functions

    Saturday, January 5, 2019 6:03 PM
  • re "transcript file", no I haven't as I don't know how to when the process is being run via Scheduler.
    Saturday, January 5, 2019 6:05 PM
  • I'll go get that done, see what I get. 

    Thanks.

    Saturday, January 5, 2019 6:07 PM
  • The following line is wrong:

    Add-Type -Path $WinSCP

    $WinSCP is undefined.

    The "File not found" is telling you that the file path is wrong.  The path reported is not a file path:

    "C:\Program Files (x86)\…\pub\Get-Sftp *"

    is not a file path.  I cannot see how this can possibly work with any account under any circumstances.  Perhaps you are not running the exact same script file in your tests.


    \_(ツ)_/

    Saturday, January 5, 2019 6:08 PM
  • You can get a very detailed look at the instance execution from the logfil:

    Get-WinEvent -FilterHashtable @{logname='Microsoft-Windows-PowerShell/Operational'} -MaxEvents 10

    Increase the logging detail level while testing this to get a complete script trace.


    \_(ツ)_/

    Saturday, January 5, 2019 6:14 PM
  • Why is it looking in there, when it's directed to the dll here $WinSCP = "X:\Scripts\WinSCPnet.dll" and that always worked before. Since the problems started I download a new version of the app and installed in the "C:\Program Files (x86)\GNU\GnuPG"...but it always previously worked fine with the files in the same directory as the script. Where is it getting the pub subdirectory from ?

    But i can confirm the file is in there:

    Script directory:


    • Edited by Firmbyte Saturday, January 5, 2019 6:20 PM
    Saturday, January 5, 2019 6:18 PM
  • To run a per-instance transcript add this to the beginning of the script"

    Start-Transcript -Path "c:\temp\$([datetime]::Now).trn)"


    \_(ツ)_/


    • Edited by jrv Saturday, January 5, 2019 6:21 PM
    Saturday, January 5, 2019 6:18 PM
  • You might prefer a sortable datetime name.

    Start-Transcript -Path "c:\temp\$($([datetime]::Now.ToString('yyyy-MM-dd HH-mm-ss'))).trn)"


    \_(ツ)_/

    Saturday, January 5, 2019 6:25 PM
  • Why is it looking in there, when it's directed to the dll here $WinSCP = "X:\Scripts\WinSCPnet.dll" and that always worked before. Since the problems started I download a new version of the app and installed in the "C:\Program Files (x86)\GNU\GnuPG"...but it always previously worked fine with the files in the same directory as the script. Where is it getting the pub subdirectory from ?

    But i can confirm the file is in there:


    First you need to not place custom scripts in vendor folders. This is a good place to create conflicts.

    Next you need to find out where you are setting the path to the module.

    To load a DLL that is an assembly just use the assembly name.  TO load a DLL in the current folder use this:

    Add-Type -Path .\mycode.dll

    You cannot load a PS1 as a type and you must specify the full path if the assembly is not in the cache or if it is not in the current folder.  I recommend using the full path always.

    To load multiple DLLs you must specify an extension

    add-type -path c:\mydlls\*.Dll


    \_(ツ)_/

    Saturday, January 5, 2019 6:33 PM
  • He missed defining $WinSCP as a param, but because he used this statement:

       $WinSCP = "X:\Scripts\WinSCPnet.dll"

    Won't the Get-SFTP function inherit the $WinSCP variable from the calling script?

    "Add-Type -Path $WinSCP"   should work. 

    Saturday, January 5, 2019 6:45 PM
  • He missed defining $WinSCP as a param, but because he used this statement:

       $WinSCP = "X:\Scripts\WinSCPnet.dll"

    Won't the Get-SFTP function inherit the $WinSCP variable from the calling script?

    "Add-Type -Path $WinSCP"   should work. 

    Not if you place it as a parameter on the command line and there is no parameter with that name.

    It will only be visible if it is a parameter or a global.

    $globalWinSCP = "X:\Scripts\WinSCPnet.dll"

    or

    Function Get-Sftp {
        param (
            $HostName,
            $remotepath,
            $localPath,
            $UserName,
            $Password,
            $WinScp
        )
     
    


    \_(ツ)_/

    Saturday, January 5, 2019 6:56 PM
  • I'd to leave yesterday, but the process worked last night as expected with no changes, but then errored with this same issue this morning. I've declared the parameter as global, but, never needed it before and still failed with same error again just now.

    When I open Visual Studio Code as the service account, and run the script in that session, so running as the service account, it functions as it should. It's failing when it's running as a scheduled task, using that same service account. 

    If the issue was the way I'd declared parameters etc, it'd fail when I ran it as that service account would it not? 

    • Edited by Firmbyte Sunday, January 6, 2019 1:45 PM
    Sunday, January 6, 2019 1:30 PM
  • If the X drive is a network share, try moving all files local to the pc. 
    Sunday, January 6, 2019 1:56 PM
  • When I run the process, suing runas the service account, the Transcript is not providing any more information than the logging I already, except for file versions. Otherwise it's providing step by step feedback, which my logging does already. 

    However, as a scheduled task, with the Start-Transcript, it will not run at all. No error, I see action started, action completed, etc in the job log in scheduler, but nothing was actually done.


    **********************
    Windows PowerShell transcript start
    Start time: 20190106075736
    Username: EBSI\svn_admin
    RunAs User: EBSI\svn_admin
    Machine: TXDF2-SQLUTL-01 (Microsoft Windows NT 6.3.9600.0)
    Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command & 'C:\Users\svn_admin\.vscode\extensions\ms-vscode.powershell-1.10.2\modules\PowerShellEditorServices\Start-EditorServices.ps1' -HostName 'Visual Studio Code Host' -HostProfileId 'Microsoft.VSCode' -HostVersion '1.10.2' -AdditionalModules @('PowerShellEditorServices.VSCode') -BundledModulesPath 'C:\Users\svn_admin\.vscode\extensions\ms-vscode.powershell-1.10.2\modules' -EnableConsoleRepl -LogLevel 'Normal' -LogPath 'C:\Users\svn_admin\.vscode\extensions\ms-vscode.powershell-1.10.2\logs\1546526935-5ba3c693-db17-4e7e-83d0-549414a3e8231546368609247\EditorServices.log' -SessionDetailsPath 'C:\Users\svn_admin\.vscode\extensions\ms-vscode.powershell-1.10.2\sessions\PSES-VSCode-1700-141005' -FeatureFlags @()
    Process ID: 12736
    PSVersion: 5.1.14409.1005
    PSEdition: Desktop
    PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14409.1005
    BuildVersion: 10.0.14409.1005
    CLRVersion: 4.0.30319.42000
    WSManStackVersion: 3.0
    PSRemotingProtocolVersion: 2.3
    SerializationVersion: 1.1.0.1
    **********************

    Sunday, January 6, 2019 2:11 PM
  • Thanks but it's a local volume.
    Sunday, January 6, 2019 2:13 PM
  • Why is it looking in there, when it's directed to the dll here $WinSCP = "X:\Scripts\WinSCPnet.dll" and that always worked before. Since the problems started I download a new version of the app and installed in the "C:\Program Files (x86)\GNU\GnuPG"...but it always previously worked fine with the files in the same directory as the script. Where is it getting the pub subdirectory from ?

    But i can confirm the file is in there:


    First you need to not place custom scripts in vendor folders. This is a good place to create conflicts.

    Next you need to find out where you are setting the path to the module.

    To load a DLL that is an assembly just use the assembly name.  TO load a DLL in the current folder use this:

    Add-Type -Path .\mycode.dll

    You cannot load a PS1 as a type and you must specify the full path if the assembly is not in the cache or if it is not in the current folder.  I recommend using the full path always.

    To load multiple DLLs you must specify an extension

    add-type -path c:\mydlls\*.Dll


    \_(ツ)_/

    The script is not in a vendor folder. It's in a folder I created along side the script, to which the service account has rights. 

    In the copy of the function I'm using that is above, you'll see "Add-Type -Path $WinSCP", the full path is declared in the script. "$:WinSCP = "X:\Scripts\WinSCPnet.dll"*Since changed to $GLOBAL:WinSCP = "X:\Scripts\WinSCPnet.dll" - and still fails with same error.

    Only 1 dll being loaded by script.

    Sunday, January 6, 2019 2:14 PM
  • He missed defining $WinSCP as a param, but because he used this statement:

       $WinSCP = "X:\Scripts\WinSCPnet.dll"

    Won't the Get-SFTP function inherit the $WinSCP variable from the calling script?

    "Add-Type -Path $WinSCP"   should work. 

    Not if you place it as a parameter on the command line and there is no parameter with that name.

    It will only be visible if it is a parameter or a global.

    $globalWinSCP = "X:\Scripts\WinSCPnet.dll"

    or

    Function Get-Sftp {
        param (
            $HostName,
            $remotepath,
            $localPath,
            $UserName,
            $Password,
            $WinScp
        )
     


    \_(ツ)_/

    It worked perfectly well as I've done it for several weeks....but I'm in process of rewriting it all following the comments.
    • Edited by Firmbyte Sunday, January 6, 2019 2:17 PM
    Sunday, January 6, 2019 2:16 PM
  • I put the function, as it was originally, in the script, and it works like that as expected. But when the script is calling the function and it's in the module, it fails - it used to work like that for several weeks. I can't see any security changes that might account for the change in behaviour.

    I'm going to reboot the server, earliest I can is Monday due to other process running on it.

    I appreciate all the comments, and I've rewritten the function, now including a parameter for the path to the dll.

    Function Get-Sftp
    {
        [CmdletBinding()]
        param (
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$HostName ,
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$remotepath ,
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$localPath  ,
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$UserName  ,
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Password ,
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({Test-Path $_ })]
        [string]$WinSCP
        )
     
    BEGIN {
                # Load WinSCP .NET assembly
                Add-Type -Path $WinSCP
                $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
                               Protocol = [WinSCP.Protocol]::Sftp
                               GiveUpSecurityAndAcceptAnySshHostKey = $true
                               HostName = $HostName 
                               UserName = $UserName
                               Password = $Password
                           }
                $session = New-Object WinSCP.Session
        $Downloaded = @()
    } # Close Begin
    PROCESS {
    
        try {
            # Connect
            $session.Open($sessionOptions)
     
            # Get list of files in the directory
            $directoryInfo = $session.ListDirectory($remotePath)
     
            # Select the most recent file
            $latest =
            $directoryInfo.Files | Where-Object { -Not $_.IsDirectory } | Sort-Object LastWriteTime -Descending | Select-Object -First 10
     
                # Any file at all?
                if ($latest -eq $Null) {
                    Write-Host "No file found"
                    exit 1
                } # if
        
                # Download the selected file
                foreach($file in $latest) { 
                    $Downloaded += $file 
                    $session.GetFiles(
                        [WinSCP.RemotePath]::EscapeFileMask($remotePath + $file.Name), $localPath).Check()
                } # foreach $file
        } # Close Try    
        catch
        {
            Write-Host "Error: $($_.Exception.Message)"
        } # Close catch
    } # Close begin
    END {
        Return $Downloaded
        # Disconnect, clean up
        $session.Dispose()
    } 
    
    }


    • Edited by Firmbyte Sunday, January 6, 2019 3:00 PM typo
    Sunday, January 6, 2019 3:00 PM
  • The script is not in a vendor folder. It's in a folder I created along side the script, to which the service account has rights. 

    In the copy of the function I'm using that is above, you'll see "Add-Type -Path $WinSCP", the full path is declared in the script. "$:WinSCP = "X:\Scripts\WinSCPnet.dll"*Since changed to $GLOBAL:WinSCP = "X:\Scripts\WinSCPnet.dll" - and still fails with same error.

    Only 1 dll being loaded by script.

    Is X a mapped drive?

    You are trying to both pass the variable on the command call and as a variable.  THat will not work.

    $Files += Get-Sftp -HostName $HostName -remotepath $remotepath -localPath $localPath -username $UserName -Password $Password -WinSCP $WinSCP -ErrorAction Stop

    With no Param called WinSCP you will cause an ambiguity.  Eiter use a global or use a param that is defined but don't use both.  Better yest just code the path in the Add-Type and not as a variable.


    \_(ツ)_/

    Sunday, January 6, 2019 3:08 PM
  • The script is not in a vendor folder. It's in a folder I created along side the script, to which the service account has rights. 

    In the copy of the function I'm using that is above, you'll see "Add-Type -Path $WinSCP", the full path is declared in the script. "$:WinSCP = "X:\Scripts\WinSCPnet.dll"*Since changed to $GLOBAL:WinSCP = "X:\Scripts\WinSCPnet.dll" - and still fails with same error.

    Only 1 dll being loaded by script.

    Is X a mapped drive?

    You are trying to both pass the variable on the command call and as a variable.  THat will not work.

    $Files += Get-Sftp -HostName $HostName -remotepath $remotepath -localPath $localPath -username $UserName -Password $Password -WinSCP $WinSCP -ErrorAction Stop

    With no Param called WinSCP you will cause an ambiguity.  Eiter use a global or use a param that is defined but don't use both.  Better yest just code the path in the Add-Type and not as a variable.


    \_(ツ)_/

    As per earlier response, no it's a local drive.

    No, this is incorrect "trying to both pass the variable on the command call and as a variable.".

    As per earlier comment, I've modified the process, and rewritten the function which now has a parameter for WinSCP and that value is passed via the command line: 

    Get-Sftp -HostName $HostName -remotepath $remotepath -localPath $localPath -username $UserName -Password $Password -WinSCP $WinSCP -ErrorAction Stop

    Sunday, January 6, 2019 3:33 PM
  • As noted earlier, troubleshooting your system is beyond the scope of this forum.  As you can see there is no way for use to troubleshoot while you are making arbitrary and multiple changes.

    I recommend that you contact someone who has experience debugging software to help you do this in the correct and organized way using standard methods.  Your shotgun approach is the most unreliable approach to debugging.  There is a formal method to debugging that must be followed.  It is the only way to narrow down intractable problems.


    \_(ツ)_/

    Sunday, January 6, 2019 3:42 PM

  • Have you tried the command with another path?
    Sunday, January 6, 2019 5:23 PM
  • Hi,

    Was your issue resolved?

    If you resolved it using our solution, please "mark it as answer" to help other community members find the helpful reply quickly.

    If you resolve it using your own solution, please share your experience and solution here. It will be very beneficial for other community members who have similar questions.

    If no, please reply and tell us the current situation in order to provide further help.

    Best Regards,

    Lee


    Just do it.

    Tuesday, January 8, 2019 7:34 AM