diff --git a/Coverage.md b/Coverage.md
index 8b23f278b..9be081a39 100644
--- a/Coverage.md
+++ b/Coverage.md
@@ -9,15 +9,15 @@
| Covered functions |
- 160 |
+ 180 |
| Missing functions |
- 855 |
+ 835 |
| Coverage |
- 15.76% |
+ 17.73% |
@@ -146,9 +146,9 @@
| `/orgs/{org}/code-security/configurations/{configuration_id}/attach` | | | | :x: | |
| `/orgs/{org}/code-security/configurations/{configuration_id}/defaults` | | | | | :x: |
| `/orgs/{org}/code-security/configurations/{configuration_id}/repositories` | | :x: | | | |
-| `/orgs/{org}/codespaces` | | :x: | | | |
-| `/orgs/{org}/codespaces/access` | | | | | :x: |
-| `/orgs/{org}/codespaces/access/selected_users` | :x: | | | :x: | |
+| `/orgs/{org}/codespaces` | | :white_check_mark: | | | |
+| `/orgs/{org}/codespaces/access` | | | | | :white_check_mark: |
+| `/orgs/{org}/codespaces/access/selected_users` | :white_check_mark: | | | :white_check_mark: | |
| `/orgs/{org}/codespaces/secrets` | | :x: | | | |
| `/orgs/{org}/codespaces/secrets/public-key` | | :x: | | | |
| `/orgs/{org}/codespaces/secrets/{secret_name}` | :x: | :x: | | | :x: |
@@ -193,10 +193,10 @@
| `/orgs/{org}/invitations/{invitation_id}/teams` | | :x: | | | |
| `/orgs/{org}/issues` | | :x: | | | |
| `/orgs/{org}/members` | | :white_check_mark: | | | |
-| `/orgs/{org}/members/{username}` | :x: | :x: | | | |
-| `/orgs/{org}/members/{username}/codespaces` | | :x: | | | |
+| `/orgs/{org}/members/{username}` | :x: | :white_check_mark: | | | |
+| `/orgs/{org}/members/{username}/codespaces` | | :white_check_mark: | | | |
| `/orgs/{org}/members/{username}/codespaces/{codespace_name}` | :x: | | | | |
-| `/orgs/{org}/members/{username}/codespaces/{codespace_name}/stop` | | | | :x: | |
+| `/orgs/{org}/members/{username}/codespaces/{codespace_name}/stop` | | | | :white_check_mark: | |
| `/orgs/{org}/members/{username}/copilot` | | :x: | | | |
| `/orgs/{org}/memberships/{username}` | :x: | :x: | | | :x: |
| `/orgs/{org}/migrations` | | :x: | | :x: | |
@@ -383,8 +383,8 @@
| `/repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}` | | :x: | | | |
| `/repos/{owner}/{repo}/code-security-configuration` | | :x: | | | |
| `/repos/{owner}/{repo}/codeowners/errors` | | :white_check_mark: | | | |
-| `/repos/{owner}/{repo}/codespaces` | | :x: | | :x: | |
-| `/repos/{owner}/{repo}/codespaces/devcontainers` | | :x: | | | |
+| `/repos/{owner}/{repo}/codespaces` | | :white_check_mark: | | :white_check_mark: | |
+| `/repos/{owner}/{repo}/codespaces/devcontainers` | | :white_check_mark: | | | |
| `/repos/{owner}/{repo}/codespaces/machines` | | :x: | | | |
| `/repos/{owner}/{repo}/codespaces/new` | | :x: | | | |
| `/repos/{owner}/{repo}/codespaces/permissions_check` | | :x: | | | |
@@ -511,13 +511,13 @@
| `/repos/{owner}/{repo}/private-vulnerability-reporting` | :white_check_mark: | :x: | | | :white_check_mark: |
| `/repos/{owner}/{repo}/projects` | | :x: | | :x: | |
| `/repos/{owner}/{repo}/properties/values` | | :white_check_mark: | :x: | | |
-| `/repos/{owner}/{repo}/pulls` | | :white_check_mark: | | :x: | |
+| `/repos/{owner}/{repo}/pulls` | | :white_check_mark: | | :white_check_mark: | |
| `/repos/{owner}/{repo}/pulls/comments` | | :x: | | | |
| `/repos/{owner}/{repo}/pulls/comments/{comment_id}` | :x: | :x: | :x: | | |
| `/repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions` | | :x: | | :x: | |
| `/repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions/{reaction_id}` | :x: | | | | |
| `/repos/{owner}/{repo}/pulls/{pull_number}` | | :x: | :x: | | |
-| `/repos/{owner}/{repo}/pulls/{pull_number}/codespaces` | | | | :x: | |
+| `/repos/{owner}/{repo}/pulls/{pull_number}/codespaces` | | | | :white_check_mark: | |
| `/repos/{owner}/{repo}/pulls/{pull_number}/comments` | | :x: | | :x: | |
| `/repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies` | | | | :x: | |
| `/repos/{owner}/{repo}/pulls/{pull_number}/commits` | | :x: | | | |
@@ -606,19 +606,19 @@
| `/user` | | :white_check_mark: | :white_check_mark: | | |
| `/user/blocks` | | :white_check_mark: | | | |
| `/user/blocks/{username}` | :white_check_mark: | :white_check_mark: | | | :white_check_mark: |
-| `/user/codespaces` | | :x: | | :x: | |
+| `/user/codespaces` | | :white_check_mark: | | :white_check_mark: | |
| `/user/codespaces/secrets` | | :x: | | | |
| `/user/codespaces/secrets/public-key` | | :x: | | | |
| `/user/codespaces/secrets/{secret_name}` | :x: | :x: | | | :x: |
| `/user/codespaces/secrets/{secret_name}/repositories` | | :x: | | | :x: |
| `/user/codespaces/secrets/{secret_name}/repositories/{repository_id}` | :x: | | | | :x: |
-| `/user/codespaces/{codespace_name}` | :x: | :x: | :x: | | |
-| `/user/codespaces/{codespace_name}/exports` | | | | :x: | |
-| `/user/codespaces/{codespace_name}/exports/{export_id}` | | :x: | | | |
+| `/user/codespaces/{codespace_name}` | :x: | :white_check_mark: | :white_check_mark: | | |
+| `/user/codespaces/{codespace_name}/exports` | | | | :white_check_mark: | |
+| `/user/codespaces/{codespace_name}/exports/{export_id}` | | :white_check_mark: | | | |
| `/user/codespaces/{codespace_name}/machines` | | :x: | | | |
| `/user/codespaces/{codespace_name}/publish` | | | | :x: | |
-| `/user/codespaces/{codespace_name}/start` | | | | :x: | |
-| `/user/codespaces/{codespace_name}/stop` | | | | :x: | |
+| `/user/codespaces/{codespace_name}/start` | | | | :white_check_mark: | |
+| `/user/codespaces/{codespace_name}/stop` | | | | :white_check_mark: | |
| `/user/docker/conflicts` | | :x: | | | |
| `/user/email/visibility` | | | :white_check_mark: | | |
| `/user/emails` | :white_check_mark: | :white_check_mark: | | :white_check_mark: | |
diff --git a/src/classes/public/Codespaces/GitHubCodespace.ps1 b/src/classes/public/Codespaces/GitHubCodespace.ps1
new file mode 100644
index 000000000..7b90e62b5
--- /dev/null
+++ b/src/classes/public/Codespaces/GitHubCodespace.ps1
@@ -0,0 +1,54 @@
+class GitHubCodespace {
+ # Unique identifier of the delivery.
+ [uint64] $ID
+
+ [string] $Name
+
+ [Guid] $environment_id
+
+ # Time when the delivery was delivered.
+ [object] $Owner
+ [object] $Billable_Owner
+ [object] $Repository
+ [object] $Machine
+ [bool] $Prebuild
+ [datetime] $created_at
+ [Nullable[datetime]] $updated_at
+ [Nullable[datetime]] $last_used_at
+ [string]$State
+ [string] $url
+ [object] $git_status
+ [string] $location
+ [uint16] $idle_timeout_minutes
+ [string] $web_url
+ [string] $machines_url
+ [string] $start_url
+ [string] $stop_url
+ [string] $pulls_url
+ [string[]] $recent_folders
+ [object] $runtime_constraints
+ [string] $display_name
+ [string] $devcontainer_path
+ [bool] $pending_operation
+ [UInt32] $retention_period_minutes
+ [Nullable[datetime]] $retention_expires_at
+ [string] $template
+ [string] $publish_url
+
+ # Simple parameterless constructor
+ GitHubCodespace() {}
+
+ # Creates a context object from a hashtable of key-vaule pairs.
+ GitHubCodespace([hashtable]$Properties) {
+ foreach ($Property in $Properties.Keys) {
+ $this.$Property = $Properties.$Property
+ }
+ }
+
+ # Creates a context object from a PSCustomObject.
+ GitHubCodespace([PSCustomObject]$Object) {
+ $Object.PSObject.Properties | ForEach-Object {
+ $this.($_.Name) = $_.Value
+ }
+ }
+}
diff --git a/src/formats/GitHubCodespace.Format.ps1xml b/src/formats/GitHubCodespace.Format.ps1xml
new file mode 100644
index 000000000..929310fc3
--- /dev/null
+++ b/src/formats/GitHubCodespace.Format.ps1xml
@@ -0,0 +1,173 @@
+
+
+
+
+
+ GitHubCodespaceTableView
+
+ GitHubCodespace
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+ display_name
+
+
+ location
+
+
+ state
+
+
+ created_at
+
+
+ updated_at
+
+
+ last_used_at
+
+
+
+
+
+
+
+
+
+ GitHubCodespaceListView
+
+ GitHubCodespace
+
+
+
+
+
+
+ ID
+
+
+ Name
+
+
+ environment_id
+
+
+ Owner
+
+
+ Billable_Owner
+
+
+ Repository
+
+
+ Machine
+
+
+ Prebuild
+
+
+
+ created_at
+
+
+
+ updated_at
+
+
+
+ last_used_at
+
+
+ State
+
+
+ url
+
+
+ git_status
+
+
+ location
+
+
+ idle_timeout_minutes
+
+
+ web_url
+
+
+ machines_url
+
+
+ start_url
+
+
+ stop_url
+
+
+ pulls_url
+
+
+ recent_folders
+
+
+ runtime_constraints
+
+
+ display_name
+
+
+ devcontainer_path
+
+
+ pending_operation
+
+
+ retention_period_minutes
+
+
+ retention_expires_at
+
+
+ template
+
+
+ publish_url
+
+
+
+
+
+
+
+
diff --git a/src/functions/private/Codespaces/ConvertTo-GitHubCodespace.ps1 b/src/functions/private/Codespaces/ConvertTo-GitHubCodespace.ps1
new file mode 100644
index 000000000..860686de1
--- /dev/null
+++ b/src/functions/private/Codespaces/ConvertTo-GitHubCodespace.ps1
@@ -0,0 +1,11 @@
+function ConvertTo-GitHubCodespace {
+ [OutputType([GitHubCodespace])]
+ [CmdletBinding()]
+ param(
+ [Parameter(ValueFromPipeline)]
+ $InputObject
+ )
+ process {
+ [GitHubCodespace]$InputObject
+ }
+}
diff --git a/src/functions/public/Codespaces/Add-GitHubCodespaceUser.ps1 b/src/functions/public/Codespaces/Add-GitHubCodespaceUser.ps1
new file mode 100644
index 000000000..1d1a00fe2
--- /dev/null
+++ b/src/functions/public/Codespaces/Add-GitHubCodespaceUser.ps1
@@ -0,0 +1,54 @@
+function Add-GitHubCodespaceUser {
+ <#
+ .SYNOPSIS
+ Adds users to Codespaces access for an organization.
+
+ .DESCRIPTION
+ Codespaces for the specified users will be billed to the organization.
+ To use this endpoint, the access settings for the organization must be set to selected_members.
+ For information on how to change this setting please see [these docs](https://docs.github.com/rest/codespaces/organizations#manage-access-control-for-organization-codespaces)
+ You must authenticate using an access token with the admin:org scope to use this endpoint.
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ Handle for the GitHub user account(s).
+
+ .EXAMPLE
+ > Add-GitHubCodespaceUser -Organization PSModule -user fake_user_name
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#add-users-to-codespaces-access-for-an-organization
+ #>
+ [CmdletBinding(SupportsShouldProcess)]
+ param (
+ [Parameter(Mandatory)]
+ [string]$Organization,
+ [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [string[]]$User,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ if ($PSCmdLet.ShouldProcess(
+ "Adding users [$($User -join ',')] to GitHub codespace access",
+ "Are you sure you want to add $($User -join ',')?",
+ 'Add codespace users'
+ )) {
+ $postParams = @{
+ APIEndpoint = "/orgs/$Organization/codespaces/access/selected_users"
+ Body = [PSCustomObject]@{ selected_usernames = @($User) } | ConvertTo-Json
+ Context = $Context
+ Method = 'POST'
+ }
+ Invoke-GitHubAPI @postParams | Select-Object -ExpandProperty Response
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Export-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Export-GitHubCodespace.ps1
new file mode 100644
index 000000000..be2d99aac
--- /dev/null
+++ b/src/functions/public/Codespaces/Export-GitHubCodespace.ps1
@@ -0,0 +1,59 @@
+function Export-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Exports a codespace.
+
+ .DESCRIPTION
+ Triggers an export of the specified codespace and returns a URL and ID where the status of the export can be monitored.
+ If changes cannot be pushed to the codespace's repository, they will be pushed to a new or previously-existing fork instead.
+ You must authenticate using a personal access token with the codespace scope to use this endpoint.
+ GitHub Apps must have write access to the codespaces_lifecycle_admin repository permission to use this endpoint.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .PARAMETER Wait
+ If present will wait for the export to complete.
+
+ .EXAMPLE
+ > Export-GitHubCodespace -Name fluffy-disco-v7xgv7j4j52pvw9
+
+ .EXAMPLE
+ > Export-GitHubCodespace -Name $ominousSpace.name -Wait
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#export-a-codespace-for-the-authenticated-user
+ #>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory)]
+ [string]$Name,
+
+ [switch]$Wait,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ $postParams = @{
+ APIEndpoint = "/user/codespaces/$Name/exports"
+ Context = $Context
+ Method = 'POST'
+ }
+ $export = Invoke-GitHubAPI @postParams | Select-Object -ExpandProperty Response
+ if ($Wait.IsPresent) {
+ $waitParams = @{
+ Context = $Context
+ Id = $export.id
+ Name = $Name
+ }
+ $export = Wait-GitHubCodespaceExport @waitParams
+ }
+ $export
+ }
+}
diff --git a/src/functions/public/Codespaces/Get-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Get-GitHubCodespace.ps1
new file mode 100644
index 000000000..44cbf89f9
--- /dev/null
+++ b/src/functions/public/Codespaces/Get-GitHubCodespace.ps1
@@ -0,0 +1,104 @@
+function Get-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Retrieve GitHub codespace(s).
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ The handle for the GitHub user account.
+
+ .PARAMETER Owner
+ The account owner of the repository. The name is not case sensitive.
+
+ .PARAMETER Repository
+ The name of the repository. The name is not case sensitive.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .EXAMPLE
+ > Get-GitHubCodespace -Name urban-dollop-pqxgrq55v4c97g4
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-codespaces-in-a-repository-for-the-authenticated-user
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-codespaces-for-the-authenticated-user
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-the-organization
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-a-codespace-for-the-authenticated-user
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-a-user-in-organization
+ #>
+ # [CmdletBinding(DefaultParameterSetName = 'Scope', SupportsPaging)]
+ [CmdletBinding(DefaultParameterSetName = 'Scope')]
+ param (
+ [Parameter(ParameterSetName = 'Organization', Mandatory)]
+ [string]$Organization,
+ [Parameter(ParameterSetName = 'Organization')]
+ [string]$User,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Owner,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Repository,
+
+ [Parameter(ParameterSetName = 'Name', Mandatory)]
+ [string]$Name,
+
+ [Parameter(ParameterSetName = 'Scope')]
+ [ValidateSet('Organization', 'User')]
+ [string]$Scope = 'User',
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ $getParams = @{
+ APIEndpoint = switch ($PSCmdlet.ParameterSetName) {
+ 'Organization' {
+ [string]::IsNullOrWhiteSpace($User) ?
+ "/orgs/$Organization/codespaces" :
+ "/orgs/$Organization/members/$User/codespaces"
+ break
+ }
+ 'Repository' {
+ "/repos/$Owner/$Repository/codespaces"
+ break
+ }
+ 'Name' {
+ "/user/codespaces/$Name"
+ break
+ }
+ 'Scope' {
+ $Scope -eq 'Organization' ?
+ "/orgs/$Organization/codespaces" :
+ '/user/codespaces'
+ break
+ }
+ }
+ Context = $Context
+ Method = 'GET'
+ }
+ # foreach($_name in 'First','Skip') {
+ # if ($PSBoundParameters.ContainsKey($_name)) {
+ # $getParams[$_name] = $PSBoundParameters[$_name]
+ # }
+ # }
+ $response = Invoke-GitHubAPI @getParams | Select-Object -ExpandProperty Response
+ [bool]$response.PSObject.Properties['codespaces'] ? $response.codespaces : $response | ConvertTo-GitHubCodespace
+ #| Add-ObjectDetail -TypeName GitHub.Codespace -DefaultProperties name, display_name, location, state, created_at, updated_at, last_used_at
+ }
+}
\ No newline at end of file
diff --git a/src/functions/public/Codespaces/Get-GitHubCodespaceDefault.ps1 b/src/functions/public/Codespaces/Get-GitHubCodespaceDefault.ps1
new file mode 100644
index 000000000..4895f5c7d
--- /dev/null
+++ b/src/functions/public/Codespaces/Get-GitHubCodespaceDefault.ps1
@@ -0,0 +1,51 @@
+function Get-GitHubCodespaceDefault {
+ <#
+ .SYNOPSIS
+ Get default attributes for creating a new codespace.
+
+ .DESCRIPTION
+ Gets the default attributes for codespaces created by the user with the repository.
+ You must authenticate using an access token with the codespace scope to use this endpoint.
+ GitHub Apps must have write access to the codespaces repository permission to use this endpoint.
+
+ .PARAMETER Owner
+ The account owner of the repository. The name is not case sensitive.
+
+ .PARAMETER Repository
+ The name of the repository. The name is not case sensitive.
+
+ .EXAMPLE
+ > Get-GitHubCodespaceDefault -Owner PSModule -Repository Sodium
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-default-attributes-for-a-codespace
+ #>
+ # [CmdletBinding(SupportsPaging)]
+ [CmdletBinding()]
+ param (
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Owner,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Repository,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ $getParams = @{
+ ApiEndpoint = "/repos/$Owner/$Repository/codespaces/new"
+ }
+ # foreach($_name in 'First','Skip') {
+ # if ($PSBoundParameters.ContainsKey($_name)) {
+ # $getParams[$_name] = $PSBoundParameters[$_name]
+ # }
+ # }
+ $response = Invoke-GitHubAPI @getParams | Select-Object -ExpandProperty Response
+ [bool]$response.PSObject.Properties['billable_owner'] ? $response.billable_owner : $response
+ # | Add-ObjectDetail -DefaultProperties login,type,site_admin
+}
diff --git a/src/functions/public/Codespaces/Get-GitHubCodespaceDevContainer.ps1 b/src/functions/public/Codespaces/Get-GitHubCodespaceDevContainer.ps1
new file mode 100644
index 000000000..448cce4f2
--- /dev/null
+++ b/src/functions/public/Codespaces/Get-GitHubCodespaceDevContainer.ps1
@@ -0,0 +1,57 @@
+function Get-GitHubCodespaceDevContainer {
+ <#
+ .SYNOPSIS
+ List devcontainer configurations in a repository for the authenticated user.
+
+ .DESCRIPTION
+ Lists the devcontainer.json files associated with a specified repository and the authenticated user.
+ These files specify launchpoint configurations for codespaces created within the repository.
+ You must authenticate using an access token with the codespace scope to use this endpoint.
+ GitHub Apps must have read access to the codespaces_metadata repository permission to use this endpoint.
+
+ .PARAMETER Owner
+ The account owner of the repository. The name is not case sensitive.
+
+ .PARAMETER Repository
+ The name of the repository. The name is not case sensitive.
+
+ .EXAMPLE
+ > Get-GitHubCodespaceDevContainer -Owner PSModule -Repository Sodium
+
+ path name display_name
+ ---- ---- ------------
+ .devcontainer/devcontainer.json Debian Debian
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-devcontainer-configurations-in-a-repository-for-the-authenticated-user
+ #>
+ # [CmdletBinding(SupportsPaging)]
+ [CmdletBinding()]
+ param (
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Owner,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Repository,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ $getParams = @{
+ APIEndpoint = "/repos/$Owner/$Repository/codespaces/devcontainers"
+ ContentType = 'application/vnd.github+json'
+ Method = 'GET'
+ }
+ # foreach($_name in 'First','Skip') {
+ # if ($PSBoundParameters.ContainsKey($_name)) {
+ # $getParams[$_name] = $PSBoundParameters[$_name]
+ # }
+ # }
+ $response = Invoke-GitHubAPI @getParams | Select-Object -ExpandProperty Response
+ [bool]$response.PSObject.Properties['devcontainers'] ? $response.devcontainers : $response
+}
diff --git a/src/functions/public/Codespaces/Get-GitHubCodespaceExport.ps1 b/src/functions/public/Codespaces/Get-GitHubCodespaceExport.ps1
new file mode 100644
index 000000000..f4a68ab55
--- /dev/null
+++ b/src/functions/public/Codespaces/Get-GitHubCodespaceExport.ps1
@@ -0,0 +1,47 @@
+function Get-GitHubCodespaceExport {
+ <#
+ .SYNOPSIS
+ Get details about a codespace export.
+
+ .DESCRIPTION
+ Gets information about an export of a codespace.
+ You must authenticate using a personal access token with the codespace scope to use this endpoint.
+ GitHub Apps must have read access to the codespaces_lifecycle_admin repository permission to use this endpoint.
+
+ .PARAMETER Id
+ The ID of the export operation, or latest. For future use. Only latest is supported now.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .EXAMPLE
+ > Get-GitHubCodespaceExport -Name urban-dollop-pqxgrq55v4c97g4
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-details-about-a-codespace-export
+ #>
+ [CmdletBinding()]
+ param (
+ [Parameter()]
+ [string]$Id = 'latest',
+
+ [Parameter(Mandatory)]
+ [string]$Name,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ $getParams = @{
+ APIEndpoint = "/user/codespaces/$Name/exports/$Id"
+ Context = $Context
+ Method = 'GET'
+ }
+ Invoke-GitHubAPI @getParams | Select-Object -ExpandProperty Response
+ }
+}
diff --git a/src/functions/public/Codespaces/New-GitHubCodespace.ps1 b/src/functions/public/Codespaces/New-GitHubCodespace.ps1
new file mode 100644
index 000000000..2f84a7a16
--- /dev/null
+++ b/src/functions/public/Codespaces/New-GitHubCodespace.ps1
@@ -0,0 +1,159 @@
+function New-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Create a codespace.
+
+ .PARAMETER Owner
+ The account owner of the repository. The name is not case sensitive.
+
+ .PARAMETER Repository
+ The name of the repository. The name is not case sensitive.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .PARAMETER Ref
+ Git ref (typically a branch name) for this codespace
+
+ .PARAMETER Location
+ The requested location for a new codespace. Best efforts are made to respect this upon creation. Assigned by IP if not provided.
+
+ .PARAMETER ClientIp
+ IP for location auto-detection when proxying a request
+
+ .PARAMETER Machine
+ Machine type to use for this codespace
+
+ .PARAMETER Devcontainer
+ Path to devcontainer.json config to use for this codespace
+
+ .PARAMETER NoMultipleRepoPermissions
+ Whether to authorize requested permissions from devcontainer.json
+
+ .PARAMETER WorkingDirectory
+ Working directory for this codespace
+
+ .PARAMETER Timeout
+ Time in minutes before codespace stops from inactivity
+
+ .PARAMETER DisplayName
+ Display name for this codespace
+
+ .PARAMETER RetentionPeriod
+ Duration in minutes after codespace has gone idle in which it will be deleted. Must be integer minutes between 0 and 43200 (30 days).
+
+ .EXAMPLE
+ > New-GitHubCodespace -Owner PSModule -Repository Sodium
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-in-a-repository
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-from-a-pull-request
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-for-the-authenticated-user
+ #>
+ [CmdletBinding(DefaultParameterSetName = 'User', SupportsShouldProcess)]
+ param (
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [Parameter(ParameterSetName = 'PullRequest', Mandatory)]
+ [string]$Owner,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [Parameter(ParameterSetName = 'PullRequest', Mandatory)]
+ [string]$Repository,
+
+ [Parameter(ParameterSetName = 'PullRequest', Mandatory)]
+ [Parameter(ParameterSetName = 'User')]
+ [int]$PullNumber,
+
+ [Parameter(ParameterSetName = 'User', Mandatory)]
+ [int]$RepositoryId,
+
+ [Parameter(ParameterSetName = 'Repository')]
+ [Parameter(ParameterSetName = 'User')]
+ [string]$Ref,
+
+ [ValidateSet('EastUs', 'SouthEastAsia', 'WestEurope', 'WestUs2')]
+ [string]$Location,
+ [string]$ClientIp,
+ [ValidateSet('basicLinux32gb', 'standardLinux32gb', 'premiumLinux', 'largePremiumLinux')]
+ [string]$Machine,
+ [string]$Devcontainer,
+ [switch]$NoMultipleRepoPermissions,
+ [string]$WorkingDirectory,
+ [int]$Timeout,
+ [string]$DisplayName,
+ [int]$RetentionPeriod,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ begin {
+ $propertyMap = @{
+ ClientIp = 'client_ip'
+ Devcontainer = 'devcontainer_path'
+ DisplayName = 'display_name'
+ Location = 'location'
+ Machine = 'machine'
+ Ref = 'ref'
+ RetentionPeriod = 'retention_period_minutes'
+ Timeout = 'idle_timeout_minutes'
+ WorkingDirectory = 'working_directory'
+ }
+ }
+ process {
+ if ($PSCmdLet.ShouldProcess(
+ 'Creating GitHub codespace',
+ 'Are you sure you want to create a new codespace?',
+ 'Create codespace'
+ )) {
+ $properties = @{
+ multi_repo_permissions_opt_out = $NoMultipleRepoPermissions.IsPresent
+ }
+ foreach ($p in $PSBoundParameters.GetEnumerator()) {
+ if ($propertyMap.ContainsKey($p.Key) -and -not [string]::IsNullOrWhiteSpace($p.Value)) {
+ $properties.Add($propertyMap[$p.Key], $p.Value)
+ }
+ }
+ if ($PSCmdlet.ParameterSetName -eq 'User') {
+ if ($PSBoundParameters.ContainsKey('PullRequest')) {
+ $properties.Add('pull_request', [PSCustomObject]@{
+ pull_request_number = $PullNumber
+ repository_id = $RepositoryId
+ })
+ }
+ else {
+ $properties.Add('repository_id', $RepositoryId)
+ }
+ }
+ $postParams = @{
+ APIEndpoint = switch ($PSCmdlet.ParameterSetName) {
+ 'PullRequest' {
+ "/repos/$Owner/$Repository/pulls/$PullNumber/codespaces"
+ break
+ }
+ 'Repository' {
+ "/repos/$Owner/$Repository/codespaces"
+ break
+ }
+ 'User' {
+ '/user/codespaces'
+ break
+ }
+ }
+ Body = [PSCustomObject]$properties | ConvertTo-Json
+ Context = $Context
+ Method = 'POST'
+ }
+ Invoke-GitHubAPI @postParams | Select-Object -ExpandProperty Response | ConvertTo-GitHubCodespace
+ # | Add-ObjectDetail -TypeName GitHub.Codespace -DefaultProperties name, display_name, location, state, created_at, updated_at, last_used_at
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Remove-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Remove-GitHubCodespace.ps1
new file mode 100644
index 000000000..7e386fa68
--- /dev/null
+++ b/src/functions/public/Codespaces/Remove-GitHubCodespace.ps1
@@ -0,0 +1,72 @@
+function Remove-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Delete a codespace.
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ The handle for the GitHub user account.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .EXAMPLE
+ > Remove-GitHubCodespace -Name urban-dollop-pqxgrq55v4c97g4
+
+ Request : {[Authentication, Bearer], [Method, Delete], [Token, System.Security.SecureString], [Headers, System.Collections.Hashtable]…}
+ Response :
+ Headers : @{Access-Control-Allow-Origin=*; Access-Control-Expose-Headers=ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource,
+ X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset; Content-Length=2;
+ Content-Security-Policy=default-src 'none'; Content-Type=application/json; charset=utf-8; Date=Sun, 02 Feb 2025 00:51:10 GMT; github-authentication-token-expiration=2025-05-01 01:22:47 UTC;
+ Referrer-Policy=origin-when-cross-origin, strict-origin-when-cross-origin; Server=github.com; Strict-Transport-Security=max-age=31536000; includeSubdomains; preload; Vary=Accept-Encoding,
+ Accept, X-Requested-With; x-accepted-oauth-scopes=codespace; X-Content-Type-Options=nosniff; X-Frame-Options=deny; x-github-api-version-selected=2022-11-28; x-github-media-type=github.v3;
+ format=json; x-github-request-id=D313:3B725F:28042C0:50B3464:679EC17E; x-oauth-scopes=admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook,
+ admin:ssh_signing_key, audit_log, codespace, copilot, delete:packages, gist, notifications, project, repo, user, workflow, write:discussion, write:packages; x-ratelimit-limit=5000;
+ x-ratelimit-remaining=4991; x-ratelimit-reset=1738460387; x-ratelimit-resource=codespaces; x-ratelimit-used=9; X-XSS-Protection=0}
+ StatusCode : 202
+ StatusDescription : Accepted
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#about-github-codespaces
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-a-user-in-organization
+ #>
+ [CmdletBinding(DefaultParameterSetName = 'User', SupportsShouldProcess)]
+ param (
+ [Parameter(ParameterSetName = 'Organization', Mandatory)]
+ [string]$Organization,
+
+ [Parameter(ParameterSetName = 'Organization', Mandatory)]
+ [string]$User,
+
+ [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [string]$Name,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ if ($PSCmdLet.ShouldProcess(
+ "Deleting GitHub codespace [$Name]",
+ "Are you sure you want to delete $($Name)?",
+ 'Delete codespace'
+ )) {
+ $delParams = @{
+ APIEndpoint = $PSCmdlet.ParameterSetName -eq 'Organization' ?
+ "orgs/$Organization/members/$User/codespaces/$Name" :
+ "user/codespaces/$Name"
+ Context = $Context
+ Method = 'DELETE'
+ }
+ Invoke-GitHubAPI @delParams
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Remove-GitHubCodespaceUser.ps1 b/src/functions/public/Codespaces/Remove-GitHubCodespaceUser.ps1
new file mode 100644
index 000000000..e3457481f
--- /dev/null
+++ b/src/functions/public/Codespaces/Remove-GitHubCodespaceUser.ps1
@@ -0,0 +1,54 @@
+function Remove-GitHubCodespaceUser {
+ <#
+ .SYNOPSIS
+ Removes users from Codespaces access for an organization.
+
+ .DESCRIPTION
+ Codespaces for the specified users will no longer be billed to the organization.
+ To use this endpoint, the billing settings for the organization must be set to selected_members.
+ For information on how to change this setting please see [these docs](https://docs.github.com/rest/codespaces/organizations#manage-access-control-for-organization-codespaces)
+ You must authenticate using an access token with the admin:org scope to use this endpoint.
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ Handle for the GitHub user account(s).
+
+ .EXAMPLE
+ > Remove-GitHubCodespaceUser -Organization PSModule -user fake_user_name
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#remove-users-from-codespaces-access-for-an-organization
+ #>
+ [CmdletBinding(SupportsShouldProcess)]
+ param (
+ [Parameter(Mandatory)]
+ [string]$Organization,
+ [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [string[]]$User,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ if ($PSCmdLet.ShouldProcess(
+ "Removing user [$($User -join ',')] from GitHub codespace access",
+ "Are you sure you want to remove $($User -join ',') from GitHub codespace access?",
+ 'Remove codespace users'
+ )) {
+ $delParams = @{
+ APIEndpoint = "/orgs/$Organization/codespaces/access/selected_users"
+ Body = [PSCustomObject]@{ selected_usernames = @($User) } | ConvertTo-Json
+ Context = $Context
+ Method = 'DELETE'
+ }
+ Invoke-GitHubAPI @delParams | Select-Object -ExpandProperty Response
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Set-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Set-GitHubCodespace.ps1
new file mode 100644
index 000000000..917a7f1d3
--- /dev/null
+++ b/src/functions/public/Codespaces/Set-GitHubCodespace.ps1
@@ -0,0 +1,94 @@
+function Set-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Update a codespace.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .PARAMETER Ref
+ Git ref (typically a branch name) for this codespace
+
+ .PARAMETER Location
+ The requested location for a new codespace. Best efforts are made to respect this upon creation. Assigned by IP if not provided.
+
+ .PARAMETER ClientIp
+ IP for location auto-detection when proxying a request
+
+ .PARAMETER Machine
+ Machine type to use for this codespace
+
+ .PARAMETER Devcontainer
+ Path to devcontainer.json config to use for this codespace
+
+ .PARAMETER NoMultipleRepoPermissions
+ Whether to authorize requested permissions from devcontainer.json
+
+ .PARAMETER WorkingDirectory
+ Working directory for this codespace
+
+ .PARAMETER Timeout
+ Time in minutes before codespace stops from inactivity
+
+ .PARAMETER DisplayName
+ Display name for this codespace
+
+ .PARAMETER RetentionPeriod
+ Duration in minutes after codespace has gone idle in which it will be deleted. Must be integer minutes between 0 and 43200 (30 days).
+
+ .EXAMPLE
+ > Set-GitHubCodespace -Name fluffy-disco-v7xgv7j4j52pvw9 -DisplayName 'vigilant doodle'
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#update-a-codespace-for-the-authenticated-user
+ #>
+ [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
+ param (
+ [Parameter(Mandatory)]
+ [string]$Name,
+
+ [ValidateSet('basicLinux32gb', 'standardLinux32gb', 'premiumLinux', 'largePremiumLinux')]
+ [string]$Machine,
+ [string]$DisplayName,
+ [string[]]$RecentFolders,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ begin {
+ $propertyMap = @{
+ DisplayName = 'display_name'
+ Machine = 'machine'
+ RecentFolders = 'recent_folders'
+ }
+ }
+ process {
+ $properties = @{}
+ foreach ($p in $PSBoundParameters.GetEnumerator()) {
+ if ($propertyMap.ContainsKey($p.Key) -and -not [string]::IsNullOrWhiteSpace($p.Value)) {
+ $properties.Add($propertyMap[$p.Key], $p.Value)
+ }
+ }
+ if ($properties.Count -gt 0) {
+ if ($PSCmdLet.ShouldProcess(
+ "Updating github codespace [$Name]",
+ "Are you sure you want to update github codespace [$Name]?",
+ 'Update codespace'
+ )) {
+ $patchParams = @{
+ APIEndpoint = "/user/codespaces/$Name"
+ Body = [PSCustomObject]$properties | ConvertTo-Json
+ Context = $Context
+ Method = 'PATCH'
+ }
+ Invoke-GitHubAPI @patchParams | Select-Object -ExpandProperty Response | ConvertTo-GitHubCodespace
+ # | Add-ObjectDetail -TypeName GitHub.Codespace -DefaultProperties name,display_name,location,state,created_at,updated_at,last_used_at
+ }
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Set-GitHubCodespaceVisibility.ps1 b/src/functions/public/Codespaces/Set-GitHubCodespaceVisibility.ps1
new file mode 100644
index 000000000..7aa2ea2ee
--- /dev/null
+++ b/src/functions/public/Codespaces/Set-GitHubCodespaceVisibility.ps1
@@ -0,0 +1,73 @@
+function Set-GitHubCodespaceVisibility {
+ <#
+ .SYNOPSIS
+ Manage access control for organization codespaces.
+
+ .DESCRIPTION
+ Sets which users can access codespaces in an organization.
+ This is synonymous with granting or revoking codespaces access permissions for users according to the visibility.
+ You must authenticate using an access token with the admin:org scope to use this endpoint.
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ The usernames of the organization members who should have access to codespaces in the organization.
+
+ Required when visibility is selected_members. The provided list of usernames will replace any existing value.
+
+ .PARAMETER Visibility
+ Which users can access codespaces in the organization. disabled means that no users can access codespaces in the organization.
+
+ .PARAMETER Force
+ When specified, forces execution without confirmation.
+
+ .EXAMPLE
+ Set-GitHubCodespaceVisibility -Visibility selected_members -User fake_user_name -Force
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#manage-access-control-for-organization-codespaces
+ #>
+ [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
+ param (
+ [Parameter(Mandatory)]
+ [string]$Organization,
+ [ValidateSet('disabled', 'selected_members', 'all_members', 'all_members_and_outside_collaborators')]
+ [string]$Visibility,
+
+ [switch]$Force,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ dynamicparam {
+ if ($Visibility -eq 'selected_members') {
+ $paramDictionary = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
+ # Add a mandatory string array parameter called 'User'
+ $attributeCollection = @( [Management.Automation.ParameterAttribute]@{ Mandatory = $true } )
+ $paramDictionary.Add('User', [Management.Automation.RuntimeDefinedParameter]::new('User', [String[]], $attributeCollection))
+ $paramDictionary
+ }
+ }
+ process {
+ if ($Force.IsPresent -and -not $Confirm) { $ConfirmPreference = 'None' }
+ if ($PSCmdLet.ShouldProcess(
+ "Changing codespace visibility to [$($Visibility)]",
+ "Are you sure you want to set visibility to $($Visibility)?",
+ 'Change codespace visibility')) {
+ $properties = @{ visibility = $Visibility }
+ if ($Visibility -eq 'selected_members') {
+ $properties.Add('selected_usernames', @($PSBoundParameters.User))
+ }
+ $putParams = @{
+ APIEndpoint = "/orgs/$Organization/codespaces/access"
+ Body = [PSCustomObject]$properties | ConvertTo-Json
+ Context = $Context
+ Method = 'PUT'
+ }
+ Invoke-GitHubAPI @putParams | Select-Object -ExpandProperty Response
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Start-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Start-GitHubCodespace.ps1
new file mode 100644
index 000000000..dcf796e6c
--- /dev/null
+++ b/src/functions/public/Codespaces/Start-GitHubCodespace.ps1
@@ -0,0 +1,55 @@
+function Start-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Start a codespace.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .PARAMETER Wait
+ If present will wait for the codespace to start.
+
+ .EXAMPLE
+ > Start-GitHubCodespace -Name urban-dollop-pqxgrq55v4c97g4
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#start-a-codespace-for-the-authenticated-user
+ #>
+ [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Low')]
+ param (
+ [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [string]$Name,
+
+ [switch]$Wait,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ if ($PSCmdLet.ShouldProcess(
+ "Starting GitHub codespace [$Name]",
+ "Are you sure you want to start GitHub codespace [$Name]?",
+ 'Start GitHub codespace'
+ )) {
+ $postParams = @{
+ APIEndpoint = $PSCmdlet.ParameterSetName -eq 'Organization' ?
+ "/orgs/$Organization/members/$User/codespaces/$Name/start" :
+ "/user/codespaces/$Name/start"
+ Context = $Context
+ Method = 'POST'
+ }
+ $codespace = Invoke-GitHubAPI @postParams | Select-Object -ExpandProperty Response
+ # | Add-ObjectDetail -TypeName GitHub.Codespace -DefaultProperties name, display_name, location, state, created_at, updated_at, last_used_at
+ if ($Wait.IsPresent) {
+ $getParams = @{ Name = $Name }
+ $codespace = Wait-GitHubCodespaceAction -GetParameters $getParams
+ }
+ $codespace
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Stop-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Stop-GitHubCodespace.ps1
new file mode 100644
index 000000000..f1aa5cf06
--- /dev/null
+++ b/src/functions/public/Codespaces/Stop-GitHubCodespace.ps1
@@ -0,0 +1,74 @@
+function Stop-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Stop a codespace.
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ The handle for the GitHub user account.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .PARAMETER Wait
+ If present will wait for the codespace to stop.
+
+ .EXAMPLE
+ > Stop-GitHubCodespace -Name urban-dollop-pqxgrq55v4c97g4
+
+ .EXAMPLE
+ > Stop-GitHubCodespace -User fake_user_name -Name urban-dollop-pqxgrq55v4c97g4
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#stop-a-codespace-for-the-authenticated-user
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#stop-a-codespace-for-an-organization-user
+ #>
+ [CmdletBinding(DefaultParameterSetName = 'User', SupportsShouldProcess)]
+ param (
+ [Parameter(ParameterSetName = 'Organization', Mandatory)]
+ [string]$Organization,
+ [Parameter(ParameterSetName = 'Organization', Mandatory)]
+ [string]$User,
+
+ [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [string]$Name,
+
+ [switch]$Wait,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ if ($PSCmdLet.ShouldProcess(
+ "Stopping GitHub codespace [$Name]",
+ "Are you sure you want to stop GitHub codespace $($Name)?",
+ 'Stop codespace'
+ )) {
+ $postParams = @{
+ APIEndpoint = $PSCmdlet.ParameterSetName -eq 'Organization' ?
+ "/orgs/$Organization/members/$User/codespaces/$Name/stop" :
+ "/user/codespaces/$Name/stop"
+ Context = $Context
+ Method = 'POST'
+ }
+ $codespace = Invoke-GitHubAPI @postParams | Select-Object -ExpandProperty Response
+ # | Add-ObjectDetail -TypeName GitHub.Codespace -DefaultProperties name, display_name, location, state, created_at, updated_at, last_used_at
+ if ($Wait.IsPresent) {
+ $getParams = $PSCmdlet.ParameterSetName -eq 'Organization' ?
+ @{ Organization = $Organization; User = $User } :
+ @{ Name = $Name }
+ $codespace = Wait-GitHubCodespaceAction -GetParameters $getParams
+ }
+ $codespace
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Test-GitHubCodespace.ps1 b/src/functions/public/Codespaces/Test-GitHubCodespace.ps1
new file mode 100644
index 000000000..aa801fcd4
--- /dev/null
+++ b/src/functions/public/Codespaces/Test-GitHubCodespace.ps1
@@ -0,0 +1,73 @@
+function Test-GitHubCodespace {
+ <#
+ .SYNOPSIS
+ Determines whether a GitHub codespace exists.
+
+ .PARAMETER Organization
+ The organization name. The name is not case sensitive.
+
+ .PARAMETER User
+ The handle for the GitHub user account.
+
+ .PARAMETER Owner
+ The account owner of the repository. The name is not case sensitive.
+
+ .PARAMETER Repository
+ The name of the repository. The name is not case sensitive.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .EXAMPLE
+ > Test-GitHubCodespace -Name urban-dollop-pqxgrq55v4c97g4
+
+ False
+
+ .OUTPUTS
+ [bool]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#about-github-codespaces
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-a-user-in-organization
+ #>
+ [CmdletBinding(DefaultParameterSetName = 'Scope')]
+ [OutputType([bool])]
+ param (
+ [Parameter(ParameterSetName = 'Organization', Mandatory )]
+ [string]$Organization,
+ [Parameter(ParameterSetName = 'Organization')]
+ [string]$User,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Owner,
+
+ [Parameter(ParameterSetName = 'Repository', Mandatory)]
+ [string]$Repository,
+
+ [Parameter(ParameterSetName = 'Name', Mandatory)]
+ [string]$Name,
+
+ [Parameter(ParameterSetName = 'Scope')]
+ [ValidateSet('Organization','User')]
+ [string]$Scope='User',
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ try {
+ $codespace = Get-GitHubCodespace @PSBoundParameters
+ [bool]$codespace.id
+ } catch {
+ $false
+ # This part doesn't work as intended because of the error handling in Invoke-GitHubAPI :(
+ # if (404 -ne $_.Exception.Response.StatusCode.value__) {
+ # throw
+ # }
+ }
+ }
+}
diff --git a/src/functions/public/Codespaces/Test-IsCodespace.ps1 b/src/functions/public/Codespaces/Test-IsCodespace.ps1
new file mode 100644
index 000000000..06ac26159
--- /dev/null
+++ b/src/functions/public/Codespaces/Test-IsCodespace.ps1
@@ -0,0 +1,6 @@
+function Test-IsCodespace {
+ [CmdletBinding()]
+ [OutputType([bool])]
+ param ()
+ -not ($null -eq $env:CODESPACES)
+}
diff --git a/src/functions/public/Codespaces/Wait-GitHubCodespaceAction.ps1 b/src/functions/public/Codespaces/Wait-GitHubCodespaceAction.ps1
new file mode 100644
index 000000000..a05ea730d
--- /dev/null
+++ b/src/functions/public/Codespaces/Wait-GitHubCodespaceAction.ps1
@@ -0,0 +1,39 @@
+function Wait-GitHubCodespaceAction {
+ <#
+ .SYNOPSIS
+ Waits for a codespace action to complete.
+
+ .DESCRIPTION
+ Polls using Get-GitHubCodespace every 5 seconds until the codespace state -notmatch 'ing'
+
+ .PARAMETER GetParameters
+ Hashtable of parameters to splat for Get-GitHubCodespace polling.
+
+ .EXAMPLE
+ > Wait-GitHubCodespaceAction -GetParameters @{ Name='urban-dollop-pqxgrq55v4c97g4' }
+
+ .OUTPUTS
+ [PSObject]
+ #>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory)]
+ [hashtable]$GetParameters
+ )
+ process {
+ # Expected states for happy paths:
+ # Shutdown > Queued > Starting > Available
+ # Available > Queued > ShuttingDown > ShutDown
+ #
+ # To allow for unexpected results, loop until the state is something other than Queued or *ing
+ # All known states:
+ # *ings: Awaiting, Exporting, Provisioning, Rebuilding, ShuttingDown, Starting, Updating
+ # Other: Archived, Available, Created, Deleted, Failed, Moved, Queued, Shutdown, Unavailable, Unknown
+ do {
+ Start-Sleep -Seconds 5
+ $_codespace = Get-GitHubCodespace @GetParameters
+ Write-Debug ($_codespace | Out-String)
+ } until($_codespace.state -notmatch 'Queued|ing')
+ $_codespace
+ }
+}
diff --git a/src/functions/public/Codespaces/Wait-GitHubCodespaceExport.ps1 b/src/functions/public/Codespaces/Wait-GitHubCodespaceExport.ps1
new file mode 100644
index 000000000..bc89b7523
--- /dev/null
+++ b/src/functions/public/Codespaces/Wait-GitHubCodespaceExport.ps1
@@ -0,0 +1,47 @@
+function Wait-GitHubCodespaceExport {
+ <#
+ .SYNOPSIS
+ Waits for a codespace export to complete.
+
+ .DESCRIPTION
+ Polls using Get-GitHubCodespaceExport every 5 seconds until the export state is -ne `in_progress`
+
+ .PARAMETER Id
+ The ID of the export operation.
+
+ .PARAMETER Name
+ The name of the codespace.
+
+ .EXAMPLE
+ > Wait-GitHubCodespace -Name urban-dollop-pqxgrq55v4c97g4
+
+
+ .OUTPUTS
+ [PSObject[]]
+
+ .LINK
+ https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#export-a-codespace-for-the-authenticated-user
+ #>
+ [CmdletBinding()]
+ param (
+ [Parameter()]
+ [string]$Id='latest',
+
+ [Parameter(Mandatory)]
+ [string]$Name,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+ process {
+ $_export = Get-GitHubCodespaceExport @PSBoundParameters
+ while ($_export.state -eq 'in_progress') {
+ $_export = Get-GitHubCodespaceExport -Name $Name
+ Write-Debug ($_export | Out-String)
+ Start-Sleep -Seconds 5
+ }
+ $_export
+ }
+}