resourcesAfter.ps1
<#
Registers the cmdlets published by this module. Necessary for full hybrid module support. #> $commonParam = @{ HelpFile = (Resolve-Path "$($script:ModuleRoot)\en-us\PSFramework.dll-Help.xml") Module = $ExecutionContext.SessionState.Module } Import-PSFCmdlet @commonParam -Name Remove-PSFNull -Type ([PSFramework.Commands.RemovePSFNullCommand]) Import-PSFCmdlet @commonParam -Name Select-PSFObject -Type ([PSFramework.Commands.SelectPSFObjectCommand]) Import-PSFCmdlet @commonParam -Name Set-PSFConfig -Type ([PSFramework.Commands.SetPSFConfigCommand]) Import-PSFCmdlet @commonParam -Name Test-PSFShouldProcess -Type ([PSFramework.Commands.TestPSFShouldProcessCommand]) Import-PSFCmdlet @commonParam -Name Write-PSFMessage -Type ([PSFramework.Commands.WritePSFMessageCommand]) Register-PSFConfigValidation -Name "bool" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { if ($Value.GetType().FullName -ne "System.Boolean") { $Result.Message = "Not a boolean: $Value" $Result.Success = $False return $Result } } catch { $Result.Message = "Not a boolean: $Value" $Result.Success = $False return $Result } $Result.Value = $Value return $Result } Register-PSFConfigValidation -Name "consolecolor" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { [System.ConsoleColor]$color = $Value } catch { $Result.Message = "Not a console color: $Value" $Result.Success = $False return $Result } $Result.Value = $color return $Result } Register-PSFConfigValidation -Name "datetime" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { [DateTime]$DateTime = $Value } catch { $Result.Message = "Not a DateTime: $Value" $Result.Success = $False return $Result } $Result.Value = $DateTime return $Result } Register-PSFConfigValidation -Name "double" -ScriptBlock { Param ( $Value ) $Result = New-Object PSOBject -Property @{ Success = $True Value = $null Message = "" } try { [double]$number = $Value } catch { $Result.Message = "Not a double: $Value" $Result.Success = $False return $Result } $Result.Value = $number return $Result } Register-PSFConfigValidation -Name "integer" -ScriptBlock { Param ( $Value ) $Result = New-Object PSOBject -Property @{ Success = $True Value = $null Message = "" } try { [int]$number = $Value } catch { $Result.Message = "Not an integer: $Value" $Result.Success = $False return $Result } $Result.Value = $number return $Result } Register-PSFConfigValidation -Name "integer0to9" -ScriptBlock { Param ( $Value ) $Result = New-Object PSOBject -Property @{ Success = $True Value = $null Message = "" } try { [int]$number = $Value } catch { $Result.Message = "Not an integer: $Value" $Result.Success = $False return $Result } if (($number -lt 0) -or ($number -gt 9)) { $Result.Message = "Out of range. Specify a number ranging from 0 to 9" $Result.Success = $False return $Result } $Result.Value = $Number return $Result } Register-PSFConfigValidation -Name "integerarray" -ScriptBlock { param ( $var ) $test = $true try { [int[]]$res = $var } catch { $test = $false } [pscustomobject]@{ Success = $test Value = $res Message = "Casting $var as [int[]] failure. Input is being identified as $($var.GetType())" } } Register-PSFConfigValidation -Name "integerpositive" -ScriptBlock { Param ( $Value ) $Result = New-Object PSOBject -Property @{ Success = $True Value = $null Message = "" } try { [int]$number = $Value } catch { $Result.Message = "Not an integer: $Value" $Result.Success = $False return $Result } if ($number -lt 0) { $Result.Message = "Negative value: $Value" $Result.Success = $False return $Result } $Result.Value = $number return $Result } Register-PSFConfigValidation -Name "psframework.logfilefiletype" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { [PSFramework.Logging.LogFileFileType]$type = $Value } catch { $Result.Message = "Not a logfile file type: $Value . Specify one of these values: $(([enum]::GetNames([PSFramework.Logging.LogFileFileType])) -join ", ")" $Result.Success = $False return $Result } $Result.Value = $type return $Result } Register-PSFConfigValidation -Name "long" -ScriptBlock { Param ( $Value ) $Result = New-Object PSOBject -Property @{ Success = $True Value = $null Message = "" } try { [long]$number = $Value } catch { $Result.Message = "Not a long: $Value" $Result.Success = $False return $Result } $Result.Value = $number return $Result } Register-PSFConfigValidation -Name "string" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { # Seriously, this should work for almost anybody and anything [string]$data = $Value } catch { $Result.Message = "Not a string: $Value" $Result.Success = $False return $Result } if ([string]::IsNullOrEmpty($data)) { $Result.Message = "Is an empty string: $Value" $Result.Success = $False return $Result } if ($data -eq $Value.GetType().FullName) { $Result.Message = "Is an object with no proper string representation: $Value" $Result.Success = $False return $Result } $Result.Value = $data return $Result } Register-PSFConfigValidation -Name "stringarray" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { $data = @() # Seriously, this should work for almost anybody and anything foreach ($item in $Value) { $data += [string]$item } } catch { $Result.Message = "Not a string array: $Value" $Result.Success = $False return $Result } $Result.Value = $data return $Result } Register-PSFConfigValidation -Name "timespan" -ScriptBlock { Param ( $Value ) $Result = New-Object PSObject -Property @{ Success = $True Value = $null Message = "" } try { [timespan]$timespan = $Value } catch { $Result.Message = "Not a Timespan: $Value" $Result.Success = $False return $Result } $Result.Value = $timespan return $Result } Set-PSFConfig -Module 'PSFramework' -Name 'ComputerManagement.PSSession.IdleTimeout' -Value (New-TimeSpan -Minutes 15) -Initialize -Validation 'timespan' -Handler { [PSFramework.ComputerManagement.ComputerManagementHost]::PSSessionIdleTimeout = $args[0] } -Description "The idle timeout for cached pssessions. When using Invoke-PSFCommand, it will remember sessions for up to this time after last using them, before cleaning them up." # Unattended mode, so there is a central flag scripts & moduls can detect Set-PSFConfig -Module PSFramework -Name 'System.Unattended' -Value $false -Initialize -Validation "bool" -Handler { [PSFramework.PSFCore.PSFCoreHost]::Unattended = $args[0] } -Description "Central setting, showing whether the current execution is unattended or not. This allows scripts/moduls to react to whether there is a user at the controls or not." Set-PSFConfig -Module PSFramework -Name 'SupportPackage.ContactMessage' -Value ' ' -Initialize -Validation 'string' -Description 'Message shown when using New-PSFSUpportPackage. This allows an organization to tie information on how to submit a support package into the command that generates it' # Encoding Settings Set-PSFConfig -Module PSFramework -Name 'Text.Encoding.FullTabCompletion' -Value $false -Initialize -Validation 'bool' -Description 'Whether all eoncodings should be part of the tab completion for encodings. By default, only a manageable subset is shown.' Set-PSFConfig -Module PSFramework -Name 'Text.Encoding.DefaultWrite' -Value 'utf-8' -Initialize -Validation 'string' -Description 'The default encoding to use when writing to file. Only applied by implementing commands.' Set-PSFConfig -Module PSFramework -Name 'Text.Encoding.DefaultRead' -Value 'utf-8' -Initialize -Validation 'string' -Description 'The default encoding to use when reading from file. Only applied by implementing commands.' #region Setting the configuration Set-PSFConfig -Module PSFramework -Name 'Logging.MaxErrorCount' -Value 128 -Initialize -Validation "integerpositive" -Handler { [PSFramework.Message.LogHost]::MaxErrorCount = $args[0] } -Description "The maximum number of error records maintained in-memory. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.MaxMessageCount' -Value 1024 -Initialize -Validation "integerpositive" -Handler { [PSFramework.Message.LogHost]::MaxMessageCount = $args[0] } -Description "The maximum number of messages that can be maintained in the in-memory message queue. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.MessageLogEnabled' -Value $true -Initialize -Validation "bool" -Handler { [PSFramework.Message.LogHost]::MessageLogEnabled = $args[0] } -Description "Governs, whether a log of recent messages is kept in memory. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.ErrorLogEnabled' -Value $true -Initialize -Validation "bool" -Handler { [PSFramework.Message.LogHost]::ErrorLogEnabled = $args[0] } -Description "Governs, whether a log of recent errors is kept in memory. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.DisableLogFlush' -Value $false -Initialize -Validation "bool" -Handler { } -Description "When shutting down the process, PSFramework will by default flush the log. This ensures that all events are properly logged. If this is not desired, it can be turned off with this setting." #endregion Setting the configuration Set-PSFConfig -Module PSFramework -Name 'message.info.minimum' -Value 1 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::MinimumInformation = $args[0] } -Description "The minimum required message level for messages that will be shown to the user." Set-PSFConfig -Module PSFramework -Name 'message.info.maximum' -Value 3 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::MaximumInformation = $args[0] } -Description "The maximum message level to still display to the user directly." Set-PSFConfig -Module PSFramework -Name 'message.verbose.minimum' -Value 4 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::MinimumVerbose = $args[0] } -Description "The minimum required message level where verbose information is written." Set-PSFConfig -Module PSFramework -Name 'message.verbose.maximum' -Value 6 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::MaximumVerbose = $args[0] } -Description "The maxium message level where verbose information is still written." Set-PSFConfig -Module PSFramework -Name 'message.debug.minimum' -Value 1 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::MinimumDebug = $args[0] } -Description "The minimum required message level where debug information is written." Set-PSFConfig -Module PSFramework -Name 'message.debug.maximum' -Value 9 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::MaximumDebug = $args[0] } -Description "The maximum message level where debug information is still written." Set-PSFConfig -Module PSFramework -Name 'message.info.color' -Value 'Cyan' -Initialize -Validation "consolecolor" -Handler { [PSFramework.Message.MessageHost]::InfoColor = $args[0] } -Description "The color to use when writing text to the screen on PowerShell." Set-PSFConfig -Module PSFramework -Name 'message.info.color.emphasis' -Value 'green' -Initialize -Validation "consolecolor" -Handler { [PSFramework.Message.MessageHost]::InfoColorEmphasis = $args[0] } -Description "The color to use when emphasizing written text to the screen on PowerShell." Set-PSFConfig -Module PSFramework -Name 'message.info.color.subtle' -Value 'gray' -Initialize -Validation "consolecolor" -Handler { [PSFramework.Message.MessageHost]::InfoColorSubtle = $args[0] } -Description "The color to use when making writing text to the screen on PowerShell appear subtle." Set-PSFConfig -Module PSFramework -Name 'message.developercolor' -Value 'Gray' -Initialize -Validation "consolecolor" -Handler { [PSFramework.Message.MessageHost]::DeveloperColor = $args[0] } -Description "The color to use when writing text with developer specific additional information to the screen on PowerShell." Set-PSFConfig -Module PSFramework -Name 'message.consoleoutput.disable' -Value $false -Initialize -Validation "bool" -Handler { [PSFramework.Message.MessageHost]::DisableVerbosity = $args[0] } -Description "Global toggle that allows disabling all regular messages to screen. Messages from '-Verbose' and '-Debug' are unaffected" Set-PSFConfig -Module PSFramework -Name 'message.transform.errorqueuesize' -Value 512 -Initialize -Validation "integerpositive" -Handler { [PSFramework.Message.MessageHost]::TransformErrorQueueSize = $args[0] } -Description "The size of the queue for transformation errors. May be useful for advanced development, but can be ignored usually." Set-PSFConfig -Module PSFramework -Name 'message.nestedlevel.decrement' -Value 0 -Initialize -Validation "integer0to9" -Handler { [PSFramework.Message.MessageHost]::NestedLevelDecrement = $args[0] } -Description "How many levels should be reduced per callstack depth. This makes commands less verbose, the more nested they are called" Set-PSFConfig -Module PSFramework -Name 'developer.mode.enable' -Value $false -Initialize -Validation "bool" -Handler { [PSFramework.Message.MessageHost]::DeveloperMode = $args[0] } -Description "Developermode enables advanced logging and verbosity features. There is little benefit for enabling this as a regular user. but developers can use it to more easily troubleshoot issues." Set-PSFConfig -Module PSFramework -Name 'message.style.breadcrumbs' -Value $false -Initialize -Validation "bool" -Handler { [PSFramework.Message.MessageHost]::EnableMessageBreadcrumbs = $args[0] } -Description "Controls how messages are displayed. Enables Breadcrumb display, showing the entire callstack. Takes precedence over command name display." Set-PSFConfig -Module PSFramework -Name 'message.style.functionname' -Value $true -Initialize -Validation "bool" -Handler { [PSFramework.Message.MessageHost]::EnableMessageDisplayCommand = $args[0] } -Description "Controls how messages are displayed. Enables command name, showing the name of the writing command. Is overwritten by enabling breadcrumbs." Set-PSFConfig -Module PSFramework -Name 'message.style.timestamp' -Value $true -Initialize -Validation "bool" -Handler { [PSFramework.Message.MessageHost]::EnableMessageTimestamp = $args[0] } -Description "Controls how messages are displayed. Enables timestamp display, including a timestamp in each message." #region Setting the configuration Set-PSFConfig -Module PSFramework -Name 'Runspace.StopTimeoutSeconds' -Value 30 -Initialize -Validation "integerpositive" -Handler { [PSFramework.Runspace.RunspaceHost]::StopTimeoutSeconds = $args[0] } -Description "Time in seconds that Stop-PSFRunspace will wait for a scriptspace to selfterminate before killing it." #endregion Setting the configuration # The path where type-files are stored when registered Set-PSFConfig -Module PSFramework -Name 'Serialization.WorkingDirectory' -Value $script:path_typedata -Initialize -Validation "string" -Description "The folder in which registered type extension files are placed before import. Relevant for Register-PSFTypeSerializationData." if (-not [PSFramework.Configuration.ConfigurationHost]::ImportFromRegistryDone) { # Read config from all settings $config_hash = Read-PsfConfigPersisted -Scope 127 foreach ($value in $config_hash.Values) { try { if (-not $value.KeepPersisted) { Set-PSFConfig -FullName $value.FullName -Value $value.Value -EnableException } else { Set-PSFConfig -FullName $value.FullName -PersistedValue $value.Value -PersistedType $value.Type -EnableException } [PSFramework.Configuration.ConfigurationHost]::Configurations[$value.FullName.ToLower()].PolicySet = $value.Policy [PSFramework.Configuration.ConfigurationHost]::Configurations[$value.FullName.ToLower()].PolicyEnforced = $value.Enforced } catch { } } [PSFramework.Configuration.ConfigurationHost]::ImportFromRegistryDone = $true } # Action that is performed on registration of the provider using Register-PSFLoggingProvider $registrationEvent = { } #region Logging Execution # Action that is performed when starting the logging script (or the very first time if enabled after launching the logging script) $begin_event = { #region Helper Functions function Clean-FileSystemErrorXml { [CmdletBinding()] Param ( $Path ) $totalLength = $Null $files = Get-ChildItem -Path $Path.FullName -Filter "$($env:ComputerName)_$($pid)_error_*.xml" | Sort-Object LastWriteTime $totalLength = $files | Measure-Object Length -Sum | Select-Object -ExpandProperty Sum if (([PSFramework.Message.LogHost]::MaxErrorFileBytes) -gt $totalLength) { return } $removed = 0 foreach ($file in $files) { $removed += $file.Length Remove-Item -Path $file.FullName -Force -Confirm:$false if (($totalLength - $removed) -lt ([PSFramework.Message.LogHost]::MaxErrorFileBytes)) { break } } } function Clean-FileSystemMessageLog { [CmdletBinding()] Param ( $Path ) if ([PSFramework.Message.LogHost]::MaxMessagefileCount -eq 0) { return } $files = Get-ChildItem -Path $Path.FullName -Filter "$($env:ComputerName)_$($pid)_message_*.log" | Sort-Object LastWriteTime if (([PSFramework.Message.LogHost]::MaxMessagefileCount) -ge $files.Count) { return } $removed = 0 foreach ($file in $files) { $removed++ Remove-Item -Path $file.FullName -Force -Confirm:$false if (($files.Count - $removed) -le ([PSFramework.Message.LogHost]::MaxMessagefileCount)) { break } } } function Clean-FileSystemGlobalLog { [CmdletBinding()] Param ( $Path ) # Kill too old files Get-ChildItem -Path $Path.FullName | Where-Object Name -Match "^$([regex]::Escape($env:ComputerName))_.+" | Where-Object LastWriteTime -LT ((Get-Date) - ([PSFramework.Message.LogHost]::MaxLogFileAge)) | Remove-Item -Force -Confirm:$false # Handle the global overcrowding $files = Get-ChildItem -Path $Path.FullName | Where-Object Name -Match "^$([regex]::Escape($env:ComputerName))_.+" | Sort-Object LastWriteTime if (-not ($files)) { return } $totalLength = $files | Measure-Object Length -Sum | Select-Object -ExpandProperty Sum if (([PSFramework.Message.LogHost]::MaxTotalFolderSize) -gt $totalLength) { return } $removed = 0 foreach ($file in $files) { $removed += $file.Length Remove-Item -Path $file.FullName -Force -Confirm:$false if (($totalLength - $removed) -lt ([PSFramework.Message.LogHost]::MaxTotalFolderSize)) { break } } } #endregion Helper Functions } # Action that is performed at the beginning of each logging cycle $start_event = { $filesystem_path = [PSFramework.Message.LogHost]::LoggingPath if (-not (Test-Path $filesystem_path)) { $filesystem_root = New-Item $filesystem_path -ItemType Directory -Force -ErrorAction Stop } else { $filesystem_root = Get-Item -Path $filesystem_path } try { [int]$filesystem_num_Error = (Get-ChildItem -Path $filesystem_path.FullName -Filter "$($env:ComputerName)_$($pid)_error_*.xml" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty Name | Select-String -Pattern "(\d+)" -AllMatches).Matches[1].Value } catch { } try { [int]$filesystem_num_Message = (Get-ChildItem -Path $filesystem_path.FullName -Filter "$($env:ComputerName)_$($pid)_message_*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty Name | Select-String -Pattern "(\d+)" -AllMatches).Matches[1].Value } catch { } if (-not ($filesystem_num_Error)) { $filesystem_num_Error = 0 } if (-not ($filesystem_num_Message)) { $filesystem_num_Message = 0 } } # Action that is performed for each message item that is being logged $message_Event = { Param ( $Message ) $filesystem_CurrentFile = Join-Path $filesystem_root.FullName "$($env:ComputerName)_$($pid)_message_$($filesystem_num_Message).log" if (Test-Path $filesystem_CurrentFile) { $filesystem_item = Get-Item $filesystem_CurrentFile if ($filesystem_item.Length -gt ([PSFramework.Message.LogHost]::MaxMessagefileBytes)) { $filesystem_num_Message++ $filesystem_CurrentFile = Join-Path $($filesystem_root.FullName) "$($env:ComputerName)_$($pid)_message_$($filesystem_num_Message).log" } } if ($Message) { Add-Content -Path $filesystem_CurrentFile -Value (ConvertTo-Csv ($Message | Select-Object ComputerName, Timestamp, Level, Message, Type, FunctionName, ModuleName, File, Line, @{ n = "Tags"; e = { $_.Tags -join "," } }, TargetObject, Runspace) -NoTypeInformation)[1] } } # Action that is performed for each error item that is being logged $error_Event = { Param ( $ErrorItem ) if ($ErrorItem) { $ErrorItem | Export-Clixml -Path (Join-Path $filesystem_root.FullName "$($env:ComputerName)_$($pid)_error_$($filesystem_num_Error).xml") -Depth 3 $filesystem_num_Error++ } Clean-FileSystemErrorXml -Path $filesystem_root } # Action that is performed at the end of each logging cycle $end_event = { Clean-FileSystemMessageLog -Path $filesystem_root Clean-FileSystemGlobalLog -Path $filesystem_root } # Action that is performed when stopping the logging script $final_event = { } #endregion Logging Execution #region Function Extension / Integration # Script that generates the necessary dynamic parameter for Set-PSFLoggingProvider $configurationParameters = { $configroot = "psframework.logging.filesystem" $configurations = Get-PSFConfig -FullName "$configroot.*" $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($config in $configurations) { $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute $ParamAttrib.ParameterSetName = '__AllParameterSets' $AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttribColl.Add($ParamAttrib) $RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter(($config.FullName.Replace($configroot, "").Trim(".")), $config.Value.GetType(), $AttribColl) $RuntimeParamDic.Add(($config.FullName.Replace($configroot, "").Trim(".")), $RuntimeParam) } return $RuntimeParamDic } # Script that is executes when configuring the provider using Set-PSFLoggingProvider $configurationScript = { $configroot = "psframework.logging.filesystem" $configurations = Get-PSFConfig -FullName "$configroot.*" foreach ($config in $configurations) { if ($PSBoundParameters.ContainsKey(($config.FullName.Replace($configroot, "").Trim(".")))) { Set-PSFConfig -Module $config.Module -Name $config.Name -Value $PSBoundParameters[($config.FullName.Replace($configroot, "").Trim("."))] } } } # Script that returns a boolean value. "True" if all prerequisites are installed, "False" if installation is required $isInstalledScript = { return $true } # Script that provides dynamic parameter for Install-PSFLoggingProvider $installationParameters = { # None needed } # Script that performs the actual installation, based on the parameters (if any) specified in the $installationParameters script $installationScript = { # Nothing to be done - if you need to install your filesystem, you probably have other issues you need to deal with first ;) } #endregion Function Extension / Integration # Configuration settings to initialize $configuration_Settings = { Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.MaxMessagefileBytes' -Value 5MB -Initialize -Validation "long" -Handler { [PSFramework.Message.LogHost]::MaxMessagefileBytes = $args[0] } -Description "The maximum size of a given logfile. When reaching this limit, the file will be abandoned and a new log created. Set to 0 to not limit the size. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.MaxMessagefileCount' -Value 5 -Initialize -Validation "integerpositive" -Handler { [PSFramework.Message.LogHost]::MaxMessagefileCount = $args[0] } -Description "The maximum number of logfiles maintained at a time. Exceeding this number will cause the oldest to be culled. Set to 0 to disable the limit. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.MaxErrorFileBytes' -Value 20MB -Initialize -Validation "long" -Handler { [PSFramework.Message.LogHost]::MaxErrorFileBytes = $args[0] } -Description "The maximum size all error files combined may have. When this number is exceeded, the oldest entry is culled. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.MaxTotalFolderSize' -Value 100MB -Initialize -Validation "long" -Handler { [PSFramework.Message.LogHost]::MaxTotalFolderSize = $args[0] } -Description "This is the upper limit of length all items in the log folder may have combined across all processes." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.MaxLogFileAge' -Value (New-TimeSpan -Days 7) -Initialize -Validation "timespan" -Handler { [PSFramework.Message.LogHost]::MaxLogFileAge = $args[0] } -Description "Any logfile older than this will automatically be cleansed. This setting is global." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.MessageLogFileEnabled' -Value $true -Initialize -Validation "bool" -Handler { [PSFramework.Message.LogHost]::MessageLogFileEnabled = $args[0] } -Description "Governs, whether a log file for the system messages is written. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.ErrorLogFileEnabled' -Value $true -Initialize -Validation "bool" -Handler { [PSFramework.Message.LogHost]::ErrorLogFileEnabled = $args[0] } -Description "Governs, whether log files for errors are written. This setting is on a per-Process basis. Runspaces share, jobs or other consoles counted separately." Set-PSFConfig -Module PSFramework -Name 'Logging.FileSystem.LogPath' -Value $script:path_Logging -Initialize -Validation "string" -Handler { [PSFramework.Message.LogHost]::LoggingPath = $args[0] } -Description "The path where the PSFramework writes all its logs and debugging information." Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.Enabled' -Value $true -Initialize -Validation "bool" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['filesystem']) { [PSFramework.Logging.ProviderHost]::Providers['filesystem'].Enabled = $args[0] } } -Description "Whether the logging provider should be enabled on registration" Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.AutoInstall' -Value $false -Initialize -Validation "bool" -Handler { } -Description "Whether the logging provider should be installed on registration" Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.InstallOptional' -Value $true -Initialize -Validation "bool" -Handler { } -Description "Whether installing the logging provider is mandatory, in order for it to be enabled" Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.IncludeModules' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['filesystem']) { [PSFramework.Logging.ProviderHost]::Providers['filesystem'].IncludeModules = $args[0] } } -Description "Module whitelist. Only messages from listed modules will be logged" Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.ExcludeModules' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['filesystem']) { [PSFramework.Logging.ProviderHost]::Providers['filesystem'].ExcludeModules = $args[0] } } -Description "Module blacklist. Messages from listed modules will not be logged" Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.IncludeTags' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['filesystem']) { [PSFramework.Logging.ProviderHost]::Providers['filesystem'].IncludeTags = $args[0] } } -Description "Tag whitelist. Only messages with these tags will be logged" Set-PSFConfig -Module LoggingProvider -Name 'FileSystem.ExcludeTags' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['filesystem']) { [PSFramework.Logging.ProviderHost]::Providers['filesystem'].ExcludeTags = $args[0] } } -Description "Tag blacklist. Messages with these tags will not be logged" } Register-PSFLoggingProvider -Name "filesystem" -RegistrationEvent $registrationEvent -BeginEvent $begin_event -StartEvent $start_event -MessageEvent $message_Event -ErrorEvent $error_Event -EndEvent $end_event -FinalEvent $final_event -ConfigurationParameters $configurationParameters -ConfigurationScript $configurationScript -IsInstalledScript $isInstalledScript -InstallationScript $installationScript -InstallationParameters $installationParameters -ConfigurationSettings $configuration_Settings # Action that is performed on registration of the provider using Register-PSFLoggingProvider $registrationEvent = { } #region Logging Execution # Action that is performed when starting the logging script (or the very first time if enabled after launching the logging script) $begin_event = { function Get-LogFilePath { [CmdletBinding()] param ( ) $path = Get-PSFConfigValue -FullName 'PSFramework.Logging.LogFile.FilePath' $logname = Get-PSFConfigValue -FullName 'PSFramework.Logging.LogFile.LogName' $scriptBlock = { param ( [string] $Match ) $hash = @{ '%date%' = (Get-Date -Format 'yyyy-MM-dd') '%dayofweek%' = (Get-Date).DayOfWeek '%day%' = (Get-Date).Day '%hour%' = (Get-Date).Hour '%minute%' = (Get-Date).Minute '%username%' = $env:USERNAME '%userdomain%' = $env:USERDOMAIN '%computername%' = $env:COMPUTERNAME '%processid%' = $PID '%logname%' = $logname } $hash.$Match } [regex]::Replace($path, '%day%|%computername%|%hour%|%processid%|%date%|%username%|%dayofweek%|%minute%|%userdomain%|%logname%', $scriptBlock) } function Write-LogFileMessage { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] $Message, [bool] $IncludeHeader, [string] $FileType, [string] $Path, [string] $CsvDelimiter, [string[]] $Headers ) $parent = Split-Path $Path if (-not (Test-Path $parent)) { $null = New-Item $parent -ItemType Directory -Force } $fileExists = Test-Path $Path #region Type-Based Output switch ($FileType) { #region Csv "Csv" { if ((-not $fileExists) -and $IncludeHeader) { $Message | ConvertTo-Csv -NoTypeInformation -Delimiter $CsvDelimiter | Set-Content -Path $Path -Encoding UTF8 } else { $Message | ConvertTo-Csv -NoTypeInformation -Delimiter $CsvDelimiter | Select-Object -Skip 1 | Add-Content -Path $Path -Encoding UTF8 } } #endregion Csv #region Json "Json" { if ($fileExists) { Add-Content -Path $Path -Value "," -Encoding UTF8 } $Message | ConvertTo-Json | Add-Content -Path $Path -NoNewline -Encoding UTF8 } #endregion Json #region XML "XML" { [xml]$xml = $message | ConvertTo-Xml -NoTypeInformation $xml.Objects.InnerXml | Add-Content -Path $Path -Encoding UTF8 } #endregion XML #region Html "Html" { [xml]$xml = $message | ConvertTo-Html -Fragment if ((-not $fileExists) -and $IncludeHeader) { $xml.table.tr[0].OuterXml | Add-Content -Path $Path -Encoding UTF8 } $xml.table.tr[1].OuterXml | Add-Content -Path $Path -Encoding UTF8 } #endregion Html } #endregion Type-Based Output } $logfile_includeheader = Get-PSFConfigValue -FullName 'PSFramework.Logging.LogFile.IncludeHeader' $logfile_headers = Get-PSFConfigValue -FullName 'PSFramework.Logging.LogFile.Headers' $logfile_filetype = Get-PSFConfigValue -FullName 'PSFramework.Logging.LogFile.FileType' $logfile_CsvDelimiter = Get-PSFConfigValue -FullName 'PSFramework.Logging.LogFile.CsvDelimiter' if ($logfile_headers -contains 'Tags') { $logfile_headers = $logfile_headers | ForEach-Object { if ($_ -ne 'Tags') { $_ } else { @{ Name = 'Tags' Expression = { $_.Tags -join "," } } } } } $logfile_paramWriteLogFileMessage = @{ IncludeHeader = $logfile_includeheader FileType = $logfile_filetype CsvDelimiter = $logfile_CsvDelimiter Headers = $logfile_headers } } # Action that is performed at the beginning of each logging cycle $start_event = { $logfile_paramWriteLogFileMessage["Path"] = Get-LogFilePath } # Action that is performed for each message item that is being logged $message_Event = { Param ( $Message ) $Message | Select-Object $logfile_headers | Write-LogFileMessage @logfile_paramWriteLogFileMessage } # Action that is performed for each error item that is being logged $error_Event = { Param ( $ErrorItem ) } # Action that is performed at the end of each logging cycle $end_event = { } # Action that is performed when stopping the logging script $final_event = { } #endregion Logging Execution #region Function Extension / Integration # Script that generates the necessary dynamic parameter for Set-PSFLoggingProvider $configurationParameters = { $configroot = "psframework.logging.logfile" $configurations = Get-PSFConfig -FullName "$configroot.*" $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($config in $configurations) { $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute $ParamAttrib.ParameterSetName = '__AllParameterSets' $AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttribColl.Add($ParamAttrib) $RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter(($config.FullName.Replace($configroot, "").Trim(".")), $config.Value.GetType(), $AttribColl) $RuntimeParamDic.Add(($config.FullName.Replace($configroot, "").Trim(".")), $RuntimeParam) } return $RuntimeParamDic } # Script that is executes when configuring the provider using Set-PSFLoggingProvider $configurationScript = { $configroot = "psframework.logging.logfile" $configurations = Get-PSFConfig -FullName "$configroot.*" foreach ($config in $configurations) { if ($PSBoundParameters.ContainsKey(($config.FullName.Replace($configroot, "").Trim(".")))) { Set-PSFConfig -Module $config.Module -Name $config.Name -Value $PSBoundParameters[($config.FullName.Replace($configroot, "").Trim("."))] } } } # Script that returns a boolean value. "True" if all prerequisites are installed, "False" if installation is required $isInstalledScript = { return $true } # Script that provides dynamic parameter for Install-PSFLoggingProvider $installationParameters = { # None needed } # Script that performs the actual installation, based on the parameters (if any) specified in the $installationParameters script $installationScript = { # Nothing to be done - if you need to install your filesystem, you probably have other issues you need to deal with first ;) } #endregion Function Extension / Integration # Configuration settings to initialize $configuration_Settings = { Set-PSFConfig -Module PSFramework -Name 'Logging.LogFile.FilePath' -Value "" -Initialize -Validation string -Handler { } -Description "The path to where the logfile is written. Supports some placeholders such as %Date% to allow for timestamp in the name. For full documentation on the supported wildcards, see the documentation on https://psframework.org" Set-PSFConfig -Module PSFramework -Name 'Logging.LogFile.Logname' -Value "" -Initialize -Validation string -Handler { } -Description "A special string you can use as a placeholder in the logfile path (by using '%logname%' as placeholder)" Set-PSFConfig -Module PSFramework -Name 'Logging.LogFile.IncludeHeader' -Value $true -Initialize -Validation bool -Handler { } -Description "Whether a written csv file will include headers" Set-PSFConfig -Module PSFramework -Name 'Logging.LogFile.Headers' -Value @('ComputerName', 'File', 'FunctionName', 'Level', 'Line', 'Message', 'ModuleName', 'Runspace', 'Tags', 'TargetObject', 'Timestamp', 'Type', 'Username') -Initialize -Validation stringarray -Handler { } -Description "The properties to export, in the order to select them." Set-PSFConfig -Module PSFramework -Name 'Logging.LogFile.FileType' -Value "CSV" -Initialize -Validation psframework.logfilefiletype -Handler { } -Description "In what format to write the logfile. Supported styles: CSV, XML, Html or Json. Html, XML and Json will be written as fragments." Set-PSFConfig -Module PSFramework -Name 'Logging.LogFile.CsvDelimiter' -Value "," -Initialize -Validation string -Handler { } -Description "The delimiter to use when writing to csv." Set-PSFConfig -Module LoggingProvider -Name 'LogFile.Enabled' -Value $false -Initialize -Validation "bool" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['logfile']) { [PSFramework.Logging.ProviderHost]::Providers['logfile'].Enabled = $args[0] } } -Description "Whether the logging provider should be enabled on registration" Set-PSFConfig -Module LoggingProvider -Name 'LogFile.AutoInstall' -Value $false -Initialize -Validation "bool" -Handler { } -Description "Whether the logging provider should be installed on registration" Set-PSFConfig -Module LoggingProvider -Name 'LogFile.InstallOptional' -Value $true -Initialize -Validation "bool" -Handler { } -Description "Whether installing the logging provider is mandatory, in order for it to be enabled" Set-PSFConfig -Module LoggingProvider -Name 'LogFile.IncludeModules' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['logfile']) { [PSFramework.Logging.ProviderHost]::Providers['logfile'].IncludeModules = $args[0] } } -Description "Module whitelist. Only messages from listed modules will be logged" Set-PSFConfig -Module LoggingProvider -Name 'LogFile.ExcludeModules' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['logfile']) { [PSFramework.Logging.ProviderHost]::Providers['logfile'].ExcludeModules = $args[0] } } -Description "Module blacklist. Messages from listed modules will not be logged" Set-PSFConfig -Module LoggingProvider -Name 'LogFile.IncludeTags' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['logfile']) { [PSFramework.Logging.ProviderHost]::Providers['logfile'].IncludeTags = $args[0] } } -Description "Tag whitelist. Only messages with these tags will be logged" Set-PSFConfig -Module LoggingProvider -Name 'LogFile.ExcludeTags' -Value @() -Initialize -Validation "stringarray" -Handler { if ([PSFramework.Logging.ProviderHost]::Providers['logfile']) { [PSFramework.Logging.ProviderHost]::Providers['logfile'].ExcludeTags = $args[0] } } -Description "Tag blacklist. Messages with these tags will not be logged" } Register-PSFLoggingProvider -Name "logfile" -RegistrationEvent $registrationEvent -BeginEvent $begin_event -StartEvent $start_event -MessageEvent $message_Event -ErrorEvent $error_Event -EndEvent $end_event -FinalEvent $final_event -ConfigurationParameters $configurationParameters -ConfigurationScript $configurationScript -IsInstalledScript $isInstalledScript -InstallationScript $installationScript -InstallationParameters $installationParameters -ConfigurationSettings $configuration_Settings $scriptBlock = { try { $script:___ScriptName = 'PSFramework.Logging' while ($true) { # This portion is critical to gracefully closing the script if ([PSFramework.Runspace.RunspaceHost]::Runspaces[$___ScriptName.ToLower()].State -notlike "Running") { break } #region Manage Begin Event foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetEnabled()) { if (-not $___provider.Initialized) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.BeginEvent)), $null, $null) $___provider.Initialized = $true } catch { $___provider.Errors.Push($_) } } } #endregion Manage Begin Event #region Start Event foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.StartEvent)), $null, $null) } catch { $___provider.Errors.Push($_) } } #endregion Start Event #region Message Event while ([PSFramework.Message.LogHost]::OutQueueLog.Count -gt 0) { $Entry = $null [PSFramework.Message.LogHost]::OutQueueLog.TryDequeue([ref]$Entry) if ($Entry) { foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { if ($___provider.MessageApplies($Entry)) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.MessageEvent)), $null, $Entry) } catch { $___provider.Errors.Push($_) } } } } } #endregion Message Event #region Error Event while ([PSFramework.Message.LogHost]::OutQueueError.Count -gt 0) { $Record = $null [PSFramework.Message.LogHost]::OutQueueError.TryDequeue([ref]$Record) if ($Record) { foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { if ($___provider.MessageApplies($Record)) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.ErrorEvent)), $null, $Record) } catch { $___provider.Errors.Push($_) } } } } } #endregion Error Event #region End Event foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.EndEvent)), $null, $null) } catch { $___provider.Errors.Push($_) } } #endregion End Event Start-Sleep -Seconds 1 } } catch { } finally { #region Flush log on exit if (([PSFramework.Runspace.RunspaceHost]::Runspaces[$___ScriptName.ToLower()].State -like "Running") -and ([PSFramework.Configuration.ConfigurationHost]::Configurations["psframework.logging.disablelogflush"].Value)) { #region Start Event foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.StartEvent)), $null, $null) } catch { $___provider.Errors.Push($_) } } #endregion Start Event #region Message Event while ([PSFramework.Message.LogHost]::OutQueueLog.Count -gt 0) { $Entry = $null [PSFramework.Message.LogHost]::OutQueueLog.TryDequeue([ref]$Entry) if ($Entry) { foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { if ($___provider.MessageApplies($Entry)) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.MessageEvent)), $null, $Entry) } catch { $___provider.Errors.Push($_) } } } } } #endregion Message Event #region Error Event while ([PSFramework.Message.LogHost]::OutQueueError.Count -gt 0) { $Record = $null [PSFramework.Message.LogHost]::OutQueueError.TryDequeue([ref]$Record) if ($Record) { foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { if ($___provider.MessageApplies($Record)) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.MessageEvent)), $null, $Record) } catch { $___provider.Errors.Push($_) } } } } } #endregion Error Event #region End Event foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.EndEvent)), $null, $null) } catch { $___provider.Errors.Push($_) } } #endregion End Event } #endregion Flush log on exit #region Final Event foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([System.Management.Automation.ScriptBlock]::Create($___provider.FinalEvent)), $null, $null) } catch { $___provider.Errors.Push($_) } } foreach ($___provider in [PSFramework.Logging.ProviderHost]::GetInitialized()) { $___provider.Initialized = $false } #endregion Final Event [PSFramework.Runspace.RunspaceHost]::Runspaces[$___ScriptName.ToLower()].SignalStopped() } } Register-PSFRunspace -ScriptBlock $scriptBlock -Name 'PSFramework.Logging' -NoMessage Start-PSFRunspace -Name 'PSFramework.Logging' -NoMessage Register-PSFTeppScriptblock -Name "PSFramework-config-fullname" -ScriptBlock { [PSFramework.Configuration.ConfigurationHost]::Configurations.Values | Where-Object { -not $_.Hidden } | Select-Object -ExpandProperty FullName } Register-PSFTeppScriptblock -Name "PSFramework-config-module" -ScriptBlock { [PSFramework.Configuration.ConfigurationHost]::Configurations.Values.Module | Select-Object -Unique } Register-PSFTeppScriptblock -Name "PSFramework-config-name" -ScriptBlock { $moduleName = "*" if ($fakeBoundParameter.Module) { $moduleName = $fakeBoundParameter.Module } [PSFramework.Configuration.ConfigurationHost]::Configurations.Values | Where-Object { -not $_.Hidden -and ($_.Module -like $moduleName) } | Select-Object -ExpandProperty Name } Register-PSFTeppScriptblock -Name 'PSFramework-config-validation' -ScriptBlock { [PSFramework.Configuration.ConfigurationHost]::Validation.Keys } Register-PSFTeppScriptblock -Name 'PSFramework-dynamiccontentobject-name' -ScriptBlock { [PSFramework.Utility.DynamicContentObject]::List } Register-PSFTeppScriptblock -Name "PSFramework-Encoding" -ScriptBlock { 'Unicode' 'BigEndianUnicode' 'UTF8' 'UTF8Bom' 'UTF8NoBom' 'UTF7' 'UTF32' 'Ascii' 'Default' 'BigEndianUTF32' if (Get-PSFConfigValue -FullName 'PSFramework.Text.Encoding.FullTabCompletion') { [System.Text.Encoding]::GetEncodings().BodyName } } Register-PSFTeppScriptblock -Name 'PSFramework-license-name' -ScriptBlock { (Get-PSFLicense).Product } Register-PSFTeppScriptblock -Name 'PSFramework-logging-provider' -ScriptBlock { (Get-PSFLoggingProvider).Name } Register-PSFTeppScriptblock -Name 'PSFramework.Message.Module' -ScriptBlock { Get-PSFMessage | Select-Object -ExpandProperty ModuleName | Select-Object -Unique } Register-PSFTeppScriptblock -Name 'PSFramework.Message.Function' -ScriptBlock { Get-PSFMessage | Select-Object -ExpandProperty FunctionName | Select-Object -Unique } Register-PSFTeppScriptblock -Name 'PSFramework.Message.Tags' -ScriptBlock { Get-PSFMessage | Select-Object -ExpandProperty Tags | Remove-PSFNull -Enumerate | Select-Object -Unique } Register-PSFTeppScriptblock -Name 'PSFramework.Message.Runspace' -ScriptBlock { Get-PSFMessage | Select-Object -ExpandProperty Runspace | Select-Object -Unique } Register-PSFTeppScriptblock -Name 'PSFramework.Message.Level' -ScriptBlock { Get-PSFMessage | Select-Object -ExpandProperty Level | Select-Object -Unique } Register-PSFTeppScriptblock -Name 'PSFramework-utility-psprovider' -ScriptBlock { (Get-PSProvider).Name } Register-PSFTeppScriptblock -Name 'PSFramework-runspace-name' -ScriptBlock { (Get-PSFRunspace).Name } Register-PSFTeppScriptblock -Name 'PSFramework-tepp-scriptblockname' -ScriptBlock { [PSFramework.TabExpansion.TabExpansionHost]::Scripts.Keys } Register-PSFTeppScriptblock -Name "PSFramework-Unregister-PSFConfig-FullName" -ScriptBlock { switch ("$($fakeBoundParameter.Scope)") { "UserDefault" { $path = "HKCU:\SOFTWARE\Microsoft\WindowsPowerShell\PSFramework\Config\Default" } "UserMandatory" { $path = "HKCU:\SOFTWARE\Microsoft\WindowsPowerShell\PSFramework\Config\Enforced" } "SystemDefault" { $path = "HKLM:\SOFTWARE\Microsoft\WindowsPowerShell\PSFramework\Config\Default" } "SystemMandatory" { $path = "HKLM:\SOFTWARE\Microsoft\WindowsPowerShell\PSFramework\Config\Enforced" } default { $path = "HKCU:\SOFTWARE\Microsoft\WindowsPowerShell\PSFramework\Config\Default" } } if (Test-Path $path) { $properties = Get-ItemProperty -Path $path $common = 'PSPath', 'PSParentPath', 'PSChildName', 'PSDrive', 'PSProvider' $properties.PSObject.Properties.Name | Where-Object { $_ -notin $common } } } Register-PSFTeppScriptblock -Name "PSFramework-Unregister-PSFConfig-Module" -ScriptBlock { [PSFramework.Configuration.ConfigurationHost]::Configurations.Values.Module | Select-Object -Unique } #region Configuration Register-PSFTeppArgumentCompleter -Command Export-PSFConfig -Parameter FullName -Name 'PSFramework-config-fullname' Register-PSFTeppArgumentCompleter -Command Export-PSFConfig -Parameter Module -Name 'PSFramework-config-module' Register-PSFTeppArgumentCompleter -Command Export-PSFConfig -Parameter Name -Name 'PSFramework-config-name' Register-PSFTeppArgumentCompleter -Command Get-PSFConfig -Parameter FullName -Name 'PSFramework-config-fullname' Register-PSFTeppArgumentCompleter -Command Get-PSFConfig -Parameter Module -Name 'PSFramework-config-module' Register-PSFTeppArgumentCompleter -Command Get-PSFConfig -Parameter Name -Name 'PSFramework-config-name' Register-PSFTeppArgumentCompleter -Command Set-PSFConfig -Parameter FullName -Name 'PSFramework-config-fullname' Register-PSFTeppArgumentCompleter -Command Set-PSFConfig -Parameter Module -Name 'PSFramework-config-module' Register-PSFTeppArgumentCompleter -Command Set-PSFConfig -Parameter Name -Name 'PSFramework-config-name' Register-PSFTeppArgumentCompleter -Command Set-PSFConfig -Parameter Validation -Name 'PSFramework-config-validation' Register-PSFTeppArgumentCompleter -Command Register-PSFConfig -Parameter FullName -Name 'PSFramework-config-fullname' Register-PSFTeppArgumentCompleter -Command Register-PSFConfig -Parameter Module -Name 'PSFramework-config-module' Register-PSFTeppArgumentCompleter -Command Register-PSFConfig -Parameter Name -Name 'PSFramework-config-name' Register-PSFTeppArgumentCompleter -Command Get-PSFConfigValue -Parameter FullName -Name 'PSFramework-config-fullname' Register-PSFTeppArgumentCompleter -Command Unregister-PSFConfig -Parameter FullName -Name 'PSFramework-Unregister-PSFConfig-FullName' Register-PSFTeppArgumentCompleter -Command Unregister-PSFConfig -Parameter Module -Name 'PSFramework-Unregister-PSFConfig-Module' #endregion Configuration #region License Register-PSFTeppArgumentCompleter -Command Get-PSFLicense -Parameter Filter -Name 'PSFramework-license-name' #endregion License #region Logging Register-PSFTeppArgumentCompleter -Command Get-PSFLoggingProvider -Parameter Name -Name 'PSFramework-logging-provider' Register-PSFTeppArgumentCompleter -Command Install-PSFLoggingProvider -Parameter Name -Name 'PSFramework-logging-provider' Register-PSFTeppArgumentCompleter -Command Set-PSFLoggingProvider -Parameter Name -Name 'PSFramework-logging-provider' #endregion Logging #region Message Register-PSFTeppArgumentCompleter -Command Get-PSFMessage -Parameter ModuleName -Name 'PSFramework.Message.Module' Register-PSFTeppArgumentCompleter -Command Get-PSFMessage -Parameter FunctionName -Name 'PSFramework.Message.Function' Register-PSFTeppArgumentCompleter -Command Get-PSFMessage -Parameter Tag -Name 'PSFramework.Message.Tags' Register-PSFTeppArgumentCompleter -Command Get-PSFMessage -Parameter Runspace -Name 'PSFramework.Message.Runspace' Register-PSFTeppArgumentCompleter -Command Get-PSFMessage -Parameter Level -Name 'PSFramework.Message.Level' #endregion Message #region Runspace Register-PSFTeppArgumentCompleter -Command Get-PSFRunspace -Parameter Name -Name 'PSFramework-runspace-name' Register-PSFTeppArgumentCompleter -Command Register-PSFRunspace -Parameter Name -Name 'PSFramework-runspace-name' Register-PSFTeppArgumentCompleter -Command Stop-PSFRunspace -Parameter Name -Name 'PSFramework-runspace-name' Register-PSFTeppArgumentCompleter -Command Start-PSFRunspace -Parameter Name -Name 'PSFramework-runspace-name' Register-PSFTeppArgumentCompleter -Command Get-PSFDynamicContentObject -Parameter Name -Name 'PSFramework-dynamiccontentobject-name' Register-PSFTeppArgumentCompleter -Command Set-PSFDynamicContentObject -Parameter Name -Name 'PSFramework-dynamiccontentobject-name' #endregion Runspace #region Serialization Register-PSFTeppArgumentCompleter -Command Export-PSFClixml -Parameter Encoding -Name 'PSFramework-Encoding' Register-PSFTeppArgumentCompleter -Command Import-PSFClixml -Parameter Encoding -Name 'PSFramework-Encoding' #endregion Serialization #region Tab Completion Register-PSFTeppArgumentCompleter -Command Set-PSFTeppResult -Parameter TabCompletion -Name 'PSFramework-tepp-scriptblockname' #endregion Tab Completion #region Utility Register-PSFTeppArgumentCompleter -Command Resolve-PSFPath -Parameter Provider -Name 'PSFramework-utility-psprovider' #endregion Utility $mappings = @{ "microsoft.sqlserver.management.smo.server" = @("NetName", "DomainInstanceName") "deserialized.microsoft.sqlserver.management.smo.server" = @("NetName", "DomainInstanceName") "microsoft.sqlserver.management.smo.linkedserver" = @("Name") "deserialized.microsoft.sqlserver.management.smo.linkedserver" = @("Name") "microsoft.activedirectory.management.adcomputer" = @("DNSHostName", "Name") "deserialized.microsoft.activedirectory.management.adcomputer" = @("DNSHostName", "Name") "Microsoft.DnsClient.Commands.DnsRecord_A" = @("Name", "IPAddress") "Deserialized.Microsoft.DnsClient.Commands.DnsRecord_A" = @("Name", "IPAddress") "Microsoft.DnsClient.Commands.DnsRecord_AAAA" = @("Name", "IPAddress") "Deserialized.Microsoft.DnsClient.Commands.DnsRecord_AAAA" = @("Name", "IPAddress") } foreach ($key in $mappings.Keys) { Register-PSFParameterClassMapping -ParameterClass 'Computer' -TypeName $key -Properties $mappings[$key] } # Define our type aliases $TypeAliasTable = @{ PSFComputer = "PSFramework.Parameter.ComputerParameter" PSFComputerParameter = "PSFramework.Parameter.ComputerParameter" PSFDateTime = "PSFramework.Parameter.DateTimeParameter" PSFDateTimeParameter = "PSFramework.Parameter.DateTimeParameter" PSFEncoding = "PSFramework.Parameter.EncodingParameter" PSFEncodingParameter = "PSFramework.Parameter.EncodingParameter" psfrgx = "PSFramework.Utility.RegexHelper" PSFTimeSpan = "PSFramework.Parameter.TimeSpanParameter" PSFTimeSpanParameter = "PSFramework.Parameter.TimeSpanParameter" PSFValidatePattern = "PSFramework.Validation.PsfValidatePatternAttribute" PSFValidateScript = "PSFramework.Validation.PsfValidateScriptAttribute" PSFValidateSet = "PSFramework.Validation.PsfValidateSetAttribute" } Set-PSFTypeAlias -Mapping $TypeAliasTable $scriptBlock = { $script:___ScriptName = 'psframework.taskengine' try { #region Main Execution while ($true) { # This portion is critical to gracefully closing the script if ([PSFramework.Runspace.RunspaceHost]::Runspaces[$___ScriptName.ToLower()].State -notlike "Running") { break } $task = $null $tasksDone = @() while ($task = [PSFramework.TaskEngine.TaskHost]::GetNextTask($tasksDone)) { try { ([ScriptBlock]::Create($task.ScriptBlock.ToString())).Invoke() } catch { Write-PSFMessage -EnableException $false -Level Warning -Message "[Maintenance] Task '$($task.Name)' failed to execute: $_" -ErrorRecord $_ -FunctionName "task:TaskEngine" -Target $task } $task.LastExecution = Get-Date $tasksDone += $task.Name } # If there will no more tasks need executing in the future, might as well kill the runspace if (-not ([PSFramework.TaskEngine.TaskHost]::HasPendingTasks)) { break } Start-Sleep -Seconds 5 } #endregion Main Execution } catch { } finally { [PSFramework.Runspace.RunspaceHost]::Runspaces[$___ScriptName.ToLower()].SignalStopped() } } Register-PSFRunspace -ScriptBlock $scriptBlock -Name 'psframework.taskengine' -NoMessage #region Handle Module Removal $PSF_OnRemoveScript = { # Stop all managed runspaces ONLY on the main runspace's termination if ([runspace]::DefaultRunspace.Id -eq 1) { Get-PSFRunspace | Stop-PSFRunspace } # Properly disconnect all remote sessions still held open $psframework_pssessions.Values | Remove-PSSession } $ExecutionContext.SessionState.Module.OnRemove += $PSF_OnRemoveScript Register-EngineEvent -SourceIdentifier ([System.Management.Automation.PsEngineEvent]::Exiting) -Action $PSF_OnRemoveScript #endregion Handle Module Removal #region Declare runtime variable for the flow control component $paramNewVariable = @{ Name = "psframework_killqueue" Value = (New-Object PSFramework.Utility.LimitedConcurrentQueue[int](25)) Option = 'ReadOnly' Scope = 'Script' Description = 'Variable that is used to maintain the list of commands to kill. This is used by Test-PSFFunctionInterrupt. Note: The value tested is the hashcade from the callstack item.' } New-Variable @paramNewVariable #endregion Declare runtime variable for the flow control component #region Declare PSSession Cache $paramNewVariable2 = @{ Name = "psframework_pssessions" Value = (New-Object PSFramework.ComputerManagement.PSSessionContainer) Option = 'ReadOnly' Scope = 'Script' Description = 'Variable containing the list of established powershell remoting sessions. This is used by Invoke-PSFCommand to track connections, disconnect expired sessions and reconnect sessions by name.' } New-Variable @paramNewVariable2 #endregion Declare PSSession Cache $license = New-PSFLicense -Product 'PSFramework' -Manufacturer 'Friedrich Weinmann' -ProductVersion $ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date -Year 2017 -Month 04 -Day 27 -Hour 0 -Minute 0 -Second 0) -Text @" Copyright (c) Friedrich Weinmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ #region Chris Dent $null = New-PSFLicense -Product 'Import-PSCmdlet' -Manufacturer 'Chris Dent' -ProductVersion '1.0.0.0' -ProductType Script -Name MIT -Version '1.0.0.0' -Date (Get-Date -Year 2018 -Month 05 -Day 16).Date -Text @" Copyright (c) Chris Dent Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ -Description @" The PSFramework is happy to publish the Import-PSFCmdlet command, based on the original work of Chris Dent's, 'Import-PSCmdlet' Thank you for allowing its use :) - Original Source: https://www.indented.co.uk/cmdlets-without-a-dll/ - Author blog: https://www.indented.co.uk/ "@ -Parent $license #endregion Chris Dent #region Joel Bennet $null = New-PSFLicense -Product 'Configuration-ExportPaths' -Manufacturer 'Joel Bennet' -ProductVersion '1.3.0' -ProductType Script -Name MIT -Version '1.0.0.0' -Date (Get-Date -Year 2018 -Month 05 -Day 16).Date -Text @" Copyright (c) 2015 Joel Bennett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ -Description @" The PSFramework is happy to base its internal path selection for configuration exports on the original work of Joel Bennet's, 'Configuration' module. Its implementation can be found in the internal script file: internal/scripts/loadConfigurationPersisted.ps1 Thank you for allowing its use :) - Original Source: https://github.com/PoshCode/Configuration - Author blog: http://huddledmasses.org/blog/ - Author Twitter: https://twitter.com/jaykul?lang=en "@ -Parent $license #endregion Joel Bennet |