保存已删除的 Powershell 脚本
Saving a deleted Powershell script
我不小心从命令行删除了几个Powershell脚本,恢复工具没有成功恢复它们。碰巧的是,两个最重要的脚本在删除时是 运行(在正常的 Powershell 提示符下而不是 ISE 中),并且它们仍然是 运行 通常。是否可以从内存中恢复这两个脚本?
PowerShell caches the result 每次它从脚本文件编译一个脚本块,然后通过脚本 name/path 和内容索引编译的块 - 所以我们可以提取已经 name/path 的原始脚本=43=] 在给定的主机应用程序中有一点反射:
function Get-ScriptBlockCache {
# Internal variable name changed in PowerShell core, take into account
$fieldName = '_cachedScripts'
if($PSVersionTable.PSVersion.Major -ge 6){
$fieldName = 's_cachedScripts'
}
# Obtain type metadata for the field we want to extract values from
$cachedScriptsMemberInfo = [scriptblock].GetMember($fieldName, 'Static,NonPublic')[0]
# We're only interested in the keys, since they contain the original script text
return @($cachedScriptsMemberInfo.GetValue($null).Keys) |Select @{Name='Path';Expression='Item1'},@{Name='ScriptSourceCode';Expression='Item2'}
}
现在你可以做:
Get-ScriptBlockCache |Where-Object Path -like "*nameOfDeletedScript.ps1" |ForEach-Object ScriptSourceCode
如果您没有及时访问怎么办?
如果进程 运行ning 无人值守(例如,作为计划任务或 运行 与 -File
和 -NoExit
),您可以使用 PowerShell 的惊人功能用于在目标进程中开辟辅助 运行 空间并从那里 运行 缓存恢复的调试工具:
Enter-PSHostProcess -Id <targetProcessId>
# Once you're dropped into the target process, define the `Get-ScriptBlockCache` function and execute it
如果进程已经退出怎么办?
如果进程不再 运行ning,那么 缓存也会丢失 - 但还有另一种选择:ScriptBlock 日志!
如果机器配置为启用了强制脚本块日志记录,您还可以从事件日志中获取 PowerShell 已解析的任何脚本或脚本块(前提是日志条目尚未被覆盖):
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4104} |Select TimeCreated,@{Name='SourceCode';Expression={$_.Properties[2].Value}}
这不会显示进程 ID 或脚本 path/name,但如果您知道它执行的时间并大致了解脚本内容,您应该能够从这些日志中收集到它:)
注意:如果您从磁盘调用脚本,脚本块缓存提取技巧仅在 ISE 中有效,例如 & path\to\script.ps1
- 在编辑器窗格中打开并执行的脚本直接在 ISE 内将不会以这种方式缓存。
我不小心从命令行删除了几个Powershell脚本,恢复工具没有成功恢复它们。碰巧的是,两个最重要的脚本在删除时是 运行(在正常的 Powershell 提示符下而不是 ISE 中),并且它们仍然是 运行 通常。是否可以从内存中恢复这两个脚本?
PowerShell caches the result 每次它从脚本文件编译一个脚本块,然后通过脚本 name/path 和内容索引编译的块 - 所以我们可以提取已经 name/path 的原始脚本=43=] 在给定的主机应用程序中有一点反射:
function Get-ScriptBlockCache {
# Internal variable name changed in PowerShell core, take into account
$fieldName = '_cachedScripts'
if($PSVersionTable.PSVersion.Major -ge 6){
$fieldName = 's_cachedScripts'
}
# Obtain type metadata for the field we want to extract values from
$cachedScriptsMemberInfo = [scriptblock].GetMember($fieldName, 'Static,NonPublic')[0]
# We're only interested in the keys, since they contain the original script text
return @($cachedScriptsMemberInfo.GetValue($null).Keys) |Select @{Name='Path';Expression='Item1'},@{Name='ScriptSourceCode';Expression='Item2'}
}
现在你可以做:
Get-ScriptBlockCache |Where-Object Path -like "*nameOfDeletedScript.ps1" |ForEach-Object ScriptSourceCode
如果您没有及时访问怎么办?
如果进程 运行ning 无人值守(例如,作为计划任务或 运行 与 -File
和 -NoExit
),您可以使用 PowerShell 的惊人功能用于在目标进程中开辟辅助 运行 空间并从那里 运行 缓存恢复的调试工具:
Enter-PSHostProcess -Id <targetProcessId>
# Once you're dropped into the target process, define the `Get-ScriptBlockCache` function and execute it
如果进程已经退出怎么办?
如果进程不再 运行ning,那么 缓存也会丢失 - 但还有另一种选择:ScriptBlock 日志!
如果机器配置为启用了强制脚本块日志记录,您还可以从事件日志中获取 PowerShell 已解析的任何脚本或脚本块(前提是日志条目尚未被覆盖):
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4104} |Select TimeCreated,@{Name='SourceCode';Expression={$_.Properties[2].Value}}
这不会显示进程 ID 或脚本 path/name,但如果您知道它执行的时间并大致了解脚本内容,您应该能够从这些日志中收集到它:)
注意:如果您从磁盘调用脚本,脚本块缓存提取技巧仅在 ISE 中有效,例如 & path\to\script.ps1
- 在编辑器窗格中打开并执行的脚本直接在 ISE 内将不会以这种方式缓存。