diff --git a/Scripts/SAPSetupAssistantValidationScripts.zip b/Scripts/SAPSetupAssistantValidationScripts.zip new file mode 100644 index 00000000..fe3ea157 Binary files /dev/null and b/Scripts/SAPSetupAssistantValidationScripts.zip differ diff --git a/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateGateway.ps1 b/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateGateway.ps1 new file mode 100644 index 00000000..738fc99f --- /dev/null +++ b/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateGateway.ps1 @@ -0,0 +1,73 @@ +<# +.SYNOPSIS + Checks for on-premises data gateway installation. +.DESCRIPTION + This script attempts to + 1. Check if the on-premises data gateway is installed and validates the + if the version is greater than the minimum version requirement + 2. CheckSapConnector + 3. CheckVisualCPlusPlus +#> + +$minimumVersion = "3000.150.11" # November 2022 +$serviceName = "PBIEgwService" +$service = Get-Service $serviceName -ErrorAction SilentlyContinue + +if ($service) { + $servicePath = (Get-WmiObject Win32_Service | Where-Object { $_.Name -eq $serviceName }).PathName + $exePath = $servicePath.Trim('"') + $versionInfo = (Get-Command $exePath).FileVersionInfo + $versionNumber = $versionInfo.ProductVersion + + if ([version]$versionNumber -ge [version]$minimumVersion) { + Write-Host -NoNewLine "{'step': 'CheckGatewayVersion', 'status': 'Success', 'message': 'The on-premises data gateway is installed and version ($versionNumber) is greater than or equal to ($minimumVersion).'}," + } + else { + Write-Host -NoNewLine "{'step': 'CheckGatewayVersion', 'status': 'Error', 'message': 'Your on-premises data gateway doesn't meet the minimum version, please upgrade by downloading the latest version here: https://go.microsoft.com/fwlink/?linkid=2240537.'}," + } + } +else { + Write-Host -NoNewLine "{'step': 'CheckGatewayVersion', 'status': 'Error', 'message': 'The on-premises data gateway is not installed. Download it here: https://go.microsoft.com/fwlink/?linkid=2240537.'}," +} + + # .NET SDK for SAP + $currentLocation = Get-Location + $location = "C:\Windows\Microsoft.NET\assembly" + $ncoAssemblies = Get-ChildItem -Path $location -Filter sapnco.dll -Recurse | Select-Object -ExpandProperty VersionInfo + $location = "C:\Program Files\SAP\SAP_DotNetConnector3_Net40_x64" + $ncoAssemblies += Get-ChildItem -Path $location -Filter sapnco.dll -Recurse | Select-Object -ExpandProperty VersionInfo + $counter = 0 + Write-Host "value is $ncoAssemblies" + foreach ($assembly in $ncoAssemblies) { + $fileName = $assembly.FileName + + if ($assembly.FileVersion.StartsWith("3.1.")) { + Write-Host -NoNewLine "{'step': 'CheckSapConnector', 'status': 'Error', 'message': 'SAP NetWeaver Connector version 3.1 was found. You need to uninstall $fileName. Visit this link for more information: https://go.microsoft.com/fwlink/?linkid=2240708.'}," + } + + if ($fileName -like "*GAC_32*") { + Write-Host -NoNewLine "{'step': 'CheckSapConnector', 'status': 'Error', 'message': 'A 32-bit version of the SAP NetWeaver Connector was found. You need to uninstall $fileName. Visit this link for more information: https://go.microsoft.com/fwlink/?linkid=2240708.'}," + } + + if (($fileName -like "*GAC_64*" -or $fileName -like "*x64*") -and $assembly.FileVersion.StartsWith("3.0.")) { + $counter++ + Write-Host -NoNewLine "{'step': 'CheckSapConnector', 'status': 'Success', 'message': 'SAP NetWeaver Connector 3.0 64-bit was successfully found.'}," + } + } + + if ($counter -eq 0) { + Write-Host -NoNewLine "{'step': 'CheckSapConnector', 'status': 'Error', 'message': 'SAP NetWeaver Connector 3.0 64-bit was not found. Visit this link for more information: https://go.microsoft.com/fwlink/?linkid=2240708.'}," + } + + Set-Location $currentLocation + +$installedSoftware = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall" +$name = "Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219" +$obj = $installedSoftware | Where-Object { $_.GetValue("DisplayName") -eq $name } + +if ($obj) { + Write-Host -NoNewLine "{'step': 'CheckVisualCPlusPlus', 'status': 'Success', 'message': '$name is installed.'}" +} +else { + Write-Host -NoNewLine "{'step': 'CheckVisualCPlusPlus', 'status': 'Error', 'message': '$name is not installed.'}" +} \ No newline at end of file diff --git a/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateKerberosConfiguration.ps1 b/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateKerberosConfiguration.ps1 new file mode 100644 index 00000000..2b5e5c08 --- /dev/null +++ b/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateKerberosConfiguration.ps1 @@ -0,0 +1,275 @@ +<# +.SYNOPSIS + Validates Kerberos Configuration. +.DESCRIPTION + This script validates Kerberos configuration. +.PARAMETER sapCclDllPath + The path to the SAP Common Crypto Library Dll. +.PARAMETER sapCclIniPath + The path to the sapcrypto.ini file +.PARAMETER sapServicePrincipalName + The SAP Service Principal Name +.PARAMETER servicePrincipal + The Service Principal +.PARAMETER opdgServicePrincipal + The OPDG Service Principal +#> + +param ( + [string]$sapCclDllPath, + [string]$sapCclIniPath, + [string]$sapServicePrincipalName, + [string]$servicePrincipal, + [string]$opdgServicePrincipal +) + +# Required for Kerberos checks +$module = Get-Module -ListAvailable -Name ActiveDirectory + +if ($module) { + Write-Host -NoNewLine "{'step': 'CheckActiveDirectoryPowerShellModule', 'status': 'Success', 'message': 'The ActiveDirectory PowerShell module is installed.'}," +} +else { + Write-Host -NoNewLine "{'step': 'CheckActiveDirectoryPowerShellModule', 'status': 'Error', 'message': 'The ActiveDirectory PowerShell module is not installed. Kerberos checks can not be performed. Install it by following this link: https://go.microsoft.com/fwlink/?linkid=2240709.'}," +} + +#CheckCommonCryptoLibVersion +$path = $sapCclDllPath +$minimumVersion = "8.5.25.0" + +try { + $actualVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($path).FileVersion +} +catch { + Write-Host -NoNewLine "{'step': 'CheckCommonCryptoLibVersion', 'status': 'Error', 'message': 'CommonCryptoLibVersion error occurred: $_. Did you specify the correct path to the SAP CommonCryptoLib DLL?'}," + return +} + +if ([version]$actualVersion -ge [version]$minimumVersion) { + Write-Host -NoNewLine "{'step': 'CheckCommonCryptoLibVersion', 'status': 'Success', 'message': 'SAP Common Crypto Library is running version $actualVersion.'}," +} +else { + Write-Host -NoNewLine "{'step': 'CheckCommonCryptoLibVersion', 'status': 'Error', 'message': 'SAP Common Crypto Library is running an old version $actualVersion. Download the latest version of the SAP Common Crypto Library from SAP.'}," +} + +#CheckSapCryptoIniFile +$path = $sapCclIniPath + +if (-not $path) { + Write-Host -NoNewLine "{'step': 'CheckSapCryptoIniFile', 'status': 'Warning', 'message': 'Skipping SapCryptoIniFile check because no file path was provided.'}," + return +} + +$clientRole = "ccl/snc/enable_kerberos_in_client_role=1" + +try { + $iniContent = Get-Content -Path $path -ErrorAction Stop +} +catch { + Write-Host -NoNewLine "{'step': 'CheckSapCryptoIniFile', 'status': 'Error', 'message': 'SapCryptoIniFile error occurred: $_. Did you specify the correct path to the sapcrypto.ini file?'}," + return +} + +if ($iniContent -match [regex]::Escape($clientRole).Replace('=', '\s*=\s*')) { + Write-Host -NoNewLine "{'step': 'CheckSapCryptoIniFile', 'status': 'Success', 'message': 'sapcrypto.ini has the correct parameters: $clientRole.'}," +} +else { + Write-Host -NoNewLine "{'step': 'CheckSapCryptoIniFile', 'status': 'Error', 'message': 'sapcrypto.ini is missing the correct parameters. Modify sapcrypto.ini and add $clientRole.'}," +} + +#checkSystemEnvVariable -variableName "CCL_PROFILE" + +if ($env:CCL_PROFILE) { + Write-Host -NoNewLine "{'step': 'CheckSapCryptoIniFile', 'status': 'Success', 'message': 'System Environment variable CCL_PROFILE exists'}," +} +else { +Write-Host -NoNewLine "{'step': 'CheckSapCryptoIniFile', 'status': 'Error', 'message': 'Need to create a CCL_PROFILE system environment variable and set its value to the path to sapcrypto.ini.'}," +} + +#CheckServicePrincipalName +$sapServicePrincipalName = $sapServicePrincipalName + +if (-not $sapServicePrincipalName) { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalName', 'status': 'Warning', 'message': 'Skipping ServicePrincipalName check because no service principal name was provided.'}," + return +} +try { + $servicePrincipal = Get-ADUser -Filter { ServicePrincipalNames -like $sapServicePrincipalName } -Properties ServicePrincipalNames -ErrorAction Stop +} +catch { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalName', 'status': 'Error', 'message': 'ServicePrincipalName error occurred: $_.'}," + return +} + +if ($servicePrincipal) { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalName', 'status': 'Success', 'message': 'Service Principal Name $sapServicePrincipalName exists on $servicePrincipal'}," +} +else { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalName', 'status': 'Error', 'message': 'Service Principal Name $sapServicePrincipalName does not exist in Active Directory.'}," +} + +#CheckServicePrincipalSupportedEncryptionTypes +$servicePrincipal = $servicePrincipal + if (-not $servicePrincipal) { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalSupportedEncryptionTypes', 'status': 'Warning', 'message': 'Skipping ServicePrincipalSupportedEncryptionTypes check because no service principal was provided.'}," + return + } + # All the decimal values that contain AES encryption types + # https://go.microsoft.com/fwlink/?linkid=2240296 + $aesEncryptionTypes = @(8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31) + + try { + $supportedEncryptionTypes = Get-ADUser $servicePrincipal -Properties msDS-SupportedEncryptionTypes -ErrorAction Stop + $value = $supportedEncryptionTypes."msDS-SupportedEncryptionTypes" + } + catch { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalSupportedEncryptionTypes', 'status': 'Error', 'message': 'ServicePrincipalSupportedEncryptionTypes error occurred: $_.'}," + return + } + + if ($aesEncryptionTypes.Contains($value)) { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalSupportedEncryptionTypes', 'status': 'Success', 'message': 'AES is enabled (msDS-SupportedEncryptionTypes => $value) for $servicePrincipal.'}," + } + else { + Write-Host -NoNewLine "{'step': 'CheckServicePrincipalSupportedEncryptionTypes', 'status': 'Error', 'message': 'AES is missing (msDS-SupportedEncryptionTypes) for $servicePrincipal.'}," + } + +#CheckAllowedToDelegateTo +$servicePrincipal = $opdgServicePrincipal +$servicePrincipalName = $sapServicePrincipalName + + # Checks if OPDG servicePrincipal is allowed to delegate to the SAP service principal name + if (-not $servicePrincipal -or -not $servicePrincipalName) { + Write-Host -NoNewLine "{'step': 'CheckAllowedToDelegateTo', 'status': 'Warning', 'message': 'Skipping AllowedToDelegate check because no service principal name was provided.'}," + return + } + + try { + $allowedToDelegateTo = Get-ADUser $servicePrincipal -Properties msDS-AllowedToDelegateTo -ErrorAction Stop + $value = $allowedToDelegateTo."msDS-AllowedToDelegateTo" + } + catch { + Write-Host -NoNewLine "{'step': 'CheckAllowedToDelegateTo', 'status': 'Error', 'message': 'AllowedToDelegateTo error occurred: $_.'}," + return + } + + if ($null -ne $value -and $value.Contains($servicePrincipalName)) { + Write-Host -NoNewLine "{'step': 'CheckAllowedToDelegateTo', 'status': 'Success', 'message': 'Delegation is enabled (msDS-AllowedToDelegateTo => $value) for $servicePrincipal.'}," + } + else { + Write-Host -NoNewLine "{'step': 'CheckAllowedToDelegateTo', 'status': 'Error', 'message': 'Delegation is disabled (msDS-AllowedToDelegateTo) for $servicePrincipal. Check the $servicePrincipal account in Active Directory and add $servicePrincipalName on the Delegation tab.'}," + } + +#CheckTrustedToAuthForDelegation +$servicePrincipal = $opdgServicePrincipal + # Checks if OPDG service principal in Active Directory has "Use any authentication protocol" enabled on Delegation tab + if (-not $servicePrincipal) { + Write-Host -NoNewLine "{'step': 'CheckTrustedToAuthForDelegation', 'status': 'Warning', 'message': 'Skipping TrustedToAuthForDelegation check because no service principal name was provided.'}," + return + } + + try { + $trustedToAuthForDelegation = Get-ADUser -Identity $servicePrincipal -Properties TrustedToAuthForDelegation -ErrorAction Stop | Select-Object TrustedToAuthForDelegation + $value = $trustedToAuthForDelegation."trustedToAuthForDelegation" + } + catch { + Write-Host -NoNewLine "{'step': 'CheckTrustedToAuthForDelegation', 'status': 'Error', 'message': 'TrustedToAuthForDelegation error occurred: $_.'}," + return + } + + if ($value) { + Write-Host -NoNewLine "{'step': 'CheckTrustedToAuthForDelegation', 'status': 'Success', 'message': 'TrustedToAuthForDelegation enabled ($value) for $servicePrincipal.'}," + } + else { + Write-Host -NoNewLine "{'step': 'CheckTrustedToAuthForDelegation', 'status': 'Error', 'message': 'TrustedToAuthForDelegation disabled for $servicePrincipal. Check the $servicePrincipal account in AD and enable 'Use any authentication protocol' on Delegation the tab.'}," + } + +#CheckActAsPartOfOperatingSystem +$servicePrincipal = $opdgServicePrincipal + # Checks OPDG operating system that service servicePrincipal has "Act as part of the operating system" privilege + if (-not $servicePrincipal) { + Write-Host -NoNewLine "{'step': 'CheckActAsPartOfOperatingSystem', 'status': 'Warning', 'message': 'Skipping ActAsPartOfOperatingSystem check because no service principal name was provided.'}," + return + } + + try { + $accountSid = Get-ADUser -Identity $servicePrincipal -Properties ObjectGUID | Select-Object SID | Out-Null + } + catch { + Write-Host -NoNewLine "{'step': 'CheckActAsPartOfOperatingSystem', 'status': 'Error', 'message': 'ActAsPartOfOperatingSystem error occurred: $_.'}," + return + } + + # This is not a PowerShell cmdlet, so we need to use the old command line tool + secedit /export /cfg $env:TEMP\secpol.cfg | Out-Null + + # Checks if the secedit command was successful or not + if ($LASTEXITCODE -ne 0) { + Write-Host -NoNewLine "{'step': 'CheckActAsPartOfOperatingSystem', 'status': 'Error', 'message': 'ActAsPartOfOperatingSystem failed. Try running with an elevated PowerShell prompt.'}," + return + } + + $value = (Get-Content $env:TEMP\secpol.cfg | Select-String "SeTcbPrivilege").ToString() + Remove-Item $env:TEMP\secpol.cfg + $servicePrincipal = $servicePrincipal.replace("\", "\\") + if ($value.Contains($accountSid.SID.Value)) { + Write-Host -NoNewLine "{'step': 'CheckActAsPartOfOperatingSystem', 'status': 'Success', 'message': 'ActAsPartOfOperatingSystem enabled ($value) for $servicePrincipal.'}," + } + else { + Write-Host -NoNewLine "{'step': 'CheckActAsPartOfOperatingSystem', 'status': 'Error', 'message': 'ActAsPartOfOperatingSystem disabled ($value) for $servicePrincipal. Check the 'Act as part of the operating system' property of the $servicePrincipal in the Local Security Policy console.'}," + } + +#CheckImpersonateAClientAfterAuthentication +$servicePrincipal = $opdgServicePrincipal + # Checks OPDG operating system that service principal has "Impersonate a client after authentication" privilege + if (-not $servicePrincipal) { + Write-Host -NoNewLine "{'step': 'CheckImpersonateAClientAfterAuthentication', 'status': 'Warning', 'message': 'Skipping ImpersonateAClientAfterAuthentication check because no service principal name was provided.'}," + return + } + + try { + $accountSid = Get-ADUser -Identity $servicePrincipal -Properties ObjectGUID -ErrorAction Stop | Select-Object SID + } + catch { + Write-Host -NoNewLine "{'step': 'CheckImpersonateAClientAfterAuthentication', 'status': 'Error', 'message': 'ImpersonateAClientAfterAuthentication error occurred: $_.'}," + return + } + + # This is not a PowerShell cmdlet, so we need to use the old command line tool + secedit /export /cfg $env:TEMP\secpol.cfg | Out-Null + + # Checks if the secedit command was successful or not + if ($LASTEXITCODE -ne 0) { + Write-Host -NoNewLine "{'step': 'CheckImpersonateAClientAfterAuthentication', 'status': 'Error', 'message': 'ImpersonateAClientAfterAuthentication failed. Try running with an elevated PowerShell prompt.'}," + return + } + + $value = (Get-Content $env:TEMP\secpol.cfg | Select-String "SeImpersonatePrivilege").ToString() + Remove-Item $env:TEMP\secpol.cfg + + if ($value.Contains($accountSid.SID.Value)) { + Write-Host -NoNewLine "{'step': 'CheckImpersonateAClientAfterAuthentication', 'status': 'Success', 'message': 'ImpersonateAClientAfterAuthentication enabled ($value).'}," + } + else { + Write-Host -NoNewLine "{'step': 'CheckImpersonateAClientAfterAuthentication', 'status': 'Error', 'message': 'ImpersonateAClientAfterAuthentication disabled ($value). Check the 'Impersonate a client after authentication' property in the Local Security Policy console.'}," + } + +#CheckGatewayServiceRunsAs +$servicePrincipal = $opdgServicePrincipal + # Check what servicePrincipal the OPDG service is running as + if (-not $servicePrincipal) { + Write-Host -NoNewLine "{'step': 'CheckGatewayServiceRunsAs', 'status': 'Warning', 'message': 'Skipping GatewayServiceRunsAs check because no service principal name was provided.'}]" + return + } + + $service = Get-WmiObject -Class Win32_Service -Filter "Name='PBIEgwService'" + + if ($null -ne $service -and $service.StartName -ilike "*$servicePrincipal*") { + $servicePrincipal = $servicePrincipal.replace("\", "\\") + Write-Host -NoNewLine "{'step': 'CheckGatewayServiceRunsAs', 'status': 'Success', 'message': 'GatewayServiceRunsAs is running as $servicePrincipal.'}]" + } + else { + $servicePrincipal = $servicePrincipal.replace("\", "\\") + Write-Host -NoNewLine "{'step': 'CheckGatewayServiceRunsAs', 'status': 'Error', 'message': 'GatewayServiceRunsAs is not running as $servicePrincipal. Check the 'Log On As' property of the 'On-premises data gateway service' in the Windows Services console. It should be running as $servicePrincipal.'}]" + } + diff --git a/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateNetworkConnection.ps1 b/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateNetworkConnection.ps1 new file mode 100644 index 00000000..6de52356 --- /dev/null +++ b/Scripts/SAPSetupAssistantValidationScripts/SetupAssistantSAPValidateNetworkConnection.ps1 @@ -0,0 +1,39 @@ +<# +.SYNOPSIS + Tests network connection to a specified host and port. +.DESCRIPTION + This script attempts to establish a TCP connection to the specified host and port, + and reports the result in a JSON format. +.PARAMETER HostName + The hostname or IP address to connect to. +.PARAMETER Port + The port number to connect to. +#> +param ( + [Parameter(Mandatory=$true)] + [string]$hostName, + + [Parameter(Mandatory=$true)] + [string]$port +) + +$job = Start-Job -ScriptBlock { + param($hostName, $port) + Test-NetConnection -ComputerName $hostName -Port $port +} -ArgumentList $hostName, $port + +if (Wait-Job -Job $job -Timeout 10) { + $result = Receive-Job -Job $job + + if ($result.TcpTestSucceeded) { + Write-Host -NoNewLine "[{'step': 'CheckNetworkConnection', 'status': 'Success', 'message': 'Successfully connected to $hostName over port $port.'}]" + } + else { + Write-Host -NoNewLine "[{'step': 'CheckNetworkConnection', 'status': 'Error', 'message': 'Failed to connect to $hostName over port $port.'}]" + } +} +else { + Write-Host -NoNewLine "[{'step': 'CheckNetworkConnection', 'status': 'Error', 'message': 'The connection to $hostName over port $port timed out after 5 seconds.'}]" +} + +Remove-Job -Force -Job $job \ No newline at end of file diff --git a/Solution Packages For Manual Install/SAP Setup Assistant/mpa_SAPSetupAssistantDropDownValues_managed.zip b/Solution Packages For Manual Install/SAP Setup Assistant/mpa_SAPSetupAssistantDropDownValues_managed.zip new file mode 100644 index 00000000..537376b1 Binary files /dev/null and b/Solution Packages For Manual Install/SAP Setup Assistant/mpa_SAPSetupAssistantDropDownValues_managed.zip differ