feat(installer): add standalone Windows service deployment for DLP agent
This commit is contained in:
@@ -0,0 +1,88 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string]$ConfigPath = 'C:\ProgramData\AWatch-rus\deployment-config.json',
|
||||||
|
[int]$LoopSeconds = 20
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Get-Config {
|
||||||
|
param([string]$Path)
|
||||||
|
if (-not (Test-Path -LiteralPath $Path)) {
|
||||||
|
throw "Config not found: $Path"
|
||||||
|
}
|
||||||
|
Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-ServiceLog {
|
||||||
|
param([string]$Message)
|
||||||
|
try {
|
||||||
|
Add-Content -LiteralPath $script:LogPath -Value ('{0} {1}' -f (Get-Date -Format s), $Message)
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Start-CollectorIfNeeded {
|
||||||
|
param(
|
||||||
|
[string]$ScriptPath,
|
||||||
|
[string]$ConfigPath
|
||||||
|
)
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($ScriptPath) -or -not (Test-Path -LiteralPath $ScriptPath)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$escaped = [Regex]::Escape($ScriptPath)
|
||||||
|
$running = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object {
|
||||||
|
$_.Name -eq 'powershell.exe' -and
|
||||||
|
$_.CommandLine -match $escaped -and
|
||||||
|
$_.CommandLine -match [Regex]::Escape($ConfigPath)
|
||||||
|
} |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
|
if ($running) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = @('-NoProfile', '-ExecutionPolicy', 'Bypass')
|
||||||
|
if ($ScriptPath -like '*dlp-endpoint-signals*') {
|
||||||
|
$args += '-STA'
|
||||||
|
}
|
||||||
|
$args += @('-File', $ScriptPath, '-ConfigPath', $ConfigPath)
|
||||||
|
Start-Process -FilePath 'powershell.exe' -ArgumentList $args -WindowStyle Hidden | Out-Null
|
||||||
|
Write-ServiceLog ("started collector: {0}" -f $ScriptPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
$cfg = Get-Config -Path $ConfigPath
|
||||||
|
$stateRoot = if ($cfg.paths -and $cfg.paths.stateRoot) { [string]$cfg.paths.stateRoot } else { 'C:\ProgramData\AWatch-rus' }
|
||||||
|
$logsRoot = Join-Path $stateRoot 'logs'
|
||||||
|
if (-not (Test-Path -LiteralPath $logsRoot)) {
|
||||||
|
New-Item -Path $logsRoot -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
$script:LogPath = Join-Path $logsRoot 'standalone-agent-service.log'
|
||||||
|
|
||||||
|
Write-ServiceLog ('service loop started, config={0}' -f $ConfigPath)
|
||||||
|
|
||||||
|
while ($true) {
|
||||||
|
try {
|
||||||
|
$cfg = Get-Config -Path $ConfigPath
|
||||||
|
$paths = $cfg.paths
|
||||||
|
|
||||||
|
Start-CollectorIfNeeded -ScriptPath ([string]$paths.collectorScript) -ConfigPath $ConfigPath
|
||||||
|
Start-CollectorIfNeeded -ScriptPath ([string]$paths.endpointCollectorScript) -ConfigPath $ConfigPath
|
||||||
|
Start-CollectorIfNeeded -ScriptPath ([string]$paths.fileCollectorScript) -ConfigPath $ConfigPath
|
||||||
|
if ($paths.PSObject.Properties.Name -contains 'emailCollectorScript') {
|
||||||
|
Start-CollectorIfNeeded -ScriptPath ([string]$paths.emailCollectorScript) -ConfigPath $ConfigPath
|
||||||
|
}
|
||||||
|
if ($paths.PSObject.Properties.Name -contains 'sessionCollectorScript') {
|
||||||
|
Start-CollectorIfNeeded -ScriptPath ([string]$paths.sessionCollectorScript) -ConfigPath $ConfigPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-ServiceLog ("loop error: {0}" -f $_.Exception.Message)
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds ([Math]::Max($LoopSeconds, 5))
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$ServerHost,
|
||||||
|
[int]$ServerPort = 5600,
|
||||||
|
[ValidateSet('http', 'https')]
|
||||||
|
[string]$ServerScheme = 'http',
|
||||||
|
[string]$StateRoot = 'C:\ProgramData\AWatch-rus',
|
||||||
|
[string]$InstallRoot = 'C:\Program Files\AWatch-rus\bin',
|
||||||
|
[string]$ServiceName = 'AWatchRusStandaloneAgent',
|
||||||
|
[string]$AwHostname
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Assert-Admin {
|
||||||
|
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
$p = [Security.Principal.WindowsPrincipal]::new($id)
|
||||||
|
if (-not $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||||
|
throw 'Run as Administrator.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-Dir {
|
||||||
|
param([string]$Path)
|
||||||
|
if (-not (Test-Path -LiteralPath $Path)) {
|
||||||
|
New-Item -Path $Path -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert-Admin
|
||||||
|
|
||||||
|
$logsRoot = Join-Path $StateRoot 'logs'
|
||||||
|
Ensure-Dir -Path $StateRoot
|
||||||
|
Ensure-Dir -Path $logsRoot
|
||||||
|
|
||||||
|
$collectorScript = Join-Path $StateRoot 'browser-domains-native-collector.ps1'
|
||||||
|
$endpointCollectorScript = Join-Path $StateRoot 'dlp-endpoint-signals-collector.ps1'
|
||||||
|
$fileCollectorScript = Join-Path $StateRoot 'file-operations-collector.ps1'
|
||||||
|
$emailCollectorScript = Join-Path $StateRoot 'email-outbound-collector.ps1'
|
||||||
|
$sessionCollectorScript = Join-Path $StateRoot 'worktime-session-collector.ps1'
|
||||||
|
$rulesPath = Join-Path $StateRoot 'web-category-rules.json'
|
||||||
|
$policyPath = Join-Path $StateRoot 'dlp-policy.json'
|
||||||
|
$configPath = Join-Path $StateRoot 'deployment-config.json'
|
||||||
|
$serviceScriptPath = Join-Path $PSScriptRoot 'aw-standalone-service.ps1'
|
||||||
|
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'browser-domains-native-collector.ps1') -Destination $collectorScript -Force
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'dlp-endpoint-signals-collector.ps1') -Destination $endpointCollectorScript -Force
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'file-operations-collector.ps1') -Destination $fileCollectorScript -Force
|
||||||
|
if (Test-Path -LiteralPath (Join-Path $PSScriptRoot 'email-outbound-collector.ps1')) {
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'email-outbound-collector.ps1') -Destination $emailCollectorScript -Force
|
||||||
|
}
|
||||||
|
if (Test-Path -LiteralPath (Join-Path $PSScriptRoot 'worktime-session-collector.ps1')) {
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'worktime-session-collector.ps1') -Destination $sessionCollectorScript -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $rulesPath)) {
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'web-category-rules.example.json') -Destination $rulesPath -Force
|
||||||
|
}
|
||||||
|
if (-not (Test-Path -LiteralPath $policyPath)) {
|
||||||
|
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'dlp-policy.example.json') -Destination $policyPath -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
$effectiveHostname = if ([string]::IsNullOrWhiteSpace($AwHostname)) { [string]$env:COMPUTERNAME } else { [string]$AwHostname }
|
||||||
|
|
||||||
|
$config = [pscustomobject]@{
|
||||||
|
version = 1
|
||||||
|
generatedAtUtc = (Get-Date).ToUniversalTime().ToString('o')
|
||||||
|
awHostname = $effectiveHostname
|
||||||
|
server = [pscustomobject]@{
|
||||||
|
host = $ServerHost
|
||||||
|
port = $ServerPort
|
||||||
|
scheme = $ServerScheme
|
||||||
|
}
|
||||||
|
paths = [pscustomobject]@{
|
||||||
|
installRoot = $InstallRoot
|
||||||
|
stateRoot = $StateRoot
|
||||||
|
logsRoot = $logsRoot
|
||||||
|
collectorScript = $collectorScript
|
||||||
|
endpointCollectorScript = $endpointCollectorScript
|
||||||
|
fileCollectorScript = $fileCollectorScript
|
||||||
|
emailCollectorScript = $emailCollectorScript
|
||||||
|
sessionCollectorScript = $sessionCollectorScript
|
||||||
|
rulesPath = $rulesPath
|
||||||
|
policyPath = $policyPath
|
||||||
|
}
|
||||||
|
collector = [pscustomobject]@{
|
||||||
|
pollSeconds = 5
|
||||||
|
pulseSeconds = 30
|
||||||
|
}
|
||||||
|
collectors = [pscustomobject]@{
|
||||||
|
afkEnabled = $false
|
||||||
|
windowEnabled = $false
|
||||||
|
fileOpsEnabled = $true
|
||||||
|
emailEnabled = $true
|
||||||
|
}
|
||||||
|
logging = [pscustomobject]@{
|
||||||
|
localAgentLogsEnabled = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$config | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $configPath -Encoding UTF8
|
||||||
|
|
||||||
|
$existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
||||||
|
if ($existing) {
|
||||||
|
sc.exe stop $ServiceName | Out-Null
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
sc.exe delete $ServiceName | Out-Null
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$binPath = "`"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`" -NoProfile -ExecutionPolicy Bypass -File `"$serviceScriptPath`" -ConfigPath `"$configPath`""
|
||||||
|
sc.exe create $ServiceName binPath= "$binPath" start= auto DisplayName= "AWatch-rus Standalone Agent" | Out-Null
|
||||||
|
sc.exe description $ServiceName "Standalone AWatch-rus DLP agent service wrapper" | Out-Null
|
||||||
|
sc.exe failure $ServiceName reset= 60 actions= restart/5000/restart/5000/restart/5000 | Out-Null
|
||||||
|
sc.exe start $ServiceName | Out-Null
|
||||||
|
|
||||||
|
Write-Output "Standalone service installed: $ServiceName"
|
||||||
|
Write-Output "Config: $configPath"
|
||||||
|
Write-Output ("Host: {0} -> {1}://{2}:{3}" -f $effectiveHostname, $ServerScheme, $ServerHost, $ServerPort)
|
||||||
@@ -34,6 +34,8 @@ Name: "validate"; Description: "Запустить validate-deployment (чере
|
|||||||
[Files]
|
[Files]
|
||||||
Source: "..\..\ActivityWatch.Windows.Common.psd1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\ActivityWatch.Windows.Common.psd1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\ActivityWatch.Windows.Common.psm1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\ActivityWatch.Windows.Common.psm1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
|
Source: "..\..\install-standalone-service.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
|
Source: "..\..\aw-standalone-service.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\deploy-single-user.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\deploy-single-user.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\deploy-domain-users.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\deploy-domain-users.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\deploy-ensemble.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\deploy-ensemble.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
@@ -43,6 +45,7 @@ Source: "..\..\migrate-awatch-rus-paths.ps1"; DestDir: "{app}\windows"; Flags: i
|
|||||||
Source: "..\..\worktime-session-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\worktime-session-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\browser-domains-native-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\browser-domains-native-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\dlp-endpoint-signals-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\dlp-endpoint-signals-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
|
Source: "..\..\file-operations-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\email-outbound-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\email-outbound-collector.ps1"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\web-category-rules.example.json"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\web-category-rules.example.json"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
Source: "..\..\dlp-policy.example.json"; DestDir: "{app}\windows"; Flags: ignoreversion
|
Source: "..\..\dlp-policy.example.json"; DestDir: "{app}\windows"; Flags: ignoreversion
|
||||||
@@ -51,95 +54,11 @@ Source: "payload\{#AwDefaultZipName}"; DestDir: "{app}\payload"; Flags: ignoreve
|
|||||||
Source: "innosetup-rdp-package-filelist.md"; DestDir: "{app}\windows\installkit\innosetup"; Flags: ignoreversion
|
Source: "innosetup-rdp-package-filelist.md"; DestDir: "{app}\windows\installkit\innosetup"; Flags: ignoreversion
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "powershell.exe"; Parameters: "{code:GetDeployEnsembleParams}"; Flags: runhidden; Tasks: deploy
|
Filename: "powershell.exe"; Parameters: "{code:GetStandaloneInstallParams}"; Flags: runhidden; Tasks: deploy
|
||||||
|
|
||||||
[Code]
|
[Code]
|
||||||
var
|
var
|
||||||
ServerHostPage: TInputQueryWizardPage;
|
ServerHostPage: TInputQueryWizardPage;
|
||||||
UsersPage: TInputQueryWizardPage;
|
|
||||||
OptionsPage: TInputOptionWizardPage;
|
|
||||||
|
|
||||||
function NormalizeUserCsv(const UserCsv: string): string;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
s: string;
|
|
||||||
token: string;
|
|
||||||
begin
|
|
||||||
Result := '';
|
|
||||||
s := UserCsv;
|
|
||||||
while True do
|
|
||||||
begin
|
|
||||||
i := Pos(',', s);
|
|
||||||
if i = 0 then
|
|
||||||
begin
|
|
||||||
token := Trim(s);
|
|
||||||
s := '';
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
token := Trim(Copy(s, 1, i - 1));
|
|
||||||
Delete(s, 1, i);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if token <> '' then
|
|
||||||
begin
|
|
||||||
if Result <> '' then
|
|
||||||
Result := Result + ',';
|
|
||||||
Result := Result + token;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if s = '' then
|
|
||||||
Break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function BuildUsersPowerShellArg(const UserCsv: string): string;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
s: string;
|
|
||||||
token: string;
|
|
||||||
quoted: string;
|
|
||||||
begin
|
|
||||||
Result := '';
|
|
||||||
s := UserCsv;
|
|
||||||
while True do
|
|
||||||
begin
|
|
||||||
i := Pos(',', s);
|
|
||||||
if i = 0 then
|
|
||||||
begin
|
|
||||||
token := Trim(s);
|
|
||||||
s := '';
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
token := Trim(Copy(s, 1, i - 1));
|
|
||||||
Delete(s, 1, i);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if token <> '' then
|
|
||||||
begin
|
|
||||||
quoted := '"' + token + '"';
|
|
||||||
if Result <> '' then
|
|
||||||
Result := Result + ',';
|
|
||||||
Result := Result + quoted;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if s = '' then
|
|
||||||
Break;
|
|
||||||
end;
|
|
||||||
if Result <> '' then
|
|
||||||
Result := '-Users ' + Result;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function PayloadZipPath: string;
|
|
||||||
begin
|
|
||||||
Result := ExpandConstant('{app}\payload\{#AwDefaultZipName}');
|
|
||||||
end;
|
|
||||||
|
|
||||||
function HasPayloadZip: Boolean;
|
|
||||||
begin
|
|
||||||
Result := FileExists(ExpandConstant('{src}\payload\{#AwDefaultZipName}'));
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure InitializeWizard;
|
procedure InitializeWizard;
|
||||||
begin
|
begin
|
||||||
@@ -155,62 +74,24 @@ begin
|
|||||||
ServerHostPage.Add('ServerPort', False);
|
ServerHostPage.Add('ServerPort', False);
|
||||||
ServerHostPage.Values[0] := '{#AwDefaultServerHost}';
|
ServerHostPage.Values[0] := '{#AwDefaultServerHost}';
|
||||||
ServerHostPage.Values[1] := '{#AwDefaultServerPort}';
|
ServerHostPage.Values[1] := '{#AwDefaultServerPort}';
|
||||||
|
|
||||||
UsersPage := CreateInputQueryPage(
|
|
||||||
ServerHostPage.ID,
|
|
||||||
'Пользователи (RDP)',
|
|
||||||
'Перечень пользователей, для которых разворачиваем агенты.',
|
|
||||||
'Введите список через запятую. Пример: user1,user2,user3'
|
|
||||||
);
|
|
||||||
UsersPage.Add('Users (CSV)', False);
|
|
||||||
UsersPage.Values[0] := '{#AwDefaultUsers}';
|
|
||||||
|
|
||||||
OptionsPage := CreateInputOptionPage(
|
|
||||||
UsersPage.ID,
|
|
||||||
'Опции деплоя',
|
|
||||||
'Выберите опции для установки/валидации.',
|
|
||||||
'',
|
|
||||||
False,
|
|
||||||
False
|
|
||||||
);
|
|
||||||
OptionsPage.Add('Использовать offline payload (встроенный ZIP)');
|
|
||||||
OptionsPage.Add('Запустить validate-deployment после деплоя');
|
|
||||||
OptionsPage.Values[0] := HasPayloadZip;
|
|
||||||
OptionsPage.Values[1] := True;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GetDeployEnsembleParams(Param: string): string;
|
function GetStandaloneInstallParams(Param: string): string;
|
||||||
var
|
var
|
||||||
serverHost: string;
|
serverHost: string;
|
||||||
serverPort: string;
|
serverPort: string;
|
||||||
usersCsv: string;
|
|
||||||
usersArg: string;
|
|
||||||
zipArg: string;
|
|
||||||
validateArg: string;
|
|
||||||
begin
|
begin
|
||||||
serverHost := Trim(ServerHostPage.Values[0]);
|
serverHost := Trim(ServerHostPage.Values[0]);
|
||||||
serverPort := Trim(ServerHostPage.Values[1]);
|
serverPort := Trim(ServerHostPage.Values[1]);
|
||||||
usersCsv := NormalizeUserCsv(UsersPage.Values[0]);
|
if serverHost = '' then
|
||||||
|
RaiseException('ServerHost is empty.');
|
||||||
usersArg := BuildUsersPowerShellArg(usersCsv);
|
if serverPort = '' then
|
||||||
if usersArg = '' then
|
RaiseException('ServerPort is empty.');
|
||||||
RaiseException('Users list is empty.');
|
|
||||||
|
|
||||||
zipArg := '';
|
|
||||||
if OptionsPage.Values[0] then
|
|
||||||
zipArg := ' -PackageZipPath "' + PayloadZipPath + '"';
|
|
||||||
|
|
||||||
validateArg := '';
|
|
||||||
if OptionsPage.Values[1] and WizardIsTaskSelected('validate') then
|
|
||||||
validateArg := ' -ValidateAfterDeploy';
|
|
||||||
|
|
||||||
Result :=
|
Result :=
|
||||||
'-NoProfile -ExecutionPolicy Bypass -File "' + ExpandConstant('{app}\windows\deploy-ensemble.ps1') + '"' +
|
'-NoProfile -ExecutionPolicy Bypass -File "' + ExpandConstant('{app}\windows\install-standalone-service.ps1') + '"' +
|
||||||
' -ServerHost "' + serverHost + '"' +
|
' -ServerHost "' + serverHost + '"' +
|
||||||
' -ServerPort ' + serverPort +
|
' -ServerPort ' + serverPort +
|
||||||
' ' + usersArg +
|
|
||||||
zipArg +
|
|
||||||
' -InstallRoot "{#AwDefaultInstallRoot}"' +
|
' -InstallRoot "{#AwDefaultInstallRoot}"' +
|
||||||
' -StateRoot "{#AwDefaultStateRoot}"' +
|
' -StateRoot "{#AwDefaultStateRoot}"';
|
||||||
validateArg;
|
|
||||||
end;
|
end;
|
||||||
|
|||||||
Reference in New Issue
Block a user