비밀번호 파일 생성

비밀번호 파일 생성

Microsoft에서 로컬 관리자 비밀번호를 변경하는 데 사용하는 스크립트가 있습니다. https://support.microsoft.com/en-us/kb/2962486?wa=wsignin1.0제가 찾은 곳이에요. 클릭하기가 너무 귀찮은 분들을 위한 스크립트는 다음과 같습니다.

function Invoke-PasswordRoll
{
<#
.SYNOPSIS

This script can be used to set the local account passwords on remote machines to random passwords. The 

username/password/server combination will be saved in a CSV file.
The account passwords stored in the CSV file can be encrypted using a password of the administrators choosing to 

ensure clear-text account passwords aren't written to disk.
The encrypted passwords can be decrypted using another function in this file: ConvertTo-CleartextPassword


Function: Invoke-PasswordRoll
Author: Microsoft
Version: 1.0

.DESCRIPTION

This script can be used to set the local account passwords on remote machines to random passwords. The 

username/password/server combination will be saved in a CSV file.
The account passwords stored in the CSV file can be encrypted using a password of the administrators choosing to 

ensure clear-text account passwords aren't written to disk.
The encrypted passwords can be decrypted using another function in this file: ConvertTo-CleartextPassword

.PARAMETER ComputerName

An array of computers to run the script against using PowerShell remoting.

.PARAMETER LocalAccounts

An array of local accounts whose password should be changed.

.PARAMETER TsvFileName

The file to output the username/password/server combinations to.

.PARAMETER EncryptionKey

A password to encrypt the TSV file with. Uses AES encryption. Only the passwords stored in the TSV file will be 

encrypted, the username and servername will be clear-text.

.PARAMETER PasswordLength

The length of the passwords which will be randomly generated for local accounts.

.PARAMETER NoEncryption

Do not encrypt the account passwords stored in the TSV file. This will result in clear-text passwords being 

written to disk.

.EXAMPLE

. .\Invoke-PasswordRoll.ps1    #Loads the functions in this script file
Invoke-PasswordRoll -ComputerName (Get-Content computerlist.txt) -LocalAccounts @

("administrator","CustomLocalAdmin") -TsvFileName "LocalAdminCredentials.tsv" -EncryptionKey "Password1"

Connects to all the computers stored in the file "computerlist.txt". If the local account "administrator" and/or 

"CustomLocalAdmin" are present on the system, their password is changed
to a randomly generated password of length 20 (the default). The username/password/server combinations are 

stored in LocalAdminCredentials.tsv, and the account passwords are AES encrypted using the password "Password1".

.EXAMPLE

. .\Invoke-PasswordRoll.ps1    #Loads the functions in this script file
Invoke-PasswordRoll -ComputerName (Get-Content computerlist.txt) -LocalAccounts @("administrator") -TsvFileName 

"LocalAdminCredentials.tsv" -NoEncryption -PasswordLength 40

Connects to all the computers stored in the file "computerlist.txt". If the local account "administrator" is 

present on the system, its password is changed to a random generated
password of length 40. The username/password/server combinations are stored in LocalAdminCredentials.tsv 

unencrypted.

.NOTES
Requirements: 
-PowerShellv2 or above must be installed
-PowerShell remoting must be enabled on all systems the script will be run against

Script behavior:
-If a local account is present on the system, but not specified in the LocalAccounts parameter, the script will 

write a warning to the screen to alert you to the presence of this local account. The script will continue 

running when this happens.
-If a local account is specified in the LocalAccounts parameter, but the account does not exist on the computer, 

nothing will happen (an account will NOT be created).
-The function ConvertTo-CleartextPassword, contained in this file, can be used to decrypt passwords that are 

stored encrypted in the TSV file.
-If a server specified in ComputerName cannot be connected to, PowerShell will output an error message.
-Microsoft advises companies to regularly roll all local and domain account passwords.

#>
    [CmdletBinding(DefaultParameterSetName="Encryption")]
    Param(
        [Parameter(Mandatory=$true)]
        [String[]]
        $ComputerName,

        [Parameter(Mandatory=$true)]
        [String[]]
        $LocalAccounts,

        [Parameter(Mandatory=$true)]
        [String]
        $TsvFileName,

        [Parameter(ParameterSetName="Encryption", Mandatory=$true)]
        [String]
        $EncryptionKey,

        [Parameter()]
        [ValidateRange(20,120)]
        [Int]
        $PasswordLength = 20,

        [Parameter(ParameterSetName="NoEncryption", Mandatory=$true)]
        [Switch]
        $NoEncryption
    )


    #Load any needed .net classes
    Add-Type -AssemblyName "System.Web" -ErrorAction Stop


    #This is the scriptblock that will be executed on every computer specified in ComputerName
    $RemoteRollScript = {
        Param(
            [Parameter(Mandatory=$true, Position=1)]
            [String[]]
            $Passwords,

            [Parameter(Mandatory=$true, Position=2)]
            [String[]]
            $LocalAccounts,

            #This is here so I can record what the server name that the script connected to was, sometimes the 

DNS records get messed up, it can be nice to have this.
            [Parameter(Mandatory=$true, Position=3)]
            [String]
            $TargettedServerName
        )

        $LocalUsers = Get-WmiObject Win32_UserAccount -Filter "LocalAccount=true" | Foreach {$_.Name}

        #Check if the computer has any local user accounts whose passwords are not going to be rolled by this 

script
        foreach ($User in $LocalUsers)
        {
            if ($LocalAccounts -inotcontains $User)
            {
                Write-Warning "Server: '$($TargettedServerName)' has a local account '$($User)' whos password is 

NOT being changed by this script"
            }
        }

        #For every local account specified that exists on this server, change the password
        $PasswordIndex = 0
        foreach ($LocalAdmin in $LocalAccounts)
        {
            $Password = $Passwords[$PasswordIndex]

            if ($LocalUsers -icontains $LocalAdmin)
            {
                try
                {
                    $objUser = [ADSI]"WinNT://localhost/$($LocalAdmin), user"
                    $objUser.psbase.Invoke("SetPassword", $Password)

                    $Properties = @{
                        TargettedServerName = $TargettedServerName
                        Username =  $LocalAdmin
                        Password = $Password
                        RealServerName = $env:computername
                    }

                    $ReturnData = New-Object PSObject -Property $Properties
                    Write-Output $ReturnData
                }
                catch
                {
                    Write-Error "Error changing password for user:$($LocalAdmin) on server:

$($TargettedServerName)"
                }
            }

            $PasswordIndex++
        }
    }


    #Generate the password on the client running this script, not on the remote machine. System.Web.Security 

isn't available in the .NET Client profile. Making this call
    #    on the client running the script ensures only 1 computer needs the full .NET runtime installed (as 

opposed to every system having the password rolled).
    function Create-RandomPassword
    {
        Param(
            [Parameter(Mandatory=$true)]
            [ValidateRange(20,120)]
            [Int]
            $PasswordLength
        )

        $Password = [System.Web.Security.Membership]::GeneratePassword($PasswordLength, $PasswordLength / 4)

        #This should never fail, but I'm putting a sanity check here anyways
        if ($Password.Length -ne $PasswordLength)
        {
            throw new Exception("Password returned by GeneratePassword is not the same length as required. 

Required length: $($PasswordLength). Generated length: $($Password.Length)")
        }

        return $Password
    }


    #Main functionality - Generate a password and remote in to machines to change the password of local accounts 

specified
    if ($PsCmdlet.ParameterSetName -ieq "Encryption")
    {
        try
        {
            $Sha256 = new-object System.Security.Cryptography.SHA256CryptoServiceProvider
            $SecureStringKey = $Sha256.ComputeHash([System.Text.UnicodeEncoding]::Unicode.GetBytes

($EncryptionKey))
        }
        catch
        {
            Write-Error "Error creating TSV encryption key" -ErrorAction Stop
        }
    }

    foreach ($Computer in $ComputerName)
    {
        #Need to generate 1 password for each account that could be changed
        $Passwords = @()
        for ($i = 0; $i -lt $LocalAccounts.Length; $i++)
        {
            $Passwords += Create-RandomPassword -PasswordLength $PasswordLength
        }

        Write-Output "Connecting to server '$($Computer)' to roll specified local admin passwords"
        $Result = Invoke-Command -ScriptBlock $RemoteRollScript -ArgumentList @($Passwords, $LocalAccounts, 

$Computer) -ComputerName $Computer
        #If encryption is being used, encrypt the password with the user supplied key prior to writing to disk
        if ($Result -ne $null)
        {
            if ($PsCmdlet.ParameterSetName -ieq "NoEncryption")
            {
                $Result | Select-Object Username,Password,TargettedServerName,RealServerName | Export-Csv -

Append -Path $TsvFileName -NoTypeInformation
            }
            else
            {
                #Filters out $null entries returned
                $Result = $Result | Select-Object Username,Password,TargettedServerName,RealServerName

                foreach ($Record in $Result)
                {
                    $PasswordSecureString = ConvertTo-SecureString -AsPlainText -Force -String 

($Record.Password)
                    $Record | Add-Member -MemberType NoteProperty -Name EncryptedPassword -Value (ConvertFrom-

SecureString -Key $SecureStringKey -SecureString $PasswordSecureString)
                    $Record.PSObject.Properties.Remove("Password")
                    $Record | Select-Object Username,EncryptedPassword,TargettedServerName,RealServerName | 

Export-Csv -Append -Path $TsvFileName -NoTypeInformation
                }
            }
        }
    }
}


