Skip to content

Commit

Permalink
Merge pull request #3 from webmd-health-services/feature/type-data-fu…
Browse files Browse the repository at this point in the history
…nctions-from-carbon

1.1.0  Add type data functions from Carbon
  • Loading branch information
splatteredbits authored Jul 26, 2022
2 parents c0a7f65 + 3cba228 commit f1f477d
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 126 deletions.
63 changes: 63 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

# 1.1.0

Added `Test-CTypeDataMember` and `Add-CTypeData` functions for testing if a type has any defined custom type data and
adding custom type data, respectively. Defining type data with .ps1xml files can result in errors importing the same
module multiple times: PowerShell complains that the type data is already defined. Using `Add-CTypeData` prevents these
this error as it only adds members that don't already exist.


# 1.0.0

## Upgrade Instructions

We're breaking up Carbon into smaller and more targeted modules. Hopefully, this will help maintenance, and make it
easier to use Carbon across many versions and editions of PowerShell. This module will be the place where core functions
used by other Carbon modules will be put.

If you're upgrading from Carbon to this module, you should do the following:

* Replace usages of `Test-COSIs64Bit` with `Test-COperatingSystem -Is64Bit`.
* Replace usages of `Test-COSIs32Bit` with `Test-COperatingSystem -Is32Bit`.
* Replace usages of `Test-CPowerShellIs32Bit` with `Test-CPowerShell -Is32Bit`.
* Replace usages of `Test-CPowerShellIs64Bit` with `Test-CPowerShell -Is64Bit`.
* Rename usages of the `ConvertTo-CBase64` function's `Value` parameter to `InputObject`, or pipe the value to the
function instead.

We made a lot of changes to the `Invoke-CPowerShell` function:

* The `Invoke-CPowerShell` function no longer allows you to pass script blocks. Instead, convert your script block to
a string, and pass that string to the `Command` parameter. This will base64 encode the command and pass it to
PowerShell's -EncodedCommand property.
* The `Invoke-CPowerShell` function no longer has `FilePath`, `OutputFormat`, `ExecutionPolicy`, `NonInteractive`,
or `Runtime` parameters. Instead, pass these as arguments to the `ArgumentList` parameter, e.g.
`-ArgumentList @('-NonInteractive', '-ExecutionPolicy', 'Bypasss')`. You are now responsible for passing all PowerShell
arguments via the `ArgumentList` parameter.
* The `Invoke-CPowerShell` function no longer supports running PowerShell 2 under .NET 4.
* Remove the `-Encode` switch. `Invoke-CPowerShell` now always base64 encodes the value of the `Command` parameter.
* The `Invoke-CPowerShell` function only accepts strings to the `-Command` parameter. Check all usages to ensure you're
passing a string.
* The `Invoke-CPowerShell` function now returns output when running PowerShell as a different user. You may see more
output in your scripts.


## Changes Since Carbon 2.9.4

* Migrated `Invoke-CPowerShell` and `ConvertTo-CBase64` from Carbon.
* `ConvertTo-CBase64` now converts chars, ints (signed and unsigned, 16, 32, and 64-bit sizes), floats, and doubles to
base64. You can now also pipe an array of bytes or chars and it will collect each item in the array and encode them at
as one unit.
* Renamed the `ConvertTo-CBase64` function's `Value` parameter to `InputObject`.
* Created `Test-COperatingSystem` function that can test if the current OS is 32-bit, 62-bit, Windows, Linux, and/or
macOS. This function was adapted from and replaces's Carbon's `Test-COSIs64Bit` and `Test-COSIs32Bit`.
* Created `Test-CPowerShell` function that can test if the current PowerShell instance is 32-bit, 64-bit, Core edition,
or Desktop edition. It treats versions of PowerShell that don't specify a version as "Desktop". This function was
adapted from and replaces Carbon's `Test-CPowerShellIs32Bit` and `Test-CPowerShellIs64Bit` functions.
* `Invoke-CPowerShell` now works on Linux and macOS. On Windows, it will start a new PowerShell process using the same
edition. If you want to use a custom version of PowerShell, pass the path to the PowerShell executable to use to the
new `Path` parameter.

