PowerShell 技能连载 - 快速创建编码的 PowerShell 命令

当在 PowerShell 控制台之外执行 PowerShell 代码时,您需要传递代码给 powershell.exe。要确保您的代码不与特殊字符冲突,命令可以编码后传给 powershell.exe。

一个最简单的将纯文本命令行转换为编码后的命令的方法如下:

PS C:\> cmd /c echo powershell { Get-Service | Where-Object Status -eq Running }
powershell -encodedCommand IABHAGUAdAAtAFMAZQByAHYAaQBjAGUAIAB8ACAAVwBoAGUAcgBlAC0ATwBiAGoAZQ
BjAHQAIABTAHQAYQB0AHUAcwAgAC0AZQBxACAAUgB1AG4AbgBpAG4AZwAgAA== -inputFormat xml -outputFormat
 xml
PS C:\>

Here you’d find out that you can run the Get-Service | Where-Object statement as an encoded command like this:
然后可以以这样的方式执行编码后的 Get-Service | Where-Object 语句。

powershell.exe -encodedCommand
IABHAGUAdAAtAFMAZQByAHYAaQBjAGUAIAB8ACAAVwBoAGUAcgBlAC0ATwBiAGoAZQBjAHQAIABTAHQAYQB0AHUAcwAgAC0AZQBxACAAUgB1AG4AbgBpAG4AZwAgAA==

当您在 cmd.exe(或 PowerShell 控制台中)运行这段语句时,您能够得到所有运行中的服务。只需要移除 -inputFormat-outputFormat 参数,并且移除所有换行符。编码后的命令是一个长长的字符串。

PowerShell 技能连载 - 为变量增加 ValidateRange

如果您希望为一个变量增加一个合法数值的范围,您可以向该变量添加一个 ValidateRange 属性,很像函数参数的工作方式。唯一的区别在,它手工作用于您期望的变量上:

$test = 1
$variable = Get-Variable test
$validateRange = New-Object -TypeName System.Management.Automation.ValidateRangeAttribute(1,100)
$variable.Attributes.Add($validateRange)
$test = 10
$test = 100
$test = 1000

变量 $test 现在只允许 1 到 100 的数值。当您试图赋一个该范围之外的值时,会得到一个异常。

PS C:\> $test =  101
The variable cannot be  validated because the value 101 is not a valid value for the test
variable.
At line:1 char:1
+ $test = 101
+ ~~~~~~~~~~~
    +  CategoryInfo          : MetadataError:  (:) [], ValidationMetadataException
    +  FullyQualifiedErrorId : ValidateSetFailure

PowerShell 技能连载 - 为什么 $MaximumHistoryCount 容量有限

如果您想增加最大命令历史的容量,您可能会遇到这样的限制:

PS C:\> $MaximumHistoryCount  = 100000

The variable cannot be  validated because the value 100000 is not a valid value for the Maximum
HistoryCount variable.

这里并没有提示合法的范围是多少。有意思的地方是这个变量的合法范围保存在哪。答案是:您可以查询这个变量的 ValidateRange 属性:

$variable = Get-Variable MaximumHistoryCount
$variable.Attributes
$variable.Attributes.MinRange
$variable.Attributes.MaxRange

但您遇到一个变量在原始数据类型之外有数值限制,您可能需要检查变量的属性来确认其中是否有验证器属性。

PowerShell 技能连载 - 复制命令历史

您可以将整个命令历史拷贝到剪贴板中:

(Get-History).CommandLine | clip.exe

该技术使用 PowerShell 3.0 带来的自动展开技术。若要在 PowerShell 2.0 中使用它,您需要像这样手工展开属性:

Get-History | Select-Object -ExpandProperty commandline | clip.exe

要只拷贝最后五条命令,只需要为 Get-History 命令加上 -Count 参数即可:

(Get-History -Count 5).CommandLine | clip.exe

PowerShell 技能连载 - 增加历史缓存

当您在 PowerShell 会话中工作一段时间以后,命令历史可能十分有用。每个会话存储了您输入的所有命令,您可以按上下键浏览已输入的命令。

您甚至可以这样搜索历史缓存:

PS C:\> #obje

