Untitled
unknown
powershell
2 years ago
11 kB
5
Indexable
#Take input from XML file [xml]$configInformation = (Get-Content -Path C:\Users\a0334614\Desktop\Maintenance\MaintenanceConfig.xml) [string]$url = $configInformation.Settings.apiHostname [string]$username = $configInformation.Settings.Username [array]$tags = $configInformation.Settings.Tags.Tag [string]$passwordFromFile = $configInformation.Settings.PasswordEncryptedString $SecureStringPassword = $passwordFromFile | ConvertTo-SecureString $Password = (New-Object PSCredential "user",$SecureStringPassword).GetNetworkCredential().Password <# .Synopsis This function will send credentials to api and in exchange for an auth token .Outputs Response.token: A token that can be used to authenticate future requests #> function Get-AuthToken { Write-Verbose "Requesting auth token from api..." #$password = Get-Content $passwordFileLocation $payload = @{ client_id = 'clientID' grant_type = 'password' username = "$username" password = "$password" } | ConvertTo-Json $response = Invoke-RestMethod -Uri ($Url + "/api/api/v1/auth") -Method POST -Body $payload -ContentType application/json return $response.token } <# .Synopsis This function will get machines from api associated with a given tag .Outputs Machines: an array of machine objects #> function Get-Machine { param ( $Token, $Tag, $Url ) $machines = Invoke-RestMethod -Method GET -Uri ($Url + "/api/api/v1/servers/?tag=$Tag") -ContentType application/json -Headers $Header return $machines } <# .Synopsis This function will PATCH a given machine in api by adjusting its maintenance status .Parameter InOrOut a string representing the maintenance status to set the machine to #> function Update-MachineStatus { param ( $machine, $header ) $body = @{ attributes = @{ name = $machine.attributes.name serverType = $machine.attributes.serverType maintenanceMode = $machine.attributes.maintenanceMode tags = $machine.attributes.tags associatedApplications = $machine.attributes.associatedApplications } } | ConvertTo-Json -depth 4 $id = $machine.id Invoke-RestMethod -Method PATCH -Uri ($url + "/api/api/v1/servers/$id") -ContentType application/json -Body $Body -Headers $header > $null } <# .Synopsis This function will call the other functions for input. Then it will take the appropriate machines out and poll them until they are drained. Once they transition out of service, any maintenance actions can be performed without end user impact. After that completes, machines are brought back into service and the next tag is taken down. Status updates are given along the way for troubleshooting but user interaction is not required. #> function Main { foreach ($tag in $tags) { $AuthToken = Get-AuthToken [array]$deadcomputerNames = @() [array]$aliveMachines = @() [array]$aliveMachineNames = @() [array]$jobs = @() $body = "" $header = @{ 'Content-Type' = 'application/json' 'Authorization' = "Bearer $AuthToken" } $machines = Get-Machine -token $AuthToken -tag $tag -Url $URL #$machines foreach ($machine in $machines.data) { $machineID = $machine.ID $MachineName = $machine.attributes.Name if (Test-Connection $machineName -Count 2 -Quiet) { $aliveMachines += $machine $machine.attributes.maintenanceMode = "TransitioningOutofService" #Update-MachineStatus -machine $machine -header $header > $null $aliveMachineNames += $MachineName } else { Write-Host "fail" $deadcomputerNames += $machine.attributes.name } } $deadcomputerNames $aliveMachines foreach ($machine in $aliveMachines) { $machineID = $machine.ID $j = Start-Job -Name $('OutofServicePoller' + $machine.attributes.name) -ScriptBlock { param( $header, $machineID, $url ) $machineStatus = "default" while ($machinestatus -ne "Out of service") { Write-Host $machinestatus Start-Sleep -Seconds 10 $machineStatus = (Invoke-RestMethod -Method GET -Uri ($url + "/api/api/v1/servers/$machineid") -ContentType application/json -Headers $header).data.attributes.maintenanceMode Write-Host $machinestatus } } -ArgumentList $header, $machineID, $url $jobs += $j.id } Write-Host "Waiting for $tag servers to go out of service..." Wait-Job -Id $jobs > $null Write-Host "All $tag servers are out of service" <# Do some maintenance stuff #> <#$aliveMachineNames.ForEach({"$_" | Out-File "C:\EpicSource\UltimateMaintenance\Servers.txt" -Append}) $scriptPath = "C:\EpicSource\UltimateMaintenance\Deploy-Package.ps1" $params = "-ServerListFile 'c:\epicSource\UltimateMaintenance\servers.txt' -InstallerPath 'C:\EpicSource\UltimateMaintenance\ECSMMSApplicationRequestRouting3.msi'" Invoke-Expression -Command "$scriptPath $params"#> #& "C:\EpicSource\UltimateMaintenance\Deploy-Package.ps1" -Servers $aliveMachines -InstallerPath "C:\EpicSource\UltimateMaintenance\ECSMMSApplicationRequestRouting3.msi" Write-Host $aliveMachines.attributes.name #Example 1: Reboot machines Write-Host "Rebooting machines with tag $tag" Get-Job -Name "*restart-computer*" | Remove-Job #Invoke-CimMethod -ComputerName $aliveMachines.attributes.name -ClassName 'Win32_OperatingSystem' -MethodName 'Reboot' $aliveMachines.attributes.name | Restart-Computer -AsJob -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Out-Null (get-job | Where-Object {$_.Command -match "^Restart-Computer.*"}) | Wait-Job | Out-Null Write-Host "Completed Rebooting machines with tag $tag" <#> Example 2: Rotate through installing a prerequisite that requires a reboot $scriptPath = "C:\EpicSource\UltimateMaintenance\Deploy-Package.ps1" $params = "-ServerListFile $aliveMachinesPath -InstallerPath 'C:\EpicSource\UltimateMaintenance\ECSMMSApplicationRequestRouting3.msi'" Invoke-Expression -Command "$scriptPath $params" #> #Example 3: Install Windows Updates #Source for Module https://www.powershellgallery.com/packages/PSWindowsUpdate/2.2.0.2 $AlexsPassword = Get-Content 'C:\Users\a0334614\Desktop\Powershell-maintenance\password.txt' $AlexsUsername = "insel\a033461" $User = $AlexsUsername $PWord = ConvertTo-SecureString -String $AlexsPassword -AsPlainText -Force $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord foreach($machine in $aliveMachines) { $s = New-PSSession -ComputerName $machine -Credential $Credential $i = Invoke-Command -Session $s -ScriptBlock{ if(!(Test-Path -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdates")) { New-Item -ItemType Directory -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules" -Name "PSWindowsUpdate" -ErrorAction SilentlyContinue } [bool]$doesPsd1Exist = Test-Path -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdate\PSWindowsUpdate.psd1" return $doesPsd1Exist } if(!$i) { Start-Sleep -Seconds 2 Copy-Item -ToSession $s -Path "C:\Users\bharriso\Downloads\pswindowsupdate.2.2.0.2.zip" -Destination "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdate" Invoke-Command -Session $s -ScriptBlock{ Unblock-File -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdate\pswindowsupdate.2.2.0.2.zip" Expand-Archive -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdate\pswindowsupdate.2.2.0.2.zip" -DestinationPath "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdate" Remove-Item -Path "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSWindowsUpdate\pswindowsupdate.2.2.0.2.zip" Import-Module -Name PSWindowsUpdate } } } foreach($machine in $aliveMachines) { $machineName = $machine.attributes.name #Invoke-WUJob -ComputerName $machineName -Script { ipmo PSWindowsUpdate; Install-WindowsUpdate -AcceptAll -AutoReboot | Out-File "C:\Windows\PSWindowsUpdate.log"} -RunNow -Confirm:$false -Verbose -ErrorAction Ignore Download-WindowsUpdate -ForceDownload -ForceInstall } foreach ($machine in $aliveMachines) { $machineID = $machine.ID $machine.attributes.maintenanceMode = "InService" update-machinestatus -machine $machine -header $header > $null } #send email to admin with info on what just ran and what machines are "dead'" if($aliveMachineNames.Count -ge 1) { $Body += ("The following machine(s) have had maintenance actions taken on them successfully: " + "<br />" + $aliveMachineNames + "<br />" + "<br />") } if($deadcomputerNames.Count -ge 1) { $Body += ("The following machine(s) were not able to be connected to: " + "<br />" + $deadcomputerNames + "<br />" + "<br />") } $body += "Have an Epic day" # If we're sending email alerts import settings from EmailAlertsConfig.xml $emailSettings = @{ } if ($EmailAlerts) { [xml] $emailXML = (Get-Content -Path .\EmailAlertConfig.xml) $emailSettings = @{ To = $emailXML.Settings.MailTo From = $emailXML.Settings.MailFrom Subject = "MaintenanceActions Taken" SmtpServer = $emailXML.Settings.SmtpServer Port = $emailXML.Settings.SmtpPort } } function _sendEmailAlert { param ( [Parameter(Mandatory = $true)] [string] $Body, # Hashtable of parameters for the Send-MailMessage function # Passed using @settings [Parameter(Mandatory = $true)] [hashtable] $Settings ) if ($EmailAlerts.IsPresent) { Send-MailMessage @Settings -Body $Body -BodyAsHtml } } #send email to admin with info on what just moved _sendEmailAlert -Settings $emailSettings -Body $Body } } Main
Editor is loading...