Skip to content

Commit 8e83cd5

Browse files
committedAug 12, 2022
Useful File handling
Generates the File as UTF8 BOM
1 parent de77a07 commit 8e83cd5

File tree

1 file changed

+301
-211
lines changed

1 file changed

+301
-211
lines changed
 
+301-211
Original file line numberDiff line numberDiff line change
@@ -1,218 +1,308 @@
1+
# Original from Jeff Hicks / jdhitsolutions
2+
# https://github.com/jdhitsolutions/PSScriptTools
3+
4+
# Modified by TomTom
5+
# based on: PSFunctionTools_v1.0.0 / 28. Feb. 2022
6+
#
7+
# 220812
8+
# Added:
9+
# • -OutputFileOrSuffix 'filename'
10+
# The generated content will be written in UTF8 *with* BOM to OutputFileOrSuffix
11+
# Example:
12+
# Convert-ScriptToFunction -Path 'c:\Temp\Source.ps1'-name GitLab-RestAPI -OutputFile 'c:\Temp\Source-Func.ps1' -Verbose
13+
# # Creates: c:\Temp\Source-Func.ps1
14+
#
15+
# • -OutputFileOrSuffix 'suffix'
16+
# The generated content will be written in UTF8 *with* BOM
17+
# Example:
18+
# Convert-ScriptToFunction -Path 'c:\Temp\Source.ps1'-name GitLab-RestAPI -OutputFile '-Func' -Verbose
19+
# # Creates: c:\Temp\Source-Func.ps1
20+
21+
22+
# Sehr schnell, optional mit der expliziten Codierung
23+
# Write Text for a File
24+
# 220812: Neu: -WriteBOM
25+
Function Write-Content-Fast() {
26+
Param (
27+
[Parameter(Position = 0, Mandatory)]
28+
$LiteralPath,
29+
[Parameter(Position = 1, Mandatory, ValueFromPipeline)]
30+
$Content,
31+
[Parameter(Position = 2)]
32+
[Text.Encoding]$Encoding,
33+
[Switch]$WriteBOM,
34+
[Switch]$Overwrite = $True
35+
)
36+
37+
Begin {
38+
If (Test-Path -LiteralPath $LiteralPath) {
39+
If ($Overwrite) {
40+
Remove-Item -Force -LiteralPath $LiteralPath
41+
} Else {
42+
Return
43+
}
44+
}
45+
}
46+
47+
Process {
48+
If ($Encoding -eq [Text.Encoding]::UTF8) {
49+
If ($WriteBOM) {
50+
$Encoding = [System.Text.UTF8Encoding]::new($true)
51+
} Else {
52+
$Encoding = [System.Text.UTF8Encoding]::new($false)
53+
}
54+
}
55+
56+
Switch ($Content.GetType()) {
57+
([Object[]]) {
58+
If ($Encoding) {
59+
[System.IO.File]::WriteAllLines($LiteralPath, $Content, $Encoding)
60+
} Else {
61+
[System.IO.File]::WriteAllLines($LiteralPath, $Content)
62+
}
63+
}
64+
([String]) {
65+
If ($Encoding) {
66+
[System.IO.File]::WriteAllText($LiteralPath, $Content, $Encoding)
67+
} Else {
68+
[System.IO.File]::WriteAllText($LiteralPath, $Content)
69+
}
70+
}
71+
}
72+
}
73+
74+
End {}
75+
}
76+
77+
78+
# Ergänzt einen Dateinamen mit einem Suffix
79+
Function Filename-Add-Suffix($FileName, $Suffix) {
80+
[IO.Path]::Combine( `
81+
[IO.Path]::GetDirectoryName($FileName), `
82+
[IO.Path]::GetFileNameWithoutExtension($FileName) + $Suffix + [IO.path]::GetExtension($FileName)
83+
)
84+
}
85+
86+
187
Function Convert-ScriptToFunction {
2-
[cmdletbinding()]
3-
[Outputtype("System.String")]
4-
[alias('csf')]
5-
Param(
6-
[Parameter(
7-
Position = 0,
8-
Mandatory,
9-
ValueFromPipelineByPropertyName,
10-
HelpMessage = "Enter the path to your PowerShell script file."
11-
)]
12-
[ValidateScript({Test-Path $_ })]
13-
[ValidatePattern("\.ps1$")]
14-
[string]$Path,
15-
16-
[Parameter(
17-
Position = 1,
18-
Mandatory,
19-
ValueFromPipelineByPropertyName,
20-
HelpMessage = "What is the name of your new function?")]
21-
[ValidateScript({
22-
if ($_ -match "^\w+-\w+$") {
23-
$true
24-
}
25-
else {
26-
Throw "Your function name should have a Verb-Noun naming convention"
27-
$False
28-
}
29-
})]
30-
[string]$Name,
31-
32-
[Parameter(ValueFromPipelineByPropertyName,HelpMessage = "Specify an optional alias for your new function. You can define multiple aliases separated by commas.")]
33-
[ValidateNotNullOrEmpty()]
34-
[string[]]$Alias
35-
)
36-
DynamicParam {
37-
<#
38-
If running this function in the PowerShell ISE or VS Code,
39-
define a ToEditor switch parameter
40-
#>
41-
If ($host.name -match "ISE|Code") {
42-
43-
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
44-
45-
# Defining parameter attributes
46-
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
47-
$attributes = New-Object System.Management.Automation.ParameterAttribute
48-
$attributes.ParameterSetName = '__AllParameterSets'
49-
$attributeCollection.Add($attributes)
50-
51-
# Defining the runtime parameter
52-
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('ToEditor', [Switch], $attributeCollection)
53-
$paramDictionary.Add('ToEditor', $dynParam1)
54-
55-
return $paramDictionary
56-
} # end if
57-
} #end DynamicParam
58-
Begin {
59-
Write-Verbose "Starting $($MyInvocation.MyCommand)"
60-
Write-Verbose "Initializing"
61-
$new = [System.Collections.Generic.list[string]]::new()
62-
} #begin
63-
Process {
64-
#normalize
65-
$Path = Convert-Path $path
66-
$Name = Format-FunctionName $Name
67-
68-
Write-Verbose "Processing $path"
69-
$AST = _getAST $path
70-
71-
if ($ast.extent) {
72-
Write-Verbose "Getting any comment based help"
73-
$ch = $astTokens | Where-Object { $_.kind -eq 'comment' -AND $_.text -match '\.synopsis' }
74-
75-
if ($ast.ScriptRequirements) {
76-
Write-Verbose "Adding script requirements"
77-
if($ast.ScriptRequirements.RequiredPSVersion) {
78-
$new.Add("#requires -version $($ast.ScriptRequirements.RequiredPSVersion.ToString())")
79-
}
80-
if ($ast.ScriptRequirements.RequiredModules) {
81-
Foreach ($m in $ast.ScriptRequirements.RequiredModules) {
82-
#test for version requirements
83-
$ver = $m.psobject.properties.where({$_.name -match 'version' -AND $_.value})
84-
if ($ver) {
85-
$new.Add("#requires -module @{ModuleName = '$($m.name)';$($ver.Name) = '$($ver.value)'}")
86-
}
87-
else {
88-
$new.add("#requires -module $($m.Name)")
89-
}
90-
}
91-
}
92-
if ($ast.ScriptRequirements.IsElevationRequired) {
93-
$new.Add("#requires -RunAsAdministrator")
94-
}
95-
If ($ast.ScriptRequirements.requiredPSEditions) {
96-
$new.add("#requires -PSEdition $($ast.ScriptRequirements.requiredPSEditions)")
97-
}
98-
99-
$new.Add("`n")
100-
}
101-
else {
102-
Write-Verbose "No script requirements found"
103-
}
104-
105-
$head = @"
88+
[cmdletbinding()]
89+
[Outputtype("System.String")]
90+
[alias('csf')]
91+
Param(
92+
[Parameter(Position = 0, Mandatory, ValueFromPipelineByPropertyName,
93+
HelpMessage = "Enter the path to your PowerShell script file.")]
94+
[ValidateScript({Test-Path $_ })]
95+
[ValidatePattern("\.ps1$")]
96+
[string]$Path,
97+
98+
[Parameter(Position = 1, Mandatory, ValueFromPipelineByPropertyName,
99+
HelpMessage = "What is the name of your new function?")]
100+
[ValidateScript({
101+
if ($_ -match "^\w+-\w+$") {
102+
$true
103+
} else {
104+
Throw "Your function name should have a Verb-Noun naming convention"
105+
$False
106+
}
107+
})]
108+
[string]$Name,
109+
110+
[Parameter(ValueFromPipelineByPropertyName,
111+
HelpMessage = "Specify an optional alias for your new function. You can define multiple aliases separated by commas.")]
112+
[ValidateNotNullOrEmpty()]
113+
[string[]]$Alias,
114+
115+
[String]$OutputFileOrSuffix
116+
)
117+
118+
DynamicParam {
119+
<# If running this function in the PowerShell ISE or VS Code,
120+
define a ToEditor switch parameter
121+
#>
122+
If ($host.name -match "ISE|Code") {
123+
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
124+
125+
# Defining parameter attributes
126+
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
127+
$attributes = New-Object System.Management.Automation.ParameterAttribute
128+
$attributes.ParameterSetName = '__AllParameterSets'
129+
$attributeCollection.Add($attributes)
130+
131+
# Defining the runtime parameter
132+
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('ToEditor', [Switch], $attributeCollection)
133+
$paramDictionary.Add('ToEditor', $dynParam1)
134+
return $paramDictionary
135+
}
136+
}
137+
138+
Begin {
139+
Write-Verbose "Starting $($MyInvocation.MyCommand)"
140+
Write-Verbose "Initializing"
141+
$new = [System.Collections.Generic.list[string]]::new()
142+
}
143+
144+
Process {
145+
#normalize
146+
$Path = Convert-Path $path
147+
$Name = Format-FunctionName $Name
148+
149+
Write-Verbose "Processing $path"
150+
$AST = _getAST $path
151+
152+
if ($ast.extent) {
153+
Write-Verbose "Getting any comment based help"
154+
$ch = $astTokens | Where-Object { $_.kind -eq 'comment' -AND $_.text -match '\.synopsis' }
155+
156+
if ($ast.ScriptRequirements) {
157+
Write-Verbose "Adding script requirements"
158+
if($ast.ScriptRequirements.RequiredPSVersion) {
159+
$new.Add("#requires -version $($ast.ScriptRequirements.RequiredPSVersion.ToString())")
160+
}
161+
if ($ast.ScriptRequirements.RequiredModules) {
162+
Foreach ($m in $ast.ScriptRequirements.RequiredModules) {
163+
#test for version requirements
164+
$ver = $m.psobject.properties.where({$_.name -match 'version' -AND $_.value})
165+
if ($ver) {
166+
$new.Add("#requires -module @{ModuleName = '$($m.name)';$($ver.Name) = '$($ver.value)'}")
167+
} else {
168+
$new.add("#requires -module $($m.Name)")
169+
}
170+
}
171+
}
172+
if ($ast.ScriptRequirements.IsElevationRequired) {
173+
$new.Add("#requires -RunAsAdministrator")
174+
}
175+
If ($ast.ScriptRequirements.requiredPSEditions) {
176+
$new.add("#requires -PSEdition $($ast.ScriptRequirements.requiredPSEditions)")
177+
}
178+
$new.Add("`n")
179+
} else {
180+
Write-Verbose "No script requirements found"
181+
}
182+
183+
$head = @"
106184
# Function exported from $Path
107185
108186
Function $Name {
109187
110188
"@
111-
$new.add($head)
112-
113-
if ($ch) {
114-
$new.Add($ch.text)
115-
$new.Add("`n")
116-
}
117-
else {
118-
Write-Verbose "Generating new comment based help from parameters"
119-
if ($ast.ParamBlock) {
120-
New-CommentHelp -ParamBlock $ast.ParamBlock | Foreach-Object { $new.Add("$_")}
121-
}
122-
else {
123-
New-CommentHelp -templateonly |Foreach-Object { $new.Add("$_")}
124-
}
125-
$new.Add("`n")
126-
}
127-
128-
[regex]$rx = "\[cmdletbinding\(.*\)\]"
129-
if ($rx.Ismatch($ast.Extent.text)) {
130-
Write-Verbose "Using existing cmdletbinding"
131-
#use the first match
132-
$cb = $rx.match($ast.extent.text).Value
133-
$new.Add("`t$cb")
134-
}
135-
else {
136-
Write-Verbose "Adding [cmdletbinding()]"
137-
$new.Add("`t[cmdletbinding()]")
138-
}
139-
140-
if ($alias) {
141-
Write-Verbose "Adding function alias definition $($alias -join ',')"
142-
$new.Add("`t[Alias('$($alias -join "','")')]")
143-
}
144-
if ($ast.ParamBlock) {
145-
Write-Verbose "Adding defined Param() block"
146-
[void]($ast.ParamBlock.tostring().split("`n").Foreach({$new.add("`t$_")}) -join "`n")
147-
$new.Add("`n")
148-
}
149-
else {
150-
Write-Verbose "Adding Param() block"
151-
$new.add("`tParam()")
152-
}
153-
if ($ast.DynamicParamBlock) {
154-
#assumes no more than 1 dynamic parameter
155-
Write-Verbose "Adding dynamic parameters"
156-
[void]($ast.DynamicParamBlock.tostring().split("`n").Foreach({$new.Add($_)}) -join "`n")
157-
}
158-
159-
if ($ast.BeginBlock.Extent.text) {
160-
Write-Verbose "Adding defined Begin block"
161-
[void]($ast.BeginBlock.Extent.toString().split("`n").Foreach({$new.Add($_)}) -join "`n")
162-
$UseBPE = $True
163-
}
164-
165-
if ($ast.ProcessBlock.Extent.text) {
166-
Write-Verbose "Adding defined Process block"
167-
[void]($ast.ProcessBlock.Extent.ToString().split("`n").Foreach({$new.add($_) }) -join "`n")
168-
}
169-
170-
if ($ast.EndBlock.Extent.text) {
171-
if ($UseBPE) {
172-
Write-Verbose "Adding opening End{} block"
173-
$new.Add("`tEnd {")
174-
}
175-
Write-Verbose "Adding the remaining code or defined endblock"
176-
[void]($ast.Endblock.Statements.foreach({ $_.tostring() }).Foreach({ $new.Add($_)}))
177-
if ($UseBPE) {
178-
Write-Verbose "Adding closing End {} block"
179-
$new.Add("`t}")
180-
}
181-
}
182-
else {
183-
$new.Add("End { }")
184-
}
185-
Write-Verbose "Closing the function"
186-
$new.Add( "`n} #close $name")
187-
188-
if ($PSBoundParameters.ContainsKey("ToEditor")) {
189-
Write-Verbose "Opening result in editor"
190-
if ($host.name -match "ISE") {
191-
$newfile = $psise.CurrentPowerShellTab.Files.add()
192-
$newfile.Editor.InsertText(($new -join "`n"))
193-
$newfile.editor.select(1,1,1,1)
194-
}
195-
elseif ($host.name -match "Code") {
196-
$pseditor.Workspace.NewFile()
197-
$ctx = $pseditor.GetEditorContext()
198-
$ctx.CurrentFile.InsertText($new -join "`n")
199-
}
200-
else {
201-
$new -join "`n" | Set-Clipboard
202-
Write-Warning "Can't detect the PowerShell ISE or VS Code. Output has been copied to the clipboard."
203-
}
204-
}
205-
else {
206-
Write-Verbose "Writing output [$($new.count) lines] to the pipeline"
207-
$new -join "`n"
208-
}
209-
} #if ast found
210-
else {
211-
Write-Warning "Failed to find a script body to convert to a function."
212-
}
213-
214-
} #process
215-
End {
216-
Write-Verbose "Ending $($MyInvocation.mycommand)"
217-
}
189+
190+
$new.add($head)
191+
192+
if ($ch) {
193+
$new.Add($ch.text)
194+
$new.Add("`n")
195+
} else {
196+
Write-Verbose "Generating new comment based help from parameters"
197+
if ($ast.ParamBlock) {
198+
New-CommentHelp -ParamBlock $ast.ParamBlock | Foreach-Object { $new.Add("$_")}
199+
} else {
200+
New-CommentHelp -templateonly |Foreach-Object { $new.Add("$_")}
201+
}
202+
$new.Add("`n")
203+
}
204+
205+
[regex]$rx = "\[cmdletbinding\(.*\)\]"
206+
if ($rx.Ismatch($ast.Extent.text)) {
207+
Write-Verbose "Using existing cmdletbinding"
208+
#use the first match
209+
$cb = $rx.match($ast.extent.text).Value
210+
$new.Add("`t$cb")
211+
} else {
212+
Write-Verbose "Adding [cmdletbinding()]"
213+
$new.Add("`t[cmdletbinding()]")
214+
}
215+
216+
if ($alias) {
217+
Write-Verbose "Adding function alias definition $($alias -join ',')"
218+
$new.Add("`t[Alias('$($alias -join "','")')]")
219+
}
220+
if ($ast.ParamBlock) {
221+
Write-Verbose "Adding defined Param() block"
222+
[void]($ast.ParamBlock.tostring().split("`n").Foreach({$new.add("`t$_")}) -join "`n")
223+
$new.Add("`n")
224+
} else {
225+
Write-Verbose "Adding Param() block"
226+
$new.add("`tParam()")
227+
}
228+
if ($ast.DynamicParamBlock) {
229+
#assumes no more than 1 dynamic parameter
230+
Write-Verbose "Adding dynamic parameters"
231+
[void]($ast.DynamicParamBlock.tostring().split("`n").Foreach({$new.Add($_)}) -join "`n")
232+
}
233+
234+
if ($ast.BeginBlock.Extent.text) {
235+
Write-Verbose "Adding defined Begin block"
236+
[void]($ast.BeginBlock.Extent.toString().split("`n").Foreach({$new.Add($_)}) -join "`n")
237+
$UseBPE = $True
238+
}
239+
240+
if ($ast.ProcessBlock.Extent.text) {
241+
Write-Verbose "Adding defined Process block"
242+
[void]($ast.ProcessBlock.Extent.ToString().split("`n").Foreach({$new.add($_) }) -join "`n")
243+
}
244+
245+
if ($ast.EndBlock.Extent.text) {
246+
if ($UseBPE) {
247+
Write-Verbose "Adding opening End{} block"
248+
$new.Add("`tEnd {")
249+
}
250+
Write-Verbose "Adding the remaining code or defined endblock"
251+
[void]($ast.Endblock.Statements.foreach({ $_.tostring() }).Foreach({ $new.Add($_)}))
252+
if ($UseBPE) {
253+
Write-Verbose "Adding closing End {} block"
254+
$new.Add("`t}")
255+
}
256+
} else {
257+
$new.Add("End { }")
258+
}
259+
260+
Write-Verbose "Closing the function"
261+
$new.Add( "`n} #close $name")
262+
263+
if ($PSBoundParameters.ContainsKey("ToEditor")) {
264+
Write-Verbose "Opening result in editor"
265+
if ($host.name -match "ISE") {
266+
$newfile = $psise.CurrentPowerShellTab.Files.add()
267+
$newfile.Editor.InsertText(($new -join "`n"))
268+
$newfile.editor.select(1,1,1,1)
269+
} elseif ($host.name -match "Code") {
270+
$pseditor.Workspace.NewFile()
271+
$ctx = $pseditor.GetEditorContext()
272+
$ctx.CurrentFile.InsertText($new -join "`n")
273+
} else {
274+
$new -join "`n" | Set-Clipboard
275+
Write-Warning "Can't detect the PowerShell ISE or VS Code. Output has been copied to the clipboard."
276+
}
277+
} elseIf ([String]::IsNullOrWhiteSpace($OutputFileOrSuffix)) {
278+
Write-Verbose "Writing output [$($new.count) lines] to the pipeline"
279+
$new -join "`n"
280+
} Else {
281+
282+
# If OutputFileOrSuffix has no File Extension, then it is handled as a suffix
283+
If ([IO.Path]::GetExtension($OutputFileOrSuffix).Length -eq 0) {
284+
$OutputFileOrSuffix = Filename-Add-Suffix $Path $OutputFileOrSuffix
285+
}
286+
287+
Write-Verbose "Writing output [$($new.count) lines] to: $OutputFileOrSuffix"
288+
Write-Content-Fast -LiteralPath $OutputFileOrSuffix -Content ($new -join "`n") -Encoding ([Text.Encoding]::UTF8) -WriteBom -Overwrite
289+
290+
# Validate
291+
If (Test-Path -LiteralPath $OutputFileOrSuffix) {
292+
$BytesWritten = (Get-Item $OutputFileOrSuffix).Length
293+
Write-Verbose "$((Get-Item $OutputFileOrSuffix).Length) Bytes written"
294+
} Else {
295+
Write-Error 'Coud not write File!'
296+
}
297+
}
298+
} #if ast found
299+
else {
300+
Write-Warning "Failed to find a script body to convert to a function."
301+
}
302+
303+
} #process
304+
305+
End {
306+
Write-Verbose "Ending $($MyInvocation.mycommand)"
307+
}
218308
}

0 commit comments

Comments
 (0)
Please sign in to comment.