function ConvertTo-CleartextPassword
{
<#
.SYNOPSIS
This function can be used to decrypt passwords that were stored encrypted by the function Invoke-PasswordRoll.

Function: ConvertTo-CleartextPassword
Author: Microsoft
Version: 1.0

.DESCRIPTION
This function can be used to decrypt passwords that were stored encrypted by the function Invoke-PasswordRoll.


.PARAMETER EncryptedPassword

The encrypted password that was stored in a TSV file.

.PARAMETER EncryptionKey

The password used to do the encryption.


.EXAMPLE

. .\Invoke-PasswordRoll.ps1    #Loads the functions in this script file
ConvertTo-CleartextPassword -EncryptionKey "Password1" -EncryptedPassword 

76492d1116743f0423413b16050a5345MgB8AGcAZgBaAHUAaQBwADAAQgB2AGgAcABNADMASwBaAFoAQQBzADEAeABjAEEAPQA9AHwAZgBiAGYA

MAA1ADYANgA2ADEANwBkADQAZgAwADMANABjAGUAZQAxAGIAMABiADkANgBiADkAMAA4ADcANwBhADMAYQA3AGYAOABkADcAMQA5ADQAMwBmAGYA

NQBhADEAYQBjADcANABkADIANgBhADUANwBlADgAMAAyADQANgA1ADIAOQA0AGMAZQA0ADEAMwAzADcANQAyADUANAAzADYAMAA1AGEANgAzADEA

MQA5ADAAYwBmADQAZAA2AGQA"

Decrypts the encrypted password which was stored in the TSV file.

#>
    Param(
        [Parameter(Mandatory=$true)]
        [String]
        $EncryptedPassword,

        [Parameter(Mandatory=$true)]
        [String]
        $EncryptionKey
    )

    $Sha256 = new-object System.Security.Cryptography.SHA256CryptoServiceProvider
    $SecureStringKey = $Sha256.ComputeHash([System.Text.UnicodeEncoding]::Unicode.GetBytes($EncryptionKey))

    [SecureString]$SecureStringPassword = ConvertTo-SecureString -String $EncryptedPassword -Key 

$SecureStringKey
    Write-Output ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto

([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($SecureStringPassword)))
}

