Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions docs/docs/cmd/spe/container/container-recyclebinitem-list.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# spe container recyclebinitem list

Lists deleted containers of a specific container type

## Usage

```sh
m365 spe container recyclebinitem list [options]
```

## Options

```md definition-list
`--containerTypeId [containerTypeId]`
: The container type ID of the container instance. Use either `containerTypeId` or `containerTypeName` but not both.

`--containerTypeName [containerTypeName]`
: The container type name of the container instance. Use either `containerTypeId` or `containerTypeName` but not both.
```

<Global />

## Examples

List deleted containers of a specific container type specified by id.

```sh
m365 spe container recyclebinitem list --containerTypeId "91710488-5756-407f-9046-fbe5f0b4de73"
```

List deleted containers of a specific container type specified by name.

```sh
m365 spe container recyclebinitem list --containerTypeName "My container type name"
```

## Response

<Tabs>
<TabItem value="JSON">

```json
[
{
"id": "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z",
"displayName": "My Application Storage Container",
"containerTypeId": "1a55ba46-a673-45a4-b0d9-bd9913d06957",
"createdDateTime": "2025-04-15T21:51:48Z",
"settings": {
"isOcrEnabled": false
}
}
]
```

</TabItem>
<TabItem value="Text">

```text
id displayName
------------------------------------------------------------------ --------------------------------
b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z My Application Storage Container
```

</TabItem>
<TabItem value="CSV">

```csv
id,displayName,containerTypeId,createdDateTime
b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z,My Application Storage Container,1a55ba46-a673-45a4-b0d9-bd9913d06957,2025-04-15T21:51:48Z
```

</TabItem>
<TabItem value="Markdown">

```md
# spe container recyclebinitem list --containerTypeId "1a55ba46-a673-45a4-b0d9-bd9913d06957"

Date: 18/04/2025

## My Application Storage Container (b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z)

Property | Value
---------|-------
id | b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z
displayName | My Application Storage Container
containerTypeId | 1a55ba46-a673-45a4-b0d9-bd9913d06957
createdDateTime | 2025-04-15T21:51:48Z
```

</TabItem>
</Tabs>
5 changes: 5 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2132,6 +2132,11 @@ const sidebars: SidebarsConfig = {
type: 'doc',
label: 'container list',
id: 'cmd/spe/container/container-list'
},
{
type: 'doc',
label: 'container recyclebinitem list',
id: 'cmd/spe/container/container-recyclebinitem-list'
}
]
},
Expand Down
1 change: 1 addition & 0 deletions src/m365/spe/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
CONTAINER_ACTIVATE: `${prefix} container activate`,
CONTAINER_GET: `${prefix} container get`,
CONTAINER_LIST: `${prefix} container list`,
CONTAINER_RECYCLEBINITEM_LIST: `${prefix} container recyclebinitem list`,
CONTAINERTYPE_ADD: `${prefix} containertype add`,
CONTAINERTYPE_GET: `${prefix} containertype get`,
CONTAINERTYPE_LIST: `${prefix} containertype list`
Expand Down
64 changes: 11 additions & 53 deletions src/m365/spe/commands/container/container-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './container-list.js';
import { spo } from '../../../../utils/spo.js';
import { CommandError } from '../../../../Command.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { cli } from '../../../../cli/cli.js';
import { spe } from '../../../../utils/spe.js';

