Utilizzo di PowerShell nell'estensione

Si applica a: Windows Admin Center, Anteprima Windows Admin Center

Esaminiamo in modo più approfondito Windows Admin Center Extensions SDK illustrando l'aggiunta di comandi PowerShell all'estensione.

PowerShell in TypeScript

Il processo di compilazione di gulp include un passaggio di generazione che accetta qualsiasi {!ScriptName}.ps1 inserito nella cartella \src\resources\scripts e lo compila nella classe powershell-scripts nella cartella \src\generated.

Nota

Non aggiornare manualmente i file powershell-scripts.tsstrings.ts. Qualsiasi modifica apportata verrà sovrascritta alla successiva generazione.

Esecuzione di uno script di PowerShell

Tutti gli script da eseguire in un nodo possono essere inseriti in \src\resources\scripts\{!ScriptName}.ps1.

Importante

Tutte le modifiche apportate in un file {!ScriptName}.ps1 verranno applicate al progetto solo dopo l'esecuzione di gulp generate.

L'API funziona creando prima una sessione di PowerShell nei nodi di destinazione, creando lo script di PowerShell con tutti i parametri che devono essere passati e quindi eseguendo lo script nelle sessioni create.

Si consideri, ad esempio, questo script \src\resources\scripts\Get-NodeName.ps1:

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

Verrà creata una sessione di PowerShell per il nodo di destinazione:

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

Verrà quindi creato lo script di PowerShell con un parametro di input:

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

Infine, è necessario eseguire lo script nella sessione creata:

  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()
  }

A questo punto è necessario sottoscrivere la funzione observable appena creata. Posizionarla nel punto in cui è necessario chiamare la funzione per eseguire lo script di PowerShell:

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

Fornendo il nome del nodo al metodo createSession, viene creata, usata e quindi eliminata immediatamente una nuova sessione di PowerShell al completamento della chiamata di PowerShell.

Opzioni chiave

Quando si chiama l'API di PowerShell sono disponibili alcune opzioni. Ogni volta che viene creata una sessione, è possibile crearla con o senza chiave.

Chiave: crea una sessione con chiave che può essere cercata e riutilizzata, anche tra i componenti (il che significa che il componente 1 può creare una sessione con la chiave "SME-ROCKS" e il componente 2 può utilizzare la stessa sessione). Se viene specificata una chiave, la sessione creata deve essere eliminata chiamando dispose() come è stato fatto nell'esempio precedente. Una sessione non deve essere mantenuta senza essere eliminata per più di 5 minuti.

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

Senza chiave: verrà creata automaticamente una chiave per la sessione. Questa sessione verrà eliminata automaticamente dopo 3 minuti. L'uso senza chiave consente all'estensione di riciclare l'uso di qualsiasi spazio di esecuzione già disponibile al momento della creazione di una sessione. Se non è disponibile uno spazio di runspace, ne verrà creato uno nuovo. Questa funzionalità è utile per le chiamate una tantum, ma l'uso ripetuto può influire sulle prestazioni. La creazione di una sessione richiede circa 1 secondo, quindi il riciclo continuo delle sessioni può causare rallentamenti.

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

oppure

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

Nella maggior parte dei casi, creare una sessione con chiave nel metodo ngOnInit() e quindi eliminarla in ngOnDestroy(). Seguire questo modello quando sono presenti più script di PowerShell in un componente, ma la sessione sottostante NON È condivisa tra i componenti. Per ottenere risultati ottimali, assicurarsi che la creazione della sessione sia gestita all'interno dei componenti anziché dei servizi, in modo da garantire che la durata e la pulizia possano essere gestite correttamente.

Per ottenere risultati ottimali, assicurarsi che la creazione della sessione sia gestita all'interno dei componenti anziché dei servizi, in modo da garantire che la durata e la pulizia possano essere gestite correttamente.

Flusso di PowerShell

Se si dispone di uno script a esecuzione prolungata e i dati vengono restituiti progressivamente, un flusso di PowerShell consentirà di elaborare i dati senza dover attendere il completamento dello script. La funzione observable next() verrà chiamata non appena vengono ricevuti i dati.

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

Script a esecuzione prolungata

Se si dispone di uno script a esecuzione prolungata che si vuole eseguire in background, è possibile inviare un elemento di lavoro. Lo stato dello script verrà monitorato dal gateway e gli aggiornamenti allo stato possono essere inviati a una notifica.

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);

Nota

Per visualizzare lo stato di avanzamento, è necessario includere Write-Progress nello script creato. Ad esempio:

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

Opzioni dell'elemento di lavoro

funzione Spiegazione
submit() Invia l'elemento di lavoro
submitAndWait() Invia l'elemento di lavoro e attende il completamento dell'esecuzione
wait() Attende il completamento dell'elemento di lavoro esistente
query() Eseguire una query per un elemento di lavoro esistente in base all'ID
find() Trova un elemento di lavoro esistente in base a TargetNodeName, ModuleName o typeId.

API batch di PowerShell

Se è necessario eseguire lo stesso script in più nodi, è possibile usare una sessione batch di PowerShell. Ad esempio:

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 */ });

Opzioni di PowerShellBatch

opzione Spiegazione
runSingleCommand Esegue un singolo comando su tutti i nodi della matrice
run Esegue il comando corrispondente nel nodo associato
cancel Annulla il comando in tutti i nodi della matrice