Powershell: No different color for syntax

Created on 2 Feb 2020  路  15Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

  1. Open PowerShell
PowerShell 7.0.0-rc.2
Copyright (c) Microsoft Corporation. All rights reserved.

https://aka.ms/powershell
Type 'help' to get help.

Warning: PowerShell detected that you might be using a screen reader and has disabled PSReadLine for compatibility purposes. If you want to re-enable it, run 'Import-Module PSReadLine'
  1. Type any PowerShell command

Note : I upgraded from Windows 10 Home to Windows 10 Education by the way.

image

Expected behavior

For PowerShell commands the color should be yellow

Actual behavior

  • Commands Color is not Yellow

Environment data

Name                           Value
----                           -----
PSVersion                      7.0.0-rc.2
PSEdition                      Core
GitCommitId                    7.0.0-rc.2
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Issue-Question

Most helpful comment

Here, run this:

Add-Type -TypeDefinition '
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public static class ScreenReaderFixUtil
{
    public static bool IsScreenReaderActive()
    {
        var ptr = IntPtr.Zero;
        try
        {
            ptr = Marshal.AllocHGlobal(sizeof(int));
            int hr = Interop.SystemParametersInfo(
                Interop.SPI_GETSCREENREADER,
                sizeof(int),
                ptr,
                0);

            if (hr == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            return Marshal.ReadInt32(ptr) != 0;
        }
        finally
        {
            if (ptr != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ptr);
            }
        }
    }

    public static void SetScreenReaderActiveStatus(bool isActive)
    {
        int hr = Interop.SystemParametersInfo(
            Interop.SPI_SETSCREENREADER,
            isActive ? 1u : 0u,
            IntPtr.Zero,
            Interop.SPIF_SENDCHANGE);

        if (hr == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    private static class Interop
    {
        public const int SPIF_SENDCHANGE = 0x0002;

        public const int SPI_GETSCREENREADER = 0x0046;

        public const int SPI_SETSCREENREADER = 0x0047;

        [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern int SystemParametersInfo(
            uint uiAction,
            uint uiParam,
            IntPtr pvParam,
            uint fWinIni);
    }
}'

if ([ScreenReaderFixUtil]::IsScreenReaderActive()) {
    [ScreenReaderFixUtil]::SetScreenReaderActiveStatus($false)
}

The flag for if a screen reader is active is persistent. So if an application at some point set the flag and then crashed before disabling it (or was written poorly), that flag will stay. This script will turn the flag off. This won't help if you still have a program that is actively setting the flag, but will help in the scenario I described.

All 15 comments

@pmahend1 coloring is provided by the PSReadLine module rather than PowerShell itself.

Can you verify that PSReadLine is imported with Get-Module PSReadLine?

By default it's not getting imported. Why?
I imported, it works as expected. I don't have any screen reader on, but still it says I have one.. Not even narrator.

@pmahend1 Do you have one installed? Just having NVDA installed is enough to trigger it for me. Might be worth opening an issue in PSReadLine, but I believe that's just how the win32 API they use works.

A workaround is to put Import-Module PSReadLine in your $profile.

@SeeminglyScience I dont know which program is being considered as screenreader.
Import-Module PSRreadLine does work , and I got to know PSReadLine is another github repository, but I see someone added code to check this and turn off PSReadLine in Powershell Core.

Can that be reverted?

Or how I can check which application is causing it?

Just upgraded to PowerShell 7.0.0 final and I am getting that same unexpected behavior (no color highlighting for syntax) and warning by default. I have neither NVDA nor any other screen reader, that I know of.

Warning: PowerShell detected that you might be using a screen reader and has disabled PSReadLine for compatibility purposes. If you want to re-enable it, run 'Import-Module PSReadLine'.

@neospect Do this.

PS>$PROFILE
C:\Users\<BlahBlah>\Documents\Powershell-Core\PowerShell_profile.ps1

Open and add this line to

Import-Module PSReadline

I have added "Import-Module PSReadLine" to the top of my $PROFILE. I now get colored syntax but I still get the warning every time I start a shell. It appears to come before $PROFILE gets executed. How to stop this junk! I don't even have NVDA.

@galversonNU same here. I was not able to identify which is that screen reader. Could be any application like Adobe, Firefox Chrome which have accessibility mode.
Wish there was some code to check it

Here, run this:

Add-Type -TypeDefinition '
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public static class ScreenReaderFixUtil
{
    public static bool IsScreenReaderActive()
    {
        var ptr = IntPtr.Zero;
        try
        {
            ptr = Marshal.AllocHGlobal(sizeof(int));
            int hr = Interop.SystemParametersInfo(
                Interop.SPI_GETSCREENREADER,
                sizeof(int),
                ptr,
                0);

            if (hr == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            return Marshal.ReadInt32(ptr) != 0;
        }
        finally
        {
            if (ptr != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ptr);
            }
        }
    }

    public static void SetScreenReaderActiveStatus(bool isActive)
    {
        int hr = Interop.SystemParametersInfo(
            Interop.SPI_SETSCREENREADER,
            isActive ? 1u : 0u,
            IntPtr.Zero,
            Interop.SPIF_SENDCHANGE);

        if (hr == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    private static class Interop
    {
        public const int SPIF_SENDCHANGE = 0x0002;

        public const int SPI_GETSCREENREADER = 0x0046;

        public const int SPI_SETSCREENREADER = 0x0047;

        [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern int SystemParametersInfo(
            uint uiAction,
            uint uiParam,
            IntPtr pvParam,
            uint fWinIni);
    }
}'

if ([ScreenReaderFixUtil]::IsScreenReaderActive()) {
    [ScreenReaderFixUtil]::SetScreenReaderActiveStatus($false)
}

The flag for if a screen reader is active is persistent. So if an application at some point set the flag and then crashed before disabling it (or was written poorly), that flag will stay. This script will turn the flag off. This won't help if you still have a program that is actively setting the flag, but will help in the scenario I described.

Dear Patrick,

That does indeed appear to fix the recurring warning.

Thanks very much!

Best regards,
George

Worth mentioning, that for me the culprit was a key in ComputerHKEY_CURRENT_USERControl PanelAccessibilityBlind Access. I set "On" to 0 and the problem disappeared. I have no clue how it got enabled to begin with.

Here, run this:

Add-Type -TypeDefinition '
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public static class ScreenReaderFixUtil
{
    public static bool IsScreenReaderActive()
    {
        var ptr = IntPtr.Zero;
        try
        {
            ptr = Marshal.AllocHGlobal(sizeof(int));
            int hr = Interop.SystemParametersInfo(
                Interop.SPI_GETSCREENREADER,
                sizeof(int),
                ptr,
                0);

            if (hr == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            return Marshal.ReadInt32(ptr) != 0;
        }
        finally
        {
            if (ptr != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ptr);
            }
        }
    }

    public static void SetScreenReaderActiveStatus(bool isActive)
    {
        int hr = Interop.SystemParametersInfo(
            Interop.SPI_SETSCREENREADER,
            isActive ? 1u : 0u,
            IntPtr.Zero,
            Interop.SPIF_SENDCHANGE);

        if (hr == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    private static class Interop
    {
        public const int SPIF_SENDCHANGE = 0x0002;

        public const int SPI_GETSCREENREADER = 0x0046;

        public const int SPI_SETSCREENREADER = 0x0047;

        [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern int SystemParametersInfo(
            uint uiAction,
            uint uiParam,
            IntPtr pvParam,
            uint fWinIni);
    }
}'

if ([ScreenReaderFixUtil]::IsScreenReaderActive()) {
    [ScreenReaderFixUtil]::SetScreenReaderActiveStatus($false)
}

The flag for if a screen reader is active is persistent. So if an application _at some point_ set the flag and then crashed before disabling it (or was written poorly), that flag will stay. This script will turn the flag off. This won't help if you still have a program that is actively setting the flag, but will help in the scenario I described.

I am getting this error:

Program.cs(1,1): error CS8652: The feature 'top-level statements' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(1,26): error CS1002: ; expected [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(1,26): error CS1010: Newline in constant [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(1,26): error CS1011: Empty character literal [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(1,27): error CS1002: ; expected [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(2,1): error CS1529: A using clause must precede all other elements defined in the namespace except extern alias declarations [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(3,1): error CS1529: A using clause must precede all other elements defined in the namespace except extern alias declarations [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(4,1): error CS1529: A using clause must precede all other elements defined in the namespace except extern alias declarations [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(65,2): error CS8803: Top-level statements must precede namespace and type declarations. [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(65,2): error CS1010: Newline in constant [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(65,2): error CS1011: Empty character literal [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(65,3): error CS1002: ; expected [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(67,5): error CS1525: Invalid expression term '[' [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(67,26): error CS7000: Unexpected use of an aliased name [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(68,26): error CS1001: Identifier expected [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(68,56): error CS1056: Unexpected character '$' [C:\Users\alan\Desktop\Fixer\Fixer.csproj]
Program.cs(68,63): error CS1002: ; expected [C:\Users\alan\Desktop\Fixer\Fixer.csproj]

This issue was affecting us with VSCode's terminal window.
Running @SeeminglyScience's script as a .ps1 file worked for me.
But I'd like to know what a 'screen reader' is and what are the popular ones.

Worth mentioning, that for me the culprit was a key in ComputerHKEY_CURRENT_USERControl PanelAccessibilityBlind Access. I set "On" to 0 and the problem disappeared. I have no clue how it got enabled to begin with.

I checked this particular registry key and its value was 1. I changed it to 0 and now I don't have any issues

Here, run this:

Add-Type -TypeDefinition '
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public static class ScreenReaderFixUtil
{
    public static bool IsScreenReaderActive()
    {
        var ptr = IntPtr.Zero;
        try
        {
            ptr = Marshal.AllocHGlobal(sizeof(int));
            int hr = Interop.SystemParametersInfo(
                Interop.SPI_GETSCREENREADER,
                sizeof(int),
                ptr,
                0);

            if (hr == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            return Marshal.ReadInt32(ptr) != 0;
        }
        finally
        {
            if (ptr != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ptr);
            }
        }
    }

    public static void SetScreenReaderActiveStatus(bool isActive)
    {
        int hr = Interop.SystemParametersInfo(
            Interop.SPI_SETSCREENREADER,
            isActive ? 1u : 0u,
            IntPtr.Zero,
            Interop.SPIF_SENDCHANGE);

        if (hr == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    private static class Interop
    {
        public const int SPIF_SENDCHANGE = 0x0002;

        public const int SPI_GETSCREENREADER = 0x0046;

        public const int SPI_SETSCREENREADER = 0x0047;

        [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern int SystemParametersInfo(
            uint uiAction,
            uint uiParam,
            IntPtr pvParam,
            uint fWinIni);
    }
}'

if ([ScreenReaderFixUtil]::IsScreenReaderActive()) {
    [ScreenReaderFixUtil]::SetScreenReaderActiveStatus($false)
}

The flag for if a screen reader is active is persistent. So if an application _at some point_ set the flag and then crashed before disabling it (or was written poorly), that flag will stay. This script will turn the flag off. This won't help if you still have a program that is actively setting the flag, but will help in the scenario I described.

Oh! I was supposed to run this as a PowerShell script.

Was this page helpful?
0 / 5 - 0 ratings