## Known Issues
* There is a bug in PowerShell Core on Linux/macOS that fails when running `Start-Job` with a custom credential. The
`Invoke-CPowerShell` function will fail when run on Linux/MacOS using a custom credential. See
https://github.com/PowerShell/PowerShell/issues/7172 for more information.
65 changes: 7 additions & 58 deletions Carbon.Core/Carbon.Core.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
RootModule = 'Carbon.Core.psm1'

# Version number of this module.
ModuleVersion = '1.0.0'
ModuleVersion = '1.1.0'

# ID used to uniquely identify this module
GUID = '20DA9F42-23C4-4917-8597-DCFD7EE4AD00'
Expand Down Expand Up @@ -76,12 +76,14 @@

# Functions to export from this module. Only list public function here.
FunctionsToExport = @(
'Add-CTypeData',
'ConvertTo-CBase64',
'Get-CPowerShellPath',
'Invoke-CPowerShell',
'Start-CPowerShellProcess',
'Test-COperatingSystem',
'Test-CPowerShell'
'Test-CPowerShell',
'Test-CTypeDataMember'
)

# Cmdlets to export from this module. By default, you get a script module, so there are no cmdlets.
Expand Down Expand Up @@ -110,8 +112,8 @@
# Tags applied to this module. These help with module discovery in online galleries.
Tags = @(
'Carbon', 'Desktop', 'Core', 'encoding', 'convert', 'convertto', 'text', 'base64', 'invoke', 'os',
'operating-system', 'architecture', 'powershell', 'pwsh', 'runas', 'credential', 'x86', 'x64',
'windows', 'linux', 'macos' )
'operating', 'system', 'architecture', 'powershell', 'pwsh', 'runas', 'credential', 'x86', 'x64',
'windows', 'linux', 'macos', 'type', 'data', 'update-typedata', 'member', 'add-member' )

# A URL to the license for this module.
LicenseUri = 'http://www.apache.org/licenses/LICENSE-2.0'
Expand All @@ -125,60 +127,7 @@
Prerelease = ''

