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 |