PoshSSH/PoshSSH/GetSftpFile.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
using System.IO;
using System.Linq;
using Renci.SshNet.Common;
using System;
using System.Collections.Generic;
using System.Management.Automation;


namespace SSH
{
    [Cmdlet(VerbsCommon.Get, "SFTPFile", DefaultParameterSetName = "Index")]
    public class GetSftpFile : PSCmdlet
    {
        /// <summary>
        /// Parameter for Index of the SFTPSession.
        /// </summary>
        private Int32[] _index;
        [ValidateNotNullOrEmpty]
        [Parameter(Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            Position = 0,
            ParameterSetName = "Index")]
        public Int32[] SessionId
        {
            get { return _index; }
            set { _index = value; }
        }
        

        /// <summary>
        /// Session paramter that takes private SSH.SftpSession[] 
        /// </summary>
        private SftpSession[] _session;
        [ValidateNotNullOrEmpty]
        [Parameter(Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            Position = 0,
            ParameterSetName = "Session")]
        public SftpSession[] SFTPSession
        {
            get { return _session; }
            set { _session = value; }
        }

        /// <summary>
        /// Remote file to download.
        /// </summary>
        private String _remotefile;
        [ValidateNotNullOrEmpty]
        [Parameter(Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            Position = 2)]
        public string RemoteFile
        {
            get { return _remotefile; }
            set { _remotefile = value; }
        }

        /// <summary>
        /// The local path where to save the file.
        /// </summary>
        private String _localpath;
        [Parameter(Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            Position = 1)]
        [Alias("PSPath")]
        public String LocalPath
        {
            get { return _localpath; }
            set { _localpath = value; }
        }

        // Supress progress bar.
        private bool _noProgress = false;
        [Parameter(Mandatory = false,
            ValueFromPipelineByPropertyName = true,
            ParameterSetName = "Index")]
        [Parameter(Mandatory = false,
            ValueFromPipelineByPropertyName = true,
            ParameterSetName = "Session")]
        public SwitchParameter NoProgress
        {
            get { return _noProgress; }
            set { _noProgress = value; }
        }

        /// <summary>
        /// If the local file exists overwrite it.
        /// </summary>
        [Parameter(Position = 3)]
        public SwitchParameter Overwrite
        {
            get { return _overwrite; }
            set { _overwrite = value; }
        }
        private bool _overwrite;

        private List<SftpSession> ToProcess { get; set; }

        protected override void BeginProcessing()
        {
            // Collect the sessions we will upload to.
            var toProcess = new List<SftpSession>();
            //var toProcess = new SSH.SftpSession[];
            base.BeginProcessing();
            var sessionvar = SessionState.PSVariable.GetValue("Global:SftpSessions") as List<SftpSession>;
            switch (ParameterSetName)
            {
                case "Session":
                    // fix issue #37: Get-SFTPFile/Set-SFTPFile fail with 'Object reference not set to an instance of an object.'
                    toProcess.AddRange(_session);
                    ToProcess = toProcess;
                    break;
                case "Index":
                    if (sessionvar != null)
                    {
                        foreach (var sess in sessionvar)
                        {
                            if (_index.Contains(sess.SessionId))
                            {
                                toProcess.Add(sess);
                            }
                        }
                        ToProcess = toProcess;
                    }
                    break;
                default:
                    throw new ArgumentException("Bad ParameterSet Name");
            } // switch (ParameterSetName...
        }

        protected override void ProcessRecord()
        {
            // check if the file specified actually exists.
            // Resolve the path even if a relative one is given.
            ProviderInfo provider;
            var pathinfo = GetResolvedProviderPathFromPSPath(_localpath, out provider);
            var localfullPath = pathinfo[0];

            if (Directory.Exists(@localfullPath))
            {
                var filename = Path.GetFileName(_remotefile);
                var localfilefullpath = localfullPath + "/" + filename;
                var fil = new FileInfo(@localfilefullpath);

                foreach (var sftpSession in ToProcess)
                {

                    WriteVerbose("Downloading " + filename + " to " + localfilefullpath + " from " + sftpSession.Host);

                    // Check that the path we are downloading from actually exists on the target.
                    if (sftpSession.Session.Exists(_remotefile))
                    {
                        // Ensure the remote path is a directory. 
                        var attribs = sftpSession.Session.GetAttributes(_remotefile);
                        if (!attribs.IsRegularFile)
                        {
                            throw new SftpPathNotFoundException("Specified path is not a file.");
                        }

                        // Setup Action object for showing download progress.
                        var res = new Action<ulong>(rs =>
                        {
                            if (attribs.Size != 0)
                            {
                                var percent = (int)((((double)rs) / attribs.Size) * 100.0);
                                if (percent % 10 == 0)
                                {
                                    // This will prevent the progress message from being stuck on the screen.
                                    if (percent == 100)
                                    {
                                        return;
                                    }

                                    var progressRecord = new ProgressRecord(1,
                                    "Downloading " + fil.Name,
                                    String.Format("{0} Bytes Downloaded of {1}", rs, attribs.Size)) { PercentComplete = percent };

                                    Host.UI.WriteProgress(1, progressRecord);
                                }
                            }
                        });
                        
                        var present = File.Exists(localfilefullpath);
                        
                        if ((present & _overwrite) || (!present))
                        {
                            var localstream = File.Create(@localfilefullpath);
                            try
                            {
                                if (_noProgress)
                                {
                                    sftpSession.Session.DownloadFile(_remotefile, localstream, null);
                                }
                                else
                                {
                                    sftpSession.Session.DownloadFile(_remotefile, localstream, res);
                                }
                                localstream.Close();

                            }
                            catch
                            {
                                localstream.Close();
                                var ex = new SftpPermissionDeniedException("Unable to download file from host.");
                                WriteError(new ErrorRecord(
                                    ex,
                                    "Unable to download file from host.",
                                    ErrorCategory.InvalidOperation,
                                    sftpSession));
                            }
                        }
                        else
                        {
                            var ex = new SftpPermissionDeniedException("File already present on local host.");
                            WriteError(new ErrorRecord(
                                             ex,
                                             "File already present on local host.",
                                             ErrorCategory.InvalidOperation,
                                             sftpSession));
                        }

                    }
                    else
                    {
                        var ex = new SftpPathNotFoundException(RemoteFile + " does not exist.");
                       
                       WriteError(new ErrorRecord(
                                                ex,
                                                RemoteFile + " does not exist.",
                                                ErrorCategory.InvalidOperation,
                                                sftpSession));
                    }
                }
            }
            else
            {
                var ex = new FileNotFoundException("Local path" + localfullPath + " was not found.");

                WriteError(new ErrorRecord(
                                                ex,
                                                "Local path" + localfullPath + " was not found.",
                                                ErrorCategory.InvalidOperation,
                                                localfullPath));
            }
        }
    }
}