I've been struggling with a script that needs to copy or download the latest file from a file server to the local drive folder. Here is what i came up with:
[String]$LocalServer = "\\IP_address\D:\Interfaces\"
[String]$File_Name = "MK." + (Get-Date).ToString("ddMMyy") + ".tar.gz" #file name is example MK.040418.tar.gz
[String]$Path = "C:\Localfolder"
[String]$Username = "admin"
[String]$Password = "Admin123"
Copy-Item -Path {$LocalServer + "\" + $FileName} - Destination {$LocalPath}
#$WebClient = New-Object System.Net.WebClient
#$WebClient.Credentials = New-Object System.Net.NetworkCredential($Username,$Password)
#$WebClient.DownloadFile($LocalServer, $FileName)
There's a few issues with your code:
You don't need to use {} to wrap parameters with Powershell.
Your variable is $File_Name but you're using $FileName (missing _) with Copy-Item command.
$LocalServer ends with a \, and you're also adding one in with$LocalServer + "\" + $FileName, so the path ends up having a double slash: \\IP_address\D:\Interfaces\\MK.040418.tar.gz
Fixing these points, the command should be:
Copy-Item -Path "$LocalServer$File_Name" -Destination $LocalPath
Related
Im trying to rename every pdf file in a folder according to variables obtained from those files but i cant get it to work, i can rename one file at a time but i cant manage to make it work for every file.
Here is what i have to rename one file:
Add-Type -Path "C:\Program Files\...\itextsharp.dll"
$file = "C:\Program Files\...\pdf file.pdf"
$pdf = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList $file
$text=[iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($pdf,1)
$startss = $text.LastIndexOf("Completo")
$endss = $text.LastIndexOf("Doc")
$name = $text.Substring($startss +9,$endss - $startss-10)
$startss2 = $text.LastIndexOf("Modalidad")
$endss2 = $text.LastIndexOf("(Entre")
$mode = $text.Substring($startss2 +10,$endss2 - $startss2-10)
Rename-Item -NewName ($name + "-" + $mode + ".pdf") -Path "$file"
$pdf.Close()
And here is what i have to rename every file:
$folder = "C:\...\pdfs folder"
Add-Type -Path "C:\Program Files\...\itextsharp.dll"
$pdffiles = Get-ChildItem -File "$folder\*.pdf"
Foreach($file in $pdffiles)
{
$pdf = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList $file
$text=[iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($pdf,1)
$startss = $text.LastIndexOf("Completo")
$endss = $text.LastIndexOf("Doc")
$name = $text.Substring($startss +9,$endss - $startss-10)
$startss2 = $text.LastIndexOf("Modalidad")
$endss2 = $text.LastIndexOf("(Entre")
$mode = $text.Substring($startss2 +10,$endss2 - $startss2-10)
Rename-Item -NewName ($name + "-" + $mode + "-" + ".pdf") -Path "$file"
$pdf.Close()
}
Hope someone can help me to make it work, thanks in advance
I managed to make a script that opens a pdf file, reads it, makes 2 variables with information from it and saves the file using those variables, but i cant make it do that to all the pdf files in a folder. i dont know if anyone can help me. This is what i have so far:
$file = "C:\Users\..." #path to my pdf file
Add-Type -Path "C:\Program Files\...\itextsharp.dll"
$pdf = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList $file
$text=[iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($pdf,1)
$startss = $text.LastIndexOf("Completo")
$endss = $text.LastIndexOf("Doc")
$name = $text.Substring($startss +9,$endss - $startss-10)
$startss2 = $text.LastIndexOf("Modalidad")
$endss2 = $text.LastIndexOf("(Entre")
$mode = $text.Substring($startss2 +10,$endss2 - $startss2-10)
$pdf.Close()
Rename-Item -NewName ($name + "-" + $mode + "-" + ".pdf") -Path "$file"
You just need a foreach loop. I would recommend reading about Get-ChildItem if you're not sure what it is and some basics on foreach loops.
$folder = "C:\Users\path\to\pdf folder"
Add-Type -Path "C:\Program Files\...\itextsharp.dll"
$pdfFiles = Get-ChildItem "$folder\*.pdf"
foreach($file in $pdfFiles)
{
$pdf = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList $file
$text= [iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($pdf,1)
$startss = $text.LastIndexOf("Completo")
$endss = $text.LastIndexOf("Doc")
$name = $text.Substring($startss +9,$endss - $startss-10)
$startss2 = $text.LastIndexOf("Modalidad")
$endss2 = $text.LastIndexOf("(Entre")
$mode = $text.Substring($startss2 +10,$endss2 - $startss2-10)
$pdf.Close()
Rename-Item -NewName ($name + "-" + $mode + "-" + ".pdf") -Path $file
}
I'm trying to achieve the following via powershell:
I have a table(TBL_DDL) with 5 columns (CATALOG,SCHEMA,OBJECT_TYPE,OBJECT_NAME,DDL)
Now, i'm extract data from this table and then trying to create a folder structure by concatenating first 4 columns (CATALOG,SCHEMA,OBJECT_TYPE,OBJECT_NAME) in C: drive and then exporting the data in DDL column in txt file.
For eg: C:\"CATALOG"\"SCHEMA"\"OBJECT_TYPE"\"OBJECT_NAME"\DDL.txt
I'm trying to achieve this via powershell. Can anyone help me please?
$SqlCmd = 'snowsql -c example -d tu_test -s public -q "select catalog,schema,OBJECT_TYPE,OBJECT_NAME,DDL from SF_TBL_DDL limit 2"'
$MultiArray = #(Invoke-Expression $SqlCmd)
$dt = New-Object System.Data.Datatable
[void]$dt.Columns.Add("CATALOG")
[void]$dt.Columns.Add("SCHEMA")
$Output = foreach ($Object in $MultiArray)
{
foreach ($SCHEMA in $Object.SCHEMA)
{
$someother = New-Object -TypeName psobject -Property #{CATALOG = $Object.CATALOG; SCHEMA = $SCHEMA}
$nRow = $dt.NewRow()
$nRow.CATALOG = $someother.CATALOG
$nRow.SCHEMA = $someother.SCHEMA
$dt.Rows.Add($nRow)
}
}
$dt.row.count
At the moment, i'm getting 0 rows in $dt.
Cheers
You can use System.Data.DataTable object the pull your result set and then loop through it to perform the required operation.
Here GetTableValues function will retrieve the table values and then use following cmdlet to create directory and file
New-Item -ItemType "directory" -Path $dirPath
New-Item -ItemType "file" -Path $filePath
Complete code looks like this
function GetTableValues(){
$DBConnectionString = "<Your DB connection string>";
$sqlConn = new-object System.Data.SqlClient.sqlConnection $DBConnectionString;
$sqlConn.Open();
$sqlCommand = $sqlConn.CreateCommand();
$sqlCommand.CommandText = "select catalog,[schema],OBJECT_TYPE,OBJECT_NAME,DDL from TBL_DDL"; ##Put your correct query here
$result = $sqlCommand.ExecuteReader();
$table = New-Object System.Data.DataTable;
$table.Load($result);
$sqlConn.Close();
return $table;
}
$tableValue = GetTableValues;
foreach ($Row in $tableValue)
{
$filePath = "C:\" + $Row.catalog.TrimEnd() + "\" + $Row.schema.TrimEnd() + "\" + $Row.OBJECT_TYPE.TrimEnd() + "\" + $Row.OBJECT_NAME.TrimEnd() + "\" + $Row.DDL.TrimEnd() + ".txt"
$dirPath = "C:\" + $Row.catalog.TrimEnd() + "\" + $Row.schema.TrimEnd() + "\" + $Row.OBJECT_TYPE.TrimEnd() + "\" + $Row.OBJECT_NAME.TrimEnd()
New-Item -ItemType "directory" -Path $dirPath ##Creates directory
New-Item -ItemType "file" -Path $filePath ##Creates file in $dirPath directory
}
This works perfectly fine for me.
I like to write a PowerShell script to download all files and subfolders from my FTP server. I found a script to download all files from one specific folder, but I also like to download the subfolders and their files.
#FTP Server Information - SET VARIABLES
$ftp = "ftp://ftp.abc.ch/"
$user = 'abc'
$pass = 'abc'
$folder = '/'
$target = "C:\LocalData\Powershell\"
#SET CREDENTIALS
$credentials = new-object System.Net.NetworkCredential($user, $pass)
function Get-FtpDir ($url,$credentials) {
$request = [Net.WebRequest]::Create($url)
$request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
if ($credentials) { $request.Credentials = $credentials }
$response = $request.GetResponse()
$reader = New-Object IO.StreamReader $response.GetResponseStream()
$reader.ReadToEnd()
$reader.Close()
$response.Close()
}
#SET FOLDER PATH
$folderPath= $ftp + "/" + $folder + "/"
$Allfiles=Get-FTPDir -url $folderPath -credentials $credentials
$files = ($Allfiles -split "`r`n")
$files
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
$counter = 0
foreach ($file in ($files | where {$_ -like "*.*"})){
$source=$folderPath + $file
$destination = $target + $file
$webclient.DownloadFile($source, $target+$file)
#PRINT FILE NAME AND COUNTER
$counter++
$counter
$source
}
Thanks for your help (:
The .NET framework or PowerShell do not have any explicit support for recursive file operations (including downloads). You have to implement the recursion yourself:
List the remote directory
Iterate the entries, downloading files and recursing into subdirectories (listing them again, etc.)
Tricky part is to identify files from subdirectories. There's no way to do that in a portable way with the .NET framework (FtpWebRequest or WebClient). The .NET framework unfortunately does not support the MLSD command, which is the only portable way to retrieve directory listing with file attributes in FTP protocol. See also Checking if object on FTP server is file or directory.
Your options are:
Do an operation on a file name that is certain to fail for file and succeeds for directories (or vice versa). I.e. you can try to download the "name". If that succeeds, it's a file, if that fails, it a directory.
You may be lucky and in your specific case, you can tell a file from a directory by a file name (i.e. all your files have an extension, while subdirectories do not)
You use a long directory listing (LIST command = ListDirectoryDetails method) and try to parse a server-specific listing. Many FTP servers use *nix-style listing, where you identify a directory by the d at the very beginning of the entry. But many servers use a different format. The following example uses this approach (assuming the *nix format)
function DownloadFtpDirectory($url, $credentials, $localPath)
{
$listRequest = [Net.WebRequest]::Create($url)
$listRequest.Method =
[System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
$listRequest.Credentials = $credentials
$lines = New-Object System.Collections.ArrayList
$listResponse = $listRequest.GetResponse()
$listStream = $listResponse.GetResponseStream()
$listReader = New-Object System.IO.StreamReader($listStream)
while (!$listReader.EndOfStream)
{
$line = $listReader.ReadLine()
$lines.Add($line) | Out-Null
}
$listReader.Dispose()
$listStream.Dispose()
$listResponse.Dispose()
foreach ($line in $lines)
{
$tokens = $line.Split(" ", 9, [StringSplitOptions]::RemoveEmptyEntries)
$name = $tokens[8]
$permissions = $tokens[0]
$localFilePath = Join-Path $localPath $name
$fileUrl = ($url + $name)
if ($permissions[0] -eq 'd')
{
if (!(Test-Path $localFilePath -PathType container))
{
Write-Host "Creating directory $localFilePath"
New-Item $localFilePath -Type directory | Out-Null
}
DownloadFtpDirectory ($fileUrl + "/") $credentials $localFilePath
}
else
{
Write-Host "Downloading $fileUrl to $localFilePath"
$downloadRequest = [Net.WebRequest]::Create($fileUrl)
$downloadRequest.Method =
[System.Net.WebRequestMethods+Ftp]::DownloadFile
$downloadRequest.Credentials = $credentials
$downloadResponse = $downloadRequest.GetResponse()
$sourceStream = $downloadResponse.GetResponseStream()
$targetStream = [System.IO.File]::Create($localFilePath)
$buffer = New-Object byte[] 10240
while (($read = $sourceStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$targetStream.Write($buffer, 0, $read);
}
$targetStream.Dispose()
$sourceStream.Dispose()
$downloadResponse.Dispose()
}
}
}
Use the function like:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"
The code is translated from my C# example in C# Download all files and subdirectories through FTP.
Though Microsoft does not recommend FtpWebRequest for a new development.
If you want to avoid troubles with parsing the server-specific directory listing formats, use a 3rd party library that supports the MLSD command and/or parsing various LIST listing formats; and recursive downloads.
For example with WinSCP .NET assembly you can download whole directory with a single call to Session.GetFiles:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "ftp.example.com"
UserName = "user"
Password = "mypassword"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Download files
$session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
Internally, WinSCP uses the MLSD command, if supported by the server. If not, it uses the LIST command and supports dozens of different listing formats.
The Session.GetFiles method is recursive by default.
(I'm the author of WinSCP)
For retrieving files /folder from FTP via powerShell I wrote some functions, you can get even hidden stuff from FTP.
Example for getting all files and subfolders (even hidden ones) in a specific folder:
Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory -File
You can just copy the functions from the following module without needing any 3rd library installed:
https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1
I like to write a PowerShell script to download all files and subfolders from my FTP server. I found a script to download all files from one specific folder, but I also like to download the subfolders and their files.
#FTP Server Information - SET VARIABLES
$ftp = "ftp://ftp.abc.ch/"
$user = 'abc'
$pass = 'abc'
$folder = '/'
$target = "C:\LocalData\Powershell\"
#SET CREDENTIALS
$credentials = new-object System.Net.NetworkCredential($user, $pass)
function Get-FtpDir ($url,$credentials) {
$request = [Net.WebRequest]::Create($url)
$request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
if ($credentials) { $request.Credentials = $credentials }
$response = $request.GetResponse()
$reader = New-Object IO.StreamReader $response.GetResponseStream()
$reader.ReadToEnd()
$reader.Close()
$response.Close()
}
#SET FOLDER PATH
$folderPath= $ftp + "/" + $folder + "/"
$Allfiles=Get-FTPDir -url $folderPath -credentials $credentials
$files = ($Allfiles -split "`r`n")
$files
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
$counter = 0
foreach ($file in ($files | where {$_ -like "*.*"})){
$source=$folderPath + $file
$destination = $target + $file
$webclient.DownloadFile($source, $target+$file)
#PRINT FILE NAME AND COUNTER
$counter++
$counter
$source
}
Thanks for your help (:
The .NET framework or PowerShell do not have any explicit support for recursive file operations (including downloads). You have to implement the recursion yourself:
List the remote directory
Iterate the entries, downloading files and recursing into subdirectories (listing them again, etc.)
Tricky part is to identify files from subdirectories. There's no way to do that in a portable way with the .NET framework (FtpWebRequest or WebClient). The .NET framework unfortunately does not support the MLSD command, which is the only portable way to retrieve directory listing with file attributes in FTP protocol. See also Checking if object on FTP server is file or directory.
Your options are:
Do an operation on a file name that is certain to fail for file and succeeds for directories (or vice versa). I.e. you can try to download the "name". If that succeeds, it's a file, if that fails, it a directory.
You may be lucky and in your specific case, you can tell a file from a directory by a file name (i.e. all your files have an extension, while subdirectories do not)
You use a long directory listing (LIST command = ListDirectoryDetails method) and try to parse a server-specific listing. Many FTP servers use *nix-style listing, where you identify a directory by the d at the very beginning of the entry. But many servers use a different format. The following example uses this approach (assuming the *nix format)
function DownloadFtpDirectory($url, $credentials, $localPath)
{
$listRequest = [Net.WebRequest]::Create($url)
$listRequest.Method =
[System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
$listRequest.Credentials = $credentials
$lines = New-Object System.Collections.ArrayList
$listResponse = $listRequest.GetResponse()
$listStream = $listResponse.GetResponseStream()
$listReader = New-Object System.IO.StreamReader($listStream)
while (!$listReader.EndOfStream)
{
$line = $listReader.ReadLine()
$lines.Add($line) | Out-Null
}
$listReader.Dispose()
$listStream.Dispose()
$listResponse.Dispose()
foreach ($line in $lines)
{
$tokens = $line.Split(" ", 9, [StringSplitOptions]::RemoveEmptyEntries)
$name = $tokens[8]
$permissions = $tokens[0]
$localFilePath = Join-Path $localPath $name
$fileUrl = ($url + $name)
if ($permissions[0] -eq 'd')
{
if (!(Test-Path $localFilePath -PathType container))
{
Write-Host "Creating directory $localFilePath"
New-Item $localFilePath -Type directory | Out-Null
}
DownloadFtpDirectory ($fileUrl + "/") $credentials $localFilePath
}
else
{
Write-Host "Downloading $fileUrl to $localFilePath"
$downloadRequest = [Net.WebRequest]::Create($fileUrl)
$downloadRequest.Method =
[System.Net.WebRequestMethods+Ftp]::DownloadFile
$downloadRequest.Credentials = $credentials
$downloadResponse = $downloadRequest.GetResponse()
$sourceStream = $downloadResponse.GetResponseStream()
$targetStream = [System.IO.File]::Create($localFilePath)
$buffer = New-Object byte[] 10240
while (($read = $sourceStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$targetStream.Write($buffer, 0, $read);
}
$targetStream.Dispose()
$sourceStream.Dispose()
$downloadResponse.Dispose()
}
}
}
Use the function like:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"
The code is translated from my C# example in C# Download all files and subdirectories through FTP.
Though Microsoft does not recommend FtpWebRequest for a new development.
If you want to avoid troubles with parsing the server-specific directory listing formats, use a 3rd party library that supports the MLSD command and/or parsing various LIST listing formats; and recursive downloads.
For example with WinSCP .NET assembly you can download whole directory with a single call to Session.GetFiles:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "ftp.example.com"
UserName = "user"
Password = "mypassword"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Download files
$session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
Internally, WinSCP uses the MLSD command, if supported by the server. If not, it uses the LIST command and supports dozens of different listing formats.
The Session.GetFiles method is recursive by default.
(I'm the author of WinSCP)
For retrieving files /folder from FTP via powerShell I wrote some functions, you can get even hidden stuff from FTP.
Example for getting all files and subfolders (even hidden ones) in a specific folder:
Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory -File
You can just copy the functions from the following module without needing any 3rd library installed:
https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1