Check if password-protected web file exists - powershell

I need to check to see if a password-protected web file exists in a directory.
I keep getting a (401) Unauthorized error so, Lines 5-6 are not working.
Script Code:
$currdate = Get-Date -format "yyyyMMdd"
$Username = "username"
$Password = "password"
$url = "http://some.website/" + $currdate + "/somedirectory/some.file.txt"
$WebClient = New-Object System.Net.WebClient
$WebClient.Credentials = New-Object System.Net.Networkcredential($Username, $Password)
$HTTP_Request = [System.Net.WebRequest]::Create($url)
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
If ($HTTP_Status -eq 200) {
Write-Host "File exists!"
}
Else {
Write-Host "File does not exist..."
}
$HTTP_Response.Close()
What am I doing wrong?

You use two objects WebClient and WebRequest, you need only one.
You set the credential to WebClient, but you do response by WebRequest without credential.
Modify your code as:
$currdate = Get-Date -format "yyyyMMdd"
$Username = "xxxxx"
$Password = "xxxxxx"
$url = "http://some.website/" + $currdate + "/somedirectory/some.file.txt"
# comment these lines,you use WebRequest
#$WebClient = New-Object System.Net.WebClient
#$WebClient.Credentials = New-Object System.Net.Networkcredential($Username, $Password)
$HTTP_Request = [System.Net.WebRequest]::Create($url)
#add this line
$HTTP_Request.Credentials = new-object system.net.networkcredential($Username, $Password)
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
If ($HTTP_Status -eq 200) {
Write-Host "File exists!"
}
Else {
Write-Host "File does not exist..."
}
$HTTP_Response.Close()

Related

Error when trying to create site collection using CSOM PowerShell