describe(commands.CONTAINER_LIST, () => {
let log: string[];
Expand All @@ -34,40 +34,12 @@ describe(commands.CONTAINER_LIST, () => {
"createdDateTime": "2021-11-24T15:41:52.347Z"
}];

const containerTypedata = [{
"AzureSubscriptionId": "/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)",
"ContainerTypeId": "/Guid(e2756c4d-fa33-4452-9c36-2325686e1082)",
"CreationDate": "3/11/2024 2:38:56 PM",
"DisplayName": "standard container",
"ExpiryDate": "3/11/2028 2:38:56 PM",
"IsBillingProfileRequired": true,
"OwningAppId": "/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)",
"OwningTenantId": "/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)",
"Region": "West Europe",
"ResourceGroup": "Standard group",
"SPContainerTypeBillingClassification": "Standard"
},
{
"AzureSubscriptionId": "/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)",
"ContainerTypeId": "/Guid(e2756c4d-fa33-4452-9c36-2325686e1082)",
"CreationDate": "3/11/2024 2:38:56 PM",
"DisplayName": "trial container",
"ExpiryDate": "3/11/2028 2:38:56 PM",
"IsBillingProfileRequired": true,
"OwningAppId": "/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)",
"OwningTenantId": "/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)",
"Region": "West Europe",
"ResourceGroup": "Standard group",
"SPContainerTypeBillingClassification": "Standard"
}];

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').resolves();
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
sinon.stub(spo, 'getSpoAdminUrl').resolves(adminUrl);
sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' });

auth.connection.active = true;
auth.connection.spoUrl = 'https://contoso.sharepoint.com';
commandInfo = cli.getCommandInfo(command);
Expand All @@ -87,14 +59,15 @@ describe(commands.CONTAINER_LIST, () => {
}
};
loggerLogSpy = sinon.spy(logger, 'log');

sinon.stub(spe, 'getContainerTypeIdByName').withArgs(adminUrl, 'standard container').resolves('e2756c4d-fa33-4452-9c36-2325686e1082');
});

afterEach(() => {
sinonUtil.restore([
request.get,
request.post,
spo.getSpoAdminUrl,
spo.getAllContainerTypes
spe.getContainerTypeIdByName
]);
});

Expand Down Expand Up @@ -135,13 +108,11 @@ describe(commands.CONTAINER_LIST, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082", debug: true } });
await command.action(logger, { options: { containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082", verbose: true } });
assert(loggerLogSpy.calledWith(containersList));
});

it('retrieves list of container type by name', async () => {
sinon.stub(spo, 'getAllContainerTypes').resolves(containerTypedata);

sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq e2756c4d-fa33-4452-9c36-2325686e1082') {
return { "value": containersList };
Expand All @@ -150,32 +121,19 @@ describe(commands.CONTAINER_LIST, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { containerTypeName: "standard container", debug: true } });
await command.action(logger, { options: { containerTypeName: "standard container", verbose: true } });
assert(loggerLogSpy.calledWith(containersList));
});

it('throws an error when service principal is not found', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq e2756c4d-fa33-4452-9c36-2325686e1086') {
return [];
}

throw 'Invalid request';
});

sinon.stub(spo, 'getAllContainerTypes').resolves(containerTypedata);

await assert.rejects(command.action(logger, { options: { containerTypeName: "nonexisting container", debug: true } }),
new CommandError(`Container type with name nonexisting container not found`));
});

it('correctly handles error when retrieving containers', async () => {
const error = 'An error has occurred';
sinon.stub(spo, 'getAllContainerTypes').rejects(new Error(error));
sinonUtil.restore(spe.getContainerTypeIdByName);
sinon.stub(spe, 'getContainerTypeIdByName').rejects(new Error(error));

await assert.rejects(command.action(logger, {
options: {
debug: true
containerTypeName: "nonexisting container",
verbose: true
}
}), new CommandError('An error has occurred'));
});
Expand Down
15 changes: 3 additions & 12 deletions src/m365/spe/commands/container/container-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { validation } from '../../../../utils/validation.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
import { ContainerProperties } from '../../ContainerProperties.js';
import { ContainerTypeProperties, spo } from '../../../../utils/spo.js';
import { spe } from '../../../../utils/spe.js';
import { spo } from '../../../../utils/spo.js';

interface CommandArgs {
options: Options;
Expand Down Expand Up @@ -101,17 +102,7 @@ class SpeContainerListCommand extends GraphCommand {
}

const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
const containerTypes: ContainerTypeProperties[] = await spo.getAllContainerTypes(spoAdminUrl, logger, this.debug);

// Get id of the container type by name
const containerType: ContainerTypeProperties | undefined = containerTypes.find(c => c.DisplayName === options.containerTypeName);
if (!containerType) {
throw new Error(`Container type with name ${options.containerTypeName} not found`);
}

// The value is returned as "/Guid(073269af-f1d2-042d-2ef5-5bdd6ac83115)/". We need to extract the GUID from it.
const containerTypeValue = containerType.ContainerTypeId.toString();
return containerTypeValue.substring(containerTypeValue.indexOf('(') + 1, containerTypeValue.lastIndexOf(')'));
return spe.getContainerTypeIdByName(spoAdminUrl, options.containerTypeName!);
}
}

Expand Down
Loading