PoshSSH/PoshSSH/SetSftpFile.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
using System.IO;
using System.Linq;
using Renci.SshNet.Common;
using System;
using System.Collections.Generic;
using System.Management.Automation;


namespace SSH
{
    [Cmdlet(VerbsCommon.Set, "SFTPFile", DefaultParameterSetName = "Index")]
    public class SetSftpFile : 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 parameter 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>
        /// Folder on remote target to upload the file to.
        /// </summary>
        private String _remotepath;
        [ValidateNotNullOrEmpty]
        [Parameter(Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            Position = 2)]
        public string RemotePath
        {
            get { return _remotepath; }
            set { _remotepath = value; }
        }

        /// <summary>
        /// The local file to be uploaded.
        /// </summary>
        private String[] _localfile;
        [Parameter(Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            Position = 1)]
        [Alias("PSPath")]
        public String[] LocalFile
        {
            get { return _localfile; }
            set { _localfile = value; }
        }

        /// <summary>
        /// If a file on the target should be overwritten or not.
        /// </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()
        {
            foreach (var sftpSession in ToProcess)
            {
                // check if the file specified actually exists.
                // Resolve the path even if a relative one is given.
                foreach (var localfile in _localfile)
                {
                    ProviderInfo provider;
                    var pathinfo = GetResolvedProviderPathFromPSPath(localfile, out provider);
                    var localfullPath = pathinfo[0];


                    if (File.Exists(@localfullPath))
                    {
                        WriteVerbose("Uploading " + localfullPath);
                        var fil = new FileInfo(@localfullPath);
                        var remoteFullpath = RemotePath.TrimEnd(new[] { '/' }) + "/" + fil.Name;
                        WriteVerbose("Uploading to " + remoteFullpath + " on " + sftpSession.Host);

                        // Setup Action object for showing download progress.

                        var res = new Action<ulong>(rs =>
                        {
                            //if (!MyInvocation.BoundParameters.ContainsKey("Verbose")) return;
                            if (fil.Length > 1240000)
                            {
                                var percent = (int)((((double)rs) / fil.Length) * 100.0);
                                if (percent % 10 == 0)
                                {
                                    // This will prevent the progress message from being stuck on the screen.
                                    if (percent == 90 || percent > 90)
                                    {
                                        return;
                                    }

                                    var progressRecord = new ProgressRecord(1,
                                    "Uploading " + fil.Name,
                                    String.Format("{0} Bytes Uploaded of {1}", rs, fil.Length))
                                    { PercentComplete = percent };

                                    Host.UI.WriteProgress(1, progressRecord);
                                    //Host.UI.WriteVerboseLine(percent.ToString(CultureInfo.InvariantCulture) + "% Completed.");
                                }
                            }
                        });

                        // Check that the path we are uploading to actually exists on the target.
                        if (sftpSession.Session.Exists(RemotePath))
                        {
                            // Ensure the remote path is a directory. 
                            var attribs = sftpSession.Session.GetAttributes(RemotePath);
                            if (!attribs.IsDirectory)
                            {
                                throw new SftpPathNotFoundException("Specified path is not a directory");
                            }
                            // Check if the file already exists on the target system.
                            var present = sftpSession.Session.Exists(remoteFullpath);
                            if ((present & _overwrite) || (!present))
                            {
                                var localstream = File.OpenRead(localfullPath);
                                try
                                {
                                    sftpSession.Session.UploadFile(localstream, remoteFullpath, res);
                                    localstream.Close();
                                }
                                catch (Exception ex)
                                {
                                    localstream.Close();
                                    WriteError(new ErrorRecord(
                                                 ex,
                                                 "Error while Uploading",
                                                 ErrorCategory.InvalidOperation,
                                                 sftpSession));

                                }
                            }
                            else
                            {
                                var ex = new SftpPermissionDeniedException("File already exists on remote host.");
                                WriteError(new ErrorRecord(
                                                 ex,
                                                 "File already exists on remote host",
                                                 ErrorCategory.InvalidOperation,
                                                 sftpSession));
                            }

                        }
                        else
                        {
                            var ex = new SftpPathNotFoundException(RemotePath + " does not exist.");
                            WriteError(new ErrorRecord(
                                        ex,
                                        RemotePath + " does not exist.",
                                        ErrorCategory.InvalidOperation,
                                        sftpSession));
                        }

                    }
                    else
                    {
                        var ex = new FileNotFoundException("File to upload " + localfullPath + " was not found.");

                        WriteError(new ErrorRecord(
                                                ex,
                                                "File to upload " + localfullPath + " was not found.",
                                                ErrorCategory.InvalidOperation,
                                                localfullPath));
                    } // check if file exists.
                } // foreach local file
            } // sftp session.
        } // Process Record.
    }
}