I'd like to restart a remote computer that belongs to a domain. I have an administrator account but I don't know how to use it from powershell.
I know that there is a Restart-Computer
cmdlet and that I can pass credential but if my domain is for instance mydomain
, my username is myuser
and my password is mypassword
what's the right syntax to u开发者_如何学运维se it?
I need to schedule the reboot so I don't have to type the password.
The problem with Get-Credential
is that it will always prompt for a password. There is a way around this however but it involves storing the password as a secure string on the filesystem.
The following article explains how this works:
Using PSCredentials without a prompt
In summary, you create a file to store your password (as an encrypted string). The following line will prompt for a password then store it in c:\mysecurestring.txt
as an encrypted string. You only need to do this once:
read-host -assecurestring | convertfrom-securestring | out-file C:\mysecurestring.txt
Wherever you see a -Credential
argument on a PowerShell command then it means you can pass a PSCredential
. So in your case:
$username = "domain01\admin01"
$password = Get-Content 'C:\mysecurestring.txt' | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
$serverNameOrIp = "192.168.1.1"
Restart-Computer -ComputerName $serverNameOrIp `
-Authentication default `
-Credential $cred
<any other parameters relevant to you>
You may need a different -Authentication
switch value because I don't know your environment.
There is another way, but...
DO NOT DO THIS IF YOU DO NOT WANT YOUR PASSWORD IN THE SCRIPT FILE (It isn't a good idea to store passwords in scripts, but some of us just like to know how.)
Ok, that was the warning, here's the code:
$username = "John Doe"
$password = "ABCDEF"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
$cred
will have the credentials from John Doe with the password "ABCDEF".
Alternative means to get the password ready for use:
$password = convertto-securestring -String "notverysecretpassword" -AsPlainText -Force
Regarding storing credentials, I use two functions(that are normally in a module that is loaded from my profile):
#=====================================================================
# Get-MyCredential
#=====================================================================
function Get-MyCredential
{
param(
$CredPath,
[switch]$Help
)
$HelpText = @"
Get-MyCredential
Usage:
Get-MyCredential -CredPath `$CredPath
If a credential is stored in $CredPath, it will be used.
If no credential is found, Export-Credential will start and offer to
Store a credential at the location specified.
"@
if($Help -or (!($CredPath))){write-host $Helptext; Break}
if (!(Test-Path -Path $CredPath -PathType Leaf)) {
Export-Credential (Get-Credential) $CredPath
}
$cred = Import-Clixml $CredPath
$cred.Password = $cred.Password | ConvertTo-SecureString
$Credential = New-Object System.Management.Automation.PsCredential($cred.UserName, $cred.Password)
Return $Credential
}
And this one:
#=====================================================================
# Export-Credential
# Usage: Export-Credential $CredentialObject $FileToSaveTo
#=====================================================================
function Export-Credential($cred, $path) {
$cred = $cred | Select-Object *
$cred.password = $cred.Password | ConvertFrom-SecureString
$cred | Export-Clixml $path
}
You use it like this:
$Credentials = Get-MyCredential (join-path ($PsScriptRoot) Syncred.xml)
If the credential file doesnt exist, you will be prompted the first time, at that point it will store the credentials in an encrypted string inside an XML file. The second time you run that line, the xmlfile is there and will be opened automatically.
I have to run SCOM 2012 functions from a remote server that requires a different credential. I avoid clear-text passwords by passing the output of a password decryption function as input to ConvertTo-SecureString. For clarity, this is not shown here.
I like to strongly type my declarations. The type declaration for $strPass works correctly.
[object] $objCred = $null
[string] $strUser = 'domain\userID'
[System.Security.SecureString] $strPass = ''
$strPass = ConvertTo-SecureString -String "password" -AsPlainText -Force
$objCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($strUser, $strPass)
Here are two ways you could do this, if you are scheduling the reboot.
First you could create a task on one machine using credentials that have rights needed to connect and reboot another machine. This makes the scheduler responsible for securely storing the credentials. The reboot command (I'm a Powershell guy, but this is cleaner.) is:
SHUTDOWN /r /f /m \\ComputerName
The command line to create a scheduled task on the local machine, to remotely reboot another, would be:
SCHTASKS /Create /TN "Reboot Server" /TR "shutdown.exe /r /f /m \\ComputerName" /SC ONCE /ST 00:00 /SD "12/24/2012" /RU "domain\username" /RP "password"
I prefer the second way, where you use your current credentials to create a scheduled task that runs with the system account on a remote machine.
SCHTASKS /Create /TN "Reboot Server" /TR "shutdown.exe /r /f" /SC ONCE /ST 00:00 /SD "12/24/2012" /RU SYSTEM /S ComputerName
This also works through the GUI, just enter SYSTEM as the user name, leaving the password fields blank.
I saw one example that uses Import/Export-CLIXML.
These are my favorite commands for the issue you're trying to resolve. And the simplest way to use them is.
$passwordPath = './password.txt'
if (-not (test-path $passwordPath)) {
$cred = Get-Credential -Username domain\username -message 'Please login.'
Export-CliXML -InputObject $cred -Path $passwordPath
}
$cred = Import-CliXML -path $passwordPath
So if the file doesn't locally exist it will prompt for the credentials and store them. This will take a [pscredential]
object without issue and will hide the credentials as a secure string.
Finally just use the credential like you normally do.
Restart-Computer -ComputerName ... -Credentail $cred
Note on Securty:
Securely store credentials on disk
When reading the Solution, you might at first be wary of storing a password on disk. While it is natural (and prudent) to be cautious of littering your hard drive with sensitive information, the Export-CliXml cmdlet encrypts credential objects using the Windows standard Data Protection API. This ensures that only your user account can properly decrypt its contents. Similarly, the ConvertFrom-SecureString cmdlet also encrypts the password you provide.
Edit: Just reread the original question. The above will work so long as you've initialized the [pscredential]
to the hard disk. That is if you drop that in your script and run the script once it will create that file and then running the script unattended will be simple.
read-host -assecurestring | convertfrom-securestring | out-file C:\securestring.txt
$pass = cat C:\securestring.txt | convertto-securestring
$mycred = new-object -typename System.Management.Automation.PSCredential -argumentlist "test",$pass
$mycred.GetNetworkCredential().Password
Be very careful with storing passwords this way... it's not as secure as ...
Solution
$userName = 'test-domain\test-login'
$password = 'test-password'
$pwdSecureString = ConvertTo-SecureString -Force -AsPlainText $password
$credential = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList $userName, $pwdSecureString
For Build Machines
In the previous code replace user name and password values by secret ("hidden from logs") environment variables of your build-machine
Test results by
'# Results'
$credential.GetNetworkCredential().Domain
$credential.GetNetworkCredential().UserName
$credential.GetNetworkCredential().Password
and you'll see
# Results
test-domain
test-login
test-password
This is what I use and works for me.
$User="Domain\Username"
$Password=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('VABlAHMAdABQAGEAcwBzAHcAbwByAGQA'))
$SecurePassword = New-Object -TypeName System.Security.SecureString
$Password.ToCharArray() | ForEach-Object {$SecurePassword.AppendChar($_)}
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $SecurePassword
And to get VABlAHMAdABQAGEAcwBzAHcAbwByAGQA I do this:
To Encode $EString means Encrypted String and $DString means Decrypted String
$EString = Read-Host "Type Text to Encode" -AsSecureString
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($EString)
$DString=[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$Encoded=[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($DString))
$Encoded # VABlAHMAdABQAGEAcwBzAHcAbwByAGQA
$DString # TestPassword
That way I can put any password I want on the script without too much hassle.
In case below code might help someone.
function Get-RemoteConnection()
{
//$serverIp can be passed as a parameter of the function.
//I just make it static for testing.
$serverIp = '192.168.100.137'
Enable-PSRemoting -Force
Set-Item wsman:\localhost\client\trustedhosts $serverIp
Restart-Service WinRM
#Set credentials needed for remote installation
$userName = "administrator"
$password = ConvertTo-SecureString "2020core0515" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList ($userName, $password)
$session = New-PSSession -ComputerName $serverIp -Credential $cred
$a = Invoke-Command -Session $session -ScriptBlock { Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3" | Select-Object DeviceID, @{label='UsedPercent'; expression={[Math]::Round((($_.size - $_.freespace) / $_.size) * 100, 2)}} }
Write-Host $a
return $session
}
function Delete-RemoteConnection($session)
{
Disconnect-PSSession $session | Out-Null
Disable-WSManCredSSP -Role Client
}
Instead of storing the encrypted password in a text file you can store it in the credential vault. In the follwing example the user is prompted for a password only the first time, after that the password is retrieved from the credential vault.
# Load the Windows Runtime Class
[Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
$Vault = New-Object Windows.Security.Credentials.PasswordVault
$RESOURCE = "myresource"
$USERNAME = "myuser"
try {
$credentials = $Vault.Retrieve($RESOURCE,$USERNAME)
$pwd = $credentials.Password | ConvertTo-SecureString -Key (1..16)
}
catch {
$pwd = Read-Host "please enter your password:" -AsSecureString
$Encrypted = ConvertFrom-SecureString -SecureString $pwd -Key (1..16)
$credentials = new-object -Type Windows.Security.Credentials.PasswordCredential -ArgumentList $RESOURCE,$USERNAME,$Encrypted
$Vault.Add($credentials)
}
$cred = New-Object System.Management.Automation.PsCredential($USERNAME,$pwd)
why dont you try something very simple?
use psexec with command 'shutdown /r /f /t 0' and a PC list from CMD.
精彩评论