This commit is contained in:
OCram85 2022-06-15 10:50:22 +02:00
parent 9fbd57b686
commit b3342d4ebb
14 changed files with 533 additions and 168 deletions

31
.editorconfig Normal file
View File

@ -0,0 +1,31 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = crlf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.yml]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{.gitattributes,.gitignore,.gitkeep}]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

26
.gitattributes vendored
View File

@ -1,2 +1,24 @@
src/Vendor/libressl255/* filter=lfs diff=lfs merge=lfs -text # images
*.pfx filter=lfs diff=lfs merge=lfs -text *.jpg binary
*.jpeg binary
*.bmp binary
*.tiff binary
*.png binary
*.svg binary
*.ico binary
# binary files
*.exe binary
*.dll binary
# PowerShell specific
*.ps1 working-tree-encoding=UTF-8
*.psm1 working-tree-encoding=UTF-8
*.psd1 working-tree-encoding=UTF-8
# set markdown to lf for online editing
*.md working-tree-encoding=UTF-8
# Vendor resources config
src/Vendor/libressl255/* filter=lfs diff=lfs merge=lfs -text
*.pfx filter=lfs diff=lfs merge=lfs -text

21
.gitignore vendored
View File

@ -1,3 +1,18 @@
# Don't local track test builds # Don't local track test builds
bin/PSCredentialStore.zip bin/PSCredentialStore.zip
bin/PSCredentialStore/* bin/PSCredentialStore/*
# Basic ignore patterns
*.log
*.secret
# data dir related prod files
data/*.csv
# Ignore templ build artifacts
/bin/*
!bin/.gitkeep
# Ignore Unit Test result files
coverage.xml
testResults.xml

62
.vscode/cSpell.json vendored
View File

@ -1,40 +1,22 @@
// cSpell Settings // cSpell Settings
{ {
// Version of the setting file. Always 0.1 // Version of the setting file. Always 0.1
"version": "0.1", "version": "0.2",
// language - current active spelling language // language - current active spelling language
"language": "en", "language": "en,de,de-DE",
// words - list of words to be always considered correct // words - list of words to be always considered correct
"words": [ "words": [],
"Cmdlet", // flagWords - list of words to be always considered incorrect
"Cmdlets", // This is useful for offensive words and common spelling errors.
"GUID", // For example "hte" should be "the"
"Hashtable", "flagWords": [],
"Httpclient", "dictionaryDefinitions": [
"Multipart", {
"NTFS", "name": "default",
"Params", "path": "./dictionaries/default.txt"
"Ponduit", }
"Repo", ],
"Veyor", "dictionaries": [
"appveyor", "default"
"callsign", ]
"choco", }
"chocolatey",
"codecoverage",
"creds",
"formdata",
"googlemail",
"notlike",
"notmatch",
"powershellgallery",
"testresults",
"wildcards"
],
// flagWords - list of words to be always considered incorrect
// This is useful for offensive words and common spelling errors.
// For example "hte" should be "the"
"flagWords": [
"hte"
]
}

0
.vscode/dictionaries/default.txt vendored Normal file
View File

13
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
"recommendations": [
"streetsidesoftware.code-spell-checker",
"streetsidesoftware.code-spell-checker-german",
"hediet.vscode-drawio",
"editorconfig.editorconfig",
"eamodio.gitlens",
"vscode-icons-team.vscode-icons",
"redhat.vscode-xml",
"redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters"
]
}

2
.vscode/launch.json vendored
View File

@ -42,7 +42,7 @@
"type": "PowerShell", "type": "PowerShell",
"request": "launch", "request": "launch",
"name": "PowerShell Interactive Session", "name": "PowerShell Interactive Session",
"cwd": "" "cwd": "${workspaceRoot}"
} }
] ]
} }

31
.vscode/pwsh.code-snippets vendored Normal file
View File

@ -0,0 +1,31 @@
{
// Place your PowerShell-Module workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
// PSScriptAnalyzder Rule Suppression
"Rule Suppression": {
"scope": "powershell",
"prefix": "[Diag",
"description": "Suppresses Scriptanalyzer Rules",
"body": [
"[Diagnostics.CodeAnalysis.SuppressMessageAttribute(",
" '${1|PSProvideCommentHelp,PSAvoidLongLines,PSAvoidUsingWriteHost,PSUseShouldProcessForStateChangingFunctions|}',",
" '',",
" Justification = '${justification}'",
")]"
]
}
}

103
.vscode/settings.json vendored
View File

@ -1,51 +1,52 @@
// Place your settings in this file to overwrite default and user settings. {
{ "files.encoding": "utf8",
// Set basic file related options: "files.eol": "auto",
"files.encoding": "utf8", "files.trimTrailingWhitespace": true,
"files.eol": "\r\n", "files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true, "editor.renderWhitespace": "boundary",
"files.insertFinalNewline": true, "editor.formatOnSave": true,
// Formation and editor options "editor.formatOnType": true,
"editor.renderWhitespace": "boundary", "editor.rulers": [
"editor.formatOnSave": true, 116
"editor.formatOnType": true, ],
"editor.rulers": [ "cSpell.enabled": true,
116 "cSpell.enabledLanguageIds": [
], "c",
// powershell general "cpp",
"powershell.startAutomatically": true, "csharp",
"powershell.useX86Host": false, "go",
"powershell.enableProfileLoading": true, "javascript",
"powershell.scriptAnalysis.enable": true, "javascriptreact",
// powershell code Formatting "json",
"powershell.codeFormatting.openBraceOnSameLine": true, "latex",
"powershell.codeFormatting.newLineAfterOpenBrace": true, "markdown",
"powershell.codeFormatting.newLineAfterCloseBrace": true, "php",
"powershell.codeFormatting.whitespaceBeforeOpenBrace": true, "plaintext",
"powershell.codeFormatting.whitespaceBeforeOpenParen": true, "powershell",
"powershell.codeFormatting.whitespaceAroundOperator": true, "python",
"powershell.codeFormatting.whitespaceAfterSeparator": true, "text",
"powershell.codeFormatting.ignoreOneLineBlock": true, "typescript",
"powershell.codeFormatting.alignPropertyValuePairs": true, "typescriptreact",
"powershell.codeFormatting.preset": "Custom", "yaml",
// cspell spellchecker options "yml"
"cSpell.enabledLanguageIds": [ ],
"c", "cSpell.language": "en,de,de-DE",
"cpp", // powershell general
"csharp", "powershell.startAutomatically": true,
"go", "powershell.useX86Host": false,
"javascript", "powershell.enableProfileLoading": true,
"javascriptreact", "powershell.scriptAnalysis.enable": true,
"json", // powershell code Formatting
"latex", "powershell.codeFormatting.openBraceOnSameLine": true,
"markdown", "powershell.codeFormatting.newLineAfterOpenBrace": true,
"php", "powershell.codeFormatting.newLineAfterCloseBrace": true,
"plaintext", "powershell.codeFormatting.whitespaceBeforeOpenBrace": true,
"powershell", "powershell.codeFormatting.whitespaceBeforeOpenParen": true,
"python", "powershell.codeFormatting.whitespaceAroundOperator": true,
"text", "powershell.codeFormatting.whitespaceAfterSeparator": true,
"typescript", "powershell.codeFormatting.ignoreOneLineBlock": true,
"typescriptreact", "powershell.codeFormatting.alignPropertyValuePairs": true,
"yml" "powershell.scriptAnalysis.settingsPath": "./tools/PSScriptAnalyzerSettings.psd1",
] "coverage-gutters.showGutterCoverage": false,
} "coverage-gutters.showLineCoverage": true
}

151
.vscode/tasks.json vendored
View File

@ -1,56 +1,121 @@
// A task runner that invokes Pester to run all Pester tests under the
// current workspace folder.
// NOTE: This Test task runner requires an updated version of Pester (>=4.0.3)
// in order for the problemMatcher to find failed test information (message, line, file).
// If you don't have that version, you can update Pester from the PowerShell Gallery
// with this command:
//
// PS C:\> Update-Module Pester
//
// If that gives an error like:
// "Module 'Pester' was not installed by using Install-Module, so it cannot be updated."
// then execute:
//
// PS C:\> Install-Module Pester -Scope CurrentUser -Force
//
// NOTE: The Clean, Build and Publish tasks require PSake. PSake can be installed
// from the PowerShell Gallery with this command:
//
// PS C:\> Install-Module PSake -Scope CurrentUser -Force
//
// Available variables which can be used inside of strings:
// ${workspaceFolder} the path of the workspace folder that contains the tasks.json file
// ${workspaceFolderBasename} the name of the workspace folder that contains the tasks.json file without any slashes (/)
// ${file} the current opened file
// ${relativeFile} the current opened file relative to the workspace folder containing the file
// ${fileBasename} the current opened file's basename
// ${fileBasenameNoExtension} the current opened file's basename without the extension
// ${fileDirname} the current opened file's dirname
// ${fileExtname} the current opened file's extension
// ${cwd} the task runner's current working directory on startup
// ${lineNumber} the current selected line number in the active file
{ {
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0", "version": "2.0.0",
// Start PowerShell //"windows": {
"windows": { // "options": {
"command": "${env:windir}/System32/WindowsPowerShell/v1.0/powershell.exe", // "shell": {
"args": [ // // switch back to windows powershell 5.1
"-NoProfile", // // "executable": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
"-ExecutionPolicy", // "executable": "pwsh.exe",
"Bypass" // "args": [
] // "-NoProfile",
}, // "-ExecutionPolicy",
// "Bypass",
// "-Command"
// ]
// }
// }
//},
"linux": { "linux": {
"command": "/usr/bin/powershell", "options": {
"args": [ "shell": {
"-NoProfile" "executable": "/usr/bin/pwsh",
] "args": [
}, "-NoProfile",
"osx": { "-Command"
"command": "/usr/local/bin/powershell", ]
"args": [ }
"-NoProfile" }
]
}, },
//"osx": {
// "options": {
// "shell": {
// "executable": "/usr/local/bin/pwsh",
// "args": [
// "-NoProfile",
// "-Command"
// ]
// }
// }
//},
"tasks": [ "tasks": [
{ {
"taskName": "Test", "label": "DroneIO: Invoke-Linter",
"suppressTaskName": true, "type": "shell",
"args": [ "command": [
"Write-Host 'Invoking Pester...'; $ProgressPreference = 'SilentlyContinue'; Invoke-Pester -Script ( Get-ChildItem -Path '.\\tests\\*.Tests.ps1' -Recurse | Sort-Object -Property Name ) -EnableExit $flase -PesterOption @{IncludeVSCodeMarker=$true};", "Import-Module ./tools/DroneIO.psm1;",
"Invoke-Command { Write-Host 'Completed Test task in task runner.' }" "Invoke-Linterq | Format-Table -AutoSize"
], ],
"problemMatcher": "$pester", "group": "test",
"group": { "problemMatcher": [
"kind": "test", "$pester"
"isDefault": true ]
}
}, },
{ {
"taskName": "DebugBuild", "label": "DroneIO: Invoke-UnitTest",
"suppressTaskName": true, "type": "shell",
"args": [ "command": [
"Write-Host 'Invoking Build...';", "Remove-Item ./coverage.xml -ErrorAction 'SilentlyContinue';",
"Write-Host -Object 'Test previous builds.' -ForegroundColor Blue;", "Remove-Item ./testResults.xml -ErrorAction 'SilentlyContinue';",
"If (Test-Path -Path '.\\bin\\PSCredentialStore.zip') { Remove-Item -Path '.\\bin\\PSCredentialStore.zip' -Verbose};", "Import-Module ./tools/DroneIO.psm1;",
"Copy-Item -Path '.\\src\\' -Destination '.\\bin\\PSCredentialStore' -Recurse -Verbose -Force;", "Invoke-UnitTest -CoverageFormat 'CoverageGutters' -Verbosity 'Debug'"
"Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose;"
], ],
"group": { "group": "test",
"kind": "build", "problemMatcher": [
"isDefault": true "$pester"
} ]
},
{
"label": "Add dictionary item",
"type": "shell",
"command": [
"$DefaultFile = Get-ChildItem -Path './.vscode/dictionaries/default.txt';",
"$Content = Get-Content -Path $DefaultFile;",
"$Content += '${input:DictionaryItem}';",
"$Content = $Content | Sort-Object -Unique;",
"Set-Content -Value $Content -Path $DefaultFile"
],
"group": "none",
"problemMatcher": [
"$pester"
]
}
],
"inputs": [
{
"id": "DictionaryItem",
"type": "promptString",
"description": "Input for dictionary file default.txt"
} }
] ]
} }

View File

@ -21,7 +21,7 @@ function Get-CSCertificate {
.EXAMPLE .EXAMPLE
Get-CSCertificate -Type 'Shared' -Thumbprint '12334456' Get-CSCertificate -Type 'Shared' -Thumbprint '12334456'
#> #>
[CmdletBinding()] [CmdletBinding()]
[OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])]
param ( param (

14
src/PSModule.Tests.ps1 Normal file
View File

@ -0,0 +1,14 @@
Describe 'Test module meta' {
It 'Test manifest file' {
$ManifestFile = (Get-Item -Path "./src/*.psd1").FullName
Test-ModuleManifest -Path $ManifestFile | Should -Be $true
}
It 'Import Module' {
$ManifestFile = (Get-Item -Path "./src/*.psd1").FullName
{ Import-Module $ManifestFile } | Should -Not -Throw
}
# Dummy test to force pester error
#It 'Force Pester Error' {
# $true | Should -BeFalse
#}
}

View File

@ -1,7 +1,13 @@
$Global:ProgressPreference = 'SilentlyContinue' $Global:ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
function Invoke-ShowEnv { function Invoke-ShowEnv {
[CmdletBinding()] [CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
param () param ()
process { process {
@ -11,6 +17,16 @@ function Invoke-ShowEnv {
function Invoke-InstallDependencies { function Invoke-InstallDependencies {
[CmdletBinding()] [CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseSingularNouns',
'',
Justification = 'internal function'
)]
param () param ()
process { process {
@ -36,44 +52,78 @@ function Invoke-InstallDependencies {
function Invoke-Linter { function Invoke-Linter {
[CmdletBinding()] [CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
param () param ()
process { process {
Invoke-ScriptAnalyzer -Path './src/' -Recurse Import-Module -Name PSScriptAnalyzer
$AnalyzerSettings = @{
Path = './src/'
Recurse = $true
Settings = './tools/PSScriptAnalyzerSettings.psd1'
ReportSummary = $true
}
Invoke-ScriptAnalyzer @AnalyzerSettings
} }
} }
function Invoke-UnitTests { function Invoke-UnitTest {
[CmdletBinding()] [CmdletBinding()]
param () [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSProvideCommentHelp',
'',
Justification = 'internal function'
)]
param (
[Parameter( Mandatory = $false )]
[ValidateSet('JaCoCo', 'CoverageGutters')]
[string]$CoverageFormat = 'JaCoCo',
[Parameter(Mandatory = $false)]
[ValidateSet('None', 'Normal', 'Detailed', 'Diagnostic')]
[string]$Verbosity = 'Normal',
[Parameter(Mandatory = $false)]
[switch]$PassThru,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string[]]$Tag,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string[]]$ExcludeTag
)
process { process {
try { Write-Verbose -Message '===== Running Pester =====' -Verbose:$VerbosePreference
Write-Host '===== Preload internal private functions =====' -ForegroundColor Black -BackgroundColor Yellow $PesterConf = New-PesterConfiguration
$PesterConf.Run.Path = (Resolve-Path -Path './src').Path
$Privates = Get-ChildItem -Path (Join-Path -Path $Env:DRONE_WORKSPACE -ChildPath '/src/Private/*') -Include "*.ps1" -Recurse -ErrorAction Stop $PesterConf.Run.Exit = $false
foreach ($File in $Privates) { $PesterConf.Run.PassThru = $true
if (Test-Path -Path $File.FullName) { $PesterConf.CodeCoverage.Enabled = $true
. $File.FullName $PesterConf.CodeCoverage.OutputFormat = $CoverageFormat
Write-Verbose -Message ('Private function dot-sourced: {0}' -f $File.FullName) -Verbose $PesterConf.TestResult.Enabled = $true
} $CovFiles = Get-ChildItem -Path "./src/*.ps1" -Recurse | Where-Object {
else { $_.BaseName -notmatch '.Tests'
Write-Warning -Message ('Could not find file: {0} !' -f $File.FullName) } | Select-Object -ExpandProperty 'FullName'
} $PesterConf.CodeCoverage.Path = $CovFiles
} $PesterConf.Output.Verbosity = $Verbosity
# Set Tags if given
if ($Tag) {
$PesterConf.Filter.Tag = $Tag
} }
catch { if ($ExcludeTag) {
$_.Exception.Message | Write-Error $PesterConf.Filter.ExcludeTag = $ExcludeTag
throw 'Could not load required private functions!'
} }
$TestResults = Invoke-Pester -Configuration $PesterConf -ErrorAction 'Stop'
Write-Host '===== Running Pester =====' -ForegroundColor Black -BackgroundColor Yellow if ($PassThru.IsPresent) {
$srcFiles = Get-ChildItem -Path "./src/*.ps1" -Recurse | Sort-Object -Property 'Name' | Select-Object -ExpandProperty 'FullName' Write-Output -InputObject $TestResults
$TestFiles = Get-ChildItem -Path (Join-Path -Path '.' -ChildPath './tests/*.Tests.ps1') -Recurse | Sort-Object -Property Name
$TestResults = Invoke-Pester -Path $testFiles -CodeCoverage $srcFiles -PassThru -CodeCoverageOutputFile "./coverage.xml" -CodeCoverageOutputFileEncoding ascii -CodeCoverageOutputFileFormat JaCoCo
if ($TestResults.FailedCount -gt 0) {
throw ('{0} tests failed!' -f $TestResults.FailedCount)
} }
} }
} }

View File

@ -0,0 +1,141 @@
@{
Severity = 'Error', 'Warning', 'Information'
IncludeRules = @(
'PSAlignAssignmentStatement',
'PSAvoidAssignmentToAutomaticVariable',
'PSAvoidDefaultValueForMandatoryParameter',
'PSAvoidDefaultValueSwitchParameter',
'PSAvoidGlobalAliases',
'PSAvoidGlobalFunctions',
'PSAvoidGlobalVars',
'PSAvoidInvokingEmptyMembers',
'PSAvoidLongLines',
'PSAvoidNullOrEmptyHelpMessageAttribute',
'PSAvoidOverwritingBuiltInCmdlets',
'PSAvoidShouldContinueWithoutForce',
'PSAvoidTrailingWhitespace',
'PSAvoidUsingCmdletAliases',
'PSAvoidUsingComputerNameHardcoded',
'PSAvoidUsingConvertToSecureStringWithPlainText',
'PSAvoidUsingDeprecatedManifestFields',
'PSAvoidUsingDoubleQuotesForConstantString',
'PSAvoidUsingEmptyCatchBlock',
'PSAvoidUsingInvokeExpression',
'PSAvoidUsingPlainTextForPassword',
'PSAvoidUsingPositionalParameters',
'PSAvoidUsingUsernameAndPasswordParams',
'PSAvoidUsingWMICmdlet',
'PSAvoidUsingWriteHost',
'PSMisleadingBacktick',
'PSMissingModuleManifestField',
'PSPlaceCloseBrace',
'PSPlaceOpenBrace',
'PSPossibleIncorrectComparisonWithNull',
'PSPossibleIncorrectUsageOfAssignmentOperator',
'PSPossibleIncorrectUsageOfRedirectionOperator',
'PSProvideCommentHelp',
'PSReservedCmdletChar',
'PSReservedParams',
'PSReviewUnusedParameter',
'PSShouldProcess',
'PSUseApprovedVerbs',
'PSUseBOMForUnicodeEncodedFile',
'PSUseCmdletCorrectly',
# There is no predefined set for Pwsh7 Cmdlets
'PSUseCompatibleCmdlets',
#'PSUseCompatibleCommands',
'PSUseCompatibleSyntax',
#'PSUseCompatibleTypes',
'PSUseConsistentIndentation',
# Disable if bug in 1.19.1 version occurs.
'PSUseConsistentWhitespace',
'PSUseCorrectCasing',
'PSUseDeclaredVarsMoreThanAssignments',
'PSUseLiteralInitializerForHashtable',
'PSUseOutputTypeCorrectly',
'PSUsePSCredentialType',
'PSUseProcessBlockForPipelineCommand',
'PSUseShouldProcessForStateChangingFunctions',
'PSUseSingularNouns',
'PSUseSupportsShouldProcess',
'PSUseToExportFieldsInManifest',
'PSUseUTF8EncodingForHelpFile',
'PSUseUsingScopeModifierInNewRunspaces'
)
Rules = @{
PSAvoidLongLines = @{
Enable = $true
MaximumLineLength = 116
}
PSPlaceOpenBrace = @{
Enable = $true
OnSameLine = $true
NewLineAfter = $true
IgnoreOneLineBlock = $true
}
PSPlaceCloseBrace = @{
Enable = $true
NewLineAfter = $true
IgnoreOneLineBlock = $true
NoEmptyLineBefore = $false
}
PSProvideCommentHelp = @{
Enable = $true
ExportedOnly = $false
BlockComment = $true
VSCodeSnippetCorrection = $false
Placement = "begin"
}
PSUseCompatibleCmdlets = @{
compatibility = @(
"desktop-5.1.14393.206-windows",
"core-6.1.0-windows"
)
}
PSUseCompatibleSyntax = @{
Enable = $true
TargetVersions = @(
"7.0",
"5.1"
)
}
PSUseConsistentIndentation = @{
Enable = $true
Kind = 'space'
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
IndentationSize = 4
}
PSUseConsistentWhitespace = @{
Enable = $true
CheckInnerBrace = $true
CheckOpenBrace = $true
CheckOpenParen = $true
CheckOperator = $true
CheckPipe = $true
CheckPipeForRedundantWhitespace = $false
CheckSeparator = $true
CheckParameter = $false
IgnoreAssignmentOperatorInsideHashTable = $true
}
PSAlignAssignmentStatement = @{
Enable = $true
CheckHashtable = $false
}
PSUseCorrectCasing = @{
Enable = $true
}
}
}