PowerShell 技能连载 - 使用 FTP:下载文件(第 2 部分)
PowerShell 不附带用于通过 FTP 下载和上传数据的 cmdlet。但是,您可以为此使用 .NET。
要从 FTP 服务器下载文件,请尝试使用以下代码:
1 | $localFile = "C:\test.txt" |
PowerShell 不附带用于通过 FTP 下载和上传数据的 cmdlet。但是,您可以为此使用 .NET。
要从 FTP 服务器下载文件,请尝试使用以下代码:
1 | $localFile = "C:\test.txt" |
PowerShell 不附带用于通过 FTP 下载和上传数据的 cmdlet。但是,您可以使用 .NET 来实现。
要显示 FTP 文件夹的内容,请尝试使用以下代码:
1 | $username='testuser' |
使用 Web 服务,确定您的公共 IP 地址和有关您的 ISP 的信息几乎是举手之劳:
1 | PS> Invoke-RestMethod -Uri https://ipinfo.io |
在之前的技能中,我们创建了新的快捷方式文件,您已经看到 CreateShortcut()
方法如何提供方法来控制快捷方式的几乎所有细节。这是在桌面上创建 PowerShell 快捷方式的代码:
这个技能可以帮助您始终在其他窗口的顶部显示对话框。为此,下面的代码创建了一个新的虚拟窗口,并确保该窗口位于所有其他窗口的顶部。然后,此窗口用作弹出对话框的父级:
1 | Add-Type -AssemblyName System.Windows.Forms |
这是一个显示弹出警告对话框的快速代码示例:
1 | Add-Type -AssemblyName System.Windows.Forms |
这些是可用的按钮样式:
1 | PS> [Enum]::GetNames([System.Windows.Forms.MessageBoxButtons]) |
这些是可用的图标样式:
1 | PS> [Enum]::GetNames([System.Windows.Forms.MessageBoxIcon]) |
有时,在 PowerShell 脚本中使用控制台应用程序很有用,甚至是必要的。例如,在上一个技能中,我们研究了删除映射网络驱动器的方法,尽管 Remove-PSDrive
声称能够执行此操作,但最可靠的方法仍然是使用旧的 net.exe 控制台命令。
让我们快速看看如何检查控制台命令是否成功完成。
让我们尝试通过映射一个新的网络驱动器,然后使用控制台应用程序将其删除。当然,您可以将相同的原则应用于您可能需要在 PowerShell 脚本中运行的任何控制台应用程序:
1 | PS> net use z: \\127.0.0.1\c$ |
创建好映射驱动器,然后再删除。但是,状态消息是本地化的(因此很难将它们与多国环境中的预期值进行比较),并且错误会作为异常出现。
通过使用 $?
,您可以将输出转换为仅 $true
或 $false
:$true
表示命令成功完成,而 $false
表示(任何)错误:
1 | PS> $null = net use z: \\127.0.0.1\c$; $result = $?; $result |
这要好得多,因为您的脚本随后可以判断 $result
并在出现错误时采取适当的步骤或将消息写入日志文件。
但是,如果出现错误,详细的错误信息仍会发送到控制台,并且没有(明显的)方法可以将其删除。即使是成熟的 try...catch
错误处理程序也不会响应它们:
1 | PS> $null = try { net use z: \\127.0.0.1\c$} catch {}; $result = $?; $result |
原因是:控制台应用程序不会抛出 .NET 异常。发生错误时,控制台应用程序仅通过输出流 #2 发出信息。
而这恰好是包装控制台应用程序的解决方案:将所有流重定向到输出流。这段代码映射了一个网络驱动器:第一次调用成功所有后续调用都失败:
1 | PS> $null = net use z: \\127.0.0.1\c$ *>&1; $? |
同样,这会再次删除映射的驱动器,就像在第一次调用成功之前一样,所有剩余的调用都会失败:
1 | PS> $null = net use z: /delete *>&1; $result = $?; $result |
虽然 Remove-PSDrive
可以删除包括网络驱动器在内的所有类型的驱动器,但更改可能要等系统重新启动时才能生效。这当然是荒谬的。
这个任务是一个很好的例子,为什么 PowerShell 使控制台应用程序成为平等公民是有用的。事实上,即使在 2021 年,移除网络驱动器的最可靠方法也是使用旧的但经过验证的 net.exe。下面的示例删除网络驱动器号 Z:
1 | PS> net use z: /delete |
有很多方法可以列出映射的网络驱动器。其中之一使用 PowerShell 的 Get-PSDrive
并检查目标根目录是否以 “\“ 开头,表示 UNC 网络路径:
1 | PS> Get-PSDrive -PSProvider FileSystem | Where-Object DisplayRoot -like '\\*' |
一个不错的方面是 Get-PSDrive
返回有用的附加详细信息,例如驱动器的大小。
在之前的技能中,我们研究了如何使用 Get-PrinterProperty
读取本地安装打印机的打印机属性。此 cmdlet 是所有 Windows 操作系统附带的 PrintManagement
模块的一部分。
重要提示:由于属性名称是特定于打印驱动程序的,如果您需要在整个企业中管理相同类型的打印机,此 cmdlet 会非常有用。如果您想为大量不同的打印机类型创建详细的打印机清单,这不是最佳选择,因为您必须为每个正在使用的打印机驱动程序确定确切的属性名称。同样,在下面的示例中,请确保将打印机属性名称替换为您的打印机支持的名称。
简而言之,要读取特定的打印机属性,您需要提供打印机的名称(运行 Get-Printer
以查找打印机名称)。然后该 cmdlet 会列出所有可用的打印机属性,这些属性可能会因打印机驱动程序和型号而异:
1 | PS> Get-PrinterProperty -PrinterName 'S/W Laser HP' |
例如,您可以过滤属性名称并获取已安装和已卸载打印机附件的列表:
1 | PS> Get-PrinterProperty -PrinterName 'S/W Laser HP' | Where-Object Value -like *installed* | Select-Object -Property PropertyName, Value |
知道打印机名称和特定属性名称后,您可以查询各个属性并检索值以在脚本中使用它。以下是检查是否安装了双面打印单元的示例(确保将打印机名称和属性名称调整为您的打印机型号):
1 | PS> Get-PrinterProperty -PrinterName 'S/W Laser HP' -PropertyName Config:DuplexUnit | Select-Object -ExpandProperty Value |
要远程查询打印机,Get-PrinterProperty
具有 -ComputerName
参数。它接受单个字符串,因此您一次只能查询一台打印机,并且没有 -Credential
参数,因此您无法以其他人身份进行身份验证。你可以试试这个来查询你自己的机器,一旦成功,用真正的远程系统替换计算机名称:
1 | PS> Get-PrinterProperty -PrinterName 'S/W Laser HP' -ComputerName $env:COMPUTERNAME |
由于 cmdlet 使用 Windows 远程管理服务进行远程访问,因此目标打印服务器应启用 WinRM 远程处理(这是 Windows 服务器的默认设置),并且您应该是目标端的管理员。
实际情况中,您还希望能够查询多个服务器并以其他人身份进行身份验证。对于远程访问,首先使用 New-CimSession
指定要查询的所有服务器,并根据需要提交凭据。
接下来,将此会话提交给 Get-PrinterProperty
。如果您有适当的访问权限,现在可以并行查询会话中的所有服务器,从而节省大量时间。-ThrottleLimit
参数确定最多实际联系多少个会话。如果您指定的服务器数超过最大连接数,PowerShell 将自动将其余服务器排队:
1 | $session = New-CimSession -ComputerName server1, server2, server3 -Credential mydomain\remotinguser |
额外提示:您也可以使用 Get-Printer
查找远程打印机名称。Get-Printer
还接受 -CimSession
参数,因此您可以使用相同的网络会话从一台或多台远程服务器查询所有打印机名称。
在上一个技能中,我们查看了 Get-PrinterProperty
,它是 PrintManagement
模块的一部分,可在 Windows 操作系统上使用。
在这个技能中,让我们看看如何在自己的脚本中实际使用打印机值,以及与使用简单数组相比,如何将它们存储在哈希表中使访问打印机属性更容易。
重要提示:实际的打印机属性及其名称取决于您的打印机型号和打印机驱动程序。上面示例中使用的属性名称可能因打印机而异。
当您将 Get-PrinterProperty
返回的结果存储在一个变量中时,该变量包含一个简单的数组,您的工作是使用您所追求的属性来标识数组元素。下面是一个例子:
1 | PS> $info = Get-PrinterProperty -PrinterName 'S/W Laser HP' |
更安全的方法是将结果存储在哈希表中并使用原始属性名称作为键。众所周知,Group-Object
可以自动为您创建哈希表。只需告诉 Group-Object
要用于分组的属性的名称,并要求取回哈希表并将字符串用作哈希表键:
1 | $info = Get-PrinterProperty -PrinterName 'S/W Laser HP' | Group-Object -Property PropertyName -AsHashTable -AsString |
这一次,$info
包含一个哈希表,如果您使用带有 IntelliSense 的 PowerShell 编辑器(如 ISE 或 VSCode),一旦您在输入变量名时按下键盘上的点,就会获得丰富的 IntelliSense,显示可用的属性名称。在控制台中,您可以按 TAB 以使用自动完成功能。
由于 IntelliSense 菜单和 TAB 自动完成还包含一些与哈希表相关的属性和方法,因此您可能需要向下滚动一点或分别按 TAB 几次。
要查询打印机属性的值,选择属性名称后,您需要在属性名称周围添加引号,因为通常打印机属性名称包含特殊字符,如冒号:
1 | # hash table keys need to be quoted |