我有一个PowerShell脚本,用于检查远程位置文件的现有时间戳数据,以便与本地文件进行比较。
使用此代码段检索本地信息:
$SrcEntries = Get-ChildItem $FolderLocation -Recurse
然后,我可以使用以下代码段获取有关文件夹和文件的具体信息:
$Srcfolders = $SrcEntries | Where-Object{$_.PSIsContainer}
$SrcFiles = $SrcEntries | Where-Object{!$_.PSIsContainer}
目前使用此代码段检索远程信息,该代码段针对每个文件单独执行:
$Credentials = New-Object System.Net.NetworkCredential($FTPUser,$FTPPassword)
$FTPrequest = [System.Net.FtpWebRequest]::Create($RemoteFilePath)
$FTPrequest.Method = [System.Net.WebRequestMethods+FTP]::GetDateTimestamp
$FTPrequest.Credentials = $Credentials
$response = $FTPrequest.GetResponse().StatusDescription
然后解析$response
以检索远程文件的时间戳。
以与检索本地数据相同的方式检索远程数据似乎更好,即在单个操作中与上面的第一个代码段一样,以避免多次往返远程服务器。
是否可以使用PowerShell在单个快速FTP操作中递归获取文件夹和文件目录数据?我该怎么做?
答案 0 :(得分:2)
在没有任何外部库的情况下实现它并不容易。不幸的是,.NET Framework和PowerShell都没有明确支持递归列出FTP文件夹中的文件。
你必须自己实现:
第一个棘手的部分是识别子文件夹中的文件。使用.NET框架(FtpWebRequest
)以便携方式无法做到这一点。遗憾的是,.NET框架不支持MLSD
命令,这是在FTP协议中使用文件属性检索目录列表的唯一可移植方式。另请参阅Checking if object on FTP server is file or directory。
您的选择是:
LIST
command = ListDirectoryDetails
方法)并尝试解析特定于服务器的列表。许多FTP服务器使用* nix样式列表,您可以在条目的最开始通过d
标识目录。但是许多服务器使用不同的格式。以下示例使用此方法(假设为* nix格式)function ListFtpDirectory($url, $credentials)
{
$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]
if ($permissions[0] -eq 'd')
{
Write-Host "Directory $name"
$fileUrl = ($url + $name)
ListFtpDirectory ($fileUrl + "/") $credentials
}
else
{
Write-Host "File $name"
}
}
}
使用如下功能:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/list/"
ListFtpDirectory $url $credentials
虽然上面的代码只会列出名称。由于你也需要时间戳,你甚至必须解析那些。如果条目是文件夹或文件,那就像确定一样复杂。
我没有PowerShell代码,但请查看我对其他类似问题的回答,这些问题显示了C#代码。它应该很容易转换为PowerShell:
如果您想避免解析特定于服务器的目录列表格式的麻烦,请使用支持MLSD
命令和/或解析各种LIST
列表格式的第三方库。
例如,使用WinSCP .NET assembly,您可以通过一次调用Session.EnumerateRemoteFiles
递归地列出整个目录:
# 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
$options =
[WinSCP.EnumerationOptions]::EnumerateDirectories -bor
[WinSCP.EnumerationOptions]::AllDirectories
$fileInfos = $session.EnumerateRemoteFiles("/directory/to/list", $Null, $options)
foreach ($fileInfo in $fileInfos)
{
Write-Host $fileInfo.FullName
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
不仅代码更简单,更容易和独立于平台。它还可以通过RemoteFileInfo
class轻松获取所有其他文件属性(大小,修改时间,权限,所有权)。
如果服务器支持,WinSCP在内部使用MLSD
命令。如果没有,它使用LIST
命令并支持许多不同的列表格式。
虽然您似乎想要比较本地和远程时间戳以同步文件夹。
WinSCP .NET程序集可以使用Session.SynchronizeDirectories
进行一次调用。
您也可能会发现这些问题(由我回答)很有用:
(我是WinSCP的作者)