1
+ function Convert-PSMDMessage
2
+ {
3
+ <#
4
+ . SYNOPSIS
5
+ Converts a file's use of PSFramework messages to strings.
6
+
7
+ . DESCRIPTION
8
+ Converts a file's use of PSFramework messages to strings.
9
+
10
+ . PARAMETER Path
11
+ Path to the file to convert.
12
+
13
+ . PARAMETER OutPath
14
+ Folder in which to generate the output ps1 and psd1 file.
15
+
16
+ . PARAMETER EnableException
17
+ Replaces user friendly yellow warnings with bloody red exceptions of doom!
18
+ Use this if you want the function to throw terminating errors you want to catch.
19
+
20
+ . EXAMPLE
21
+ PS C:\> Convert-PSMDMessage -Path 'C:\Scripts\logrotate.ps1' -OutPath 'C:\output'
22
+
23
+ Converts all instances of writing messages in logrotate.ps1 to use strings instead.
24
+ #>
25
+ [CmdletBinding ()]
26
+ param (
27
+ [Parameter (Mandatory = $true , Position = 0 )]
28
+ [PsfValidateScript (' PSFramework.Validate.FSPath.File' , ErrorString = ' PSFramework.Validate.FSPath.File' )]
29
+ [string ]
30
+ $Path ,
31
+
32
+ [Parameter (Mandatory = $true , Position = 1 )]
33
+ [PsfValidateScript (' PSFramework.Validate.FSPath.Folder' , ErrorString = ' PSFramework.Validate.FSPath.Folder' )]
34
+ [string ]
35
+ $OutPath ,
36
+
37
+ [switch ]
38
+ $EnableException
39
+ )
40
+
41
+ begin
42
+ {
43
+ # region Utility Functions
44
+ function Get-Text
45
+ {
46
+ [OutputType ([string ])]
47
+ [CmdletBinding ()]
48
+ param (
49
+ $Value
50
+ )
51
+
52
+ if (-not $Value.NestedExpressions ) { return $Value.Extent.Text }
53
+
54
+ $expressions = @ { }
55
+ $expIndex = 0
56
+
57
+ $builder = [System.Text.StringBuilder ]::new()
58
+ $baseIndex = $Value.Extent.StartOffset
59
+ $astIndex = 0
60
+
61
+ foreach ($nestedExpression in $Value.NestedExpressions )
62
+ {
63
+ $null = $builder.Append ($Value.Extent.Text.SubString ($astIndex , ($nestedExpression.Extent.StartOffset - $baseIndex - $astIndex )).Replace(" {" , " {{" ).Replace(' }' , ' }}' ))
64
+ $astIndex = $nestedExpression.Extent.EndOffset - $baseIndex
65
+
66
+ if ($expressions.ContainsKey ($nestedExpression.Extent.Text )) { $effectiveIndex = $expressions [$nestedExpression.Extent.Text ] }
67
+ else
68
+ {
69
+ $expressions [$nestedExpression.Extent.Text ] = $expIndex
70
+ $effectiveIndex = $expIndex
71
+ $expIndex ++
72
+ }
73
+
74
+ $null = $builder.Append (" {$effectiveIndex }" )
75
+ }
76
+
77
+ $null = $builder.Append ($Value.Extent.Text.SubString ($astIndex ).Replace(" {" , " {{" ).Replace(' }' , ' }}' ))
78
+ $builder.ToString ()
79
+ }
80
+
81
+ function Get-Insert
82
+ {
83
+ [OutputType ([string ])]
84
+ [CmdletBinding ()]
85
+ param (
86
+ $Value
87
+ )
88
+
89
+ if (-not $Value.NestedExpressions ) { return " " }
90
+
91
+ $processed = @ { }
92
+ $elements = foreach ($nestedExpression in $Value.NestedExpressions )
93
+ {
94
+ if ($processed [$nestedExpression.Extent.Text ]) { continue }
95
+ else { $processed [$nestedExpression.Extent.Text ] = $true }
96
+
97
+ if ($nestedExpression -is [System.Management.Automation.Language.SubExpressionAst ])
98
+ {
99
+ if (
100
+ ($nestedExpression.SubExpression.Statements.Count -eq 1 ) -and
101
+ ($nestedExpression.SubExpression.Statements [0 ].PipelineElements.Count -eq 1 ) -and
102
+ ($nestedExpression.SubExpression.Statements [0 ].PipelineElements[0 ].Expression -is [System.Management.Automation.Language.MemberExpressionAst ])
103
+ ) { $nestedExpression.SubExpression.Extent.Text }
104
+ else { $nestedExpression.Extent.Text.SubString (1 ) }
105
+ }
106
+ else { $nestedExpression.Extent.Text }
107
+ }
108
+ $elements -join " , "
109
+ }
110
+ # endregion Utility Functions
111
+
112
+ $parameterMapping = @ {
113
+ ' Message' = ' String'
114
+ ' Action' = ' ActionString'
115
+ }
116
+ $insertMapping = @ {
117
+ ' String' = ' -StringValues'
118
+ ' Action' = ' -ActionStringValues'
119
+ }
120
+ }
121
+ process
122
+ {
123
+ $ast = (Read-PSMDScript - Path $Path ).Ast
124
+
125
+ # region Parse Input
126
+ $functionName = (Get-Item $Path ).BaseName
127
+
128
+ $commandAsts = $ast.FindAll ({
129
+ if ($args [0 ] -isnot [System.Management.Automation.Language.CommandAst ]) { return $false }
130
+ if ($args [0 ].CommandElements[0 ].Value -notmatch ' ^Invoke-PSFProtectedCommand$|^Write-PSFMessage$|^Stop-PSFFunction$' ) { return $false }
131
+ if (-not ($args [0 ].CommandElements.ParameterName -match ' ^Message$|^Action$' )) { return $false }
132
+ $true
133
+ }, $true )
134
+ if (-not $commandAsts )
135
+ {
136
+ Write-PSFMessage - Level Host - String ' Convert-PSMDMessage.Parameter.NonAffected' - StringValues $Path
137
+ return
138
+ }
139
+ # endregion Parse Input
140
+
141
+ # region Build Replacements table
142
+ $currentCount = 1
143
+ $replacements = foreach ($command in $commandAsts )
144
+ {
145
+ $parameter = $command.CommandElements | Where-Object ParameterName -in ' Message' , ' Action'
146
+ $paramIndex = $command.CommandElements.IndexOf ($parameter )
147
+ $parameterValue = $command.CommandElements [$paramIndex + 1 ]
148
+
149
+ [PSCustomObject ]@ {
150
+ OriginalText = $parameterValue.Value
151
+ Text = Get-Text - Value $parameterValue
152
+ Inserts = Get-Insert - Value $parameterValue
153
+ String = " $ ( $functionName ) .Message$ ( $currentCount ) "
154
+ StartOffset = $parameter.Extent.StartOffset
155
+ EndOffset = $parameterValue.Extent.EndOffset
156
+ OldParameterName = $parameter.ParameterName
157
+ NewParameterName = $parameterMapping [$parameter.ParameterName ]
158
+ Parameter = $parameter
159
+ ParameterValue = $parameterValue
160
+ }
161
+ $currentCount ++
162
+ }
163
+ # endregion Build Replacements table
164
+
165
+ # region Calculate new text body
166
+ $fileText = [System.IO.File ]::ReadAllText((Resolve-PSFPath - Path $Path ))
167
+ $builder = [System.Text.StringBuilder ]::new()
168
+ $index = 0
169
+ foreach ($replacement in $replacements )
170
+ {
171
+ $null = $builder.Append ($fileText.Substring ($index , ($replacement.StartOffset - $index )))
172
+ $null = $builder.Append (" -$ ( $replacement.NewParameterName ) '$ ( $replacement.String ) '" )
173
+ if ($replacement.Inserts ) { $null = $builder.Append (" $ ( $insertMapping [$replacement.NewParameterName ]) $ ( $replacement.Inserts ) " ) }
174
+ $index = $replacement.EndOffset
175
+ }
176
+ $null = $builder.Append ($fileText.Substring ($index ))
177
+ $newDefinition = $builder.ToString ()
178
+ $testResult = Read-PSMDScript - ScriptCode ([Scriptblock ]::create($newDefinition ))
179
+
180
+ if ($testResult.Errors )
181
+ {
182
+ Stop-PSFFunction - String ' Convert-PSMDMessage.SyntaxError' - StringValues $Path - Target $Path - EnableException $EnableException
183
+ return
184
+ }
185
+ # endregion Calculate new text body
186
+
187
+ $resolvedOutPath = Resolve-PSFPath - Path $OutPath
188
+ $encoding = [System.Text.UTF8Encoding ]::new($true )
189
+ $filePath = Join-Path - Path $resolvedOutPath - ChildPath " $functionName .ps1"
190
+ [System.IO.File ]::WriteAllText($filePath , $newDefinition , $encoding )
191
+ $stringsPath = Join-Path - Path $resolvedOutPath - ChildPath " $functionName .psd1"
192
+ $stringsText = @"
193
+ @{
194
+ $ ( $replacements | Format-String " `t '{0}' = {1} # {2}" - Property String, Text, Inserts | Join-String - Separator " `n " )
195
+ }
196
+ "@
197
+ [System.IO.File ]::WriteAllText($stringsPath , $stringsText , $encoding )
198
+ }
199
+ }
0 commit comments