键入一个注释符(# 号),然后跟上您所能回忆起的命令关键字,然后按下 TAB 键,每按一次 TAB 将会显示命令历史中匹配的一条命令(如果没有匹配成功,将不会显示)。

要限制命令历史的大小,请使用 $MaximumHistoryCount 变量。缺省值是 4096。

PS C:\> $MaximumHistoryCount
4096

PS C:\> $MaximumHistoryCount = 32KB-1

PS C:\> $MaximumHistoryCount
32767

PS C:\>

历史缓存最大允许的容量是 32KB-1。

PowerShell 技能连载 - 获取最后启动时间

在 PowerShell 3.0 以上版本中,可以很容易地用 Get-CimInstance 从 WMI 中获取真实的 DateTime 类型信息。这段代码将告诉您系统上次启动的时间:

#requires -Version 3
(Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime

在 PowerShell 2.0 中,您只能使用 Get-WmiObject,它是以 WMI 格式反馈数据的:

(Get-WmiObject -Class Win32_OperatingSystem).LastBootUpTime

这里,您必须手工转换 WMI 格式:

$object = Get-WmiObject -Class Win32_OperatingSystem
$lastboot = $object.LastBootUpTime
$object.ConvertToDateTime($lastboot)

ConvertToDateTime() 转换函数实际上是一个附加的方法。在这个场景背后,是一个静态方法实现了以上工作:

$object = Get-WmiObject -Class Win32_OperatingSystem
$lastboot = $object.LastBootUpTime
[System.Management.ManagementDateTimeConverter]::ToDateTime($lastboot)

PowerShell 技能连载 - 复制对象

在前一个技能中我们演示了 PowerShell 是通过引用存储对象的。如果您想创建一个浮板,您可能需要手工复制对象的所有属性。

以下是一个简单的克隆对象的方法:

$object1 = @{Name='Weltner'; ID=12 }
$object2 = @{Name='Frank'; ID=99 }


$a = $object1, $object2

# clone entire object by serializing it back and forth:
$b = $a | ConvertTo-Json -Depth 99 | ConvertFrom-Json

$b[0].Name = 'changed'
$b[0].Name
$a[0].Name

不过,请注意序列化的过程可能会改变复制的对象类型。

PS C:\> $a[0].GetType().FullName
System.Collections.Hashtable

PS C:\> $b[0].GetType().FullName
System.Management.Automation.PSCustomObject

PS C:\>

PowerShell 技能连载 - 复制数组(第 2 部分)

在前一个技能中我们解释了如何用 Clone() 方法安全地“克隆”一个数组。这将把一个数组的内容复制到一个新的数组。

然而,如果数组的元素是对象(不是数字或字符串等原始数据类型),数组存储了这些对象的内存地址,所以克隆方法虽然创建了一个新的数组,但是新的数组仍然引用了相同对象。请看:

$object1 = @{Name='Weltner'; ID=12 }
$object2 = @{Name='Frank'; ID=99 }


$a = $object1, $object2
$b = $a.Clone()
$b[0].Name = 'changed'
$b[0].Name
$a[0].Name

虽然您克隆了数组 $a,但是新的数组 $b 仍然引用了相同的对象,对对象的更改会同时影响两个数组。只有对数组内容的更改是独立的:

$object1 = @{Name='Weltner'; ID=12 }
$object2 = @{Name='Frank'; ID=99 }


$a = $object1, $object2
$b = $a.Clone()
$b[0] = 'deleted'
$b[0]
$a[0]

小米路由器 mini 与 OpenWRT

今天拿到小米路由器 mini ,准备对它刷入 OpenWRT 固件。这类操作通常都有些坑,所以将过程记录如下:

初始化

难度 ★★☆☆☆
陷阱 ★☆☆☆☆

小米路由器 mini 开箱以后,按照内附的纸质说明书对它进行简单的初始化,使得电脑可以通过它上网。这个过程是面向普通消费者的,所以过程不再赘述。

初始化完成后,路由器 WEB 管理界面中可能会提示有可升级的固件,在此可以忽略,因为我们下一步可能对它进行降级。

在路由器的 USB 口中插入一个格式化为 FAT32 的空白 U 盘,容量在 1GB 以上即可,最好是带指示灯的,这样可以看得到它的读写状态。首次插入 U 盘的时候,小米路由器会向 U 盘里写入十来兆的数据,要等 U 盘指示灯停止闪烁以后再进行后续的断电、刷机等操作比较保险。

用小米路由器的手机 APP(扫盒子上的二维码下载)将路由器和小米账户绑定。这步是打开 SSH 的基础。

固件降级

难度 ★★☆☆☆
陷阱 ★★★☆☆

为了打开 SSH 功能,我们需要刷入小米路由 mini 的开发版固件。注意,我们不仅不能刷入最新版的固件,相反,要对已有的固件降级。因为经过一系列实验,发现若使用高版本的小米路由器 mini 固件,在后续打开 SSH 操作的时候,会遇到黄灯闪烁 3 秒后变成了红灯的问题。

请自行搜索 0.6.40 版的 miwifi_r1cm_all_ace8a_0.6.40.bin 并下载,这个版本亲测可以用。官网的MiWiFi成长日志提供的 0.8.x 和 0.7.x 版都无法打开 SSH。

然后在路由器的 WEB 控制台的路由设置中手动刷入上述 .bin 文件。按照提示等待 5-8 分钟,就可以再次进入路由器的 WEB 控制台了。可以在 WEB 控制台中确认降级成功。

打开 SSH

难度 ★★★☆☆
陷阱 ★★☆☆☆

打开 SSH 意味着失去保修。不过准备继续折腾的人早已做好放弃保修的准备了。

访问MiWiFi – 小米路由器官网,点击“开放/开启 SSH 工具/下载工具包”,并记下 root 密码。注意这将下载一个专属的 miwifi_ssh.bin 文件,同款不同机器是不通用的。

把下载下来的 miwifi_ssh.bin 复制到刚才的 U 盘中。断电,插入 U 盘,按住复位键,通电,在黄色指示灯闪烁的时候,放开复位键,等待….
当指示灯变成 蓝色长亮的时候,说明我们获取到 root 权限并启动 SSH 服务了。

刷入 PandoraBox

难度 ★★★☆☆
陷阱 ★★★☆☆

访问 Index of /PandoraBox/Xiaomi-Mini-R1CM/,目前 stable 目录下没东西,只有 testing 目录下有东西,也就是只有测试版。

下载最新的 PandoraBox-ralink-mt7620-xiaomi-mini-squashfs-sysupgrade-r460-20150216.bin(还有个文件名不带 mt7620 字样的固件不知道是做什么的)。

用 XSHELL、SecureCRT、PUTTY 等 SSH 客户端,以及 WinSCP 文件传输器(以 SCP 协议)以前面记录的 root 密码登录 192.168.31.1。

用 WinSCP 把下载的 PandoraBox 固件上传到小米路由 mini 的 /tmp/ 目录下,顺便改个短点的名字 PandoraBox.bin

在 SSH 客户端中执行以下命令开始刷入 PandoraBox 固件:

mtd -r write /tmp/PandoraBox.bin firmware

注意,如果遇到 Could not open mtd device: firmware 提示,请按前面的步骤进行固件降级。

等路由重启后,可以搜索到信号PandoraBox_XXXX,没有密码,连上去后进入192.168.1.1,密码 admin,之后就能看到可爱的 OpenWRT 界面了。

刷 u-boot

刷 u-boot 应该在刷 PandoraBox 步骤之前。刷 PandoraBox u-boot 不是必须的,但是刷了可以方便后续的上传固件,不用一直SS H 操作。

u-boot是一种普遍用于嵌入式系统中的Bootloader,Bootloader是在操作系统运行之前执行的一小段程序。他可以用来恢复小米路由器的固件,可以说只要刷了uboot,你的路由器基本上刷不死了。

  • 小米 u-boot 的用法是将固件命名为 miwifi.bin,存在 FAT32 U 盘根目录中,插入路由器,按住 reset 键接通电源,待黄灯闪烁之后松开。
  • PandoraBox u-boot 的用法是将 PC 网卡配置成 192.168.1.2/255.255.255.0/192.168.1.1,按住 reset 键接通电源,待黄灯闪烁之后松开,用 PC 浏览器打开 http://192.168.1.1,即可通过上传 PandoraBox 的固件来刷。

注意,小米官方的 u-boot 和 PandoraBox 的不同。刷了 PandoraBox 的固件之后,不能通过 WEB 方式刷小米固件,但可以通过 WEB 方式刷小米 u-boot,然后通过小米 u-boot 可以刷小米固件。这样来实现从 PandoraBox 刷回原产小米固件。

主要攻略如下:

小米路由器mini折腾之刷不死uboot篇 - 老高的技术博客
小米mini使用不死uboot刷宽带宝教程 - 交流讨论 - 宽带宝论坛 - Powered by Discuz!

参考

PowerShell 技能连载 - 复制数组(第 1 部分)

当您复制变量内容时,您也可以只拷贝“引用”(内存地址),而不是内容。请看这个例子:

$a = 1..10
$b = $a
$b[0] = 'changed'
$b[0]
$a[0]

虽然您改变了 $b,但 $a 也跟着改变。两个变量都引用了相同的内存地址,所以两者具有相同的内容。

要创建一个数组的全新拷贝,您需要先对它进行克隆:

$a = 1..10
$b = $a.Clone()
$b[0] = 'changed'
$b[0]
$a[0]