├── media ├── Invoke-VeeamLogParser-LogType_All.png └── Invoke-VeeamLogParser-LogType_PowerShell-Limit-Content.png ├── .vscode ├── settings.json └── tasks.json ├── ReleaseNotes.md ├── docs ├── index.rst └── en-US │ └── Invoke-VeeamLogParser.md ├── README.md ├── .gitignore ├── LICENSE ├── tests └── VeeamLogParser.Tests.ps1 ├── VeeamLogParser.psd1 ├── functions └── Invoke-VeeamLogParser.psm1 └── Build.ps1 /media/Invoke-VeeamLogParser-LogType_All.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vMarkusK/VeeamLogParser/HEAD/media/Invoke-VeeamLogParser-LogType_All.png -------------------------------------------------------------------------------- /media/Invoke-VeeamLogParser-LogType_PowerShell-Limit-Content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vMarkusK/VeeamLogParser/HEAD/media/Invoke-VeeamLogParser-LogType_PowerShell-Limit-Content.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // When enabled, will trim trailing whitespace when you save a file. 3 | "files.trimTrailingWhitespace": true, 4 | "files.defaultLanguage": "powershell" 5 | } 6 | -------------------------------------------------------------------------------- /ReleaseNotes.md: -------------------------------------------------------------------------------- 1 | # What is New in VeeamLogParser 1.0.0 2 | 3 | August, 2018 4 | 5 | - First official release shipped to the PowerShell Gallery! 6 | 7 | ## Feedback 8 | 9 | Send feedback to https://github.com/mycloudrevolution/VeeamLogParser/issues -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to my VeeamLogParser Module 2 | ======================== 3 | 4 | The Veeam Log Parser extracts Error and Warning Messages from the Veeam File Logs of various Veeam products and services. 5 | 6 | This is the basic documentation of the 'VeeamLogParser PowerShell Module. 7 | 8 | GitHub: https://github.com/mycloudrevolution/VeeamLogParser/ 9 | 10 | WebSite: https://mycloudrevolution.com/ 11 | 12 | 13 | * :ref:`feature-docs` 14 | 15 | .. _feature-docs: 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | :glob: 20 | :caption: Feature Documentation 21 | 22 | en-US/* 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VeeamLogParser PowerShell Module 2 | ============= 3 | 4 | # About 5 | 6 | ## Project Owner: 7 | 8 | Markus Kraus [@vMarkus_K](https://twitter.com/vMarkus_K) 9 | 10 | MY CLOUD-(R)EVOLUTION [mycloudrevolution.com](http://mycloudrevolution.com/) 11 | 12 | ## Project WebSite: 13 | 14 | [mycloudrevolution.com](http://mycloudrevolution.com/) 15 | 16 | ## Project Documentation: 17 | 18 | [Read the Docs - VeeamLogParser](https://veeamlogparser.readthedocs.io/) 19 | 20 | ## Project Description: 21 | 22 | The Veeam Log Parser extracts Error and Warning Messages from the Veeam File Logs of various Veeam products and services. 23 | 24 | ### Examples 25 | 26 | ![Invoke-VeeamLogParser-LogType_All](/media/Invoke-VeeamLogParser-LogType_All.png) 27 | 28 | ![Invoke-VeeamLogParser-LogType_PowerShell-Limit-Content](/media/Invoke-VeeamLogParser-LogType_PowerShell-Limit-Content.png) 29 | 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Release/ 2 | 3 | # ========================= 4 | # Operating System Files 5 | # ========================= 6 | 7 | # Windows 8 | # ========================= 9 | 10 | # Windows image file caches 11 | Thumbs.db 12 | 13 | # Folder config file 14 | Desktop.ini 15 | 16 | # Recycle Bin used on file shares 17 | $RECYCLE.BIN/ 18 | 19 | # Windows Installer files 20 | *.cab 21 | *.msi 22 | *.msm 23 | *.msp 24 | 25 | # Windows shortcuts 26 | *.lnk 27 | 28 | # OSX 29 | # ========================= 30 | 31 | .DS_Store 32 | .AppleDouble 33 | .LSOverride 34 | 35 | # Thumbnails 36 | ._* 37 | 38 | # Files that might appear in the root of a volume 39 | .DocumentRevisions-V100 40 | .fseventsd 41 | .Spotlight-V100 42 | .TemporaryItems 43 | .Trashes 44 | .VolumeIcon.icns 45 | 46 | # Directories potentially created on remote AFP share 47 | .AppleDB 48 | .AppleDesktop 49 | Network Trash Folder 50 | Temporary Items 51 | .apdisk -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Markus Kraus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/VeeamLogParser.Tests.ps1: -------------------------------------------------------------------------------- 1 | $moduleRoot = Resolve-Path "$PSScriptRoot\.." 2 | $moduleName = "VeeamLogParser" 3 | 4 | Describe "General Code validation: $moduleName" { 5 | 6 | $scripts = Get-ChildItem $moduleRoot -Include *.psm1, *.ps1, *.psm1 -Recurse 7 | $testCase = $scripts | Foreach-Object {@{file = $_}} 8 | It "Script should be valid powershell" -TestCases $testCase { 9 | param($file) 10 | 11 | $file.fullname | Should Exist 12 | $contents = Get-Content -Path $file.fullname -ErrorAction Stop 13 | $errors = $null 14 | $null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors) 15 | $errors.Count | Should Be 0 16 | } 17 | 18 | $modules = Get-ChildItem $moduleRoot -Include *.psd1 -Recurse 19 | $testCase = $modules | Foreach-Object {@{file = $_}} 20 | It "Module can import cleanly" -TestCases $testCase { 21 | param($file) 22 | 23 | $file.fullname | Should Exist 24 | $error.clear() 25 | {Import-Module $file.fullname } | Should Not Throw 26 | $error.Count | Should Be 0 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /docs/en-US/Invoke-VeeamLogParser.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Invoke-VeeamLogParser-help.xml 3 | Module Name: VeeamLogParser 4 | online version: https://mycloudrevolution.com/ 5 | schema: 2.0.0 6 | --- 7 | 8 | # Invoke-VeeamLogParser 9 | 10 | ## SYNOPSIS 11 | 12 | ## SYNTAX 13 | 14 | ``` 15 | Invoke-VeeamLogParser [[-VeeamBasePath] ] [[-Context] ] [[-Limit] ] [-LogType] 16 | [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | The Veeam Log Parser Function extracts Error and Warning Messages from the Veeam File Logs of various products and services. 21 | 22 | ## EXAMPLES 23 | 24 | ### EXAMPLE 1 25 | ``` 26 | Invoke-VeeamLogParser -LogType Endpoint -Limit 2 27 | ``` 28 | 29 | ### EXAMPLE 2 30 | ``` 31 | Invoke-VeeamLogParser -LogType Endpoint -Limit 2 -Context 2 32 | ``` 33 | 34 | ## PARAMETERS 35 | 36 | ### -VeeamBasePath 37 | The Base Path of the Veeam Log Files 38 | 39 | Default: "C:\ProgramData\Veeam\" 40 | 41 | ```yaml 42 | Type: String 43 | Parameter Sets: (All) 44 | Aliases: 45 | 46 | Required: False 47 | Position: 1 48 | Default value: C:\ProgramData\Veeam\ 49 | Accept pipeline input: False 50 | Accept wildcard characters: False 51 | ``` 52 | 53 | ### -Context 54 | Show messages in Context 55 | 56 | ```yaml 57 | Type: Int32 58 | Parameter Sets: (All) 59 | Aliases: 60 | 61 | Required: False 62 | Position: 2 63 | Default value: 0 64 | Accept pipeline input: False 65 | Accept wildcard characters: False 66 | ``` 67 | 68 | ### -Limit 69 | Show limited number of messages 70 | 71 | ```yaml 72 | Type: Int32 73 | Parameter Sets: (All) 74 | Aliases: 75 | 76 | Required: False 77 | Position: 3 78 | Default value: 0 79 | Accept pipeline input: False 80 | Accept wildcard characters: False 81 | ``` 82 | 83 | ### -LogType 84 | The products or services Log you want to show 85 | 86 | Valid Pattern: "All","Endpoint","Mount","Backup","EnterpriseServer","Broker","Catalog","RestAPI","BackupManager", 87 | "CatalogReplication","DatabaseMaintenance","WebApp","PowerShell" 88 | 89 | ```yaml 90 | Type: String 91 | Parameter Sets: (All) 92 | Aliases: 93 | 94 | Required: True 95 | Position: 4 96 | Default value: None 97 | Accept pipeline input: False 98 | Accept wildcard characters: False 99 | ``` 100 | 101 | ### CommonParameters 102 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). 103 | 104 | ## INPUTS 105 | 106 | ## OUTPUTS 107 | 108 | ## NOTES 109 | File Name : Invoke-VeeamLogParser.psm1 110 | Author : Markus Kraus 111 | Version : 1.0 112 | State : Ready 113 | 114 | ## RELATED LINKS 115 | 116 | [https://mycloudrevolution.com/](https://mycloudrevolution.com/) 117 | 118 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // A task runner that invokes Pester to run all Pester tests under the 2 | // current workspace folder. 3 | // NOTE: This Test task runner requires an updated version of Pester (>=4.0.3) 4 | // in order for the problemMatcher to find failed test information (message, line, file). 5 | // If you don't have that version, you can update Pester from the PowerShell Gallery 6 | // with this command: 7 | // 8 | // PS C:\> Update-Module Pester 9 | // 10 | // If that gives an error like: 11 | // "Module 'Pester' was not installed by using Install-Module, so it cannot be updated." 12 | // then execute: 13 | // 14 | // PS C:\> Install-Module Pester -Scope CurrentUser -Force 15 | // 16 | // NOTE: The Clean, Build and Publish tasks require PSake. PSake can be installed 17 | // from the PowerShell Gallery with this command: 18 | // 19 | // PS C:\> Install-Module PSake -Scope CurrentUser -Force 20 | // 21 | // Available variables which can be used inside of strings: 22 | // ${workspaceFolder} the path of the workspace folder that contains the tasks.json file 23 | // ${workspaceFolderBasename} the name of the workspace folder that contains the tasks.json file without any slashes (/) 24 | // ${file} the current opened file 25 | // ${relativeFile} the current opened file relative to the workspace folder containing the file 26 | // ${fileBasename} the current opened file's basename 27 | // ${fileBasenameNoExtension} the current opened file's basename without the extension 28 | // ${fileDirname} the current opened file's dirname 29 | // ${fileExtname} the current opened file's extension 30 | // ${cwd} the task runner's current working directory on startup 31 | // ${lineNumber} the current selected line number in the active file 32 | { 33 | "version": "2.0.0", 34 | "windows": { 35 | "options": { 36 | "shell": { 37 | "executable": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", 38 | "args": [ 39 | "-NoProfile", 40 | "-ExecutionPolicy", 41 | "Bypass", 42 | "-Command" 43 | ] 44 | } 45 | } 46 | }, 47 | "linux": { 48 | "options": { 49 | "shell": { 50 | "executable": "/usr/bin/pwsh", 51 | "args": [ 52 | "-NoProfile", 53 | "-Command" 54 | ] 55 | } 56 | } 57 | }, 58 | "osx": { 59 | "options": { 60 | "shell": { 61 | "executable": "/usr/local/bin/pwsh", 62 | "args": [ 63 | "-NoProfile", 64 | "-Command" 65 | ] 66 | } 67 | } 68 | }, 69 | "tasks": [ 70 | { 71 | "label": "Clean", 72 | "type": "shell", 73 | "command": "Invoke-PSake build.ps1 -taskList Clean" 74 | }, 75 | { 76 | "label": "Build", 77 | "type": "shell", 78 | "command": "Invoke-PSake build.ps1 -taskList Build", 79 | "group": { 80 | "kind": "build", 81 | "isDefault": true 82 | }, 83 | "problemMatcher": [] 84 | }, 85 | { 86 | "label": "BuildHelp", 87 | "type": "shell", 88 | "command": "Invoke-PSake build.ps1 -taskList BuildHelp", 89 | "group": { 90 | "kind": "build", 91 | "isDefault": true 92 | }, 93 | "problemMatcher": [] 94 | }, 95 | { 96 | "label": "Test", 97 | "type": "shell", 98 | "command": "Import-Module Pester; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true}", 99 | "group": { 100 | "kind": "test", 101 | "isDefault": true 102 | }, 103 | "problemMatcher": [ 104 | "$pester" 105 | ] 106 | }, 107 | { 108 | "label": "Publish", 109 | "type": "shell", 110 | "command": "Invoke-PSake build.ps1 -taskList Publish", 111 | "problemMatcher": [] 112 | } 113 | ] 114 | } -------------------------------------------------------------------------------- /VeeamLogParser.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Modulmanifest für das Modul "VeeamLogParser" 3 | # 4 | # Generiert von: Markus 5 | # 6 | # Generiert am: 8/7/2018 7 | # 8 | 9 | @{ 10 | 11 | # Die diesem Manifest zugeordnete Skript- oder Binärmoduldatei. 12 | RootModule = 'functions/Invoke-VeeamLogParser.psm1' 13 | 14 | # Die Versionsnummer dieses Moduls 15 | ModuleVersion = '1.0.0' 16 | 17 | # ID zur eindeutigen Kennzeichnung dieses Moduls 18 | GUID = 'e2d8c4e4-2823-4da7-98b5-2ad1123f0ce2' 19 | 20 | # Autor dieses Moduls 21 | Author = 'Markus Kraus (@vMarkus_K)' 22 | 23 | # Unternehmen oder Hersteller dieses Moduls 24 | CompanyName = 'mycloudrevolution.com' 25 | 26 | # Urheberrechtserklärung für dieses Modul 27 | Copyright = '(c) 2018 Markus. Alle Rechte vorbehalten.' 28 | 29 | # Beschreibung der von diesem Modul bereitgestellten Funktionen 30 | Description = 'The Veeam Log Parser Function extracts Error and Warning Messages from the Veeam File Logs of various Veeam products and services.' 31 | 32 | # Die für dieses Modul mindestens erforderliche Version des Windows PowerShell-Moduls 33 | PowerShellVersion = '5.0' 34 | 35 | # Der Name des für dieses Modul erforderlichen Windows PowerShell-Hosts 36 | # PowerShellHostName = '' 37 | 38 | # Die für dieses Modul mindestens erforderliche Version des Windows PowerShell-Hosts 39 | # PowerShellHostVersion = '' 40 | 41 | # Die für dieses Modul mindestens erforderliche Microsoft .NET Framework-Version 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Die für dieses Modul mindestens erforderliche Version der CLR (Common Language Runtime) 45 | # CLRVersion = '' 46 | 47 | # Die für dieses Modul erforderliche Prozessorarchitektur ("Keine", "X86", "Amd64"). 48 | # ProcessorArchitecture = '' 49 | 50 | # Die Module, die vor dem Importieren dieses Moduls in die globale Umgebung geladen werden müssen 51 | # RequiredModules = @() 52 | 53 | # Die Assemblys, die vor dem Importieren dieses Moduls geladen werden müssen 54 | # RequiredAssemblies = @() 55 | 56 | # Die Skriptdateien (PS1-Dateien), die vor dem Importieren dieses Moduls in der Umgebung des Aufrufers ausgeführt werden. 57 | # ScriptsToProcess = @() 58 | 59 | # Die Typdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen 60 | # TypesToProcess = @() 61 | 62 | # Die Formatdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen 63 | # FormatsToProcess = @() 64 | 65 | # Die Module, die als geschachtelte Module des in "RootModule/ModuleToProcess" angegebenen Moduls importiert werden sollen. 66 | # NestedModules = @() 67 | 68 | # Aus diesem Modul zu exportierende Funktionen 69 | FunctionsToExport = 'Invoke-VeeamLogParser' 70 | 71 | # Aus diesem Modul zu exportierende Cmdlets 72 | #CmdletsToExport = '*' 73 | 74 | # Die aus diesem Modul zu exportierenden Variablen 75 | #VariablesToExport = '*' 76 | 77 | # Aus diesem Modul zu exportierende Aliase 78 | #AliasesToExport = '*' 79 | 80 | # Aus diesem Modul zu exportierende DSC-Ressourcen 81 | # DscResourcesToExport = @() 82 | 83 | # Liste aller Module in diesem Modulpaket 84 | # ModuleList = @() 85 | 86 | # Liste aller Dateien in diesem Modulpaket 87 | # FileList = @() 88 | 89 | # Die privaten Daten, die an das in "RootModule/ModuleToProcess" angegebene Modul übergeben werden sollen. Diese können auch eine PSData-Hashtabelle mit zusätzlichen von PowerShell verwendeten Modulmetadaten enthalten. 90 | PrivateData = @{ 91 | 92 | PSData = @{ 93 | 94 | # 'Tags' wurde auf das Modul angewendet und unterstützt die Modulermittlung in Onlinekatalogen. 95 | ags = @('Veeam') 96 | 97 | # Eine URL zur Lizenz für dieses Modul. 98 | LicenseUri = 'https://github.com/mycloudrevolution/VeeamLogParser/blob/master/LICENSE' 99 | 100 | # Eine URL zur Hauptwebsite für dieses Projekt. 101 | ProjectUri = 'https://github.com/mycloudrevolution/VeeamLogParser' 102 | 103 | # Eine URL zu einem Symbol, das das Modul darstellt. 104 | # IconUri = '' 105 | 106 | # 'ReleaseNotes' des Moduls 107 | # ReleaseNotes = '' 108 | 109 | } # Ende der PSData-Hashtabelle 110 | 111 | } # Ende der PrivateData-Hashtabelle 112 | 113 | # HelpInfo-URI dieses Moduls 114 | # HelpInfoURI = '' 115 | 116 | # Standardpräfix für Befehle, die aus diesem Modul exportiert werden. Das Standardpräfix kann mit "Import-Module -Prefix" überschrieben werden. 117 | # DefaultCommandPrefix = '' 118 | 119 | } 120 | 121 | 122 | -------------------------------------------------------------------------------- /functions/Invoke-VeeamLogParser.psm1: -------------------------------------------------------------------------------- 1 | function Invoke-VeeamLogParser { 2 | <# 3 | .DESCRIPTION 4 | The Veeam Log Parser Function extracts Error and Warning Messages from the Veeam File Logs of various products and services. 5 | 6 | .NOTES 7 | File Name : Invoke-VeeamLogParser.psm1 8 | Author : Markus Kraus 9 | Version : 1.0 10 | State : Ready 11 | 12 | .LINK 13 | https://mycloudrevolution.com/ 14 | 15 | .EXAMPLE 16 | Invoke-VeeamLogParser -LogType Endpoint -Limit 2 17 | 18 | .EXAMPLE 19 | Invoke-VeeamLogParser -LogType Endpoint -Limit 2 -Context 2 20 | 21 | .PARAMETER VeeamBasePath 22 | The Base Path of the Veeam Log Files 23 | 24 | Default: "C:\ProgramData\Veeam\" 25 | 26 | .PARAMETER Context 27 | Show messages in Context 28 | 29 | .PARAMETER Limit 30 | Show limited number of messages 31 | 32 | .PARAMETER LogType 33 | The products or services Log you want to show 34 | 35 | Valid Pattern: "All","Endpoint","Mount","Backup","EnterpriseServer","Broker","Catalog","RestAPI","BackupManager", 36 | "CatalogReplication","DatabaseMaintenance","WebApp","PowerShell" 37 | #> 38 | 39 | [CmdletBinding()] 40 | param( 41 | [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="The Base Path of the Veeam Log Files")] 42 | [ValidateNotNullorEmpty()] 43 | [String] $VeeamBasePath = "C:\ProgramData\Veeam\", 44 | [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Show messages in Context")] 45 | [ValidateNotNullorEmpty()] 46 | [int]$Context, 47 | [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Show limited number of messages")] 48 | [ValidateNotNullorEmpty()] 49 | [Int]$Limit, 50 | [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="The products or services Log you want to show")] 51 | [ValidateNotNullorEmpty()] 52 | [ValidateSet("All","Endpoint","Mount","Backup","EnterpriseServer","Broker","Catalog","RestAPI","BackupManager", 53 | "CatalogReplication","DatabaseMaintenance","WebApp","PowerShell")] 54 | [String]$LogType 55 | ) 56 | 57 | Begin { 58 | 59 | class LogParser { 60 | #Properties 61 | [String]$Name 62 | [String]$BasePath 63 | [String]$Folder 64 | [String]$File 65 | 66 | #Static 67 | Static [String] $WarningPattern = "\[\d+.\d+.\d+\s\d+\:\d+:\d+]\s\<\d+\>\sWarning" 68 | Static [String] $ErrorPattern = "\[\d+.\d+.\d+\s\d+\:\d+:\d+]\s\<\d+\>\sError" 69 | 70 | #Constructor 71 | LogParser ([String] $Name, [String]$BasePath, [String]$Folder, [String]$File) { 72 | $this.Name = $Name 73 | $this.BasePath = $BasePath 74 | $this.Folder = $Folder 75 | $this.File = $File 76 | } 77 | 78 | #Method 79 | [Bool]checkFolder() { 80 | return Test-Path $($this.BasePath + $this.Folder) 81 | } 82 | 83 | #Method 84 | [Bool]checkFile() { 85 | return Test-Path $($this.BasePath + $this.Folder + "\" + $this.File) 86 | } 87 | 88 | #Method 89 | [Array]getContent() { 90 | if ($this.checkFolder()) { 91 | if ($this.checkFile()) { 92 | return Get-Content $($this.BasePath + $this.Folder + "\" + $this.File) 93 | } 94 | else { 95 | return Write-Warning "File not found" 96 | } 97 | } 98 | else { 99 | return Write-Warning "Folder not found" 100 | } 101 | } 102 | 103 | #Method 104 | [Array]getErrors() { 105 | $Content = $this.getContent() 106 | return $Content | Select-String -Pattern $([LogParser]::ErrorPattern) -AllMatches 107 | 108 | } 109 | 110 | #Method 111 | [Array]getErrors([int]$ContentB, [int]$ContentA) { 112 | $Content = $this.getContent() 113 | return $Content | Select-String -Pattern $([LogParser]::ErrorPattern) -AllMatches -Context $ContentB, $ContentA 114 | } 115 | 116 | #Method 117 | [Array]getWarnings() { 118 | $Content = $this.getContent() 119 | return $Content | Select-String -Pattern $([LogParser]::WarningPattern) -AllMatches 120 | 121 | } 122 | 123 | #Method 124 | [Array]getWarnings([int]$ContentB, [int]$ContentA) { 125 | $Content = $this.getContent() 126 | return $Content | Select-String -Pattern $([LogParser]::WarningPattern) -AllMatches -Context $ContentB, $ContentA 127 | 128 | } 129 | 130 | #Method 131 | [Array]getErrorsAndWarnings() { 132 | $Content = $this.getContent() 133 | return $Content | Select-String -Pattern $([LogParser]::ErrorPattern), $([LogParser]::WarningPattern) -AllMatches 134 | 135 | } 136 | 137 | #Method 138 | [Array]getErrorsAndWarnings([int]$ContentB, [int]$ContentA) { 139 | $Content = $this.getContent() 140 | return $Content | Select-String -Pattern $([LogParser]::ErrorPattern), $([LogParser]::WarningPattern) -AllMatches -Context $ContentB, $ContentA 141 | 142 | } 143 | 144 | } 145 | function Invoke-Output ($item) { 146 | if ($Context) { 147 | $Select = $item.getErrorsAndWarnings($Context, $Context) 148 | } 149 | else { 150 | $Select = $item.getErrorsAndWarnings() 151 | } 152 | 153 | if ($Limit) { 154 | $Select | Select-Object -Last $Limit 155 | } 156 | else { 157 | $Select 158 | } 159 | 160 | } 161 | 162 | $LogTypes = @() 163 | $LogTypes += [LogParser]::new("Endpoint", $VeeamBasePath, "Endpoint", "Svc.VeeamEndpointBackup.log") 164 | $LogTypes += [LogParser]::new("Mount", $VeeamBasePath, "Backup", "Svc.VeeamMount.log") 165 | $LogTypes += [LogParser]::new("Backup", $VeeamBasePath, "Backup", "Svc.VeeamBackup.log") 166 | $LogTypes += [LogParser]::new("EnterpriseServer", $VeeamBasePath, "Backup", "Svc.VeeamBES.log") 167 | $LogTypes += [LogParser]::new("Broker", $VeeamBasePath, "Backup", "Svc.VeeamBroker.log") 168 | $LogTypes += [LogParser]::new("Catalog", $VeeamBasePath, "Backup", "Svc.VeeamCatalog.log") 169 | $LogTypes += [LogParser]::new("RestAPI", $VeeamBasePath, "Backup", "Svc.VeeamRestAPI.log") 170 | $LogTypes += [LogParser]::new("BackupManager", $VeeamBasePath, "Backup", "VeeamBackupManager.log") 171 | $LogTypes += [LogParser]::new("CatalogReplication", $VeeamBasePath, "Backup", "CatalogReplicationJob.log") 172 | $LogTypes += [LogParser]::new("DatabaseMaintenance", $VeeamBasePath, "Backup", "Job.DatabaseMaintenance.log") 173 | $LogTypes += [LogParser]::new("WebApp", $VeeamBasePath, "Backup", "Veeam.WebApp.log") 174 | $LogTypes += [LogParser]::new("PowerShell", $VeeamBasePath, "Backup", "VeeamPowerShell.log") 175 | 176 | } 177 | 178 | Process { 179 | 180 | if ($LogType -eq "All") { 181 | foreach ($item in $LogTypes) { 182 | Write-Host "`nProcessing '$($item.File)' in '$($item.BasePath + $item.Folder + "\")'" -ForegroundColor Gray 183 | Invoke-Output $item 184 | } 185 | } 186 | else { 187 | $item = $LogTypes | Where-Object {$_.Name -eq $LogType } 188 | if ($item) { 189 | Write-Host "`nProcessing '$($item.File)' in '$($item.BasePath + $item.Folder + "\")'" -ForegroundColor Gray 190 | Invoke-Output $item 191 | } 192 | else { 193 | Throw "Internal Error: LogType Missmatch" 194 | } 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /Build.ps1: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # PREVIEW VERSION OF PSAKE SCRIPT FOR MODULE BUILD & PUBLISH TO THE PSGALLERY 3 | ############################################################################## 4 | # 5 | # We are hoping to add support for publishing modules to the PowerShell gallery 6 | # and private repositories in a future release of this extension. This is an 7 | # early look at the approach we are considering which is to supply a 8 | # PSake-based script that will: 9 | # 10 | # 1. Create a directory from which to publish your module. 11 | # 2. Copy the appropriate module files to that directory excluding items like 12 | # the .vscode directory, Pester tests, etc. These are configurable in Build.ps1. 13 | # 3. Verify all existing Pester tests pass. 14 | # 4. Publish the module to the desired repository (defaulting to the PSGallery). 15 | # 16 | # Requirements: PSake. If you don't have this module installed use the following 17 | # command to install it: 18 | # 19 | # PS C:\> Install-Module PSake -Scope CurrentUser 20 | # 21 | ############################################################################## 22 | # This is a PSake script that supports the following tasks: 23 | # clean, build, test and publish. The default task is build. 24 | # 25 | # The publish task uses the Publish-Module command to publish 26 | # to either the PowerShell Gallery (the default) or you can change 27 | # the $Repository property to the name of an alternate repository. 28 | # 29 | # The test task invokes Pester to run any Pester tests in your 30 | # workspace folder. Name your test scripts .Tests.ps1 31 | # and Pester will find and run the tests contained in the files. 32 | # 33 | # You can run this build script directly using the invoke-psake 34 | # command which will execute the build task. This task "builds" 35 | # a temporary folder from which the module can be published. 36 | # 37 | # PS C:\> invoke-psake build.ps1 38 | # 39 | # You can run your Pester tests (if any) by running the following command. 40 | # 41 | # PS C:\> invoke-psake build.ps1 -taskList test 42 | # 43 | # You can execute the publish task with the following command. Note that 44 | # the publish task will run the test task first. The Pester tests must pass 45 | # before the publish task will run. The first time you run the publish 46 | # command, you will be prompted to enter your PowerShell Gallery NuGetApiKey. 47 | # After entering the key, it is encrypted and stored so you will not have to 48 | # enter it again. 49 | # 50 | # PS C:\> invoke-psake build.ps1 -taskList publish 51 | # 52 | # You can verify the stored and encrypted NuGetApiKey by running the following 53 | # command. This will display your NuGetApiKey in plain text! 54 | # 55 | # PS C:\> invoke-psake build.ps1 -taskList showKey 56 | # 57 | # You can store a new NuGetApiKey with this command. You can leave off 58 | # the -properties parameter and you'll be prompted for the key. 59 | # 60 | # PS C:\> invoke-psake build.ps1 -taskList storeKey -properties @{NuGetApiKey='test123'} 61 | # 62 | 63 | ############################################################################### 64 | # Customize these properties for your module. 65 | ############################################################################### 66 | Properties { 67 | # The name of your module should match the basename of the PSD1 file. 68 | $ModuleName = (Get-Item $PSScriptRoot\*.psd1 | 69 | Foreach-Object {$null = Test-ModuleManifest -Path $_ -ErrorAction SilentlyContinue; if ($?) {$_}})[0].BaseName 70 | 71 | # Path to the release notes file. Set to $null if the release notes reside in the manifest file. 72 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 73 | $ReleaseNotesPath = "$PSScriptRoot\ReleaseNotes.md" 74 | 75 | # The directory used to publish the module from. If you are using Git, the 76 | # $PublishRootDir should be ignored if it is under the workspace directory. 77 | $PublishRootDir = "$PSScriptRoot\Release" 78 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 79 | $PublishDir = "$PublishRootDir\$ModuleName" 80 | 81 | # Docs 82 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 83 | $DocsRootDir = "$PSScriptRoot\docs" 84 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 85 | $DefaultLocale = 'en-US' 86 | 87 | # The following items will not be copied to the $PublishDir. 88 | # Add items that should not be published with the module. 89 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 90 | $Exclude = @( 91 | (Split-Path $PSCommandPath -Leaf), 92 | 'Release', 93 | 'docs', 94 | 'examples', 95 | 'helper', 96 | 'media', 97 | 'Tests', 98 | '.git*', 99 | '.vscode' 100 | ) 101 | 102 | # Name of the repository you wish to publish to. Default repo is the PSGallery. 103 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 104 | $PublishRepository = $null 105 | 106 | # Your NuGet API key for the PSGallery. Leave it as $null and the first time 107 | # you publish you will be prompted to enter your API key. The build will 108 | # store the key encrypted in a file, so that on subsequent publishes you 109 | # will no longer be prompted for the API key. 110 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 111 | $NuGetApiKey = $null 112 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 113 | $EncryptedApiKeyPath = "$env:LOCALAPPDATA\vscode-powershell\NuGetApiKey.clixml" 114 | } 115 | 116 | ############################################################################### 117 | # Customize these tasks for performing operations before and/or after publish. 118 | ############################################################################### 119 | Task PrePublish { 120 | } 121 | 122 | Task PostPublish { 123 | } 124 | 125 | ############################################################################### 126 | # Core task implementations - this possibly "could" ship as part of the 127 | # vscode-powershell extension and then get dot sourced into this file. 128 | ############################################################################### 129 | Task default -depends Build 130 | 131 | Task Publish -depends Test, BuildHelp, PrePublish, PublishImpl, PostPublish { 132 | } 133 | 134 | Task PublishImpl -depends Test -requiredVariables EncryptedApiKeyPath, PublishDir { 135 | if ($NuGetApiKey) { 136 | "Using script embedded NuGetApiKey" 137 | } 138 | elseif (Test-Path -LiteralPath $EncryptedApiKeyPath) { 139 | $NuGetApiKey = LoadAndUnencryptNuGetApiKey $EncryptedApiKeyPath 140 | "Using stored NuGetApiKey" 141 | } 142 | else { 143 | $cred = PromptUserForNuGetApiKeyCredential -DestinationPath $EncryptedApiKeyPath 144 | $NuGetApiKey = $cred.GetNetworkCredential().Password 145 | "The NuGetApiKey has been stored in $EncryptedApiKeyPath" 146 | } 147 | 148 | $publishParams = @{ 149 | Path = $PublishDir 150 | NuGetApiKey = $NuGetApiKey 151 | } 152 | 153 | if ($PublishRepository) { 154 | $publishParams['Repository'] = $PublishRepository 155 | } 156 | 157 | # Consider not using -ReleaseNotes parameter when Update-ModuleManifest has been fixed. 158 | if ($ReleaseNotesPath) { 159 | $publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath) 160 | } 161 | 162 | "Calling Publish-Module..." 163 | Publish-Module @publishParams 164 | } 165 | 166 | Task Test -depends Build { 167 | Import-Module Pester 168 | Invoke-Pester $PSScriptRoot 169 | } 170 | 171 | Task Build -depends Clean, Init -requiredVariables PublishDir, Exclude, ModuleName { 172 | Copy-Item -Path $PSScriptRoot\* -Destination $PublishDir -Recurse -Exclude $Exclude 173 | 174 | # Get contents of the ReleaseNotes file and update the copied module manifest file 175 | # with the release notes. 176 | # DO NOT USE UNTIL UPDATE-MODULEMANIFEST IS FIXED - DOES NOT HANDLE SINGLE QUOTES CORRECTLY. 177 | # if ($ReleaseNotesPath) { 178 | # $releaseNotes = @(Get-Content $ReleaseNotesPath) 179 | # Update-ModuleManifest -Path $PublishDir\${ModuleName}.psd1 -ReleaseNotes $releaseNotes 180 | # } 181 | } 182 | 183 | Task Clean -requiredVariables PublishRootDir { 184 | # Sanity check the dir we are about to "clean". If $PublishRootDir were to 185 | # inadvertently get set to $null, the Remove-Item commmand removes the 186 | # contents of \*. That's a bad day. Ask me how I know? :-( 187 | if ((Test-Path $PublishRootDir) -and $PublishRootDir.Contains($PSScriptRoot)) { 188 | Remove-Item $PublishRootDir\* -Recurse -Force 189 | } 190 | } 191 | 192 | Task Init -requiredVariables PublishDir { 193 | if (!(Test-Path $PublishDir)) { 194 | $null = New-Item $PublishDir -ItemType Directory 195 | } 196 | } 197 | 198 | Task RemoveKey -requiredVariables EncryptedApiKeyPath { 199 | if (Test-Path -LiteralPath $EncryptedApiKeyPath) { 200 | Remove-Item -LiteralPath $EncryptedApiKeyPath 201 | } 202 | } 203 | 204 | Task StoreKey -requiredVariables EncryptedApiKeyPath { 205 | [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')] 206 | $nuGetApiKeyCred = PromptUserForNuGetApiKeyCredential -DestinationPath $EncryptedApiKeyPath 207 | "The NuGetApiKey has been stored in $EncryptedApiKeyPath" 208 | } 209 | 210 | Task ShowKey -requiredVariables EncryptedApiKeyPath { 211 | if ($NuGetApiKey) { 212 | "The embedded (partial) NuGetApiKey is: $($NuGetApiKey[0..7])" 213 | } 214 | else { 215 | $NuGetApiKey = LoadAndUnencryptNuGetApiKey -Path $EncryptedApiKeyPath 216 | "The stored (partial) NuGetApiKey is: $($NuGetApiKey[0..7])" 217 | } 218 | 219 | "To see the full key, use the task 'ShowFullKey'" 220 | } 221 | 222 | Task ShowFullKey -requiredVariables EncryptedApiKeyPath { 223 | if ($NuGetApiKey) { 224 | "The embedded NuGetApiKey is: $NuGetApiKey" 225 | } 226 | else { 227 | $NuGetApiKey = LoadAndUnencryptNuGetApiKey -Path $EncryptedApiKeyPath 228 | "The stored NuGetApiKey is: $NuGetApiKey" 229 | } 230 | } 231 | 232 | Task ? -description 'Lists the available tasks' { 233 | "Available tasks:" 234 | $PSake.Context.Peek().Tasks.Keys | Sort-Object 235 | } 236 | 237 | 238 | Task BuildHelp -depends Build, GenerateMarkdown, GenerateHelpFiles { 239 | } 240 | 241 | Task GenerateMarkdown -requiredVariables DefaultLocale, DocsRootDir, ModuleName, PublishDir { 242 | if (!(Get-Module platyPS -ListAvailable)) { 243 | "platyPS module is not installed. Skipping $($psake.context.currentTaskName) task." 244 | return 245 | } 246 | 247 | $moduleInfo = Import-Module $PublishDir\$ModuleName.psd1 -Global -Force -PassThru 248 | 249 | try { 250 | if ($moduleInfo.ExportedCommands.Count -eq 0) { 251 | "No commands have been exported. Skipping $($psake.context.currentTaskName) task." 252 | return 253 | } 254 | 255 | if (!(Test-Path -LiteralPath $DocsRootDir)) { 256 | New-Item $DocsRootDir -ItemType Directory > $null 257 | } 258 | 259 | if (Get-ChildItem -LiteralPath $DocsRootDir -Filter *.md -Recurse) { 260 | Get-ChildItem -LiteralPath $DocsRootDir -Directory | ForEach-Object { 261 | [Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; Update-MarkdownHelp -Path $_.FullName -Verbose:$VerbosePreference > $null 262 | } 263 | } 264 | 265 | # ErrorAction set to SilentlyContinue so this command will not overwrite an existing MD file. 266 | [Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; New-MarkdownHelp -Module $ModuleName -Locale $DefaultLocale -OutputFolder $DocsRootDir\$DefaultLocale ` 267 | -WithModulePage:$false -ErrorAction SilentlyContinue -Verbose:$VerbosePreference > $null 268 | } 269 | finally { 270 | Remove-Module $ModuleName 271 | } 272 | } 273 | 274 | Task GenerateHelpFiles -requiredVariables DocsRootDir, ModuleName, PublishDir { 275 | if (!(Get-Module platyPS -ListAvailable)) { 276 | "platyPS module is not installed. Skipping $($psake.context.currentTaskName) task." 277 | return 278 | } 279 | 280 | if (!(Get-ChildItem -LiteralPath $DocsRootDir -Filter *.md -Recurse -ErrorAction SilentlyContinue)) { 281 | "No markdown help files to process. Skipping $($psake.context.currentTaskName) task." 282 | return 283 | } 284 | 285 | $helpLocales = (Get-ChildItem -Path $DocsRootDir -Directory).Name 286 | 287 | # Generate the module's primary MAML help file. 288 | foreach ($locale in $helpLocales) { 289 | [Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; New-ExternalHelp -Path $DocsRootDir\$locale -OutputPath $PublishDir\$locale -Force ` 290 | -ErrorAction SilentlyContinue -Verbose:$VerbosePreference > $null 291 | } 292 | } 293 | 294 | ############################################################################### 295 | # Helper functions 296 | ############################################################################### 297 | function PromptUserForNuGetApiKeyCredential { 298 | [Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')] 299 | param( 300 | [Parameter()] 301 | [ValidateNotNullOrEmpty()] 302 | [string] 303 | $DestinationPath 304 | ) 305 | 306 | $message = "Enter your NuGet API Key in the password field (or nothing, this isn't used yet in the preview)" 307 | $nuGetApiKeyCred = Get-Credential -Message $message -UserName "ignored" 308 | 309 | if ($DestinationPath) { 310 | EncryptAndSaveNuGetApiKey -NuGetApiKeySecureString $nuGetApiKeyCred.Password -Path $DestinationPath 311 | } 312 | 313 | $nuGetApiKeyCred 314 | } 315 | 316 | function EncryptAndSaveNuGetApiKey { 317 | [Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingConvertToSecureStringWithPlainText", '')] 318 | [Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')] 319 | param( 320 | [Parameter(Mandatory, ParameterSetName='SecureString')] 321 | [ValidateNotNull()] 322 | [SecureString] 323 | $NuGetApiKeySecureString, 324 | 325 | [Parameter(Mandatory, ParameterSetName='PlainText')] 326 | [ValidateNotNullOrEmpty()] 327 | [string] 328 | $NuGetApiKey, 329 | 330 | [Parameter(Mandatory)] 331 | $Path 332 | ) 333 | 334 | if ($PSCmdlet.ParameterSetName -eq 'PlainText') { 335 | $NuGetApiKeySecureString = ConvertTo-SecureString -String $NuGetApiKey -AsPlainText -Force 336 | } 337 | 338 | $parentDir = Split-Path $Path -Parent 339 | if (!(Test-Path -LiteralPath $parentDir)) { 340 | $null = New-Item -Path $parentDir -ItemType Directory 341 | } 342 | elseif (Test-Path -LiteralPath $Path) { 343 | Remove-Item -LiteralPath $Path 344 | } 345 | 346 | $NuGetApiKeySecureString | ConvertFrom-SecureString | Export-Clixml $Path 347 | Write-Verbose "The NuGetApiKey has been encrypted and saved to $Path" 348 | } 349 | 350 | function LoadAndUnencryptNuGetApiKey { 351 | [Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')] 352 | param( 353 | [Parameter(Mandatory)] 354 | [ValidateNotNullOrEmpty()] 355 | [string] 356 | $Path 357 | ) 358 | 359 | $storedKey = Import-Clixml $Path | ConvertTo-SecureString 360 | $cred = New-Object -TypeName PSCredential -ArgumentList 'jpgr',$storedKey 361 | $cred.GetNetworkCredential().Password 362 | Write-Verbose "The NuGetApiKey has been loaded and unencrypted from $Path" 363 | } --------------------------------------------------------------------------------