Compartir a través de


Uso de PowerShell de la extensión

Vamos a profundizar más en el SDK de extensiones de Windows Admin Center: vamos a hablar sobre cómo agregar comandos de PowerShell a la extensión.

PowerShell en TypeScript

El proceso de compilación de Gulp tiene un paso de generación que tomará cualquier {!ScriptName}.ps1 que se coloque en la carpeta \src\resources\scripts y los compilará en la clase powershell-scripts bajo la carpeta \src\generated.

Nota

No actualice manualmente los archivos powershell-scripts.ts ni strings.ts. Cualquier cambio que realice se sobrescribirá en la siguiente generación.

Ejecución de un script de PowerShell

Los scripts que quiera ejecutar en un nodo se pueden colocar en \src\resources\scripts\{!ScriptName}.ps1.

Importante

Cualquier cambio realizado en un archivo {!ScriptName}.ps1 no se reflejará en su proyecto hasta que se haya ejecutado gulp generate.

La API funciona creando primero una sesión de PowerShell en los nodos de destino, creando el script de PowerShell con los parámetros que se deben pasar y, a continuación, ejecutando el script en las sesiones que se crearon.

Por ejemplo, tenemos este script \src\resources\scripts\Get-NodeName.ps1:

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

Crearemos una sesión de PowerShell para el nodo de destino:

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

A continuación, crearemos el script de PowerShell con un parámetro de entrada:

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

Por último, es necesario ejecutar ese script en la sesión que hemos creado:

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

Ahora es necesario suscribirse a la función observable que se acaba de crear. Colóquelo donde necesite llamar a la función para ejecutar el script de PowerShell:

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

Al proporcionar el nombre del nodo al método createSession, se crea, se usa una nueva sesión de PowerShell y, a continuación, se destruye inmediatamente al finalizar la llamada de PowerShell.

Opciones de clave

Hay algunas opciones disponibles al llamar a la API de PowerShell. Cada vez que se crea una sesión, se puede crear con o sin una clave.

Clave: Esto crea una sesión con clave que se puede buscar y reutilizar, incluso entre componentes (lo que significa que el componente 1 puede crear una sesión con la clave "SME-ROCKS" y el componente 2 puede usar esa misma sesión. Si se proporciona una clave, la sesión que se crea debe eliminarse llamando a dispose() como se hizo en el ejemplo anterior. No se debe mantener una sesión sin eliminarse durante más de 5 minutos.

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

Sin clave: Se creará automáticamente una clave para la sesión. Esta sesión se abandonará automáticamente transcurridos 3 minutos. El uso sin claves permite a la extensión reciclar el uso de cualquier espacio de ejecución que ya esté disponible en el momento de la creación de una sesión. Si no hay ningún espacio de ejecución disponible, se creará uno nuevo. Esta funcionalidad es buena para las llamadas puntuales, pero el uso repetido puede afectar al rendimiento. Una sesión tarda aproximadamente 1 segundo en crearse, por lo que las sesiones de reciclaje continuas pueden provocar ralentizaciones.

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

o

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

En la mayoría de las situaciones, cree una sesión con clave en el método ngOnInit() y luego deshágase de ella en ngOnDestroy(). Siga este patrón cuando haya varios scripts de PowerShell en un componente pero la sesión subyacente NO SEA compartida entre los componentes. Para obtener mejores resultados, asegúrese de que la creación de sesiones se administra dentro de componentes en lugar de servicios, lo que ayuda a garantizar que la duración y la limpieza se puedan administrar correctamente.

Para obtener mejores resultados, asegúrese de que la creación de sesiones se administra dentro de componentes en lugar de servicios, lo que ayuda a garantizar que la duración y la limpieza se puedan administrar correctamente.

Flujo de PowerShell

Si tiene un script de ejecución prolongada y los datos se generan progresivamente, una secuencia de PowerShell le permitirá procesar los datos sin tener que esperar a que finalice el script. Se llamará al observable next() en cuanto se reciban los datos.

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

Scripts de larga duración

Si tiene un script de larga duración que le gustaría ejecutar en segundo plano, se puede enviar un elemento de trabajo. La puerta de enlace realizará un seguimiento del estado del script y se pueden enviar actualizaciones al estado a una notificación.

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

Para que se muestre el progreso, Write-Progress debe incluirse en el script que ha escrito. Por ejemplo:

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

Opciones de WorkItem

function Explicación
submit() Envía el elemento de trabajo.
submitAndWait() Envíe el elemento de trabajo y espere a que finalice su ejecución.
wait() Espere a que se complete el elemento de trabajo existente
query() Consulta de un elemento de trabajo existente por identificador
find() Busque un elemento de trabajo existente por el TargetNodeName, ModuleName o typeId.

API de Batch de PowerShell

Si necesita ejecutar el mismo script en varios nodos, se puede usar una sesión de PowerShell por lotes. Por ejemplo:

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

Opciones de PowerShellBatch

Opción Explicación
runSingleCommand Ejecución de un único comando en todos los nodos de la matriz
Ejecutar Ejecución del comando correspondiente en un nodo emparejado
cancel Cancelación del comando en todos los nodos de la matriz