다음을 사용하여 스크립트를 실행할 때:

Invoke-PasswordRoll -ComputerName (Get-Content computerlist.txt) -LocalAccounts @("administrator","CustomLocalAdmin") -TsvFileName "LocalAdminCredentials.tsv" -EncryptionKey "Password1"

대상 컴퓨터의 비밀번호는 변경되지만 "Password1"로 변경되지는 않습니다. 이 스크립트는 정확히 무엇을 하고 있나요?

답변1

Tomasz와 Zoredache가 말했듯이 Microsoft가 제공하는 스크립트는 원격 컴퓨터의 로컬 계정 암호를 임의의 암호로 설정하는 데에만 사용할 수 있습니다. -EncryptionKey일반 텍스트 계정 비밀번호가 디스크에 기록되지 않도록 하기 위해 CSV 파일에 저장된 계정 비밀번호는 관리자가 선택한 비밀번호(매개변수)를 사용하여 암호화할 수 있습니다 .

암호화된 비밀번호(TSV 파일에 저장됨)는 동일한 파일의 다른 기능인 ConvertTo-CleartextPassword를 사용하여 해독할 수 있습니다.

우리 환경에서는 비밀번호를 정기적으로 변경하고 싶기 때문에 두 개의 스크립트를 만들었습니다. 하나는 암호화된 비밀번호(직접 선택한)로 새 파일을 생성하고 이 파일을 모든 워크스테이션에 배포하는 것입니다. 워크스테이션에도 배포되는 초 스크립트는 X시간마다 실행되며 파일 내용을 기반으로 비밀번호를 재설정합니다. 물론 암호화 및 복호화에 사용되는 비밀번호는 여전히 일반 텍스트로 저장되지만 비밀번호 자체는 그렇지 않습니다. 이렇게 하면 암호화 파일과 스크립트가 다른 위치에 저장되므로 꽤 안전하기 때문에 로컬 관리자 비밀번호를 검색하기 위해 무엇을 하고 있는지 알아야 합니다.