# ReleaseNotes of this module
ReleaseNotes = @'
# Upgrade Instructions
We're breaking up Carbon into smaller and more targeted modules. Hopefully, this will help maintenance, and make it
easier to use Carbon across many versions and editions of PowerShell. This module will be the place where core functions
used by other Carbon modules will be put.
If you're upgrading from Carbon to this module, you should do the following:
* Replace usages of `Test-COSIs64Bit` with `Test-COperatingSystem -Is64Bit`.
* Replace usages of `Test-COSIs32Bit` with `Test-COperatingSystem -Is32Bit`.
* Replace usages of `Test-CPowerShellIs32Bit` with `Test-CPowerShell -Is32Bit`.
* Replace usages of `Test-CPowerShellIs64Bit` with `Test-CPowerShell -Is64Bit`.
* Rename usages of the `ConvertTo-CBase64` function's `Value` parameter to `InputObject`, or pipe the value to the
function instead.
We made a lot of changes to the `Invoke-CPowerShell` function:
* The `Invoke-CPowerShell` function no longer allows you to pass script blocks. Instead, convert your script block to
a string, and pass that string to the `Command` parameter. This will base64 encode the command and pass it to
PowerShell's -EncodedCommand property.
* The `Invoke-CPowerShell` function no longer has `FilePath`, `OutputFormat`, `ExecutionPolicy`, `NonInteractive`,
or `Runtime` parameters. Instead, pass these as arguments to the `ArgumentList` parameter, e.g.
`-ArgumentList @('-NonInteractive', '-ExecutionPolicy', 'Bypasss'). You are now responsible for passing all PowerShell
arguments via the `ArgumentList` parameter.
* The `Invoke-CPowerShell` function no longer supports running PowerShell 2 under .NET 4.
* Remove the `-Encode` switch. `Invoke-CPowerShell` now always base64 encodes the value of the `Command` parameter.
* The `Invoke-CPowerShell` function only accepts strings to the `-Command` parameter. Check all usages to ensure you're
passing a string.
* The `Invoke-CPowerShell` function now returns output when running PowerShell as a different user. You may see more
output in your scripts.
# Changes Since Carbon 2.9.4
* Migrated `Invoke-CPowerShell` and `ConvertTo-CBase64` from Carbon.
* `ConvertTo-CBase64` now converts chars, ints (signed and unsigned, 16, 32, and 64-bit sizes), floats, and doubles to
base64. You can now also pipe an array of bytes or chars and it will collect each item in the array and encode them at
as one unit.
* Renamed the `ConvertTo-CBase64` function's `Value` parameter to `InputObject`.
* Created `Test-COperatingSystem` function that can test if the current OS is 32-bit, 62-bit, Windows, Linux, and/or
macOS. This function was adapted from and replaces's Carbon's `Test-COSIs64Bit` and `Test-COSIs32Bit`.
* Created `Test-CPowerShell` function that can test if the current PowerShell instance is 32-bit, 64-bit, Core edition,
or Desktop edition. It treats versions of PowerShell that don't specify a version as "Desktop". This function was
adapted from and replaces Carbon's `Test-CPowerShellIs32Bit` and `Test-CPowerShellIs64Bit` functions.
* `Invoke-CPowerShell` now works on Linux and macOS. On Windows, it will start a new PowerShell process using the same
edition. If you want to use a custom version of PowerShell, pass the path to the PowerShell executable to use to the
new `Path` parameter.
# Known Issues
* There is a bug in PowerShell Core on Linux/macOS that fails when running `Start-Job` with a custom credential. The
`Invoke-CPowerShell` function will fail when run on Linux/MacOS using a custom credential. See
https://github.com/PowerShell/PowerShell/issues/7172 for more information.
'@
ReleaseNotes = 'https://github.com/webmd-health-services/Carbon.Core/blob/main/CHANGELOG.md'
} # End of PSData hashtable

} # End of PrivateData hashtable
Expand Down
115 changes: 115 additions & 0 deletions Carbon.Core/Functions/Add-CTypeData.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
function Add-CTypeData
{
<#
.SYNOPSIS
Adds type data to a type only if the type data doesn't already exist.
.DESCRIPTION
The `Add-CTypeData` function uses PowerShell's `Update-TypeData` cmdlet to add type data to a type, but only if the
given type data doesn't already exist. Pass the type to the `Type` parameter or the type name to the `TypeName`
parameter, the new type data member type to the `MemberType` parameter (e.g. `AliasProperty`, `NoteProperty`,
`ScriptProperty`, or `ScriptMethod`), the member name to the `MemberName` parameter, and the member's
value/implementation to the `Value` parameter.
Note that the `Type` parameter should be the bare name of the type, e.g. `Diagnostics.Process`, *without* square
brackets.
If the type already has an equivalent member with the name given by the `MemberName` parameter, nothing happens, and
the function returns.
.EXAMPLE
Add-CTypeData -Type Diagnostics.Process -MemberType ScriptProperty -MemberName 'ParentID' -Value $scriptBlock
Demonstrates how to create a script property on a type. In this example, the `System.Diagnostics.Process` type will
be given a `ParentID` property that runs the code in the script block in the `$scriptBlock` variable.
.EXAMPLE
Add-CTypeData -Type Diagnostics.Process -MemberType ScriptMethod -MemberName 'GetParentID()' -Value $scriptBlock
Demonstrates how to create a script method on a type. In this example, the `System.Diagnostics.Process` type will
be given a `GetParentID()` method that runs the code in the script block in the `$scriptBlock` variable.
.EXAMPLE
Add-CTypeData -Type Diagnostics.Process -MemberType AliasProperty -MemberName 'ProcessId' -Value 'Id'
Demonstrates how to create an alias script property on a type. In this example, the `System.Diagnostics.Process`
type will be given a `ProcessId` property that is an alias to the 'Id' property.
.EXAMPLE
Add-CTypeData -Type Diagnostics.Process -MemberType NoteProperty -MemberName 'ParentID' -Value $parentPid
Demonstrates how to create a ntoe property on a type. In this example, the `System.Diagnostics.Process` type will
be given a `ParentID` property that returns the value in the `$parentPid` variable.
#>
[CmdletBinding()]
param(
# The type on which to add the type data. This should be the bare type name, e.g. Diagnostics.Process, *not*
# the type surrounded by square brackets, e.g. `[Diagnostics.Process]`.
[Parameter(Mandatory, ParameterSetName='ByType')]
[Type] $Type,

# The name of the type on which to add the type data.
[Parameter(Mandatory, ParameterSetName='ByTypeName')]
[String] $TypeName,

# The member type of the new type data. Only `AliasProperty`, `NoteProperty`, `ScriptProperty`, `ScriptMethod`
# are supported.
[Parameter(Mandatory)]
[ValidateSet('AliasProperty', 'NoteProperty', 'ScriptProperty', 'ScriptMethod')]
[Management.Automation.PSMemberTypes] $MemberType,

# The type data's member name.
[Parameter(Mandatory)]
[String] $MemberName,

# The value for the member. If `MemberName` is:
#
# * `AliasProperty`, this should be the name of the target property.
# * `NoteProperty`, the literal value of the property.
# * `ScriptProperty`, a script block that return's the property value.
# * `ScriptMethod`, a script block that implements the method logic.
[Parameter(Mandatory)]
[Object] $Value
)

Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState

$memberTypeMsg = '{0,-14}' -f $MemberType

if( -not $TypeName )
{
$TypeName = $Type.FullName
}

if( $Type )
{
if( $MemberType -like '*Property' )
{
if( ($Type.GetProperties() | Where-Object Name -EQ $MemberName) )
{
Write-Debug ("Type $($memberTypeMsg) [$($TypeName)] $($MemberName)")
return
}
}
elseif( $MemberType -like '*Method')
{
if( ($Type.GetMethods() | Where-Object Name -EQ $MemberName) )
{
Write-Debug ("Type $($memberTypeMsg) [$($TypeName)] $($MemberName)")
return
}
}
}

$typeData = Get-TypeData -TypeName $TypeName
if( $typeData -and $typeData.Members.ContainsKey($MemberName) )
{
Write-Debug ("TypeData $($memberTypeMsg) [$($TypeName)] $($MemberName)")
return
}

Write-Debug ("TypeData + $($memberTypeMsg) [$($TypeName)] $($MemberName)")
Update-TypeData -TypeName $TypeName -MemberType $MemberType -MemberName $MemberName -Value $Value
}

44 changes: 44 additions & 0 deletions Carbon.Core/Functions/Test-CTypeDataMember.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

function Test-CTypeDataMember
{
<#
.SYNOPSIS
Tests if a type has an extended type member defined.
.DESCRIPTION
`Test-CTypeDataMember` tests if a type has an extended type member defined. If the type isn't found, you'll get an
error.
Returns `$true` if the type is found and the member is defined. Otherwise, returns `$false`.
.EXAMPLE
Test-CTypeDataMember -TypeName 'Microsoft.Web.Administration.Site' -MemberName 'PhysicalPath'
Tests if the `Microsoft.Web.Administration.Site` type has a `PhysicalPath` extended type member defined.
#>
[CmdletBinding()]
[OutputType([bool])]
param(
# The type name to check.
[Parameter(Mandatory)]
[String] $TypeName,

# The name of the member to check.
[Parameter(Mandatory)]
[String] $MemberName
)

Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState

$typeData = Get-TypeData -TypeName $TypeName
if( -not $typeData )
{
# The type isn't defined or there is no extended type data on it.
return $false
}

return $typeData.Members.ContainsKey( $MemberName )
}


Loading

0 comments on commit f1f477d

Please sign in to comment.