-
Notifications
You must be signed in to change notification settings - Fork 24
/
Reset-LocalAdministratorPassword.ps1
224 lines (132 loc) · 7.09 KB
/
Reset-LocalAdministratorPassword.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "", Justification = "By design - passwords is being generated")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification = "By design - passwords is being generated")]
param (
$PasswordLength = 12,
$SpecialCharCount = 2,
$PasswordAgeThreshold = 180,
[bool]$Force = $false
)
<#
NAME: Reset-LocalAdministratorPassword.ps1
AUTHOR: Jan Egil Ring
EMAIL: jan.egil.ring@outlook.com
COMMENT: Runbook to reset the local administrator password on Windows servers (tested on Windows Server 2008 R2 - 2019).
Logic:
-4 parameters: -PasswordLength
-SpecialCharCount
-PasswordAgeThreshold
-Force
-Retrieve all computer accounts from Active Directory with "Server" present in the operating system property, except domain controllers
-Connect to Azure Key Vault
-Foreach Server in Servers
-Check if existing entry for the server is present in Key Vault
-If yes
-Check when password was last updated
If older than specified threshold (default 180 days), update password
-Check if Force parameter is true
-If yes
-Update password
-If no: Update password
VERSION HISTORY:
1.0 29.09.2019 - Initial release
Changes tracked in source control:
https://github.com/janegilring/PSCommunity/tree/master/Azure/Automation/Runbooks/Reset-LocalAdministratorPassword.ps1
#>
Write-Output -InputObject "Runbook Reset-LocalAdministratorPassword started $(Get-Date) on Azure Automation Runbook Worker $($env:computername)"
#region Variables
Write-Output 'Getting credentials and variables from Azure Automation assets...'
$ServerCredential = Get-AutomationPSCredential -name 'cred-ServerAdmin'
$AzureCredential = Get-AutomationPSCredential -Name cred-Azure
$AzureSubscriptionId = '1234567-e9b5-4648-ab8b-815e2ef18a2b'
$KeyVaultName = 'server-vault'
$KeyVaultResourceGroupName = 'infrastructure-automation-rg'
$InactiveComputerObjectThresholdInDays = 30
$ExclusionsADGroup = 'Azure_Key_Vault_LocalAdministratorPassword_Exclusions'
#endregion
#region Modules
Write-Output 'Importing prerequisite PowerShell modules'
try {
Import-Module -Name Az.KeyVault -ErrorAction Stop -RequiredVersion 1.3.0
Import-Module -Name ActiveDirectory -ErrorAction Stop
}
catch {
Write-Error -Message "Prerequisites not available. Error: $($_.Exception.Message)"
break
}
#endregion
Write-Output 'Authenticating to Azure...'
try {
$null = Add-AzAccount -Credential $AzureCredential -ErrorAction Stop
$null = Set-AzContext -Subscription $AzureSubscriptionId -ErrorAction Stop
}
catch {
Write-Error "Failed to authenticate to Azure and configure subscription context: $($_.Exception.Message)"
break
}
$KeyVault = Get-AzKeyVault -VaultName $KeyVaultName -ResourceGroupName $KeyVaultResourceGroupName
if (-not ($KeyVault)) {
Write-Warning "Key Vault does not exist - aborting"
break
}
#region Prosessing servers
Write-Output 'Getting active servers from Active Directory'
# Retrieves all computer accounts from the current domain with the operating system property starting with "Windows Server", excluding failover clustering virtual accounts as well as domain controllers (userAccountControl value 8192 = SERVER_TRUST_ACCOUNT = Domain Controller), filtering out those who haven`t logged on for the last specified amount of days.
$ServersFromAD = Get-ADComputer -LDAPFilter "(&(objectCategory=computer)(operatingSystem=Windows Server*)(!serviceprincipalname=*MSClusterVirtualServer*)(!userAccountControl:1.2.840.113556.1.4.803:=8192))" -Properties description, lastlogondate, operatingSystem, DistinguishedName |
Where-Object lastlogondate -gt (Get-Date).AddDays( - $InactiveComputerObjectThresholdInDays)
$ExcludedComputerAccounts = Get-ADGroupMember -Identity $ExclusionsADGroup | Select-Object -ExpandProperty Name
Write-Output "Found $(@($ServersFromAD).Count) server(s)"
foreach ($Server in $ServersFromAD) {
Write-Output "Processing $($Server.Name)"
if ($Server.Name -in $ExcludedComputerAccounts) {
Write-Output "$($Server.Name) is a member of AD group $ExclusionsADGroup - skipping"
} else {
try {
$ServerAvailable = Test-WSMan -ComputerName $Server.Name -Credential $ServerCredential -Authentication Negotiate -ErrorAction Stop
} catch {
Write-Output "$($Server.Name) is unavailable - skipping"
Write-Error "Message: $($_.Exception.Message)"
$ServerAvailable = $false
}
if ($ServerAvailable) {
$ExistingPassword = Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name $Server.Name
if (-not ($ExistingPassword)) {
Write-Output "Password for this server does not exist in Key Vault - creating"
$UpdatePassword = $true
} else {
$PasswordAge = (New-TimeSpan -Start $ExistingPassword.Updated).Days
if ($PasswordAge -ge $PasswordAgeThreshold -or $Force) {
Write-Output "Password age in days: $PasswordAge Threshold: $PasswordAgeThreshold"
Write-Output "Force password change variable: $Force"
Write-Output "Updating password"
$UpdatePassword = $true
} else {
Write-Output "Password age in days: $PasswordAge Threshold: $PasswordAgeThreshold"
Write-Output "Current password status OK"
$UpdatePassword = $false
}
}
if ($UpdatePassword) {
try {
Add-Type -AssemblyName System.Web
$Password = [System.Web.Security.Membership]::GeneratePassword($PasswordLength, $SpecialCharCount)
$PasswordSecureString = (ConvertTo-SecureString -String $Password -AsPlainText -Force)
Invoke-Command -ComputerName $Server.Name -Credential $ServerCredential -ScriptBlock {
try {
$account = [ADSI]("WinNT://$($env:computername)/Administrator,user")
$account.psbase.invoke("setpassword", $using:Password)
}
catch {
Write-Error "Failed to Change the administrator password. Error: $($_.Exception.Message)"
}
} -ErrorAction Stop
$null = Set-AzKeyVaultSecret -VaultName $KeyVaultName -Name $Server.Name -SecretValue $PasswordSecureString -ContentType 'Local Administrator password' -ErrorAction Stop
}
catch {
Write-Error "Error occured: $($_.Exception.Message)"
}
}
}
}
}
#endregion
Write-Output -InputObject "Runbook Reset-LocalAdministratorPassword finished $(Get-Date)"