비밀번호 파일 생성

다음 스크립트를 사용하여(오류 로깅 및 시도/캐치를 제거했습니다) 비밀번호 파일을 생성합니다.

$LocalAdminPW = "0urAdminP@ssword" #the password that is used to set as the local admin password
$EncryptionPW = "0urEncryptionP@ssword" #password to encrypt and decrypt the password
$File = "C:\Temp\Password.tsv" #file to create

#Create encryption key
$Sha256 = new-object System.Security.Cryptography.SHA256CryptoServiceProvider
$SecureStringKey = $Sha256.ComputeHash([System.Text.UnicodeEncoding]::Unicode.GetBytes($EncryptionPW))

#Encrypt the password with the user supplied encryption password
PasswordSecureString = ConvertTo-SecureString -AsPlainText -Force -String $LocalAdminPW

#Create TSV-File with the encrypted password
ConvertFrom-SecureString -Key $SecureStringKey -SecureString $PasswordSecureString | Out-File -Force -FilePath "$File"

#Gathering the new encrypted password for the local administrator account
$LocalAdminPW = Get-Content $FileLocation

생성된 비밀번호 파일로 로컬 관리자 비밀번호를 설정하세요.

다음 스크립트를 사용하여 비밀번호 파일에서 비밀번호를 해독하고 이를 사용하여 관리자 비밀번호를 설정합니다(오류 처리 및 로깅을 제거했습니다).

#function to get decrypted password
Function Get-DecryptedPassword {
    [CmdletBinding()]
    param(
        $EncryptedPW,
        $LocalAdminPW
    )

    #Decrypt the password with the user supplied encryption password
    $Sha256 = new-object System.Security.Cryptography.SHA256CryptoServiceProvider
    $SecureStringKey = $Sha256.ComputeHash([System.Text.UnicodeEncoding]::Unicode.GetBytes($EncryptionPW))
    [SecureString]$SecureStringPassword = ConvertTo-SecureString -String $LocalAdminPW -Key $SecureStringKey
    return ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($SecureStringPassword)))
}

#Change password local admin account
$LocalAdmin = "Administrator"
$objUser = [ADSI]"WinNT://localhost/$($LocalAdmin), user"
$objUser.psbase.Invoke("SetPassword", (Get-DecryptedPassword -EncryptedPW $EncryptionPW  -LocalAdminPW $LocalAdminPW))

답변2

스프레드시트에 비밀번호를 저장하는 것은 최적이 아니며 모든 컴퓨터를 동일한 비밀번호로 설정하는 것은 자격 증명 도용의 또 다른 문제입니다(정기적으로 변경하더라도). LAPS 도구를 사용하면 로컬 관리자 비밀번호를 안전하게 무작위로 지정할 수 있습니다. 문서의 문제를 해결하려는 경우 도메인 자격 증명을 사용하는 것이 좋습니다. 단순히 비밀번호를 변경하려는 경우 LAPS 도구(https://technet.microsoft.com/en-us/library/security/3062591.aspx)

답변3

붙여넣은 스크립트의 주석을 읽어보세요.

로컬 계정 "administrator" 및/또는 "CustomLocalAdmin"이 시스템에 있는 경우 해당 암호는 임의로 생성된 길이 20(기본값)의 암호로 변경됩니다.

사용자 이름/비밀번호/서버 조합은 LocalAdminCredentials.tsv에 저장되며 계정 비밀번호는 비밀번호 "Password1"을 사용하여 AES 암호화됩니다.

관련 정보