Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
Logging.Tests.ps1509 linesDownload Raw Back to Host
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3using namespace System.Text4 5Set-StrictMode -Version 3.06$ErrorActionPreference = 'Stop'7 8Import-Module HelpersCommon9Import-Module PSSysLog10 11<#12    Define enums that mirror the internal enums used13    in product code. These are used to configure14    syslog logging.15#>16enum LogLevel17{18    LogAlways = 0x019    Critical = 0x120    Error = 0x221    Warning = 0x322    Informational = 0x423    Verbose = 0x524    Debug = 0x1425}26 27enum LogChannel28{29    Operational = 0x1030    Analytic = 0x1131}32 33enum LogKeyword34{35    Runspace = 0x136    Pipeline = 0x237    Protocol = 0x438    Transport = 0x839    Host = 0x1040    Cmdlets = 0x2041    Serializer = 0x4042    Session = 0x8043    ManagedPlugin = 0x10044}45 46# mac log command can emit json, so just use that47# we need to deconstruct the eventmessage to get the event id48# we also need to filter out the non-default messages49function Get-MacOsSyslogItems {50    param ([int]$processId, [string]$logId)51    $logArgs = "show", "--process", "$processId", "--style", "json"52    log $logArgs |53        ConvertFrom-Json |54        Where-Object { $_.category -eq "$logId" -and $_.messageType -eq "Default" } |55        ForEach-Object {56            $s = $_.eventMessage.IndexOf('[') + 157            $e = $_.EventMessage.IndexOf(']')58            $l = $e - $s59            if ($l -gt 0) {60                $eventId = $_.eventMessage.SubString($s, $l)61            }62            else {63                $eventId = "unknown"64            }65            $_ | Add-Member -MemberType NoteProperty -Name EventId -Value $eventId -PassThru66        }67}68 69<#70.SYNOPSIS71   Creates a powershell.config.json file with syslog settings72 73.PARAMETER logId74    The identifier to use for logging75 76.PARAMETER logLevel77    The optional logging level, see the LogLevel enum78 79.PARAMETER logChannels80    The optional logging channels to enable; see the LogChannel enum81 82.PARAMETER logKeywords83    The optional keywords to enable ; see the LogKeyword enum84#>85function WriteLogSettings86{87    param88    (89        [Parameter(Mandatory)]90        [ValidateNotNullOrEmpty()]91        [string] $LogId,92 93        [System.Nullable[LogLevel]] $LogLevel = $null,94 95        [LogChannel[]] $LogChannels = $null,96 97        [LogKeyword[]] $LogKeywords = $null,98 99        [switch] $ScriptBlockLogging100    )101 102    $filename = [Guid]::NewGuid().ToString('N')103    $fullPath = Join-Path -Path $TestDrive -ChildPath "$filename.config.json"104 105    $values = @{}106    $values['LogIdentity'] = $LogId107 108    if ($LogChannels -ne $null)109    {110        $values['LogChannels'] = $LogChannels -join ', '111    }112 113    if ($LogKeywords -ne $null)114    {115        $values['LogKeywords'] = $LogKeywords -join ', '116    }117 118    if ($LogLevel)119    {120        $values['LogLevel'] = $LogLevel.ToString()121    }122 123    if($IsWindows)124    {125        $values["Microsoft.PowerShell:ExecutionPolicy"] = "RemoteSigned"126    }127 128    if($ScriptBlockLogging.IsPresent)129    {130        $powerShellPolicies = @{131            ScriptBlockLogging = @{132                EnableScriptBlockLogging = $ScriptBlockLogging.IsPresent133                EnableScriptBlockInvocationLogging = $true134            }135        }136 137        $values['PowerShellPolicies'] = $powerShellPolicies138    }139 140    ConvertTo-Json -InputObject $values | Set-Content -Path $fullPath -ErrorAction Stop141    return $fullPath142}143 144function Get-RegEx145{146    param($SimpleMatch)147 148    $regex = $SimpleMatch -replace '\\', '\\'149    $regex = $regex -replace '\(', '\('150    $regex = $regex -replace '\)', '\)'151    $regex = $regex -replace '\[', '\['152    $regex = $regex -replace '\]', '\]'153    $regex = $regex -replace '\-', '\-'154    $regex = $regex -replace '\$', '\$'155    $regex = $regex -replace '\^', '\^'156    return $regex157}158 159Describe 'Basic SysLog tests on Linux' -Tag @('CI','RequireSudoOnUnix') {160    BeforeAll {161        [bool] $IsSupportedEnvironment = $IsLinux162        [string] $SysLogFile = [string]::Empty163 164        if ($IsSupportedEnvironment)165        {166            # TODO: Update to use a PowerShell specific syslog file167            if (Test-Path -Path '/var/log/syslog')168            {169                $SysLogFile = '/var/log/syslog'170            }171            elseif (Test-Path -Path '/var/log/messages')172            {173                $SysLogFile = '/var/log/messages'174            }175            else176            {177                # TODO: Look into journalctl and other variations.178                Write-Warning -Message 'Unsupported Linux syslog configuration.'179                $IsSupportedEnvironment = $false180            }181            [string] $powershell = Join-Path -Path $PSHOME -ChildPath 'pwsh'182            $scriptBlockCreatedRegExTemplate = @"183Creating Scriptblock text \(1 of 1\):#012{0}(โŽ|#012)*ScriptBlock ID: [0-9a-z\-]*#012Path:.*184"@185 186        }187    }188 189    BeforeEach {190        # generate a unique log application id191        [string] $logId = [Guid]::NewGuid().ToString('N')192    }193 194    It 'Verifies basic logging with no customizations' -Skip:(!$IsSupportedEnvironment) {195        $configFile = WriteLogSettings -LogId $logId196        & $powershell -NoProfile -SettingsFile $configFile -Command '$env:PSModulePath | out-null'197 198        # Get log entries from the last 100 that match our id and are after the time we launched Powershell199        $items = Get-PSSysLog -Path $SyslogFile -Id $logId -Tail 100 -Verbose -TotalCount 3200 201        $items | Should -Not -Be $null202        $items.Length | Should -BeGreaterThan 1203        $items[0].EventId | Should -BeExactly 'Perftrack_ConsoleStartupStart:PowershellConsoleStartup.WinStart.Informational'204        $items[1].EventId | Should -BeExactly 'NamedPipeIPC_ServerListenerStarted:NamedPipe.Open.Informational'205        $items[2].EventId | Should -BeExactly 'Perftrack_ConsoleStartupStop:PowershellConsoleStartup.WinStop.Informational'206        # if there are more items than expected...207        if ($items.Length -gt 3)208        {209            # Force reporting of the first unexpected item to help diagnosis210            $items[3] | Should -Be $null211        }212    }213 214    # Skip test as it is failing in PowerShell CI on Linux platform.215    # Tracking Issue: https://github.com/PowerShell/PowerShell/issues/17092216    It 'Verifies scriptblock logging' -Skip <#-Skip:(!$IsSupportedEnvironment)#> {217        $configFile = WriteLogSettings -LogId $logId -ScriptBlockLogging -LogLevel Verbose218        $script = @'219$PID220& ([scriptblock]::create("Write-Verbose 'testheader123' ;Write-verbose 'after'"))221'@222        $testFileName = 'test01.ps1'223        $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName224        $script | Out-File -FilePath $testScriptPath -Force225        $null = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath226 227        # Get log entries from the last 100 that match our id and are after the time we launched Powershell228        $items = Get-PSSysLog -Path $SyslogFile -Id $logId -Tail 100 -Verbose -TotalCount 18229 230        $items | Should -Not -Be $null231        $items.Count | Should -BeGreaterThan 2232        $createdEvents = $items | Where-Object {$_.EventId -eq 'ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose'}233        $createdEvents.Count | Should -BeGreaterOrEqual 3234 235        # Verify we log that we are executing a file236        $createdEvents[0].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f ".*/$testFileName")237 238        # Verify we log that we are the script to create the scriptblock239        $createdEvents[1].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f (Get-RegEx -SimpleMatch $Script.Replace([System.Environment]::NewLine,"โŽ")))240 241        # Verify we log that we are executing the created scriptblock242        $createdEvents[2].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f "Write\-Verbose 'testheader123' ;Write\-verbose 'after'")243    }244 245    # Skip test as it is failing in PowerShell CI on Linux platform.246    # Tracking Issue: https://github.com/PowerShell/PowerShell/issues/17092247    It 'Verifies scriptblock logging with null character' -Skip <#-Skip:(!$IsSupportedEnvironment)#> {248        $configFile = WriteLogSettings -LogId $logId -ScriptBlockLogging -LogLevel Verbose249        $script = @'250$PID251& ([scriptblock]::create("Write-Verbose 'testheader123$([char]0x0000)' ;Write-verbose 'after'"))252'@253        $testFileName = 'test01.ps1'254        $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName255        $script | Out-File -FilePath $testScriptPath -Force256        $null = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath257 258        # Get log entries from the last 100 that match our id and are after the time we launched Powershell259        $items = Get-PSSysLog -Path $SyslogFile -Id $logId -Tail 100 -Verbose -TotalCount 18260 261        $items | Should -Not -Be $null262        $items.Count | Should -BeGreaterThan 2263        $createdEvents = $items | Where-Object {$_.EventId -eq 'ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose'}264        $createdEvents.Count | Should -BeGreaterOrEqual 3265 266        # Verify we log that we are executing a file267        $createdEvents[0].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f ".*/$testFileName")268 269        # Verify we log that we are the script to create the scriptblock270        $createdEvents[1].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f (Get-RegEx -SimpleMatch $Script.Replace([System.Environment]::NewLine,"โŽ")))271 272        # Verify we log that we are executing the created scriptblock273        $createdEvents[2].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f "Write\-Verbose 'testheader123โ€' ;Write\-verbose 'after'")274    }275 276    It 'Verifies logging level filtering works' -Skip:(!$IsSupportedEnvironment) {277        $configFile = WriteLogSettings -LogId $logId -LogLevel Warning278        $result = & $powershell -NoProfile -SettingsFile $configFile -Command '$PID'279        $result | Should -Not -BeNullOrEmpty280 281        # by default, PowerShell only logs informational events on startup. With Level = Warning, nothing should282        # have been logged. We'll collect all the syslog entries and look for $PID (there should be none).283        $items = Get-PSSysLog -Path $SyslogFile284        @($items).Count | Should -BeGreaterThan 0285        $logs = $items | Where-Object { $_.ProcessId -eq $result }286        $logs | Should -BeNullOrEmpty287    }288}289 290Describe 'Basic os_log tests on MacOS' -Tag @('CI','RequireSudoOnUnix') {291    BeforeAll {292        [bool] $IsSupportedEnvironment = $IsMacOS293        [bool] $persistenceEnabled = $false294 295        $currentWarningPreference = $WarningPreference296        $WarningPreference = "SilentlyContinue"297 298        if ($IsSupportedEnvironment)299        {300            # Check the current state.301            $persistenceEnabled  = (Get-OSLogPersistence).Enabled302            if (!$persistenceEnabled)303            {304                # enable powershell log persistence to support exporting log entries305                # for each test306                Set-OsLogPersistence -Enable307            }308        }309        [string] $powershell = Join-Path -Path $PSHOME -ChildPath 'pwsh'310        $scriptBlockCreatedRegExTemplate = @'311Creating Scriptblock text \(1 of 1\):312{0}313ScriptBlock ID: [0-9a-z\-]*314Path:.*315'@316    }317 318    BeforeEach {319        if ($IsSupportedEnvironment)320        {321            # generate a unique log application id322            [string] $logId = [Guid]::NewGuid().ToString('N')323 324            # Generate a working directory and content file for Export-OSLog325            [string] $workingDirectory = Join-Path -Path $TestDrive -ChildPath $logId326            $null = New-Item -Path $workingDirectory -ItemType Directory -ErrorAction Stop327 328            [string] $contentFile = Join-Path -Path $workingDirectory -ChildPath ('pwsh.log.txt')329            # get log items after current time.330            [DateTime] $after = [DateTime]::Now331        }332    }333 334    AfterAll {335        $WarningPreference = $currentWarningPreference336        if ($IsSupportedEnvironment -and !$persistenceEnabled)337        {338            # disable persistence if it wasn't enabled339            Set-OsLogPersistence -Disable340        }341    }342 343    It 'Verifies basic logging with no customizations' -Skip:(!$IsMacOS) {344        try {345            $timeString = [DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss')346            $configFile = WriteLogSettings -LogId $logId347            copy-item $configFile /tmp/pwshtest.config.json348            $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command '$PID'349            $items = Get-MacOsSyslogItems -processId $testPid -logId $logId350 351            $items | Should -Not -Be $null352            $items.Count | Should -BeGreaterThan 2353            $items.EventId | Should -Contain 'Perftrack_ConsoleStartupStart:PowershellConsoleStartup.WinStart.Informational'354            $items.EventId | Should -Contain 'NamedPipeIPC_ServerListenerStarted:NamedPipe.Open.Informational'355            $items.EventId | Should -Contain 'Perftrack_ConsoleStartupStop:PowershellConsoleStartup.WinStop.Informational'356        }357        catch {358            if (Test-Path $contentFile) {359                Send-VstsLogFile -Path $contentFile360            }361            throw362        }363    }364 365    It 'Verifies scriptblock logging' -Skip:(!$IsMacOS) {366        try {367            $script = @'368$PID369& ([scriptblock]::create("Write-Verbose 'testheader123' ;Write-verbose 'after'"))370'@371            $configFile = WriteLogSettings -ScriptBlockLogging -LogId $logId -LogLevel Verbose372            $testFileName = 'test01.ps1'373            $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName374            $script | Out-File -FilePath $testScriptPath -Force375            $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath376            $items = Get-MacOsSyslogItems -processId $testPid -logId $logId377 378            $items | Should -Not -Be $null379            $items.Count | Should -BeGreaterThan 2380            $createdEvents = $items | Where-Object {$_.EventId -eq 'ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose'}381            $createdEvents.Count | Should -BeGreaterOrEqual 3382 383            $createdEvents | ConvertTo-Json | set-content /tmp/createdEvents.json384 385            # Verify we log that we are executing a file386            $createdEvents[0].EventMessage | Should -Match $testFileName387 388            # Verify we log that we are the script to create the scriptblock389            $createdEvents[1].EventMessage | Should -Match (Get-RegEx -SimpleMatch $Script)390 391            # Verify we log that we are executing the created scriptblock392            $createdEvents[2].EventMessage | Should -Match "Write-Verbose 'testheader123' ;Write-verbose 'after'"393        }394        catch {395            if (Test-Path $contentFile) {396                Send-VstsLogFile -Path $contentFile397            }398            throw399        }400    }401 402    It 'Verifies scriptblock logging with null character' -Skip:(!$IsMacOS) {403        try {404            $script = @'405$PID406& ([scriptblock]::create("Write-Verbose 'testheader123$([char]0x0000)' ;Write-verbose 'after'"))407'@408            $configFile = WriteLogSettings -ScriptBlockLogging -LogId $logId -LogLevel Verbose409            $testFileName = 'test02.ps1'410            $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName411            $script | Out-File -FilePath $testScriptPath -Force412            $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath | Select-Object -First 1413 414            $items = Get-MacOsSyslogItems -processId $testPid -logId $logId415            $items | convertto-json | set-content /tmp/items.json416 417            $createdEvents = $items | Where-Object {$_.EventId -eq 'ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose'}418 419            # Verify we log that we are executing a file420            $createdEvents[0].EventMessage | Should -Match $testFileName421 422            # Verify we log the null in the message423            $createdEvents[1].EventMessage | Should -Match "Write-Verbose 'testheader123\`$\(\[char\]0x0000\)' ;Write-verbose 'after'"424        }425        catch {426            if (Test-Path $contentFile) {427                Send-VstsLogFile -Path $contentFile428            }429            throw430        }431    }432 433    # this is now specific to MacOS434    It 'Verifies logging level filtering works' -skip:(!$IsMacOs) {435        $configFile = WriteLogSettings -LogId $logId -LogLevel Warning436        $testPid = & $powershell -NoLogo -NoProfile -SettingsFile $configFile -Command '$PID'437 438        $items = Get-MacOsSyslogItems -processId $testPid -logId $logId439        $items | Should -Be $null -Because ("{0} Warning event logs were found" -f @($items).Count)440    }441}442 443Describe 'Basic EventLog tests on Windows' -Tag @('CI','RequireAdminOnWindows') {444    BeforeAll {445        [bool] $IsSupportedEnvironment = $IsWindows446        [string] $powershell = Join-Path -Path $PSHOME -ChildPath 'pwsh'447 448        $currentWarningPreference = $WarningPreference449        $WarningPreference = "SilentlyContinue"450 451        $scriptBlockLoggingCases = @(452            @{453                name = 'normal script block'454                script = "Write-Verbose 'testheader123' ;Write-verbose 'after'"455                expectedText="Write-Verbose 'testheader123' ;Write-verbose 'after'`r`n"456            }457            @{458                name = 'script block with Null'459                script = "Write-Verbose 'testheader123$([char]0x0000)' ;Write-verbose 'after'"460                expectedText="Write-Verbose 'testheader123โ€' ;Write-verbose 'after'`r`n"461            }462        )463 464        if ($IsSupportedEnvironment)465        {466            & "$PSHOME\RegisterManifest.ps1"467        }468    }469 470    AfterAll {471        $WarningPreference = $currentWarningPreference472    }473 474    BeforeEach {475        if ($IsSupportedEnvironment)476        {477            # generate a unique log application id478            [string] $logId = [Guid]::NewGuid().ToString('N')479 480            $logName = 'PowerShellCore'481 482            # get log items after current time.483            [DateTime] $after = [DateTime]::Now484            Clear-PSEventLog -Name "$logName/Operational"485        }486    }487 488    It 'Verifies scriptblock logging: <name>' -Skip:(!$IsSupportedEnvironment) -TestCases $scriptBlockLoggingCases {489        param(490            [string] $script,491            [string] $expectedText,492            [string] $name493        )494        $configFile = WriteLogSettings -ScriptBlockLogging -LogId $logId495        $testFileName = 'test01.ps1'496        $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName497        $script | Out-File -FilePath $testScriptPath -Force498        $null = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath499 500        $created = Wait-PSWinEvent -FilterHashtable @{ ProviderName=$logName; Id = 4104 } `501            -PropertyName Message -PropertyValue $expectedText502 503        $created | Should -Not -BeNullOrEmpty504        $created.Properties[0].Value | Should -Be 1505        $created.Properties[1].Value | Should -Be 1506        $created.Properties[2].Value | Should -Be $expectedText507    }508}509