Skip to content

Commit

Permalink
Add public function Assert-ElevatedUser (#84)
Browse files Browse the repository at this point in the history
- Add public function `Assert-ElevatedUser` that asserts the user has elevated
  the PowerShell session. issue #82
  • Loading branch information
hollanjs authored and johlju committed Dec 10, 2022
1 parent 33d50dc commit a26f4e4
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 1 deletion.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added public function `Assert-ElevatedUser` that asserts the user has elevated
the PowerShell session. [issue #82](https://github.com/dsccommunity/DscResource.Common/issues/71)
- Related to SqlServerDsc [issue #1797](https://github.com/dsccommunity/SqlServerDsc/issues/1797).

## [0.11.1] - 2022-08-18

### Changed
Expand Down
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,40 @@ Assert-BoundParameter @assertBoundParameterParameters
This example throws an exception if `$PSBoundParameters` contains both
the parameters `Parameter1` and `Parameter2`.

### `Assert-ElevatedUser`

Assert that the user has elevated the PowerShell session.

`Assert-ElevatedUser` will throw a statement-terminating error if the
script is not run from an elevated session.

#### Syntax

<!-- markdownlint-disable MD013 - Line length -->
```plaintext
Assert-ElevatedUser [<CommonParameters>]
```
<!-- markdownlint-enable MD013 - Line length -->

#### Outputs

None.

#### Example

```powershell
`Assert-ElevatedUser -ErrorAction 'Stop'`
```

This example stops the entire script if it is not run from an
elevated PowerShell session.

### `Assert-IPAddress`

Asserts if the IP Address is valid and optionally validates
the IP Address against an Address Family

### Syntax
#### Syntax

```plaintext
Assert-IPAddress [-Address] <string> [[-AddressFamily] <string>] [<CommonParameters>]
Expand Down
45 changes: 45 additions & 0 deletions source/Public/Assert-ElevatedUser.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<#
.SYNOPSIS
Assert that the user has elevated the PowerShell session.
.DESCRIPTION
Assert that the user has elevated the PowerShell session.
.EXAMPLE
Assert-ElevatedUser
Throws an exception if the user has not elevated the PowerShell session.
.OUTPUTS
None.
#>
function Assert-ElevatedUser
{
[CmdletBinding()]
param ()

$isElevated = $false

if ($IsMacOS -or $IsLinux)
{
$isElevated = (id -u) -eq 0
}
else
{
[Security.Principal.WindowsPrincipal] $user = [Security.Principal.WindowsIdentity]::GetCurrent()

$isElevated = $user.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

if (-not $isElevated)
{
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$script:localizedData.IsElevated_UserNotElevated,
'UserNotElevated',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
)
}
}
1 change: 1 addition & 0 deletions source/en-US/DscResource.Common.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ ConvertFrom-StringData @'
PropertyNotInDesiredState = The parameter '{0}' is not in desired state. (DRC0040)
PropertyNotInDesiredStateMessage = Property '{0}' is not in desired state. (DRC0041)
NoMatchKeyMessage = NOTMATCH: Value (type '{0}') for property '{1}' does not match. Current state has the key(s) '{2}' and desired state has not. (DRC0042)
IsElevated_UserNotElevated = This command must run in an elevated PowerShell session. (DRC0043)
'@
114 changes: 114 additions & 0 deletions tests/Unit/Public/Assert-ElevatedUser.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
param ()

BeforeDiscovery {
try
{
if (-not (Get-Module -Name 'DscResource.Test'))
{
# Assumes dependencies has been resolved, so if this module is not available, run 'noop' task.
if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null
}

# If the dependencies has not been resolved, this will throw an error.
Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
}
}
catch [System.IO.FileNotFoundException]
{
throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
}
}

BeforeAll {
$script:dscModuleName = 'DSCResource.Common'

Import-Module -Name $script:dscModuleName

$PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName
$PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName
$PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName
}

AfterAll {
$PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
$PSDefaultParameterValues.Remove('Mock:ModuleName')
$PSDefaultParameterValues.Remove('Should:ModuleName')

# Unload the module being tested so that it doesn't impact any other tests.
Get-Module -Name $script:dscModuleName -All | Remove-Module -Force
}

Describe 'Assert-ElevatedUser' -Tag 'Private' {
BeforeDiscovery {
<#
Since it is not possible to elevated (or un-elevate) a user during testing
the test that cannot run need to be skipped.
#>
if ($IsMacOS -or $IsLinux)
{
$mockIsElevated = (id -u) -eq 0
}
else
{
[Security.Principal.WindowsPrincipal] $mockCurrentUser = [Security.Principal.WindowsIdentity]::GetCurrent()

$mockIsElevated = $mockCurrentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}
}

It 'Should throw the correct error' -Skip:$mockIsElevated {
InModuleScope -ScriptBlock {
$mockErrorMessage = $script:localizedData.IsElevated_UserNotElevated

{ Assert-ElevatedUser } | Should -Throw -ExpectedMessage $mockErrorMessage
}
}

It 'Should not throw an exception' -Skip:(-not $mockIsElevated) {
InModuleScope -ScriptBlock {
{ Assert-ElevatedUser } | Should -Not -Throw
}
}

Context 'When on Linux or macOS' {
BeforeAll {
$previousIsMacOS = InModuleScope -ScriptBlock {
$IsMacOS
}

InModuleScope -ScriptBlock {
$script:IsMacOS = $true

# Stub for command 'id'.
function id
{
throw '{0}: StubNotImplemented' -f $MyInvocation.MyCommand
}

Mock -CommandName id -MockWith {
return 0
}
}
}

AfterAll {
$inModuleScopeParameters = @{
PreviousIsMacOS = $previousIsMacOS
}

InModuleScope -Parameters $inModuleScopeParameters -ScriptBlock {
$script:IsMacOS = $PreviousIsMacOS
}
}

It 'Should not throw an exception' {
InModuleScope -ScriptBlock {
{ Assert-ElevatedUser } | Should -Not -Throw
}
}
}
}

0 comments on commit a26f4e4

Please sign in to comment.