├── .gitattributes
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── 1_settingUpPowerShellDsc
├── clearDscCache.ps1
├── enterPSSession.ps1
└── localLcmSet.ps1
├── 2_settingUpArcgisModule
├── downloadUpgradeArcgisModule.ps1
├── getModuleVersion.ps1
├── installModule.ps1
└── transferModule.ps1
├── 3_settingUpServerEnvironment
├── avExceptions.ps1
├── dmz
│ ├── dmzServer
│ │ ├── createRemoveAccount
│ │ │ ├── createLocalAccount.ps1
│ │ │ └── removeLocalAccount.ps1
│ │ ├── createRemoveLocalAccountTokenFilterPolicy
│ │ │ ├── removeLocalAccountTokenFilterPolicy.ps1
│ │ │ └── setLocalAccountTokenFilterPolicy.ps1
│ │ └── createRemoveTrustedHosts
│ │ │ ├── addTrustedHosts.ps1
│ │ │ └── removeTrustedHosts.ps1
│ └── internalServers
│ │ ├── createRemoveAccount
│ │ ├── createLocalAccount.ps1
│ │ └── removeLocalAccount.ps1
│ │ ├── createRemoveLocalAccountTokenFilterPolicy
│ │ ├── removeLocalAccountTokenFilterPolicy.ps1
│ │ └── setLocalAccountTokenFilterPolicy.ps1
│ │ └── createRemoveTrustedHosts
│ │ ├── addTrustedHosts.ps1
│ │ └── removeTrustedHosts.ps1
├── forDisconnectedEnvironments
│ ├── transferInstallers.ps1
│ └── transferPreRequisites.ps1
├── forMigrations
│ ├── addHostEntry.ps1
│ ├── removeHostEntry.ps1
│ └── setFirewallRulesBlockIpFilter.ps1
├── generatePwFiles.ps1
├── setFirewallRulesAllowAge.ps1
├── transferCertificates.ps1
├── transferLicenses.ps1
└── transferODBC.ps1
├── 4_deployment
├── InvokeScript_Install.ps1
└── InvokeScript_Upgrade.ps1
├── 5_troubleshooting
├── forMigrations
│ └── checkForServiceMigrationIssues.ps1
├── restartServers.ps1
├── restartServices.ps1
├── stopServices.ps1
└── taskKillWindowsInstaller.ps1
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: BrendanEsri, adrienhafner
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: BrendanEsri, adrienhafner
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .github/ISSUE_TEMPLATE/feature_request.md
2 | . g i t h u b / I S S U E _ T E M P L A T E /
3 | . g i t h u b / I S S U E _ T E M P L A T E /
4 |
--------------------------------------------------------------------------------
/1_settingUpPowerShellDsc/clearDscCache.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 |
3 | # change the machine1, machine2 with your machines
4 | # This script sets the Local DSC configuration to Stop on Restart and to ApplyOnly so logs don't pile up and so it won't run again on restart
5 |
6 | $arcgisservers = @('machine1','machine2')
7 |
8 | foreach ($server in $arcgisservers) {
9 | Write-Host "Connecting to $server";
10 | $session = New-PSSession -ComputerName $server;
11 | Invoke-Command -Session $session -ScriptBlock {
12 | Write-Host 'clearing dsc config';
13 | Remove-DscConfigurationDocument -Stage Current, Pending, Previous -Verbose -Force;
14 | Write-Host 'cleared dsc config';
15 | }
16 | Write-Host "Disconnected from $server";
17 | Remove-PSSession $session;
18 | }
--------------------------------------------------------------------------------
/1_settingUpPowerShellDsc/enterPSSession.ps1:
--------------------------------------------------------------------------------
1 | #Adrien Hafner
2 | #This script is designed to assist with confirming WinRM connectivity between an orchestration server and other servers in the deployment before attempting a PowerShellDSC install. The script can also assist with troubleshooting if you feel there may be an issue with connecting from an orchestration or deployment server to remote servers in the environment.
3 | #If successful, this script should allow you to enter a PowerShell session on the remote computer specified.
4 | #change the "Server1","Server2", Server3" text with your machine names
5 |
6 |
7 | # List of servers
8 | $servers = @("Server1", "Server2", "Server3")
9 |
10 | # Loop through each server
11 | foreach ($server in $servers) {
12 | try {
13 | # Enter the PSSession
14 | Enter-PSSession -ComputerName $server -ErrorAction Stop
15 |
16 | # Do any necessary tasks in the session here if needed (Optional)
17 | Write-Host "Entered session for $server"
18 |
19 | } catch {
20 | # Handle any errors if the connection fails
21 | Write-Host "Failed to connect to $server. Error: $_"
22 | } finally {
23 | # Exit the session
24 | Exit-PSSession
25 | Write-Host "Exited session for $server"
26 | }
27 | }
--------------------------------------------------------------------------------
/1_settingUpPowerShellDsc/localLcmSet.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 |
3 | # This script sets the Local DSC configuration to Stop on Restart and to ApplyOnly so logs don't pile up
4 |
5 | #change the machine1, machine2 with your machines
6 | #if only one machine in deployment then can simply run the contents of the invoke command
7 | $arcgisservers = @('machine1','machine2')
8 |
9 | foreach ($server in $arcgisservers) {
10 | Write-Host "Connecting to $server";
11 | $session = New-PSSession -ComputerName $server;
12 | Invoke-Command -Session $session -ScriptBlock {
13 | Write-Host 'Setting Local DSC Configuration Manager to ApplyOnly and Stop Configuration';
14 | Set-Location C:\Windows\System32;
15 | [DSCLocalConfigurationManager()]
16 | configuration LCMConfig {
17 | Node localhost {
18 | Settings {
19 | ConfigurationMode='ApplyOnly'
20 | ActionAfterReboot = 'StopConfiguration'
21 | }
22 | }
23 | }
24 | LCMConfig;
25 | Set-DscLocalConfigurationManager -Path 'C:\Windows\System32\LCMConfig' -Force;
26 | Write-Host 'Local DSC Configuration Manager is now set to ApplyOnly';
27 | }
28 | Write-Host "Disconnected from $server";
29 | Remove-PSSession $session;
30 | }
31 |
--------------------------------------------------------------------------------
/2_settingUpArcgisModule/downloadUpgradeArcgisModule.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 |
3 | # connects to each machine in the arcgisservers array and removes the old ArcGIS module from the machine then installs the new module
4 |
5 | # change the machine1, machine2 with your machines
6 |
7 | $arcgisservers = ("machine1","machine2")
8 |
9 | # Start a new job for each server
10 | $jobs = $arcgisservers | ForEach-Object {
11 | $server = $_
12 | Start-Job -ScriptBlock {
13 | param($server)
14 | Write-Host "Connecting to $server"
15 | $session = New-PSSession -ComputerName $server
16 | Invoke-Command -Session $session -ScriptBlock {
17 | Remove-Item -Path "C:\Program Files\WindowsPowerShell\Modules\ArcGIS" -Recurse -Force -ErrorAction SilentlyContinue
18 | # Set the security protocol to TLS 1.2
19 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
20 | # Install NuGet provider
21 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
22 | #install new module to this machine
23 | Install-Module ArcGIS -Force
24 | }
25 | } -ArgumentList $server
26 | }
27 |
28 | # Wait for all jobs to complete
29 | $jobs | Wait-Job
30 |
31 | # Get the results of the jobs and print them
32 | $jobs | Receive-Job | ForEach-Object { Write-Host $_ }
33 |
34 | # Clean up the jobs
35 | $jobs | Remove-Job
--------------------------------------------------------------------------------
/2_settingUpArcgisModule/getModuleVersion.ps1:
--------------------------------------------------------------------------------
1 | ##Adrien Hafner
2 | ##This script will report on which version of the ArcGIS PowerShell DSC module is installed on each of the servers in the list you provide the script.
3 | ##This information can be helpful when determining whether or not the ArcGIS module version needs upgraded, and also indicates when there is more than one version of the module installed (this can sometimes cause issues and is not recommended).
4 |
5 | $servers = @("Server1","Server2","Server3")
6 |
7 | foreach ($server in $servers) {
8 | try {
9 | # Run Get-Module remotely on each server
10 | $modules = Invoke-Command -ComputerName $server -ScriptBlock {
11 | Get-Module -ListAvailable -Name 'ArcGIS'
12 | }
13 |
14 | # If modules are found, output the result
15 | if ($modules) {
16 | Write-Host "ArcGIS modules on ${server}:"
17 | $modules
18 | }
19 | else {
20 | Write-Host "No ArcGIS modules found on ${server}."
21 | }
22 | }
23 | catch {
24 | # If an error occurs, output the failure message
25 | Write-Host "Unable to get version on ${server}"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/2_settingUpArcgisModule/installModule.ps1:
--------------------------------------------------------------------------------
1 | #This script installs the ArcGIS PowerShellDSC module on an individual machine such an an orchestration server. Other scripts can then be used to transfer the module to other machines in the deployment.
2 |
3 | Install-Module ArcGIS
--------------------------------------------------------------------------------
/2_settingUpArcgisModule/transferModule.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 | #
3 | # this script is designed to transfer arcgis module to all the machines in the @arcgisservers block from a local directory on the machine that has the arcgis module
4 |
5 | # change the machine1, machine2 with your machines
6 |
7 | # Do not include the machine that has the arcgis module on it inside of the @arcgisservers block or it will remove your arcgis module
8 |
9 | $arcgisservers = @('machine1','machine2')
10 |
11 | $ScriptBlock = {
12 | param ($server)
13 | # Define the target directory path
14 | $targetDir = "\\$server\c$\Program Files\WindowsPowerShell\Modules"
15 |
16 | # If the directory already exists, remove its contents
17 | if (Test-Path -Path "$targetDir\ArcGIS") {
18 | Remove-Item "$targetDir\ArcGIS" -Recurse -Force
19 | }
20 | else {
21 | Write-Host "The ArcGIS Module is not installed on $server"
22 | }
23 |
24 | # Now, copy the folder of the source licenses folder to the target
25 | Copy-Item -Path "C:\Program Files\WindowsPowerShell\Modules\ArcGIS" -Destination $targetDir -Recurse -Force
26 | }
27 |
28 | $jobs = @()
29 | foreach ($server in $arcgisservers) {
30 | $job = Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server
31 | $jobs += $job
32 | }
33 |
34 | # Wait for all jobs to complete
35 | $jobs | Wait-Job
36 |
37 | # Output job results and cleanup
38 | $jobs | ForEach-Object {
39 | Receive-Job -Job $_
40 | Remove-Job -Job $_
41 | }
42 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/avExceptions.ps1:
--------------------------------------------------------------------------------
1 | # List of target machines
2 | $computers = @("Machine1", "Machine2", "Machine3")
3 |
4 | # Define the list of folders to exclude
5 | $foldersToExclude = @(
6 | "E:\ArcGIS",
7 | "E:\arcgisportal",
8 | "E:\arcgisserver",
9 | "E:\arcgisdatastore",
10 | "E:\Automation"
11 | )
12 |
13 | # Script block to execute on each machine
14 | $scriptBlock = {
15 | param($foldersToExclude)
16 | $serverName = $env:COMPUTERNAME
17 | Write-Host "Starting to exclude folders from Windows Defender on $serverName"
18 | foreach ($folder in $foldersToExclude) {
19 | Add-MpPreference -ExclusionPath $folder
20 | Write-Host "Excluded $folder on $serverName"
21 | }
22 | Write-Host "Completed excluding folders from Windows Defender on $serverName"
23 | }
24 |
25 | # Execute the script block on each target machine
26 | foreach ($computer in $computers) {
27 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock -ArgumentList $foldersToExclude
28 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/dmzServer/createRemoveAccount/createLocalAccount.ps1:
--------------------------------------------------------------------------------
1 | # Create a local user account on a Windows machine
2 |
3 | # Variables
4 | $username = "dmzUser"
5 | #$password = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
6 | $password = Read-Host "Enter password for the new user" -AsSecureString
7 | $description = "Local user for DMZ and Non-DMZ machines"
8 |
9 | try {
10 | # Create local user
11 | if (-not (Get-LocalUser -Name $username -ErrorAction SilentlyContinue)) {
12 | New-LocalUser -Name $username -Password $password -Description $description
13 | Write-Host "Local user $username created successfully."
14 | } else {
15 | Write-Host "Local user $username already exists."
16 | }
17 |
18 | # Add user to the Administrators group
19 | if (-not (Get-LocalGroupMember -Group "Administrators" -Member $username -ErrorAction SilentlyContinue)) {
20 | Add-LocalGroupMember -Group "Administrators" -Member $username
21 | Write-Host "User $username added to Administrators group."
22 | } else {
23 | Write-Host "User $username is already a member of the Administrators group."
24 | }
25 | } catch {
26 | Write-Host "An error occurred: $_"
27 | }
28 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/dmzServer/createRemoveAccount/removeLocalAccount.ps1:
--------------------------------------------------------------------------------
1 | # This script removes a local user from the Administrators group and then deletes the user account from the local machine.
2 |
3 | # Variables
4 | $username = "dmzUser"
5 |
6 | try {
7 | # Remove user from the Administrators group (if added)
8 | if (Get-LocalGroupMember -Group "Administrators" -Member $username -ErrorAction SilentlyContinue) {
9 | Remove-LocalGroupMember -Group "Administrators" -Member $username
10 | Write-Host "User $username removed from Administrators group."
11 | } else {
12 | Write-Host "User $username was not a member of the Administrators group."
13 | }
14 |
15 | # Remove the local user
16 | if (Get-LocalUser -Name $username -ErrorAction SilentlyContinue) {
17 | Remove-LocalUser -Name $username
18 | Write-Host "Local user $username removed successfully."
19 | } else {
20 | Write-Host "Local user $username does not exist."
21 | }
22 | } catch {
23 | Write-Host "An error occurred: $_"
24 | }
25 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/dmzServer/createRemoveLocalAccountTokenFilterPolicy/removeLocalAccountTokenFilterPolicy.ps1:
--------------------------------------------------------------------------------
1 | # Remove LocalAccountTokenFilterPolicy
2 | $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
3 | $regName = "LocalAccountTokenFilterPolicy"
4 |
5 | try {
6 | if (Get-ItemProperty -Path $regPath -Name $regName -ErrorAction SilentlyContinue) {
7 | Remove-ItemProperty -Path $regPath -Name $regName -Force
8 | Write-Output "LocalAccountTokenFilterPolicy registry entry removed successfully."
9 | } else {
10 | Write-Output "LocalAccountTokenFilterPolicy registry entry does not exist."
11 | }
12 | } catch {
13 | Write-Output "An error occurred: $_"
14 | }
15 |
16 | # Verify the removal
17 | try {
18 | Get-ItemProperty -Path $regPath -Name $regName -ErrorAction Stop
19 | Write-Output "Failed to remove LocalAccountTokenFilterPolicy registry entry."
20 | } catch {
21 | Write-Output "LocalAccountTokenFilterPolicy registry entry is confirmed as removed."
22 | }
23 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/dmzServer/createRemoveLocalAccountTokenFilterPolicy/setLocalAccountTokenFilterPolicy.ps1:
--------------------------------------------------------------------------------
1 | # Create LocalAccountTokenFilterPolicy
2 | # Set LocalAccountTokenFilterPolicy to 1
3 | $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
4 | $regName = "LocalAccountTokenFilterPolicy"
5 | $regValue = 1
6 |
7 | try {
8 | if (-not (Get-ItemProperty -Path $regPath -Name $regName -ErrorAction SilentlyContinue)) {
9 | New-ItemProperty -Path $regPath -Name $regName -PropertyType DWORD -Value $regValue -Force
10 | Write-Output "LocalAccountTokenFilterPolicy registry entry created and set to 1."
11 | } else {
12 | Set-ItemProperty -Path $regPath -Name $regName -Value $regValue
13 | Write-Output "LocalAccountTokenFilterPolicy registry entry already existed and if it was not set to 1, it was updated to 1."
14 | }
15 | } catch {
16 | Write-Output "An error occurred: $_"
17 | }
18 |
19 | # Verify the setting
20 | $setValue = Get-ItemProperty -Path $regPath -Name $regName
21 | if ($setValue.LocalAccountTokenFilterPolicy -eq $regValue) {
22 | Write-Output "LocalAccountTokenFilterPolicy is successfully set to 1."
23 | } else {
24 | Write-Output "Failed to set LocalAccountTokenFilterPolicy to 1."
25 | }
26 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/dmzServer/createRemoveTrustedHosts/addTrustedHosts.ps1:
--------------------------------------------------------------------------------
1 | # Creates a comma-separated string of IP addresses and hostnames and sets the TrustedHosts configuration setting for WinRM.
2 |
3 | # Variables
4 | $trustedHosts = @(
5 | "192.168.1.1", # Replace with your IP addresses
6 | "192.168.1.2",
7 | "hostname1.domain.com", # Replace with your hostnames
8 | "hostname2.domain.com"
9 | )
10 |
11 | # Convert the array to a comma-separated string
12 | $trustedHostsString = $trustedHosts -join ','
13 |
14 | # Prepare the input in the required format
15 | $input = "@{TrustedHosts=`"$trustedHostsString`"}"
16 |
17 | # Set TrustedHosts
18 | try {
19 | winrm set winrm/config/client $input
20 | Write-Host "TrustedHosts set to: $trustedHostsString"
21 | } catch {
22 | Write-Host "An error occurred: $_"
23 | }
24 |
25 | # Output the current winrm/config/client configuration
26 | $currentConfig = winrm get winrm/config/client
27 | Write-Host "Current winrm/config/client configuration:"
28 | $currentConfig | ForEach-Object { Write-Host $_ }
29 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/dmzServer/createRemoveTrustedHosts/removeTrustedHosts.ps1:
--------------------------------------------------------------------------------
1 | # Reset TrustedHosts to default (empty value)
2 | try {
3 | winrm set winrm/config/client '@{TrustedHosts=""}'
4 | Write-Host "TrustedHosts has been reset to default (empty value)."
5 | } catch {
6 | Write-Host "An error occurred: $_"
7 | }
8 |
9 | # Output the current winrm/config/client configuration
10 | $currentConfig = winrm get winrm/config/client
11 | Write-Host "Current winrm/config/client configuration:"
12 | $currentConfig | ForEach-Object { Write-Host $_ }
13 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/internalServers/createRemoveAccount/createLocalAccount.ps1:
--------------------------------------------------------------------------------
1 | # Variables
2 | $username = "dmzUser"
3 | $description = "Local user for DMZ and Non-DMZ machines"
4 | $password = Read-Host "Enter password for the new user" -AsSecureString
5 |
6 | # List of target machines
7 | $computers = @("Machine1", "Machine2", "Machine3")
8 |
9 | # Script block to execute on each machine
10 | $scriptBlock = {
11 | param($username, $password, $description)
12 |
13 | try {
14 | # Create local user
15 | if (-not (Get-LocalUser -Name $username -ErrorAction SilentlyContinue)) {
16 | New-LocalUser -Name $username -Password $password -Description $description
17 | Write-Host "Local user $username created successfully."
18 | } else {
19 | Write-Host "Local user $username already exists."
20 | }
21 |
22 | # Add user to the Administrators group
23 | if (-not (Get-LocalGroupMember -Group "Administrators" -Member $username -ErrorAction SilentlyContinue)) {
24 | Add-LocalGroupMember -Group "Administrators" -Member $username
25 | Write-Host "User $username added to Administrators group."
26 | } else {
27 | Write-Host "User $username is already a member of the Administrators group."
28 | }
29 | } catch {
30 | Write-Host "An error occurred: $_"
31 | }
32 | }
33 |
34 | # Execute the script block on each target machine
35 | foreach ($computer in $computers) {
36 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock -ArgumentList $username, $password, $description
37 | }
38 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/internalServers/createRemoveAccount/removeLocalAccount.ps1:
--------------------------------------------------------------------------------
1 | # Variables
2 | $username = "dmzUser"
3 | # List of target machines
4 | $computers = @("Machine1", "Machine2", "Machine3")
5 |
6 | # Script block to execute on each machine
7 | $scriptBlock = {
8 | param($username)
9 |
10 | try {
11 | # Remove user from the Administrators group (if added)
12 | if (Get-LocalGroupMember -Group "Administrators" -Member $username -ErrorAction SilentlyContinue) {
13 | Remove-LocalGroupMember -Group "Administrators" -Member $username
14 | Write-Host "User $username removed from Administrators group."
15 | } else {
16 | Write-Host "User $username was not a member of the Administrators group."
17 | }
18 |
19 | # Remove the local user
20 | if (Get-LocalUser -Name $username -ErrorAction SilentlyContinue) {
21 | Remove-LocalUser -Name $username
22 | Write-Host "Local user $username removed successfully."
23 | } else {
24 | Write-Host "Local user $username does not exist."
25 | }
26 | } catch {
27 | Write-Host "An error occurred: $_"
28 | }
29 | }
30 |
31 | # Execute the script block on each target machine
32 | foreach ($computer in $computers) {
33 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock -ArgumentList $username
34 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/internalServers/createRemoveLocalAccountTokenFilterPolicy/removeLocalAccountTokenFilterPolicy.ps1:
--------------------------------------------------------------------------------
1 | # List of target machines
2 | $computers = @("Machine1", "Machine2", "Machine3")
3 |
4 | # Script block to execute on each machine
5 | $scriptBlock = {
6 | $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
7 | $regName = "LocalAccountTokenFilterPolicy"
8 |
9 | try {
10 | if (Get-ItemProperty -Path $regPath -Name $regName -ErrorAction SilentlyContinue) {
11 | Remove-ItemProperty -Path $regPath -Name $regName -Force
12 | Write-Output "LocalAccountTokenFilterPolicy registry entry removed successfully."
13 | } else {
14 | Write-Output "LocalAccountTokenFilterPolicy registry entry does not exist."
15 | }
16 | } catch {
17 | Write-Output "An error occurred: $_"
18 | }
19 |
20 | # Verify the removal
21 | try {
22 | Get-ItemProperty -Path $regPath -Name $regName -ErrorAction Stop
23 | Write-Output "Failed to remove LocalAccountTokenFilterPolicy registry entry."
24 | } catch {
25 | Write-Output "LocalAccountTokenFilterPolicy registry entry is confirmed as removed."
26 | }
27 | }
28 |
29 | # Execute the script block on each target machine
30 | foreach ($computer in $computers) {
31 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock
32 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/internalServers/createRemoveLocalAccountTokenFilterPolicy/setLocalAccountTokenFilterPolicy.ps1:
--------------------------------------------------------------------------------
1 | # List of target machines
2 | $computers = @("Machine1", "Machine2", "Machine3")
3 |
4 | # Script block to execute on each machine
5 | $scriptBlock = {
6 | param($regPath, $regName, $regValue)
7 |
8 | try {
9 | if (-not (Get-ItemProperty -Path $regPath -Name $regName -ErrorAction SilentlyContinue)) {
10 | New-ItemProperty -Path $regPath -Name $regName -PropertyType DWORD -Value $regValue -Force
11 | Write-Output "LocalAccountTokenFilterPolicy registry entry created and set to 1."
12 | } else {
13 | Set-ItemProperty -Path $regPath -Name $regName -Value $regValue
14 | Write-Output "LocalAccountTokenFilterPolicy registry entry already existed and if it was not set to 1, it was updated to 1."
15 | }
16 | } catch {
17 | Write-Output "An error occurred: $_"
18 | }
19 |
20 | # Verify the setting
21 | $setValue = Get-ItemProperty -Path $regPath -Name $regName
22 | if ($setValue.LocalAccountTokenFilterPolicy -eq $regValue) {
23 | Write-Output "LocalAccountTokenFilterPolicy is successfully set to 1."
24 | } else {
25 | Write-Output "Failed to set LocalAccountTokenFilterPolicy to 1."
26 | }
27 | }
28 |
29 | # Variables for registry settings
30 | $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
31 | $regName = "LocalAccountTokenFilterPolicy"
32 | $regValue = 1
33 |
34 | # Execute the script block on each target machine
35 | foreach ($computer in $computers) {
36 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock -ArgumentList $regPath, $regName, $regValue
37 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/internalServers/createRemoveTrustedHosts/addTrustedHosts.ps1:
--------------------------------------------------------------------------------
1 | # List of target machines
2 | $computers = @("Machine1", "Machine2", "Machine3")
3 |
4 | # Trusted hosts array
5 | $trustedHosts = @(
6 | "192.168.1.1", # Replace with your IP addresses
7 | "192.168.1.2",
8 | "hostname1.domain.com", # Replace with your hostnames
9 | "hostname2.domain.com"
10 | )
11 |
12 | # Convert the array to a comma-separated string
13 | $trustedHostsString = $trustedHosts -join ','
14 |
15 | # Script block to execute on each machine
16 | $scriptBlock = {
17 | param($trustedHostsString)
18 | $input = "@{TrustedHosts=`"$trustedHostsString`"}"
19 | try {
20 | winrm set winrm/config/client $input
21 | Write-Host "TrustedHosts set to: $trustedHostsString"
22 | } catch {
23 | Write-Host "An error occurred: $_"
24 | }
25 |
26 | # Output the current winrm/config/client configuration
27 | $currentConfig = winrm get winrm/config/client
28 | Write-Host "Current winrm/config/client configuration:"
29 | $currentConfig | ForEach-Object { Write-Host $_ }
30 | }
31 |
32 | # Execute the script block on each target machine
33 | foreach ($computer in $computers) {
34 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock -ArgumentList $trustedHostsString
35 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/dmz/internalServers/createRemoveTrustedHosts/removeTrustedHosts.ps1:
--------------------------------------------------------------------------------
1 | # List of target machines
2 | $computers = @("Machine1", "Machine2", "Machine3")
3 |
4 | # Script block to execute on each machine
5 | $scriptBlock = {
6 | try {
7 | winrm set winrm/config/client '@{TrustedHosts=""}'
8 | Write-Host "TrustedHosts has been reset to default (empty value)."
9 | } catch {
10 | Write-Host "An error occurred: $_"
11 | }
12 |
13 | # Output the current winrm/config/client configuration
14 | $currentConfig = winrm get winrm/config/client
15 | Write-Host "Current winrm/config/client configuration:"
16 | $currentConfig | ForEach-Object { Write-Host $_ }
17 | }
18 |
19 | # Execute the script block on each target machine
20 | foreach ($computer in $computers) {
21 | Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock
22 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/forDisconnectedEnvironments/transferInstallers.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick and Adrien Hafner
2 |
3 | # this script is designed to transfer installers to all the machines in the $remoteServers block from the $localServer orchestration machine, and at the end of the script, it will report the contents of the folder on your remote servers so you can confirm the installers have been transferred.
4 |
5 | # change the $localServer and $remoteServers lists to reflect your machines
6 |
7 | # change the $sourceDrive, $mainDirectory and $subDirectory to match your environment
8 |
9 | # Define the local and remote servers
10 | $localServer = @('localserver') # Local server or orchestration server
11 | $remoteServers = @('remoteserver1','remoteserver2') # List of remote servers
12 |
13 | $sourceDrive = "C:" # Define the drive letter as a variable (no trailing slash or $)
14 | $mainDirectory = "Automation" # Change this to the directory that contains the folder that contains the installs folder
15 | $subDirectory = "installs" # Change this to the directory that contains the installers
16 |
17 | $ScriptBlock = {
18 | param ($server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive)
19 |
20 | $serverTrimmed = $server.Trim()
21 | Write-Host "Checking if $serverTrimmed is in remote servers list..."
22 |
23 | if ($remoteServers -contains $serverTrimmed) {
24 | try {
25 | # Clean the colon from the drive letter for UNC use (e.g., "D:" -> "D$")
26 | $driveShare = "$($sourceDrive.TrimEnd(':'))$"
27 |
28 | # Define the target directory path using the dynamic drive variable
29 | $targetDir = "\\$serverTrimmed\$driveShare\$mainDirectory\$subDirectory"
30 |
31 | # Check if the target directory exists, create it if it doesn't
32 | if (-not (Test-Path -Path $targetDir)) {
33 | Write-Host "Creating directory: $targetDir"
34 | New-Item -ItemType Directory -Path $targetDir -Force
35 | }
36 | else {
37 | Write-Host "Removing contents of directory: $targetDir"
38 | Remove-Item "$targetDir\*" -Recurse -Force
39 | }
40 |
41 | # Copy from local source to remote target
42 | $sourcePath = Join-Path -Path $sourceDrive -ChildPath "$mainDirectory\$subDirectory\*"
43 | Write-Host "Copying files from $sourcePath to $targetDir"
44 | Copy-Item -Path $sourcePath -Destination $targetDir -Recurse -Force
45 |
46 | Write-Host "Files in destination directory $targetDir after copy:"
47 | Get-ChildItem -Path $targetDir -Recurse | ForEach-Object { Write-Host $_.FullName }
48 | }
49 | catch {
50 | Write-Error "An error occurred on server ${serverTrimmed}: $_"
51 | }
52 | } else {
53 | Write-Host "Skipping local server: $serverTrimmed"
54 | }
55 | }
56 |
57 | # Loop through all servers and apply script to remote servers only
58 | $jobs = @()
59 | foreach ($server in $localServer + $remoteServers) {
60 | $job = Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive
61 | $jobs += $job
62 | }
63 |
64 | # Wait for all jobs to complete
65 | $jobs | Wait-Job
66 |
67 | # Output job results and cleanup
68 | $jobs | ForEach-Object {
69 | Receive-Job -Job $_
70 | Remove-Job -Job $_
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/forDisconnectedEnvironments/transferPreRequisites.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick and Adrien Hafner
2 |
3 | # this script is designed to transfer web adaptor 11.1+ Microsoft IIS pre-requisites to the web server machine(s) listed in the $remoteServer list from the $localServer orchestration machine. At the end of the script, it will report the contents of the folder on your remote servers so you can confirm the prerequisites have been transferred.
4 |
5 | # change the $localServer and $remoteServers lists to reflect your machines
6 |
7 | # change the $sourceDrive, $mainDirectory and $subDirectory to match your environment
8 |
9 | # Define the local and remote servers
10 | $localServer = @('localserver') # Local server or orchestration server
11 | $remoteServers = @('remoteserver1','remoteserver2') # List of remote servers
12 |
13 | $sourceDrive = "C:" # Define the drive letter as a variable (no trailing slash or $)
14 | $mainDirectory = "Automation" # Change this to the directory that contains the folder that contains the prerequisites folder
15 | $subDirectory = "prereqs" # Change this to the directory that contains the IIS prerequisites
16 |
17 | $ScriptBlock = {
18 | param ($server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive)
19 |
20 | $serverTrimmed = $server.Trim()
21 | Write-Host "Checking if $serverTrimmed is in remote servers list..."
22 |
23 | if ($remoteServers -contains $serverTrimmed) {
24 | try {
25 | # Clean the colon from the drive letter for UNC use (e.g., "D:" -> "D$")
26 | $driveShare = "$($sourceDrive.TrimEnd(':'))$"
27 |
28 | # Define the target directory path using the dynamic drive variable
29 | $targetDir = "\\$serverTrimmed\$driveShare\$mainDirectory\$subDirectory"
30 |
31 | # Check if the target directory exists, create it if it doesn't
32 | if (-not (Test-Path -Path $targetDir)) {
33 | Write-Host "Creating directory: $targetDir"
34 | New-Item -ItemType Directory -Path $targetDir -Force
35 | }
36 | else {
37 | Write-Host "Removing contents of directory: $targetDir"
38 | Remove-Item "$targetDir\*" -Recurse -Force
39 | }
40 |
41 | # Copy from local source to remote target
42 | $sourcePath = Join-Path -Path $sourceDrive -ChildPath "$mainDirectory\$subDirectory\*"
43 | Write-Host "Copying files from $sourcePath to $targetDir"
44 | Copy-Item -Path $sourcePath -Destination $targetDir -Recurse -Force
45 |
46 | Write-Host "Files in destination directory $targetDir after copy:"
47 | Get-ChildItem -Path $targetDir -Recurse | ForEach-Object { Write-Host $_.FullName }
48 | }
49 | catch {
50 | Write-Error "An error occurred on server ${serverTrimmed}: $_"
51 | }
52 | } else {
53 | Write-Host "Skipping local server: $serverTrimmed"
54 | }
55 | }
56 |
57 | # Loop through all servers and apply script to remote servers only
58 | $jobs = @()
59 | foreach ($server in $localServer + $remoteServers) {
60 | $job = Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive
61 | $jobs += $job
62 | }
63 |
64 | # Wait for all jobs to complete
65 | $jobs | Wait-Job
66 |
67 | # Output job results and cleanup
68 | $jobs | ForEach-Object {
69 | Receive-Job -Job $_
70 | Remove-Job -Job $_
71 | }
72 |
73 |
74 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/forMigrations/addHostEntry.ps1:
--------------------------------------------------------------------------------
1 | # This script adds an entry to the hosts file on multiple remote machines
2 |
3 | # Define the host entry details to add
4 | $ipAddress = "10.0.0.1" # IP address to map to the DNS name and machine name
5 | $machineName = "machine1" # Name of the machine whose IP address is being mapped (FQDN)
6 | $dnsName = "host.domain.com" # DNS name to map to the IP address
7 |
8 | # List of target machine names to modify the hosts file
9 | $targetMachines = @("machine1", "machine2", "machine3", "machine4")
10 |
11 | # Loop through each target machine
12 | foreach ($machine in $targetMachines) {
13 | # Use Invoke-Command for remote execution
14 | Invoke-Command -ComputerName $machine -ScriptBlock {
15 | param($ipAddress, $dnsName, $machineName)
16 |
17 | # Path to the hosts file
18 | $hostsPath = "C:\Windows\System32\drivers\etc\hosts"
19 |
20 | # Entry to add
21 | $entry = "$ipAddress`t$machineName`t$dnsName"
22 |
23 | # Check if the entry already exists
24 | $existingEntry = Get-Content $hostsPath | Select-String -Pattern "$ipAddress`t$machineName`t$dnsName"
25 |
26 | if (-not $existingEntry) {
27 | # Add the entry if it doesn't exist
28 | Add-Content -Path $hostsPath -Value $entry
29 | Write-Host "Added entry: $entry" -ForegroundColor Cyan
30 | } else {
31 | Write-Host "Entry for $dnsName already exists in $using:machine." -ForegroundColor Yellow
32 | }
33 |
34 | # Verify the DNS resolution
35 | $resolvedIp = [System.Net.Dns]::GetHostAddresses($dnsName) | Select-Object -First 1
36 | if ($resolvedIp.IPAddressToString -eq $ipAddress) {
37 | Write-Host "DNS resolution for $dnsName on $using:machine is correct ($resolvedIp)." -ForegroundColor Green
38 | } else {
39 | Write-Host "DNS resolution for $dnsName on $using:machine is incorrect. Expected: $ipAddress, Got: $resolvedIp" -ForegroundColor Red
40 | }
41 | } -ArgumentList $ipAddress, $dnsName, $machineName
42 | }
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/forMigrations/removeHostEntry.ps1:
--------------------------------------------------------------------------------
1 | # This script removes an entry from the hosts file on multiple remote machines
2 |
3 | # Define the host entry details to remove
4 | $ipAddress = "10.1.1.1" # IP address currently mapped in the hosts file
5 | $desiredIpAddress = "10.2.2.2" # The desired IP address you want the DNS name to resolve to after removal
6 | $machineName = "machine.domain.com" # Name of the machine whose IP address is being mapped
7 | $dnsName = "gis.website.gov" # DNS name to map to the IP address
8 |
9 | # List of target machine names/IP addresses
10 | $targetMachines = @("machine1", "machine2", "machine3")
11 |
12 | # Get the local machine name
13 | $localMachine = $env:COMPUTERNAME
14 |
15 | # Function to remove entry from the hosts file
16 | function Remove-HostEntry {
17 | param (
18 | [string]$hostsPath,
19 | [string]$ipAddress,
20 | [string]$machineName,
21 | [string]$dnsName
22 | )
23 |
24 | # Read the content of the hosts file
25 | $hostsContent = Get-Content $hostsPath
26 |
27 | # Filter the content to remove the entry, if it exists
28 | $newHostsContent = $hostsContent | Where-Object { $_ -notmatch "$ipAddress\s+$machineName\s+$dnsName" }
29 |
30 | # Check if any change is made
31 | if ($hostsContent.Count -ne $newHostsContent.Count) {
32 | # Write the updated content back to the hosts file
33 | $newHostsContent | Set-Content $hostsPath
34 | Write-Host "Entry for $dnsName and $machineName removed from $localMachine." -ForegroundColor Cyan
35 | } else {
36 | Write-Host "Entry for $dnsName and $machineName does not exist in $localMachine." -ForegroundColor Yellow
37 | }
38 | }
39 |
40 | # Loop through each target machine
41 | foreach ($machine in $targetMachines) {
42 | if ($machine -eq $localMachine) {
43 | # If the target machine is the local machine, modify the hosts file directly
44 | $hostsPath = "C:\Windows\System32\drivers\etc\hosts"
45 | Remove-HostEntry -hostsPath $hostsPath -ipAddress $ipAddress -machineName $machineName -dnsName $dnsName
46 |
47 | # Verify if the DNS now resolves to the desired IP address locally
48 | $resolvedIp = [System.Net.Dns]::GetHostAddresses($dnsName) | Select-Object -First 1
49 | if ($resolvedIp.IPAddressToString -eq $desiredIpAddress) {
50 | Write-Host "DNS resolution for $dnsName on $localMachine is correctly set to the desired IP: $desiredIpAddress." -ForegroundColor Green
51 | } else {
52 | Write-Host "DNS resolution for $dnsName on $localMachine is NOT the desired IP. It currently resolves to: $resolvedIp." -ForegroundColor Red
53 | }
54 | } else {
55 | # Use Invoke-Command for remote execution on other machines
56 | Invoke-Command -ComputerName $machine -ScriptBlock {
57 | param($ipAddress, $dnsName, $machineName, $desiredIpAddress)
58 |
59 | # Path to the hosts file
60 | $hostsPath = "C:\Windows\System32\drivers\etc\hosts"
61 |
62 | # Read the content of the hosts file
63 | $hostsContent = Get-Content $hostsPath
64 |
65 | # Filter the content to remove the entry, if it exists
66 | $newHostsContent = $hostsContent | Where-Object { $_ -notmatch "$ipAddress\s+$machineName\s+$dnsName" }
67 |
68 | # Check if any change is made
69 | if ($hostsContent.Count -ne $newHostsContent.Count) {
70 | # Write the updated content back to the hosts file
71 | $newHostsContent | Set-Content $hostsPath
72 | Write-Host "Entry for $dnsName and $machineName removed from $env:COMPUTERNAME." -ForegroundColor Cyan
73 | } else {
74 | Write-Host "Entry for $dnsName and $machineName does not exist in $env:COMPUTERNAME." -ForegroundColor Yellow
75 | }
76 |
77 | # Verify if the DNS now resolves to the desired IP address
78 | $resolvedIp = [System.Net.Dns]::GetHostAddresses($dnsName) | Select-Object -First 1
79 | if ($resolvedIp.IPAddressToString -eq $desiredIpAddress) {
80 | Write-Host "DNS resolution for $dnsName on $env:COMPUTERNAME is correctly set to the desired IP: $desiredIpAddress." -ForegroundColor Green
81 | } else {
82 | Write-Host "DNS resolution for $dnsName on $env:COMPUTERNAME is NOT the desired IP. It currently resolves to: $resolvedIp." -ForegroundColor Red
83 | }
84 | } -ArgumentList $ipAddress, $dnsName, $machineName, $desiredIpAddress
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/forMigrations/setFirewallRulesBlockIpFilter.ps1:
--------------------------------------------------------------------------------
1 | # This script creates a new firewall rule to block inbound traffic from multiple IP addresses on multiple machines.
2 |
3 | $arcgisservers = @('machine1','machine2','machine3') # List of machines to run the script on
4 | $blockIPs = '192.168.1.1,10.0.0.1,172.16.0.1' # List of IP addresses to block as a comma-separated string
5 | $environment = "Target Non-Production" # Name of the environment to block traffic from
6 |
7 | # Convert the comma-separated string of IPs into an array
8 | $blockIPsArray = $blockIPs -split ','
9 |
10 | $parameters = @{
11 | ComputerName = $arcgisservers
12 | ScriptBlock = {
13 | param($blockIPsArray, $environment) # Accepts the block IPs array and environment as parameters
14 |
15 | # Validate each IP address
16 | foreach ($ip in $blockIPsArray) {
17 | if (-not [System.Net.IPAddress]::TryParse($ip, [ref]$null)) {
18 | Write-Error "Invalid IP address: $ip"
19 | return
20 | }
21 | }
22 |
23 | # Create a single firewall rule to block inbound traffic from all specified IPs
24 | New-NetFirewallRule -DisplayName "Block Multiple IPs from $environment" -Direction Inbound -Action Block -RemoteAddress $blockIPsArray -Profile Any
25 | }
26 | ArgumentList = ($blockIPsArray, $environment) # Pass the $blockIPs array and $environment as arguments to the ScriptBlock
27 | }
28 |
29 | Invoke-Command @parameters
30 |
31 |
32 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/generatePwFiles.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 |
3 | # Script to create password files for the accounts and certificates
4 |
5 | # Define account types and their respective output file paths in an ordered hashtable
6 | $accounts = [ordered]@{ # Ordered hashtable
7 | "AD account 'domain\svcArcGIS'" = "D:\EsriInstall\passwordFiles\ADPassword.txt"
8 | "MyEsri account 'temp'" = "D:\EsriInstall\passwordFiles\myesri.txt"
9 | "Portal account 'arcgisportal'" = "D:\EsriInstall\passwordFiles\arcgisportal.txt"
10 | "Server account 'arcgisadmin'" = "D:\EsriInstall\passwordFiles\arcgisadmin.txt"
11 | "Server 'cert' certificate" = "D:\EsriInstall\passwordFiles\cert.txt"
12 | }
13 |
14 | # Ensure the directory exists before creating the password files
15 | foreach ($filePath in $accounts.Values) {
16 | $directory = [System.IO.Path]::GetDirectoryName($filePath)
17 | if (-not (Test-Path -Path $directory)) {
18 | New-Item -Path $directory -ItemType Directory | Out-Null
19 | }
20 | }
21 |
22 | # Iterate over each account, prompt for password, and save to file
23 | foreach ($account in $accounts.GetEnumerator()) { # GetEnumerator() returns a collection of key-value pairs
24 | Write-Host "Enter the password for the $($account.Key)" # Key is the account type, Value is the file path
25 | $password = Read-Host -AsSecureString | ConvertFrom-SecureString # Convert to secure string and then to plain text
26 | $password | Out-File $account.Value # Save to file
27 | }
28 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/setFirewallRulesAllowAge.ps1:
--------------------------------------------------------------------------------
1 | # This script sets the firewall rules on the specified machines to allow inbound traffic on the specified ports.
2 |
3 | # Define the list of machines to set the firewall rules on
4 | $machines = @('machine1', 'machine2', 'machine3')
5 |
6 | # Define the ports
7 | $ports = 80, 135, 443, 445, 2443, 5985, 5986, 6080, 6443, 7080, 7443, 9320, 9220, 9829, 20443, 20301, 21443, 29080, 29081, 29878, 29879, 45672, 45671
8 |
9 | # Convert the ports array to a comma-separated string
10 | $portsString = $ports -join ','
11 |
12 | # Define the name and description of the rule
13 | $ruleName = "Allow Inbound ArcGIS Enterprise, Automation and File Share traffic"
14 | $ruleDescription = "Allows inbound traffic on ports: $portsString"
15 |
16 | # Define the script block to be executed on each machine
17 | $scriptBlock = {
18 | param($ports, $ruleName, $ruleDescription)
19 |
20 | # Create the firewall rule for the Domain profile
21 | New-NetFirewallRule -DisplayName $ruleName -Description $ruleDescription -Direction Inbound -Action Allow -Protocol TCP -LocalPort $ports -Profile Domain, Private
22 |
23 | Write-Output "Firewall rules created successfully for Domain and Private profiles on $env:COMPUTERNAME."
24 | }
25 |
26 | # Iterate through each machine and execute the script block
27 | foreach ($machine in $machines) {
28 | Invoke-Command -ComputerName $machine -ScriptBlock $scriptBlock -ArgumentList $ports, $ruleName, $ruleDescription
29 | }
30 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/transferCertificates.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick and Adrien Hafner
2 |
3 | # this script is designed to transfer certificates to all the machines in the $remoteServers block from the $localServer orchestration machine, and at the end of the script, it will report the contents of the folder on your remote servers so you can confirm the certificates have been transferred.
4 |
5 | # change the $localServer and $remoteServers lists to reflect your machines
6 |
7 | # change the $sourceDrive, $mainDirectory and $subDirectory to match your environment
8 |
9 | # Define the local and remote servers
10 | $localServer = @('localserver') # Local server or orchestration server
11 | $remoteServers = @('remoteserver1','remoteserver2') # List of remote servers
12 |
13 | $sourceDrive = "C:" # Define the drive letter as a variable (no trailing slash or $)
14 | $mainDirectory = "Automation" # Change this to the directory that contains the folder that contains the certificates folder
15 | $subDirectory = "certificates" # Change this to the directory that contains the certificates
16 |
17 | $ScriptBlock = {
18 | param ($server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive)
19 |
20 | $serverTrimmed = $server.Trim()
21 | Write-Host "Checking if $serverTrimmed is in remote servers list..."
22 |
23 | if ($remoteServers -contains $serverTrimmed) {
24 | try {
25 | # Clean the colon from the drive letter for UNC use (e.g., "D:" -> "D$")
26 | $driveShare = "$($sourceDrive.TrimEnd(':'))$"
27 |
28 | # Define the target directory path using the dynamic drive variable
29 | $targetDir = "\\$serverTrimmed\$driveShare\$mainDirectory\$subDirectory"
30 |
31 | # Check if the target directory exists, create it if it doesn't
32 | if (-not (Test-Path -Path $targetDir)) {
33 | Write-Host "Creating directory: $targetDir"
34 | New-Item -ItemType Directory -Path $targetDir -Force
35 | }
36 | else {
37 | Write-Host "Removing contents of directory: $targetDir"
38 | Remove-Item "$targetDir\*" -Recurse -Force
39 | }
40 |
41 | # Copy from local source to remote target
42 | $sourcePath = Join-Path -Path $sourceDrive -ChildPath "$mainDirectory\$subDirectory\*"
43 | Write-Host "Copying files from $sourcePath to $targetDir"
44 | Copy-Item -Path $sourcePath -Destination $targetDir -Recurse -Force
45 |
46 | Write-Host "Files in destination directory $targetDir after copy:"
47 | Get-ChildItem -Path $targetDir -Recurse | ForEach-Object { Write-Host $_.FullName }
48 | }
49 | catch {
50 | Write-Error "An error occurred on server ${serverTrimmed}: $_"
51 | }
52 | } else {
53 | Write-Host "Skipping local server: $serverTrimmed"
54 | }
55 | }
56 |
57 | # Loop through all servers and apply script to remote servers only
58 | $jobs = @()
59 | foreach ($server in $localServer + $remoteServers) {
60 | $job = Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive
61 | $jobs += $job
62 | }
63 |
64 | # Wait for all jobs to complete
65 | $jobs | Wait-Job
66 |
67 | # Output job results and cleanup
68 | $jobs | ForEach-Object {
69 | Receive-Job -Job $_
70 | Remove-Job -Job $_
71 | }
72 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/transferLicenses.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick and Adrien Hafner
2 |
3 | # this script is designed to transfer licenses to all the machines in the $remoteServers block from the $localServer orchestration machine, and at the end of the script, it will report the contents of the folder on your remote servers so you can confirm the licenses have been transferred.
4 |
5 | # change the $localServer and $remoteServers lists to reflect your machines
6 |
7 | # change the $sourceDrive, $mainDirectory and $subDirectory to match your environment
8 |
9 | # Define the local and remote servers
10 | $localServer = @('localserver') # Local server or orchestration server
11 | $remoteServers = @('remoteserver1','remoteserver2') # List of remote servers
12 |
13 | $sourceDrive = "C:" # Define the drive letter as a variable (no trailing slash or $)
14 | $mainDirectory = "Automation" # Change this to the directory that contains the folder that contains the licenses folder
15 | $subDirectory = "licenses" # Change this to the directory that contains the licenses
16 |
17 | $ScriptBlock = {
18 | param ($server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive)
19 |
20 | $serverTrimmed = $server.Trim()
21 | Write-Host "Checking if $serverTrimmed is in remote servers list..."
22 |
23 | if ($remoteServers -contains $serverTrimmed) {
24 | try {
25 | # Clean the colon from the drive letter for UNC use (e.g., "D:" -> "D$")
26 | $driveShare = "$($sourceDrive.TrimEnd(':'))$"
27 |
28 | # Define the target directory path using the dynamic drive variable
29 | $targetDir = "\\$serverTrimmed\$driveShare\$mainDirectory\$subDirectory"
30 |
31 | # Check if the target directory exists, create it if it doesn't
32 | if (-not (Test-Path -Path $targetDir)) {
33 | Write-Host "Creating directory: $targetDir"
34 | New-Item -ItemType Directory -Path $targetDir -Force
35 | }
36 | else {
37 | Write-Host "Removing contents of directory: $targetDir"
38 | Remove-Item "$targetDir\*" -Recurse -Force
39 | }
40 |
41 | # Copy from local source to remote target
42 | $sourcePath = Join-Path -Path $sourceDrive -ChildPath "$mainDirectory\$subDirectory\*"
43 | Write-Host "Copying files from $sourcePath to $targetDir"
44 | Copy-Item -Path $sourcePath -Destination $targetDir -Recurse -Force
45 |
46 | Write-Host "Files in destination directory $targetDir after copy:"
47 | Get-ChildItem -Path $targetDir -Recurse | ForEach-Object { Write-Host $_.FullName }
48 | }
49 | catch {
50 | Write-Error "An error occurred on server ${serverTrimmed}: $_"
51 | }
52 | } else {
53 | Write-Host "Skipping local server: $serverTrimmed"
54 | }
55 | }
56 |
57 | # Loop through all servers and apply script to remote servers only
58 | $jobs = @()
59 | foreach ($server in $localServer + $remoteServers) {
60 | $job = Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive
61 | $jobs += $job
62 | }
63 |
64 | # Wait for all jobs to complete
65 | $jobs | Wait-Job
66 |
67 | # Output job results and cleanup
68 | $jobs | ForEach-Object {
69 | Receive-Job -Job $_
70 | Remove-Job -Job $_
71 | }
72 |
--------------------------------------------------------------------------------
/3_settingUpServerEnvironment/transferODBC.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick and Adrien Hafner
2 |
3 | # this script is designed to transfer a SQL Server ODBC driver to all the machines in the $remoteServers block from the $localServer orchestration machine, and at the end of the script, it will report the contents of the folder on your remote servers so you can confirm the ODBC driver has been transferred.
4 |
5 | # change the $localServer and $remoteServers lists to reflect your machines
6 |
7 | # change the $sourceDrive, $mainDirectory and $subDirectory to match your environment
8 |
9 | # Define the local and remote servers
10 | $localServer = @('localserver') # Local server or orchestration server
11 | $remoteServers = @('remoteserver1','remoteserver2') # List of remote servers
12 |
13 | $sourceDrive = "C:" # Define the drive letter as a variable (no trailing slash or $)
14 | $mainDirectory = "Automation" # Change this to the directory that contains the folder that contains the odbc folder
15 | $subDirectory = "odbc" # Change this to the directory that contains the odbc driver
16 |
17 | $ScriptBlock = {
18 | param ($server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive)
19 |
20 | $serverTrimmed = $server.Trim()
21 | Write-Host "Checking if $serverTrimmed is in remote servers list..."
22 |
23 | if ($remoteServers -contains $serverTrimmed) {
24 | try {
25 | # Clean the colon from the drive letter for UNC use (e.g., "D:" -> "D$")
26 | $driveShare = "$($sourceDrive.TrimEnd(':'))$"
27 |
28 | # Define the target directory path using the dynamic drive variable
29 | $targetDir = "\\$serverTrimmed\$driveShare\$mainDirectory\$subDirectory"
30 |
31 | # Check if the target directory exists, create it if it doesn't
32 | if (-not (Test-Path -Path $targetDir)) {
33 | Write-Host "Creating directory: $targetDir"
34 | New-Item -ItemType Directory -Path $targetDir -Force
35 | }
36 | else {
37 | Write-Host "Removing contents of directory: $targetDir"
38 | Remove-Item "$targetDir\*" -Recurse -Force
39 | }
40 |
41 | # Copy from local source to remote target
42 | $sourcePath = Join-Path -Path $sourceDrive -ChildPath "$mainDirectory\$subDirectory\*"
43 | Write-Host "Copying files from $sourcePath to $targetDir"
44 | Copy-Item -Path $sourcePath -Destination $targetDir -Recurse -Force
45 |
46 | Write-Host "Files in destination directory $targetDir after copy:"
47 | Get-ChildItem -Path $targetDir -Recurse | ForEach-Object { Write-Host $_.FullName }
48 | }
49 | catch {
50 | Write-Error "An error occurred on server ${serverTrimmed}: $_"
51 | }
52 | } else {
53 | Write-Host "Skipping local server: $serverTrimmed"
54 | }
55 | }
56 |
57 | # Loop through all servers and apply script to remote servers only
58 | $jobs = @()
59 | foreach ($server in $localServer + $remoteServers) {
60 | $job = Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server, $mainDirectory, $subDirectory, $remoteServers, $sourceDrive
61 | $jobs += $job
62 | }
63 |
64 | # Wait for all jobs to complete
65 | $jobs | Wait-Job
66 |
67 | # Output job results and cleanup
68 | $jobs | ForEach-Object {
69 | Receive-Job -Job $_
70 | Remove-Job -Job $_
71 | }
72 |
73 |
74 |
--------------------------------------------------------------------------------
/4_deployment/InvokeScript_Install.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 |
3 | # Invoking ArcGIS Configuration Script
4 | # Set Path to easily access logs (the location you run the Invoke from will be where the Logs show up)
5 |
6 | Set-Location -Path "E:\Logs"
7 |
8 | Invoke-ArcGISConfiguration -ConfigurationParametersFile "D:\EsriInstall\DSC\BaseEnterpriseDeployment.json" -Mode InstallLicenseConfigure -DebugSwitch
9 |
10 | # if successful, run without -DebugSwitch to turn off Debug Mode on ArcGIS Components
11 | # Invoke-ArcGISConfiguration -ConfigurationParametersFile "D:\EsriInstall\DSC\BaseEnterpriseDeployment.json" -Mode InstallLicenseConfigure
12 |
13 |
--------------------------------------------------------------------------------
/4_deployment/InvokeScript_Upgrade.ps1:
--------------------------------------------------------------------------------
1 | # Brendan Bladdick
2 |
3 | # Invoking ArcGIS Configuration Script
4 | # Set Path to easily access logs (the location you run the Invoke from will be where the Logs show up)
5 |
6 | Set-Location -Path "E:\Logs"
7 |
8 | Invoke-ArcGISConfiguration -ConfigurationParametersFile D:\EsriInstall\DSC\BaseEnterpriseDeployment.json, D:\EsriInstall\DSC\FederatedServer.json -Mode Upgrade -DebugSwitch
9 |
10 | # if successful, run without -DebugSwitch to turn off Debug Mode on ArcGIS Components
11 | # Invoke-ArcGISConfiguration -ConfigurationParametersFile D:\EsriInstall\DSC\BaseEnterpriseDeployment.json -Mode InstallLicenseConfigure
12 | # Invoke-ArcGISConfiguration -ConfigurationParametersFile D:\EsriInstall\DSC\FederatedServer.json -Mode InstallLicenseConfigure
13 |
--------------------------------------------------------------------------------
/5_troubleshooting/forMigrations/checkForServiceMigrationIssues.ps1:
--------------------------------------------------------------------------------
1 | ##Adrien Hafner
2 | ##This script is intended to be used for migrations that make use of PowerShell DSC.
3 | ##After content is migrated between a source and a target system, you can run this script targeting the ArcGIS Server logs to search for the string of text "Failed to create the service" to see if any services failed to migrate over.
4 | ##If entries are found in the logs with a time stamp coincident with that of the migration attempt, you should investigate the /arcgisserver/config-store/services folder to see if the service is present, and if not, manually copy it from the source.
5 |
6 | #$remoteserver should be the FQDN of the ArcGIS Server
7 | $remoteServer = "servername.domain.com"
8 |
9 | #$logPath should be the root location of the ArcGIS Server log files for server
10 | $logPath = "C:\arcgisserver\logs\MACHINE.DOMAIN.COM\server\*.log"
11 |
12 | $searchPattern = "Failed to create the service"
13 |
14 | Invoke-Command -ComputerName $remoteServer -ScriptBlock {
15 | param($logPath, $searchPattern)
16 |
17 | # Ensure the files exist before attempting to search
18 | if (Test-Path $logPath) {
19 | $results = Select-String -Path $logPath -Pattern $searchPattern
20 |
21 | if ($results) {
22 | $results | ForEach-Object {
23 | Write-Host "Found in file: $($_.Path)"
24 | Write-Host "Line: $($_.Line)"
25 | }
26 | } else {
27 | Write-Host "No matches found for '$searchPattern' in '$logPath'."
28 | }
29 | } else {
30 | Write-Host "Log path '$logPath' does not exist on the remote server."
31 | }
32 | } -ArgumentList $logPath, $searchPattern -Credential (Get-Credential)
33 |
34 |
35 |
--------------------------------------------------------------------------------
/5_troubleshooting/restartServers.ps1:
--------------------------------------------------------------------------------
1 | #Adrien Hafner
2 | #This script can be used for troubleshooting an issue with your deployment and simply restarts the server specified, remotely
3 | #The script first forces a restart and then waits for the reboot and for PowerShell to be available post-restart
4 | #Replace the 'server1', 'server2', etc text with the machines you'd like to restart
5 |
6 |
7 |
8 | $servers = @('server1','server2','server3')
9 |
10 | foreach ($server in $servers) {
11 | Write-Host "Connecting to $server";
12 | Restart-Computer -ComputerName $server -Force -Wait -For PowerShell -Timeout 300 -Delay 10;
13 | Write-Host 'The machine has been restarted and PowerShell is available';
14 | Write-Host "Disconnected from $server";
15 | }
--------------------------------------------------------------------------------
/5_troubleshooting/restartServices.ps1:
--------------------------------------------------------------------------------
1 | #Adrien Hafner
2 | #This script can be used for troubleshooting an issue with your deployment and simply restarts the Windows service specified on the machine specified, remotely
3 | #The script first gets the status of the service and writes it to the console, and then restarts the service, and provides the status after restart
4 | #Replace the 'server1' text and the 'W3SVC' text to represent the server name and the service name you'd like to target
5 |
6 | $targetServer = 'server1'
7 | #service option suggestions include: "ArcGIS Server", "Portal for ArcGIS", "ArcGIS Data Store" and "W3SVC" (IIS)
8 | $serviceName = 'W3SVC'
9 | $service = Get-Service -Name $serviceName -Computer $targetServer
10 |
11 | Write-Host "Connecting to $targetServer";
12 | Write-Host "Checking $serviceName service status";
13 | Write-Host $service.Status;
14 | Write-Host "Restarting $serviceName service";
15 | Restart-Service -InputObject $service;
16 | Start-Sleep -Seconds 20;
17 | Write-Host $service.Status;
18 | Write-Host "Disconnected from $targetServer";
--------------------------------------------------------------------------------
/5_troubleshooting/stopServices.ps1:
--------------------------------------------------------------------------------
1 | #Adrien Hafner
2 | #This script can be used in instances where you may wish to stop a running Windows Service for either troubleshooting or environment preparation (setting hosts file entries, etc)
3 | #Replace the 'server1' text and the 'W3SVC' text to represent the server name and the service name you'd like to target
4 |
5 |
6 | $targetServer = 'server1'
7 | #service option suggestions include: "ArcGIS Server", "Portal for ArcGIS", "ArcGIS Data Store" and "W3SVC" (IIS)
8 | $serviceName = 'W3SVC'
9 | $service = Get-Service -Name $serviceName -Computer $targetServer
10 |
11 |
12 | Write-Host "Connecting to $targetServer";
13 | Write-Host "Stopping $serviceName service";
14 | Stop-Service -inputObject $service;
15 | Start-Sleep -seconds 20;
16 | $service.Refresh()
17 | if ($service.Status -eq 'Stopped')
18 | {
19 | Write-Host "$serviceName service has been stopped"
20 | }
21 | Write-Host "Disconnected from $targetServer";
22 |
23 |
--------------------------------------------------------------------------------
/5_troubleshooting/taskKillWindowsInstaller.ps1:
--------------------------------------------------------------------------------
1 | #Adrien Hafner
2 | #This script checks to see if there is a hung Windows Installer process running on the server specified.
3 | #If a Windows Installer process is found running, the script kills it to help prepare for the next invoke attempt after failure.
4 | #Replace the value of the serverName variable with the machine you'd like to check/kill Windows Installer on.
5 |
6 | $serverName = "server1"
7 |
8 | # Establish remote session
9 | Enter-PSSession -ComputerName $serverName
10 |
11 |
12 | # Check if process is running
13 | Invoke-Command -ComputerName $serverName -ScriptBlock {
14 | $processName = "msiserver"
15 | if (Get-Service -Name $processName -ErrorAction SilentlyContinue) {
16 | Write-Output "$processName is running. Attempting to stop..."
17 | # Stop the process
18 | Stop-Service -Name $processName -Force
19 | Write-Output "$processName stopped."
20 | } else {
21 | Write-Output "$processName is not running."
22 | }
23 |
24 | # Exit remote session
25 | Exit-PSSession
26 | }
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ArcGIS PowerShell DSC Helper Scripts
2 |
3 | A series of helper scripts have been developed to assist with both setting up and configuring the PowerShell DSC environment, as well as making the ArcGIS deployment more standardized and seamless. Below is a brief description of some of them:
4 |
5 | ## [1_settingUpPowerShellDsc folder](./1_settingUpPowerShellDsc/)
6 | You should run both of these scripts for each deployment.
7 |
8 | - [**clearDscCache.ps1**](./1_settingUpPowerShellDsc/clearDscCache.ps1)
9 | - This script is good to run before and after running the Invoke-ArcGISConfiguration command, as it clears out any of the configuration settings currently in place within the PowerShell DSC module on the machine(s) specified. It’s good to run it twice, as well. The first time, it should clear out any settings. Running it again will allow you to confirm by looking at the console outputs that nothing is pending and that everything has in fact been reset/cleared.
10 |
11 | - [**localLcmSet.ps1**](./1_settingUpPowerShellDsc/localLcmSet.ps1)
12 | - This script sets the local DSC configuration by updating the LCM (local configuration manager) for each machine to ‘ApplyOnly’ configuration mode, and ‘StopConfiguration’ action after reboot. The ‘ApplyOnly’ configuration mode is not the default LCM setting but works best with PowerShell DSC deployments like we use for installing and upgrading Enterprise. What it does is specify that the LCM applies the configuration only, and then does not continue to monitor for changes and write logs about any drift. The ‘ApplyOnly’ setting essentially says “do what the script is telling you to do right now, and then nothing else until another script tells you to do something else, explicitly”. The ‘StopConfiguration’ setting for the action after reboot says that in the event the machine gets rebooted, the process will be stopped and upon reboot, the DSC process will not try to restart automatically. Run this script after running the clearDscCache.ps1 script to reset the DSC environment variables.
13 |
14 | - [**enterPSSession.ps1**](./1_settingUpPowerShellDsc/enterPSSession.ps1)
15 | - This script attempts to connect to the remote server specified, and then open a new PowerShell session on that server. This script can be helpful for testing general connectivity between an orchestration or deployment server and a remote server that it's using PowerShellDSC to control or configure before attempting to deploy with PowerShellDSC. This script can also be used for troubleshooting connectivity issues between the orchestration server and other servers in the deployment.
16 |
17 | ## [2_settingUpArcgisModule folder](./2_settingUpArcgisModule/)
18 | The scripts in this folder should be run situationally, with the help of the descriptions provided below. You may need to use just one or a combination of them in your deployment
19 |
20 | - [**getModuleVersion.ps1**](./2_settingUpArcgisModule/getModuleVersion.ps1)
21 | - This script will report on which version of the ArcGIS PowerShell DSC module is installed on each of the servers in the list you provide the script. This information can be helpful when determining whether or not the ArcGIS module version needs upgraded, and also indicates when there is more than one version of the module installed (this can sometimes cause issues and is generally not recommended).
22 |
23 |
24 | - [**installModule.ps1**](./2_settingUpArcgisModule/installModule.ps1)
25 | - This script will download the ArcGIS PowerShell module onto a single machine, such as an orchestration or deployment server. Once the ArcGIS module is installed on the single machine using this script, the transferModule.ps1 script can be used to transfer the ArcGIS module to other machines in the deployment.
26 |
27 | Note: this script requires internet access for the machine it is run from.
28 |
29 | - [**downloadUpgradeArcgisModule.ps1**](./2_settingUpArcgisModule/downloadUpgradeArcgisModule.ps1)
30 | - This script will remove any ArcGIS Modules from the machines in the list and install the most up to date ArcGIS Module to each machine. If you do not want the most recent version, download the desired version from GitHub and utilize the script within the transferScripts folder that will transfer the module from the Orchestration machine to the list of remote servers in the $arcgisservers variable.
31 |
32 | Note: this script requires internet access for each of the machines listed in the script. If the machines in your deployment do not have internet access, manually remove the old module(s) on the servers in the deployment, and then use the transferModule.ps1 script to transfer the desired ArcGIS module to the servers.
33 |
34 | - [**transferModule.ps1**](./2_settingUpArcGISModule/transferModule.ps1)
35 | - this script will transfer the local arcgis PowerShell module (without upgrading it) to a list of remote servers provided in the script. This is useful if utilizing an older version of the PowerShell DSC ArcGIS Module. Make sure not to include the orchestrating machine in the list of $arcgisservers. It's important to note that if you have manually downloaded the arcgis module from the Github repository (instead of using the Install-Module command), you should right-click on the .zip file before unzipping it, go to Properties and check the "unblock" box, and then unzip the arcgis module file and place it in the PowerShell directory.
36 |
37 | Note: this script can be used with or without internet access.
38 |
39 | ## [3_settingUpServerEnvironment folder](./3_settingUpServerEnvironment/)
40 |
41 | - [**generatePwFiles.ps1**](./3_settingUpServerEnvironment/generatePwFiles.ps1)
42 | This script will be helpful in most deployments.
43 | - This script allows for the generation of the password files that can be used in place of hard-coded password values in the JSON configuration file. Note: Once you specify the location of the password files in the script and run the script, the password files cannot be moved, or they will break. This is intentional. So, decide where you’d like for them to be located, make sure that path is specified in the script as well as the JSON configuration file, and then run the script. Note that the password files can only be used by the user who created them on the machine they were created on, within the folder they were created. This is for security purposed. The password files only need to be created on the machine that is being used to orchestrate the Invoke-ArcGISConfiguration command.
44 |
45 | - [**transferCertificates.ps1**](./3_settingUpServerEnvironment/transferCertificates.ps1)
46 | This script will be helpful in most deployments.
47 | - this script will transfer the contents of a ‘certificates’ folder on an orchestration machine, or the local machine to remote servers to be used for the deployment. Make sure not to include the orchestrating machine in the list of $arcgisservers.
48 |
49 | - [**transferLicenses.ps1**](./3_settingUpServerEnvironment/transferLicenses.ps1)
50 | This script will be helpful in most deployments.
51 | - this script will transfer the contents of a ‘licenses’ folder from a local location to a list of machines specified for each ArcGIS component. Make sure not to include the orchestrating machine in the list of $arcgisservers.
52 |
53 | - [**transferOdbc.ps1**](./3_settingUpServerEnvironment/transferOdbc.ps1)
54 | This script can be used if you're deploying a SQLServerClient role to a remote server in your deployment.
55 | - this script will transfer the contents of an ‘odbc’ folder from a local location to a list of machines specified for each ArcGIS component. Make sure not to include the orchestrating machine in the list of $arcgisservers.
56 |
57 | - [**avExceptions.ps1**](./3_settingUpServerEnvironment/avExceptions.ps1)
58 | This script is optional.
59 | - This script excludes common AGE folders from the Windows Defender Firewall program. Note that some environments may have this setting managed by GPO and/or may have external Firewalls. If this is the case, this script may not address all scenarios. Please discuss with IT on how the Firewall environment is being managed.
60 |
61 | - [**setFirewallRulesAllowAge.ps1**](./3_settingUpServerEnvironment/setFirewallRulesAllowAge.ps1)
62 | This script is optional.
63 | - This script sets up firewall rules on a list of specified machines to allow inbound traffic on designated ports. It is designed to facilitate the configuration of firewall settings for ArcGIS Enterprise by opening necessary ports for various services. Note that some environments may have this setting managed by GPO and/or may have external Firewalls. If this is the case, this script may not address all scenarios. Please discuss with IT on how the Firewall environment is being managed.
64 |
65 | ### [dmz folder](./3_settingUpServerEnvironment/dmz)
66 | These scripts can be used when there are components to install and configure with PowerShellDSC that reside inside of a DMZ. The 'local' folder represents scripts that should be run in the DMZ environment, while the 'remote' folder represents scripts that should be run on/against the servers in the internal network.
67 |
68 | #### [local folder](./3_settingUpServerEnvironment/dmz/local)
69 | The scripts in this folder are designed to be run on the DMZ server(s).
70 |
71 | ##### [createRemoveAccount folder](./3_settingUpServerEnvironment/dmz/local/createRemoveAccount/)
72 |
73 | - [**createLocalAccount.ps1**](./3_settingUpServerEnvironment/dmz/local/createRemoveAccount/createLocalAccount.ps1)
74 | - This script will create a local user account on the DMZ server(s).
75 |
76 | - [**removeLocalAccount.ps1**](./3_settingUpServerEnvironment/dmz/local/createRemoveAccount/removeLocalAccount.ps1)
77 | - This script will remove a local user account from the Administrators group and then delete the account on the DMZ server(s).
78 |
79 | ##### [createRemoveLocalAccountTokenFilterPolicy folder](./3_settingUpServerEnvironment/dmz/local/createRemoveLocalAccountTokenFilterPolicy/)
80 |
81 | - [**setLocalAccountTokenFilterPolicy.ps1**](./3_settingUpServerEnvironment/dmz/local/createRemoveLocalAccountTokenFilterPolicy/setLocalAccountTokenFilterPolicy.ps1)
82 | - This script will create a LocalAccountTokenFilterPolicy and set the value to 1. What this does is grant remote connections from all local members of the Administrators group full high-integrity tokens during negotiation. This should only be used on a temporary basis while deploying using PowerShellDSC. After the deployment is complete, the corresponding removeLocalAccountTokenFilterPolicy.ps1 script should be used to remove the policy.
83 |
84 | - [**removeLocalAccountTokenFilterPolicy.ps1**](./3_settingUpServerEnvironment/dmz/local/createRemoveLocalAccountTokenFilterPolicy/removeLocalAccountTokenFilterPolicy.ps1)
85 | - This script will remove a LocalAccountTokenFilterPolicy. What this policy does is grant remote connections from all local members of the Administrators group full high-integrity tokens during negotiation. After the PowerShellDSC deployment is complete, this policy should be removed as an additional security measure.
86 |
87 | ##### [createRemoveTrustedHosts folder](./3_settingUpServerEnvironment/dmz/local/createRemoveTrustedHosts/)
88 |
89 | - [**addTrustedHosts.ps1**](./3_settingUpServerEnvironment/dmz/local/createRemoveLocalAccountTokenFilterPolicy/addTrustedHosts.ps1)
90 | - This script will create a comma-separated string of IP addresses and hostnames of internal server machines and sets the TrustedHosts configuration setting for WinRM on the DMZ server(s).
91 |
92 | - [**removeTrustedHosts.ps1**](./3_settingUpServerEnvironment/dmz/local/createRemoveLocalAccountTokenFilterPolicy/removeTrustedHosts.ps1)
93 | - This script will reset the TrustedHosts list on the DMZ server(s) back to its default value, which is an empty list.
94 |
95 | #### [remote folder](./3_settingUpServerEnvironment/dmz/remote/)
96 | The scripts in this folder are designed to be run on the internal orchestration/deployment server and target the other internal server(s) in the deployment.
97 |
98 | ##### [createRemoveAccount folder](./3_settingUpServerEnvironment/dmz/remote/createRemoveAccount/)
99 |
100 | - [**createLocalAccount.ps1**](./3_settingUpServerEnvironment/dmz/remote/createRemoveAccount/createLocalAccount.ps1)
101 | - This script will create a local user account on the internal server(s) passed as a list in the script.
102 |
103 | - [**removeLocalAccount.ps1**](./3_settingUpServerEnvironment/dmz/remote/createRemoveAccount/removeLocalAccount.ps1)
104 | - This script will remove a local user account from the Administrators group and then delete the account on the internal server(s) passed as a list in the script.
105 |
106 | ##### [createRemoveLocalAccountTokenFilterPolicy folder](./3_settingUpServerEnvironment/dmz/remote/createRemoveLocalAccountTokenFilterPolicy/)
107 |
108 | - [**setLocalAccountTokenFilterPolicy.ps1**](./3_settingUpServerEnvironment/dmz/remote/createRemoveLocalAccountTokenFilterPolicy/setLocalAccountTokenFilterPolicy.ps1)
109 | - This script will create a LocalAccountTokenFilterPolicy and set the value to 1. What this does is grant remote connections from all local members of the Administrators group full high-integrity tokens during negotiation. This should only be used on a temporary basis while deploying using PowerShellDSC. After the deployment is complete, the corresponding removeLocalAccountTokenFilterPolicy.ps1 script should be used to remove the policy.
110 |
111 | - [**removeLocalAccountTokenFilterPolicy.ps1**](./3_settingUpServerEnvironment/dmz/remote/createRemoveLocalAccountTokenFilterPolicy/removeLocalAccountTokenFilterPolicy.ps1)
112 | - This script will remove a LocalAccountTokenFilterPolicy. What this policy does is grant remote connections from all local members of the Administrators group full high-integrity tokens during negotiation. After the PowerShellDSC deployment is complete, this policy should be removed as an additional security measure.
113 |
114 | ##### [createRemoveTrustedHosts folder](./3_settingUpServerEnvironment/dmz/remote/createRemoveTrustedHosts/)
115 |
116 | - [**addTrustedHosts.ps1**](./3_settingUpServerEnvironment/dmz/remote/createRemoveLocalAccountTokenFilterPolicy/addTrustedHosts.ps1)
117 | - This script will create a comma-separated string of IP addresses and hostnames for DMZ server(s) and sets the TrustedHosts configuration setting for WinRM on the internal server(s) passed as a list in the script.
118 |
119 | - [**removeTrustedHosts.ps1**](./3_settingUpServerEnvironment/dmz/remote/createRemoveLocalAccountTokenFilterPolicy/removeTrustedHosts.ps1)
120 | - This script will reset the TrustedHosts list, for each internal server passed in the script, back to its default value, which is an empty list.
121 |
122 | ### [forDisconnectedEnvironments folder](./3_settingUpServerEnvironment/forDisconnectedEnvironments)
123 | These scripts can be used when the servers are disconnected from the internet, or if you're not planning on making use of the downloadSetups or download URL path parameters in the ArcGIS Module.
124 |
125 | - [**transferInstallers.ps1**](./3_settingUpServerEnvironment/forDisconnectedEnvironments/transferInstallers.ps1)
126 | - this script will transfer the contents of an ‘installers’ folder (as well as any sub-directories) from a local location to a list of machines specified for each ArcGIS component. Make sure not to include the orchestrating machine in the list of $arcgisservers.
127 |
128 | - [**transferPreRequisites.ps1**](./3_settingUpServerEnvironment/forDisconnectedEnvironments/transferPreRequisites.ps1)
129 | - This script transfers the Web Adaptor prerequisites from a local machine to the web server that will be used for hosting the Web Adaptors.
130 |
131 | ### [forMigrations folder](./3_settingUpServerEnvironment/forMigrations)
132 | The scripts in this folder may be helpful for migrations and should be used as-desired and as-applicable.
133 |
134 | - [**addHostEntry.ps1**](./3_settingUpServerEnvironment/forMigrations/addHostEntry.ps1)
135 | - This script adds a new host entry to the hosts file on multiple remote machines. It ensures that the specified DNS name resolves to the given IP address locally on each target machine. After adding the entry, the script verifies the DNS resolution to confirm it points to the correct IP address. This script is useful for migrations involving PowerShellDSC, specifically while setting up the target environment for migration.
136 |
137 | - [**removeHostEntry.ps1**](./3_settingUpServerEnvironment/forMigrations/removeHostEntry.ps1)
138 | - This script removes an existing host entry from the hosts file on multiple remote machines. After removing the entry, the script verifies the DNS resolution to ensure it points to the correct IP address according to the DNS server. This script is useful for migrations involving PowerShellDSC, specifically post-migration after the migration has been completed successfully and the environment is ready for permanent DNS updates.
139 |
140 | - [**setFirewallRulesBlockIpFilter.ps1**](./3_settingUpServerEnvironment/forMigrations/setFirewallRulesBlockIpFilter.ps1)
141 | - This script sets up a firewall rule on a list of specified machines to block inbound traffic from a list of specified IP addresses. It is intended to enhance security by preventing traffic from certain IP addresses in a specified environment. This script is useful for migrations involving PowerShellDSC, specifically while setting up the target environment for migration to block unintended traffic to the new environment until its ready for use.
142 |
143 | ## [4_deployment folder](./4_deployment/)
144 | These scripts should be used for invoking the deployment, choose one of the scripts below depending on the type of deployment.
145 |
146 | - [**InvokeScript_Install.ps1**](./4_deployment/InvokeScript_Install.ps1)
147 | - This script starts the ArcGIS deployment in PowerShell. It first changes the directory to a path where logs can be accessed easily (such as within the folder structure where the rest of the deployment files are located). Then, it runs the Invoke-ArcGISConfiguration command with the configuration file. You can change the -Mode switch to one of the other options \[Install | InstallLicense | InstallLicenseConfigure | Uninstall | Upgrade | WebGISDRExport | WebGISDRImport\] to adjust to what you’d like the Invoke command to do.
148 |
149 | - [**InvokeScript_Upgrade.ps1**](./4_deployment/InvokeScript_Upgrade.ps1)
150 | - This script starts the upgrade of the ArcGIS deployment in PowerShell. It first changes the directory to a path where logs can be accessed easily (such as within the folder structure where the rest of the deployment files are located). Then, it runs the Invoke-ArcGISConfiguration command with the configuration file. You can add all of the federated ArcGIS Servers' JSON files to this command as seen in the example in the code to upgrade the entire deployment in one command.
151 |
152 | ## [5_troubleshooting folder](./5_troubleshooting/)
153 | The scripts in this folder can be used for troubleshooting issues with your PowerShell deployment and should be used as-needed.
154 |
155 | - [**restartServers.ps1**](./5_troubleshooting/restartServers.ps1)
156 | - This script remotely reboots servers provided in a list. When troubleshooting an issue with your deployment, or if you encounter a situation where the PowerShell deploment fails and stalls mid-installation, it's sometimes helpful to reboot the server to clear out any pending actions/processes or settings.
157 |
158 | - [**restartServices.ps1**](./5_troubleshooting/restartServices.ps1)
159 | - This script reports on the status of a Windows Service specified and then restarts it. This may be helpful with general troubleshooting.
160 |
161 | - [**stopServices.ps1**](./5_troubleshooting/stopServices.ps1)
162 | - This script remotely stops a Windows Service specified. This may be helpful with general troubleshooting.
163 |
164 | - [**taskKillWindowsInstaller.ps1**](./5_troubleshooting/taskKillWindowsInstaller.ps1)
165 | - This script remotely checks to see if the Windows Installer process is running, and if it is, it kills it. Sometimes when a PowerShell deployment fails, it might fail during the installation of one of the ArcGIS components, leaving the installer process in a hung state. If the Windows Installer process is not killed in these cases, any subsequent attempts to invoke the PowerShell command to install will also fail because the machine will assume another installation is still in progress. So this script helps by checking to see if there is a hung installer process (ideally ran after a failure), and then removes the hung installer process if it exists to prepare the environment for the next invoke attempt.
166 |
167 | ### [forMigrations folder](./5_troubleshooting/forMigrations/)
168 | The scripts in this folder may be helpful for migrations and should be used as-desired and as-applicable.
169 |
170 | - [**checkForServiceMigrationIssues.ps1**](./5_troubleshooting/forMigrations/checkForServiceMigrationIssues.ps1)
171 | - This script is intended to be used for migrations that make use of PowerShell DSC. After content is migrated between a source and target system, you can run this script targeting the ArcGIS Server logs to search for the string of text "Failed to create the service" to see if any services failed to migrate over. If entries are found in the logs with a time stamp that is coincident with that of the migration attempt, you should investigate the /arcgisserver/config-store/services folder to see if the service is present. If not, manually copy it from the source environment to the target environment.
172 |
173 |
174 | ## **How To Run These Scripts**
175 | These scripts can be run by opening a Windows PowerShell ISE session as an Administrator, and then choosing the "Open Script" button (second from the left) from the toolbar. The "Run" button runs the script and is located towards the middle of the same toolbar. As a general note, you must "Save" a script before running it after making any changes, and you will be prompted to save if you do not do so before clicking "Run".
--------------------------------------------------------------------------------