PowerShell and security
PowerShell security is an issue for most IT professionals. PowerShell comes with various security features that can help you both harden PowerShell and improve your environment’s security.
Security by default
The PowerShell team designed PowerShell to be secure by default. But it provides IT professionals with great power at the same time. And with great power comes great responsibility.
Windows has a wealth of access control mechanisms, such as the Access Control List (ACL) with Windows NT File System. As an administrator, setting the ACL on files and objects in Active Directory is an important line of defense. If you set an ACL that denies some user access, that user cannot use PowerShell to bypass the ACL. Likewise, numerous commands require that you run PowerShell as an administrator.
But anyone possessing administrator credentials can do almost anything on a system.
PowerShell logging
PowerShell records a variety of actions in Windows event logs automatically. These include the PowerShell engine starting up, shutting down, and more. Windows PowerShell and PowerShell 7 log the same events but use different Windows event logs.
Windows PowerShell sends event details to the event log, Windows PowerShell (underneath Applications and Services Logs in Event Viewer). PowerShell 7 writes event log entries to the PowerShellCore event log (also underneath Applications and Services Logs in Event Viewer).
From a forensic point of view, these event log entries may be useful to discover when someone uses PowerShell on a given host. To learn more about PowerShell and logging, see https://packt.link/CpBO7.
PowerShell script block logging
In addition to logging basic PowerShell engine events, PowerShell can also log any script block executed on a given host. This form of logging captures a script’s complete activity and content, providing a full audit trail of a PowerShell session.
Powershell does not enable logging by default since a performance overhead is associated with event logging, particularly script block logging. You can change this manually on a given host or via Group Policy.
The about_Logging page, noted previously, contains more information about script block logging. You can also refer to the following blog post: https://packt.link/hq0tE.
Module logging
You can turn on logging for specified PowerShell modules. If you turn on module logging for a given module, PowerShell logs pipeline execution events into the event log.
Execution policy
PowerShell has an execution policy that controls a user’s ability to run any PowerShell script directly. You can use the Set-ExecutionPolicy
to change the policy and Get-ExecutionPolicy
to view the current policy.
You can set the execution policy to different values:
AllSigned
: All scripts or configuration files must be signed by a trusted publisher.RemoteSigned
: Scripts and configuration files downloaded by the internet must be signed by a trusted publisher, while you can execute scripts authored locally.Restricted
: PowerShell does not load configuration files or run any scripts. Note: This is the default for Windows 11 hosts!Unrestricted
: PowerShell runs any script and loads all configuration files.Bypass
: PowerShell blocks nothing and issues no warning messages.Default
: Sets the execution policy to Restricted on Windows 11 hosts (and sets the policy to RemoteSigned on Windows Server systems).
Note that the execution policy is not a security barrier, but more of a minor speed bump. While a restrictive policy may stop you from running a script, you can open the file in a text editor such as Notepad, copy all the text, paste it into PowerShell, and PowerShell runs the script. For a more detailed look at execution policies, see the help file at https://packt.link/JLOd6.
Many (and possibly most) administrators use Set-ExecutionPolicy
to set the policy on the local machine to Unrestricted
and perform the administrative task. Sometimes, they may even remember to set it back to the default. As noted in the help document, you can also use the -Scope
parameter to limit the change of the execution policy in line with the current process.
In large production environments, signing the scripts you use in the enterprise, using your firm’s private key infrastructure is a best practice. You, or your security team, would need to create an X.509 certificate that enables code signing. Then you can use the Set-AuthenticodeSignature
to sign scripts.
If you plan to employ code-signing PowerShell scripts, you must clearly define the process of script signing, including detailed testing and vetting. You must ensure a good script signing process, including who can access the signing key (and how). If the certificate is put on a local file server for anyone to use, code signing achieves nothing.
Transcription
You can use the Start-Transcript
cmdlet to create a detailed plain text record of all or part of a PowerShell session. You can either set this in a script (to memorialize the execution of a script) or within a PowerShell session to record the details of the session. You use Stop-Transcript
to stop the recording.
You can also enforce transcripts of all PowerShell sessions via Group Policy. If you do a lot of transcription, remember to implement a process to review the transcripts and clear or archive older files.