I am trying to run a PowerShell script that would generate the site colletion on the SharePoint tenant. However, whenever I am trying to execute the site collection creation, I get an error:
Exception calling "ExecuteQuery" with "0" argument(s): "Unknown Error"
At C:\projects\SP\Scripts\Taxonomy\Add-NavigationTerms1.ps1:120 char:5
+ $TenantContext.ExecuteQuery()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ServerException
How would I go around this error? How can I fix it? Thank you very much for all your help!
Here is the code:
param (
[Parameter(Mandatory = $false)]
[string] $sourceWeb = '',
[string] $destinationWeb = '',
[Parameter(Mandatory = $false)]
[string] $sourceListName = 'CurrentSites', #$sourceListName = 'O365 Sites',
[Parameter(Mandatory = $false)]
[string] $sharepointAdmin = ''
)
<#
Add-Type -Path "C:/Program Files/SharePoint Client Components/Assemblies/Microsoft.Online.SharePoint.Client.Tenant.dll"
Add-Type -Path "C:/Program Files/Common Files/microsoft shared/Web Server Extensions/16/ISAPI/Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:/Program Files/Common Files/microsoft shared/Web Server Extensions/16/ISAPI/Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "C:/Program Files/Common Files/microsoft shared/Web Server Extensions/16/ISAPI/Microsoft.SharePoint.Client.UserProfiles.dll"
#>
$path = 'C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/15/ISAPI/'
$simpleLinkUrlPropertyName = '_Sys_Nav_SimpleLinkUrl'
$assemblies = 'Microsoft.SharePoint.Client.dll',
'Microsoft.SharePoint.Client.Runtime.dll',
'Microsoft.SharePoint.Client.Taxonomy.dll'
$assemblies | % { Add-Type -Path (Join-Path $path $_) }
Add-Type -Path "C:/Program Files/SharePoint Client Components/Assemblies/Microsoft.Online.SharePoint.Client.Tenant.dll"
#$context = New-Object Microsoft.SharePoint.Client.ClientContext($sourceWeb)
#$password = Read-Host -Prompt 'Please enter your password' -AsSecureString
#$context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($sharepointAdmin,$password)
$password = ''
#[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
#[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
Function Get-SPOContext([string]$Url, [string]$UserName, [string]$Password) {
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
$context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
return $context
}
Function Get-ListItems([Microsoft.SharePoint.Client.ClientContext]$Context, [String]$ListTitle) {
$list = $Context.Web.Lists.GetByTitle($listTitle)
$Context.Load($list)
$Context.ExecuteQuery()
$qry = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()
$items = $list.GetItems($qry)
$Context.Load($items)
$Context.ExecuteQuery()
return $items
}
Function Create-Site-Collection([String]$url, [String]$title) {
$TenantURL = ''
$Title = 'New Published Collection List';
[string]
$TenantUserName = '';
[Security.SecureString]
#$TenantPassword = ConvertTo-SecureString 'Anew6731' -AsPlainText -Force
$TenantPassword = convertto-securestring "Anew6731" -asplaintext -force
#Open the Tenant Administration Context with the Tenant Admin Url
$TenantContext = Get-SPOContext -Url $TenantUrl -UserName $TenantUserName -Password "Anew6731"
#$TenantContext = New-Object Microsoft.SharePoint.Client.ClientContext($TenantUrl)
#$TenantCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($TenantUserName, $TenantPassword)
#$TenantContext.Credentials = $TenantCredentials
#Get the tenant object
$Tenant = New-Object Microsoft.Online.SharePoint.TenantAdministration.Tenant($TenantContext)
#Set the Site Creation Properties values
$TenantProperties = New-Object Microsoft.Online.SharePoint.TenantAdministration.SiteCreationProperties
#$TenantProperties.Url = $url
$TenantProperties.Template = "CMSPUBLISHING#0 "
$TenantProperties.Owner = $TenantUserName
$TenantProperties.StorageMaximumLevel = 1000
$TenantProperties.UserCodeMaximumLevel = 300
$TenantProperties.Title = $title
$TenantContext.Load($Tenant)
$TenantContext.ExecuteQuery()
#$TenantContext.Load($TenantProperties)
#$TenantContext.ExecuteQuery()
#Create the site using the properties
$Tenant.CreateSite($TenantProperties) | Out-Null
Write-Host "Creating site collection "
#Create the site in the tennancy
#$TenantContext.Load($Tenant)
#$TenantContext.Load($spOnlineOperation)
$TenantContext.ExecuteQuery()
#$TenantContext.Dispose()
}
$UserName = $sharepointAdmin
#$Password = Read-Host -Prompt "Enter the password"
$Url = $sourceWeb
$context = Get-SPOContext -Url $Url -UserName $UserName -Password $Password $items = Get-ListItems -Context $context -ListTitle "O365 Sites"
foreach ($item in $items) {
$Context.Load($item)
$Context.ExecuteQuery()
Write-Host $item["NEWURL"]
Write-Host $item["Title"]
#Write-Host $item.FieldValues
Create-Site-Collection -URL $item["NEWURL"] -Title $item["Title"]
#Write-Hsost $item.DisplayName
}
$context.Dispose()
I am honestly not sure what went wrong but this code/method worked just fine
Function Create-Site-Collection([String]$fullUrl, [Microsoft.SharePoint.Client.ClientContext] $TenantContext)
{
Write-Host "Now configuring the new Site Collection"
#Get the tenant object
$tenant = New-Object Microsoft.Online.SharePoint.TenantAdministration.Tenant($TenantContext)
#Set the Site Creation Properties values
$properties = New-Object Microsoft.Online.SharePoint.TenantAdministration.SiteCreationProperties
$properties.Url = $fullUrl
$properties.Template = "BLANKINTERNETCONTAINER#0"
$properties.Owner = $AdminSiteUsername
$properties.StorageMaximumLevel = 1000
#$properties.UserCodeMaximumLevel = 100
$properties.TimeZoneId = 10 # (UTC-05:00) Eastern Time (US and Canada)
#Create the site using the properties
$tenant.CreateSite($properties) | Out-Null
$TenantContext.ExecuteQuery()
Write-Host "Creating site collection"
#Create the site in the tennancy
try
{
$TenantContext.ExecuteQuery()
Write-Host "Site Creation request completed. Note that the creation process is asynchronous and provisioning may take a short while."
}
Catch [Exception]
{
Write-host $_.Exception.Message -f Red
}
}

Powershell .NET httpclient add header

