forked from brianary/scripts
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathInvoke-CachedCommand.ps1
More file actions
114 lines (108 loc) · 4.21 KB
/
Invoke-CachedCommand.ps1
File metadata and controls
114 lines (108 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<#
.SYNOPSIS
Caches the output of a command for recall if called again.
.FUNCTIONALITY
Command
.EXAMPLE
Invoke-CachedCommand.ps1 {Invoke-RestMethod https://example.org/endpoint} -Session
Returns the result of executing the script block, or the previous cached output if available.
#>
#Requires -Version 7
[CmdletBinding()] Param(
# Specifies the expression to cache the output of.
[Parameter(Position=0,Mandatory=$true)][scriptblock] $Expression,
# Parameters to the script block.
[Parameter(Position=1,ValueFromRemainingArguments=$true)][psobject[]] $BlockArgs = @(),
# The rolling duration to cache the output for (updated with each call).
[Parameter(ParameterSetName='ExpiresAfter')][timespan] $ExpiresAfter,
# Point in time to cache the output until.
[Parameter(ParameterSetName='Expires')][datetime] $Expires,
# Caches the output for this session.
[Parameter(ParameterSetName='Session')][switch] $Session,
# Forces rerunning the command to update the cache.
[switch] $Force
)
Begin
{
function Initialize-Variables
{
[CmdletBinding()] Param()
$Script:Hash = [Security.Cryptography.MD5]::Create()
$Script:SessionCacheName = "$(Split-Path $PSCommandPath -LeafBase)#$PID"
$Script:SessionCache = Get-Variable $Script:SessionCacheName -Scope Global -ErrorAction Ignore
if(!$Script:SessionCache)
{
$Script:SessionCache = Set-Variable $Script:SessionCacheName @{} -Scope Global -Option Constant -PassThru `
-Description 'Cached command output'
}
$Script:CacheDir = if($IsWindows)
{
Join-Path $env:LocalAppData (Split-Path $PSCommandPath -LeafBase)
}
elseif($IsLinux)
{
Join-Path ($env:XDG_CACHE_HOME ?? "$HOME/.cache") (Split-Path $PSCommandPath -LeafBase)
}
else
{
Join-Path $env:TEMP (Split-Path $PSCommandPath -LeafBase)
}
New-Item $Script:CacheDir -Type Directory -ErrorAction Ignore |Out-Null
Get-ChildItem $Script:CacheDir |
Where-Object LastWriteTime -lt (Get-Date) |
Remove-Item
}
function Get-ScriptBlockHash
{
[CmdletBinding()] Param(
[Parameter(Position=0)][scriptblock] $ScriptBlock,
[Parameter(Position=1)][psobject[]] $BlockArgs = @()
)
return (@("$ScriptBlock") + @($BlockArgs |ForEach-Object {ConvertTo-Json $_ -Compress}) |
ForEach-Object {ConvertTo-Base64.ps1 $Script:Hash.ComputeHash([Text.Encoding]::UTF8.GetBytes($_)) -UriStyle}) -join '.'
}
function Get-CachedOutput
{
[CmdletBinding()] Param(
[Parameter(Position=0)][scriptblock] $ScriptBlock,
[Parameter(Position=1)][psobject[]] $BlockArgs = @(),
[datetime] $Expires,
[switch] $Force
)
$now = Get-Date
$cacheFileName = Join-Path $Script:CacheDir "$(Get-ScriptBlockHash $ScriptBlock -BlockArgs $BlockArgs).xml"
if(Test-Path $cacheFileName -Type Leaf)
{
$cacheFile = Get-Item $cacheFileName
if($now -gt $cacheFile.LastWriteTime -or $Force)
{
$ScriptBlock.InvokeReturnAsIs(@($BlockArgs)) |Export-Clixml $cacheFileName -Force
}
}
else
{
$ScriptBlock.InvokeReturnAsIs(@($BlockArgs)) |Export-Clixml $cacheFileName
$cacheFile = Get-Item $cacheFileName
}
$cacheFile.LastWriteTime = $Expires
Import-Clixml $cacheFileName
}
}
Process
{
Initialize-Variables
switch($PSCmdlet.ParameterSetName)
{
ExpiresAfter {Get-CachedOutput $Expression -BlockArgs $BlockArgs -Expires (Get-Date).Add($ExpiresAfter) -Force:$Force}
Expires {Get-CachedOutput $Expression -BlockArgs $BlockArgs -Expires $Expires -Force:$Force}
Session
{
$key = Get-ScriptBlockHash $Expression -BlockArgs $BlockArgs
if($Force -or !$Script:SessionCache.Value.ContainsKey($key))
{
$Script:SessionCache.Value[$key] = $Expression.InvokeReturnAsIs(@($BlockArgs))
}
return $Script:SessionCache.Value[$key]
}
}
}