toArray(); $validation = $this->contracts->validateInvocation($contract, $commandContract->parameters()); if (! $validation['accepted']) { return $this->blocked('command_contract_rejected', [ 'command_builder_state' => 'contract_rejected', 'command_validation' => [ 'reason_code' => is_string($validation['reason_code'] ?? null) ? $validation['reason_code'] : 'unknown', 'rejected_parameter_count' => count($commandContract->parameterNames()), ], ]); } $commandName = (string) ($contract['command_name'] ?? ''); if (! in_array($commandName, ['Get-TransportRule', 'Get-RemoteDomain', 'Get-InboundConnector'], true)) { return $this->blocked('command_contract_rejected', [ 'command_builder_state' => 'command_not_allowlisted', 'command_validation' => [ 'reason_code' => 'command_not_allowlisted', 'rejected_parameter_count' => 0, ], ]); } if ($commandContract->parameterNames() !== []) { return $this->blocked('command_contract_rejected', [ 'command_builder_state' => 'parameter_policy_rejected', 'command_validation' => [ 'reason_code' => 'unknown_parameter_rejected', 'rejected_parameter_count' => count($commandContract->parameterNames()), ], ]); } return ExchangePowerShellProcessCommandBuilderResult::built( command: new ExchangePowerShellProcessCommand( arguments: [ $policy->powershellBinary, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command', $commandName, ], timeoutSeconds: $policy->invocationTimeoutSeconds, stdoutMaxBytes: $policy->stdoutMaxBytes, stderrMaxBytes: $policy->stderrMaxBytes, ), context: [ 'command_builder_state' => 'fixed_allowlist_argument_vector', 'command_name' => $commandName, 'parameter_count' => 0, ], ); } /** * @param array $context */ private function blocked(string $failureCode, array $context): ExchangePowerShellProcessCommandBuilderResult { return ExchangePowerShellProcessCommandBuilderResult::blocked( reasonCode: ProviderReasonCodes::ProviderBindingUnsupported, failureCode: $failureCode, message: 'Exchange PowerShell command construction was rejected.', context: $context, ); } }