I want to upload a file using powershell to a RestAPI. Sadly the invoke-restmethod does not support MultipartForm Uploads and even with building my own body it does not work. Therefore, I have to get this working using another way :)
Luckily I found this excellent blog post: http://blog.majcica.com/2016/01/13/powershell-tips-and-tricks-multipartform-data-requests/ and now I'm trying to build me a request using the .NET Client within Powershell. But I do hit my borders right now. I need to edit the standard header to add an authorization token. And I have no clue how! Would somebody please so kind and point me in the right direction how to do this? Thank you very much!
function Invoke-MultipartFormDataUpload
{
[CmdletBinding()]
PARAM
(
[string][parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$InFile,
[string]$ContentType,
[Uri][parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$Uri,
[System.Management.Automation.PSCredential]$Credential
)
BEGIN
{
if (-not (Test-Path $InFile))
{
$errorMessage = ("File {0} missing or unable to read." -f $InFile)
$exception = New-Object System.Exception $errorMessage
$errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, 'MultipartFormDataUpload', ([System.Management.Automation.ErrorCategory]::InvalidArgument), $InFile
$PSCmdlet.ThrowTerminatingError($errorRecord)
}
if (-not $ContentType)
{
Add-Type -AssemblyName System.Web
$mimeType = [System.Web.MimeMapping]::GetMimeMapping($InFile)
if ($mimeType)
{
$ContentType = $mimeType
}
else
{
$ContentType = "application/octet-stream"
}
}
}
PROCESS
{
Add-Type -AssemblyName System.Net.Http
$httpClientHandler = New-Object System.Net.Http.HttpClientHandler
if ($Credential)
{
$networkCredential = New-Object System.Net.NetworkCredential #($Credential.UserName, $Credential.Password)
$httpClientHandler.Credentials = $networkCredential
}
$httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler
$packageFileStream = New-Object System.IO.FileStream #($InFile, [System.IO.FileMode]::Open)
$contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data"
$contentDispositionHeaderValue.Name = "fileData"
$contentDispositionHeaderValue.FileName = (Split-Path $InFile -leaf)
$streamContent = New-Object System.Net.Http.StreamContent $packageFileStream
$streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue
$streamContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue $ContentType
$content = New-Object System.Net.Http.MultipartFormDataContent
$content.Add($streamContent)
try
{
$response = $httpClient.PostAsync($Uri, $content).Result
if (!$response.IsSuccessStatusCode)
{
$responseBody = $response.Content.ReadAsStringAsync().Result
$errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody
throw [System.Net.Http.HttpRequestException] $errorMessage
}
return $response.Content.ReadAsStringAsync().Result
}
catch [Exception]
{
$PSCmdlet.ThrowTerminatingError($_)
}
finally
{
if($null -ne $httpClient)
{
$httpClient.Dispose()
}
if($null -ne $response)
{
$response.Dispose()
}
}
}
END { }
}
Try this
#Authorization
$httpClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $accesstoken);

PowerShell - Send-MailMessage - Export mail to a file

I'm using the Send-MailMessgae Cmdlet to send an automated message with content each quarter.
The actual email works as expected etc however I want to save a copy of this email to a network share.
I've tried using Tee-Object to place it in a variable and then out-file to save it but this did not work.
I'm I'm thinking the only way i'm going to be able to do this is to just create a Here String with the details in it them output that.
Ideally I would like it to be in the .eml format as its a conformation that we are notifying users for the project the email is for.
I hope this makes sense.
Kind Regards,
Nigel Tatschner
You could actually use Tee-Object to send the data straight to the file, instead of trying to use both Out-File and Tee-Object.
$logfile = 'C:\data\logfiles'
<data> | Tee-Object $logfile -Append
You can use System.Net.Mail.MailMessage
# Based on MailMessageExt
# By Allan Eagle | 11 Jan 2009
# http://www.codeproject.com/KB/IP/smtpclientext.aspx
######################################
function createMailMessage([string]$from, [string]$to, [string]$subject) {
[System.Net.Mail.MailMessage]$msg = New-Object -TypeName "System.Net.Mail.MailMessage" -ArgumentList $from, $to
[System.Text.Encoding]$enc = [System.Text.Encoding]::UTF8
$msg.SubjectEncoding = $enc
$msg.Subject = $subject
$msg.BodyEncoding = $enc
return $msg
}
######################################
function mailAddAttachment([System.Net.Mail.MailMessage]$msg, [string]$filePath) {
$fileExists = Test-Path -path $filePath -pathtype leaf
if ($fileExists) {
$fileName = Split-Path $filePath -Leaf
[System.Net.Mail.Attachment]$att = New-Object -TypeName "System.Net.Mail.Attachment" -ArgumentList $filePath
$att.ContentType.MediaType = [System.Net.Mime.MediaTypeNames+Application]::Octet
$att.ContentType.Name = $fileName
$att.ContentDisposition.FileName = $fileName
$att.ContentDisposition.DispositionType = [System.Net.Mime.DispositionTypeNames]::Attachment
$att.ContentDisposition.Inline = $false
$att.TransferEncoding = [System.Net.Mime.TransferEncoding]::Base64
$msg.Attachments.Add($att)
$att = $null
return $true
} else {
$txt = "File ""$filePath"" not found"
Write-Output $txt
return $false
}
}
######################################
function saveMailMessage([System.Net.Mail.MailMessage]$msg, [string]$filePath) {
$binding = [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic
$mailMessageType = $msg.GetType()
$emlFilePath = $filePath
[System.Type]$scType = [System.Type]::GetType("System.Net.Mail.SmtpClient")
[System.Net.Mail.SmtpClient]$smtpClient = New-Object -TypeName "System.Net.Mail.SmtpClient"
$scType = $smtpClient.GetType()
[System.Type]$booleanType = [System.Type]::GetType("System.Boolean")
[System.Reflection.Assembly]$assembly = $scType.Assembly
[System.Type]$mailWriterType = $assembly.GetType("System.Net.Mail.MailWriter")
[System.IO.FileStream]$fileStream = New-Object -TypeName "System.IO.FileStream" -ArgumentList ($emlFilePath,[System.IO.FileMode]::Create)
[System.Array]$typeArray = ([System.Type]::GetType("System.IO.Stream"))
[System.Reflection.ConstructorInfo]$mailWriterConstructor = $mailWriterType.GetConstructor($binding ,$null, $typeArray, $null)
[System.Array]$paramArray = ($fileStream)
$mailWriter = $mailWriterConstructor.Invoke($paramArray)
#get MailMessage.Send(MailWriter,Boolean,Boolean)
$doubleBool = $true
[System.Array]$typeArray = ($mailWriter.GetType(),$booleanType,$booleanType)
[System.Reflection.MethodInfo]$sendMethod = $mailMessageType.GetMethod("Send", $binding, $null, $typeArray, $null)
if ($null -eq $sendMethod) {
$doubleBool = $false
[System.Array]$typeArray = ($mailWriter.GetType(),$booleanType)
[System.Reflection.MethodInfo]$sendMethod = $mailMessageType.GetMethod("Send", $binding, $null, $typeArray, $null)
}
#get MailWriter.Close()
[System.Array]$typeArray = #()
[System.Reflection.MethodInfo]$closeMethod = $mailWriterType.GetMethod("Close", $binding, $null, $typeArray, $null)
#execute MailMessage.Send(MailWriter,Boolean,Boolean)
[System.Array]$sendParams = ($mailWriter,$true)
if ($doubleBool) {
[System.Array]$sendParams = ($mailWriter,$true,$true)
}
$sendMethod.Invoke($msg,$binding,$null,$sendParams,$null)
#execute MailWriter.Close()
[System.Array]$closeParams = #()
$closeMethod.Invoke($mailWriter,$binding,$null,$closeParams,$null)
}
######################################
function Get-ScriptDirectory {
Split-Path -Parent $PSCommandPath
}
######################################
$smtpServer = "smtp.here.com"
$smtpPort = 25
######################################
#$fileDir = Convert-Path "."
$fileDir = Get-ScriptDirectory
$fileDir
[System.Text.Encoding]$enc = [System.Text.Encoding]::UTF8
$dt = Get-Date
$dtStart = Get-Date $dt -Hour 0 -Minute 0 -Second 0
$baseName = $fileDir+"\report_"+$dtStart.toString("yyyy-MM-dd")
$repName = $baseName+".csv"
$emlName = $baseName+".eml"
[System.Collections.ArrayList]$rep = #()
$rep.Add("This is a report")
$rep.Add("----------------")
for ($i=0; $i -lt 100; $i++) {
$index = $rep.Add("Line $i")
}
Set-Content $repName $rep
$from = "Sender <Me#here.com>"
$to = "Recipient <Them#there.com>"
$subject = "This is a report generated here on "+$dtStart.toString("yyyy-MM-dd")
$body = "$subject`n`n$repName"
[System.Net.Mail.MailMessage]$msg = createMailMessage $from $to $subject
$msg.IsBodyHtml = $false
$msg.Body = $body
mailAddAttachment $msg $repName
$emlName
[System.Net.Mail.SmtpClient]$smtp = New-Object -TypeName "System.Net.Mail.SmtpClient" -ArgumentList $smtpServer, $smtpPort
# $smtp.Send($msg)
saveMailMessage $msg $emlName
$msg.Dispose()
Remove-Item $repName
Pause

Powershell Http post request

Read over the stackoverflow for the answer, still can't find what causing this..
Trying to connect and send a POST request using powershell, and getting "unable to connect to remote server" error. Tried 3 different dummy servers like http://posttestserver.com/post.php
Script:
Get-ExecutionPolicy
[string]$url = "http://posttestserver.com/post.php"
function Execute-HTTPPostCommand()
{
param([string]$target = $null)
#$username = "administrator"
#$password = "mypass"
$webRequest = [System.Net.WebRequest]::Create($target)
$webRequest.ContentType = "text/html"
$post = "abcdefg"
$PostStr = [System.Text.Encoding]::UTF8.GetBytes($Post)
$webrequest.ContentLength = $PostStr.Length
$webRequest.ServicePoint.Expect100Continue = $false
#$webRequest.Credentials = New-Object System.Net.NetworkCredential -ArgumentList $username, $password
#$webRequest.PreAuthenticate = $true
$webRequest.Method = "POST"
try
{
$requestStream = $webRequest.GetRequestStream()
}
catch
{
write-host $_.Exception
}
$requestStream.Write($PostStr, 0,$PostStr.length)
$requestStream.Close()
[System.Net.WebResponse]$resp = $webRequest.GetResponse();
$rs = $resp.GetResponseStream();
[System.IO.StreamReader]$sr = New-Object System.IO.StreamReader -argumentList $rs;
[string]$results = $sr.ReadToEnd();
return $results;
}
Execute-HTTPPostCommand $url
[System.GC]::Collect()

Upload files with FTP using PowerShell

I want to use PowerShell to transfer files with FTP to an anonymous FTP server. I would not use any extra packages. How?
I am not sure you can 100% bullet proof the script from not hanging or crashing, as there are things outside your control (what if the server loses power mid-upload?) - but this should provide a solid foundation for getting you started:
# create the FtpWebRequest and configure it
$ftp = [System.Net.FtpWebRequest]::Create("ftp://localhost/me.png")
$ftp = [System.Net.FtpWebRequest]$ftp
$ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$ftp.Credentials = new-object System.Net.NetworkCredential("anonymous","anonymous#localhost")
$ftp.UseBinary = $true
$ftp.UsePassive = $true
# read in the file to upload as a byte array
$content = [System.IO.File]::ReadAllBytes("C:\me.png")
$ftp.ContentLength = $content.Length
# get the request stream, and write the bytes into it
$rs = $ftp.GetRequestStream()
$rs.Write($content, 0, $content.Length)
# be sure to clean up after ourselves
$rs.Close()
$rs.Dispose()
There are some other ways too. I have used the following script:
$File = "D:\Dev\somefilename.zip";
$ftp = "ftp://username:password#example.com/pub/incoming/somefilename.zip";
Write-Host -Object "ftp url: $ftp";
$webclient = New-Object -TypeName System.Net.WebClient;
$uri = New-Object -TypeName System.Uri -ArgumentList $ftp;
Write-Host -Object "Uploading $File...";
$webclient.UploadFile($uri, $File);
And you could run a script against the windows FTP command line utility using the following command
ftp -s:script.txt
(Check out this article)
The following question on SO also answers this: How to script FTP upload and download?
I'm not gonna claim that this is more elegant than the highest-voted solution...but this is cool (well, at least in my mind LOL) in its own way:
$server = "ftp.lolcats.com"
$filelist = "file1.txt file2.txt"
"open $server
user $user $password
binary
cd $dir
" +
($filelist.split(' ') | %{ "put ""$_""`n" }) | ftp -i -in
As you can see, it uses that dinky built-in windows FTP client. Much shorter and straightforward, too. Yes, I've actually used this and it works!
Easiest way
The most trivial way to upload a binary file to an FTP server using PowerShell is using WebClient.UploadFile:
$client = New-Object System.Net.WebClient
$client.Credentials =
New-Object System.Net.NetworkCredential("username", "password")
$client.UploadFile(
"ftp://ftp.example.com/remote/path/file.zip", "C:\local\path\file.zip")
Advanced options
If you need a greater control, that WebClient does not offer (like TLS/SSL encryption, etc), use FtpWebRequest. Easy way is to just copy a FileStream to FTP stream using Stream.CopyTo:
$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.zip")
$request.Credentials =
New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.zip")
$ftpStream = $request.GetRequestStream()
$fileStream.CopyTo($ftpStream)
$ftpStream.Dispose()
$fileStream.Dispose()
Progress monitoring
If you need to monitor an upload progress, you have to copy the contents by chunks yourself:
$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.zip")
$request.Credentials =
New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.zip")
$ftpStream = $request.GetRequestStream()
$buffer = New-Object Byte[] 10240
while (($read = $fileStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$ftpStream.Write($buffer, 0, $read)
$pct = ($fileStream.Position / $fileStream.Length)
Write-Progress `
-Activity "Uploading" -Status ("{0:P0} complete:" -f $pct) `
-PercentComplete ($pct * 100)
}
$ftpStream.Dispose()
$fileStream.Dispose()
Uploading folder
If you want to upload all files from a folder, see
PowerShell Script to upload an entire folder to FTP
I recently wrote for powershell several functions for communicating with FTP, see https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1. The second function below, you can send a whole local folder to FTP. In the module are even functions for removing / adding / reading folders and files recursively.
#Add-FtpFile -ftpFilePath "ftp://myHost.com/folder/somewhere/uploaded.txt" -localFile "C:\temp\file.txt" -userName "User" -password "pw"
function Add-FtpFile($ftpFilePath, $localFile, $username, $password) {
$ftprequest = New-FtpRequest -sourceUri $ftpFilePath -method ([System.Net.WebRequestMethods+Ftp]::UploadFile) -username $username -password $password
Write-Host "$($ftpRequest.Method) for '$($ftpRequest.RequestUri)' complete'"
$content = $content = [System.IO.File]::ReadAllBytes($localFile)
$ftprequest.ContentLength = $content.Length
$requestStream = $ftprequest.GetRequestStream()
$requestStream.Write($content, 0, $content.Length)
$requestStream.Close()
$requestStream.Dispose()
}
#Add-FtpFolderWithFiles -sourceFolder "C:\temp\" -destinationFolder "ftp://myHost.com/folder/somewhere/" -userName "User" -password "pw"
function Add-FtpFolderWithFiles($sourceFolder, $destinationFolder, $userName, $password) {
Add-FtpDirectory $destinationFolder $userName $password
$files = Get-ChildItem $sourceFolder -File
foreach($file in $files) {
$uploadUrl ="$destinationFolder/$($file.Name)"
Add-FtpFile -ftpFilePath $uploadUrl -localFile $file.FullName -username $userName -password $password
}
}
#Add-FtpFolderWithFilesRecursive -sourceFolder "C:\temp\" -destinationFolder "ftp://myHost.com/folder/" -userName "User" -password "pw"
function Add-FtpFolderWithFilesRecursive($sourceFolder, $destinationFolder, $userName, $password) {
Add-FtpFolderWithFiles -sourceFolder $sourceFolder -destinationFolder $destinationFolder -userName $userName -password $password
$subDirectories = Get-ChildItem $sourceFolder -Directory
$fromUri = new-object System.Uri($sourceFolder)
foreach($subDirectory in $subDirectories) {
$toUri = new-object System.Uri($subDirectory.FullName)
$relativeUrl = $fromUri.MakeRelativeUri($toUri)
$relativePath = [System.Uri]::UnescapeDataString($relativeUrl.ToString())
$lastFolder = $relativePath.Substring($relativePath.LastIndexOf("/")+1)
Add-FtpFolderWithFilesRecursive -sourceFolder $subDirectory.FullName -destinationFolder "$destinationFolder/$lastFolder" -userName $userName -password $password
}
}
Here's my super cool version BECAUSE IT HAS A PROGRESS BAR :-)
Which is a completely useless feature, I know, but it still looks cool \m/ \m/
$webclient = New-Object System.Net.WebClient
Register-ObjectEvent -InputObject $webclient -EventName "UploadProgressChanged" -Action { Write-Progress -Activity "Upload progress..." -Status "Uploading" -PercentComplete $EventArgs.ProgressPercentage } > $null
$File = "filename.zip"
$ftp = "ftp://user:password#server/filename.zip"
$uri = New-Object System.Uri($ftp)
try{
$webclient.UploadFileAsync($uri, $File)
}
catch [Net.WebException]
{
Write-Host $_.Exception.ToString() -foregroundcolor red
}
while ($webclient.IsBusy) { continue }
PS. Helps a lot, when I'm wondering "did it stop working, or is it just my slow ASDL connection?"
You can simply handle file uploads through PowerShell, like this.
Complete project is available on Github here https://github.com/edouardkombo/PowerShellFtp
#Directory where to find pictures to upload
$Dir= 'c:\fff\medias\'
#Directory where to save uploaded pictures
$saveDir = 'c:\fff\save\'
#ftp server params
$ftp = 'ftp://10.0.1.11:21/'
$user = 'user'
$pass = 'pass'
#Connect to ftp webclient
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
#Initialize var for infinite loop
$i=0
#Infinite loop
while($i -eq 0){
#Pause 1 seconde before continue
Start-Sleep -sec 1
#Search for pictures in directory
foreach($item in (dir $Dir "*.jpg"))
{
#Set default network status to 1
$onNetwork = "1"
#Get picture creation dateTime...
$pictureDateTime = (Get-ChildItem $item.fullName).CreationTime
#Convert dateTime to timeStamp
$pictureTimeStamp = (Get-Date $pictureDateTime).ToFileTime()
#Get actual timeStamp
$timeStamp = (Get-Date).ToFileTime()
#Get picture lifeTime
$pictureLifeTime = $timeStamp - $pictureTimeStamp
#We only treat pictures that are fully written on the disk
#So, we put a 2 second delay to ensure even big pictures have been fully wirtten in the disk
if($pictureLifeTime -gt "2") {
#If upload fails, we set network status at 0
try{
$uri = New-Object System.Uri($ftp+$item.Name)
$webclient.UploadFile($uri, $item.FullName)
} catch [Exception] {
$onNetwork = "0"
write-host $_.Exception.Message;
}
#If upload succeeded, we do further actions
if($onNetwork -eq "1"){
"Copying $item..."
Copy-Item -path $item.fullName -destination $saveDir$item
"Deleting $item..."
Remove-Item $item.fullName
}
}
}
}
You can use this function :
function SendByFTP {
param (
$userFTP = "anonymous",
$passFTP = "anonymous",
[Parameter(Mandatory=$True)]$serverFTP,
[Parameter(Mandatory=$True)]$localFile,
[Parameter(Mandatory=$True)]$remotePath
)
if(Test-Path $localFile){
$remoteFile = $localFile.Split("\")[-1]
$remotePath = Join-Path -Path $remotePath -ChildPath $remoteFile
$ftpAddr = "ftp://${userFTP}:${passFTP}#${serverFTP}/$remotePath"
$browser = New-Object System.Net.WebClient
$url = New-Object System.Uri($ftpAddr)
$browser.UploadFile($url, $localFile)
}
else{
Return "Unable to find $localFile"
}
}
This function send specified file by FTP.
You must call the function with these parameters :
userFTP = "anonymous" by default or your username
passFTP = "anonymous" by default or your password
serverFTP = IP address of the FTP server
localFile = File to send
remotePath = the path on the FTP server
For example :
SendByFTP -userFTP "USERNAME" -passFTP "PASSWORD" -serverFTP "MYSERVER" -localFile "toto.zip" -remotePath "path/on/the/FTP/"
Goyuix's solution works great, but as presented it gives me this error: "The requested FTP command is not supported when using HTTP proxy."
Adding this line after $ftp.UsePassive = $true fixed the problem for me:
$ftp.Proxy = $null;
Simple solution if you can install curl.
curl.exe -p --insecure "ftp://<ftp_server>" --user "user:password" -T "local_file_full_path"