Partilhar via


Como usar o PowerShell em sua extensão

Vamos nos aprofundar no SDK de Extensões do Windows Admin Center – vamos falar sobre como adicionar comandos do PowerShell à sua extensão.

PowerShell no TypeScript

O processo de build do gulp tem uma etapa de geração que usa qualquer {!ScriptName}.ps1 colocado na pasta \src\resources\scripts e o compila na classe powershell-scripts da pasta \src\generated.

Observação

Não atualize manualmente os arquivos powershell-scripts.ts e strings.ts. Qualquer alteração feita será substituída na próxima geração.

Executando um script do PowerShell

Todos os scripts que você deseja executar em um nó podem ser colocados em \src\resources\scripts\{!ScriptName}.ps1.

Importante

Todas as alterações feitas em um arquivo {!ScriptName}.ps1 não serão refletidas em seu projeto até que gulp generate tenha sido executado.

A API funciona criando uma sessão do PowerShell nos nós que você está direcionando, criando o script do PowerShell com todos os parâmetros que precisam ser passados e, em seguida, executando o script nas sessões que foram criadas.

Por exemplo, temos esse script \src\resources\scripts\Get-NodeName.ps1:

Param
 (
    [String] $stringFormat
 )
 $nodeName = [string]::Format($stringFormat,$env:COMPUTERNAME)
 Write-Output $nodeName

Criaremos uma sessão do PowerShell para nosso nó de destino:

const session = this.appContextService.powerShell.createSession('{!TargetNode}');

Em seguida, criaremos o script do PowerShell com um parâmetro de entrada:

const command = PowerShell.createCommand(PowerShellScripts.Get_NodeName, {stringFormat: 'The name of the node is {0}!'});

Por fim, precisamos executar esse script na sessão que criamos:

  public ngOnInit(): void {
    this.session = this.appContextService.powerShell.createAutomaticSession('{!TargetNode}');
  }

  public getNodeName(): Observable<any> {
    const command = PowerShell.createCommand(PowerShellScripts.Get_NodeName, { stringFormat: 'The name of the node is {0}!'});
    return this.appContextService.powerShell.run(this.session, command)
    .pipe(
        map(
        response => {
            if (response && response.results) {
                return response.results;
            }
            return 'no response';
        }
      )
    );
  }

  public ngOnDestroy(): void {
    this.session.dispose()
  }

Agora, precisaremos assinar a função observável que acabamos de criar. Coloque isso onde você precisa chamar a função para executar o script do PowerShell:

this.getNodeName().subscribe(
     response => {
	console.log(response)
     }
);

Ao fornecer o nome do nó para o método createSession, uma nova sessão do PowerShell é criada, usada e imediatamente destruída após a conclusão da chamada do PowerShell.

Opções de chave

Algumas opções estão disponíveis ao chamar a API do PowerShell. Uma sessão sempre pode ser criada com ou sem uma chave.

Chave: cria uma sessão com chave que pode ser pesquisada e reutilizada, mesmo entre componentes (o que significa que o Componente 1 pode criar uma sessão com a chave "SME-ROCKS" e o Componente 2 pode usar essa mesma sessão). Se uma chave for fornecida, a sessão criada deverá ser descartada chamando dispose() como foi feito no exemplo acima. Uma sessão não deve ser mantida sem ser descartada por mais de 5 minutos.

  const session = this.appContextService.powerShell.createSession('{!TargetNode}', '{!Key}');

Sem chave: uma chave será criada automaticamente para a sessão. Esta sessão com ser descartada automaticamente após 3 minutos. O uso sem chave permite que a extensão recicle o uso de qualquer runspace que já esteja disponível no momento da criação de uma sessão. Se nenhum runspace estiver disponível, um novo será criado. Essa funcionalidade é ideal para chamadas pontuais, mas o uso repetido pode afetar o desempenho. Uma sessão leva aproximadamente 1 segundo para ser criada.Portanto, sessões de reciclagem contínuas podem causar lentidão.

  const session = this.appContextService.powerShell.createSession('{!TargetNodeName}');

ou

const session = this.appContextService.powerShell.createAutomaticSession('{!TargetNodeName}');

Na maioria das situações, crie uma sessão com chave no método ngOnInit() e descarte-a em ngOnDestroy(). Siga esse padrão quando houver vários scripts do PowerShell em um componente, mas a sessão subjacente NÃO for compartilhada entre componentes. Para obter melhores resultados, verifique se a criação de sessão é gerenciada dentro de componentes em vez de serviços – isso ajuda a garantir que o tempo de vida e a limpeza possam ser gerenciados corretamente.

Para obter melhores resultados, verifique se a criação de sessão é gerenciada dentro de componentes em vez de serviços – isso ajuda a garantir que o tempo de vida e a limpeza possam ser gerenciados corretamente.

Fluxo do PowerShell

Se você tiver um script de execução prolongada e os dados forem gerados progressivamente, um fluxo do PowerShell permitirá que você processe os dados sem precisar aguardar a conclusão do script. O next() observável será chamado assim que os dados forem recebidos.

this.appContextService.powerShellStream.run(session, script);

Scripts de execução prolongada

Se você tiver um script de execução prolongada que gostaria de executar em segundo plano, um item de trabalho poderá ser enviado. O estado do script será rastreado pelo Gateway e as atualizações no status podem ser enviadas para uma notificação.

const workItem: WorkItemSubmitRequest = {
	typeId: 'Long Running Script',
	objectName: 'My long running service',
	powerShellScript: script,

	//in progress notifications
	inProgressTitle: 'Executing long running request',
	startedMessage: 'The long running request has been started',
	progressMessage: 'Working on long running script – {{ percent }} %',

	//success notification
	successTitle: 'Successfully executed a long running script!',
	successMessage: '{{objectName}} was successful',
	successLinkText: 'Bing',
	successLink: 'http://www.bing.com',
	successLinkType: NotificationLinkType.Absolute,

	//error notification
	errorTitle: 'Failed to execute long running script',
	errorMessage: 'Error: {{ message }}'

	nodeRequestOptions: {
	   logAudit: true,
	   logTelemetry: true
	}
};

return this.appContextService.workItem.submit('{!TargetNode}', workItem);

Observação

Para que o progresso seja mostrado, Write-Progress deve ser incluído no script que você gravou. Por exemplo:

 Write-Progress -Activity ‘The script is almost done!' -percentComplete 95

Opções do WorkItem

função Explicação
submit() Envia o item de trabalho
submitAndWait() Enviar o item de trabalho e aguardar a conclusão de sua execução
wait() Aguardar a conclusão do item de trabalho existente
query() Consultar um item de trabalho existente pela ID
find() Localizar um item de trabalho existente pelo TargetNodeName, ModuleName ou typeId.

APIs do Lote do PowerShell

Se você precisar executar o mesmo script em vários nós, uma sessão do PowerShell em lote poderá ser usada. Por exemplo:

const batchSession = this.appContextService.powerShell.createBatchSession(
	['{!TargetNode1}', '{!TargetNode2}', sessionKey);
  this.appContextService.powerShell.runBatchSingleCommand(batchSession, command).subscribe((responses: PowerShellBatchResponseItem[]) => {
	for (const response of responses) {
	  if (response.error || response.errors) {
	    //handle error
	  } else {
	    const results = response.properties && response.properties.results;
	    //response.nodeName
	    //results[0]
	  }
	}
     },
     Error => { /* handle error */ });

Opções do PowerShellBatch

Opção Explicação
runSingleCommand Executar um único comando em todos os nós na matriz
Executar Executar o comando correspondente no nó emparelhado
cancel Cancelar o comando em todos os nós na matriz