I have built a few Powershell functions using Azure Functions, and it is working like a charm.
Now that I have proven the concept I would very much like to refactor my existing functions.
First of all I would like to move the authentication required in my function to some kind of shared function or whatever.
Here is my example function, which return a list of all web apps in my resource group.
# Authenticate with subscription
$subscriptionId = "<SubscriptionId>"
$resourceGroupName = "<ResourceGroupName>";
$tenantId = "<TenantId>"
$applicationId = "<ApplicationId>"
$password = "<Password>"
$userPassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$userCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $applicationId, $userPassword
Add-AzureRmAccount -TenantId $tenantid -ServicePrincipal -SubscriptionId $subscriptionId -Credential $userCredential
Get-AzureRmSubscription –SubscriptionId $subscriptionId | Select-AzureRmSubscription
# Get all web apps
$Websites = Get-AzureRmWebApp -ResourceGroupName $resourceGroupName
$Websites = $Websites | select name | ConvertTo-Json -Compress
# Write output
Out-File -Encoding Ascii -FilePath $res -inputObject $Websites
I would very much like to move everything from line 1 to line 10 somewhere else. Is it possible? If yes, can anyone please point me in the right direction here?
Update
Thanks to both Walter and Pragna I combined the two methods like this.
run.ps1
# Authenticate with subscription
Import-Module 'D:\home\site\wwwroot\bin\Authentication.ps1'
# Get all web apps
$Websites = Get-AzureRmWebApp -ResourceGroupName $env:ResourceGroupName
$Websites = $Websites | select name | ConvertTo-Json -Compress
# Write output
Out-File -Encoding Ascii -FilePath $res -inputObject $Websites
Authentication.ps1
$secpasswd = ConvertTo-SecureString $env:Password -AsPlainText -Force;
$userCredential = New-Object System.Management.Automation.PSCredential ($env:ApplicationId, $secpasswd)
Add-AzureRmAccount -TenantId $env:TenantId -ServicePrincipal -SubscriptionId $env:SubscriptionId -Credential $userCredential
Get-AzureRmSubscription –SubscriptionId $env:SubscriptionId | Select-AzureRmSubscription
It is unsafe for you to save your account information in script. I suggest you could store these to App Setting. You could find it Your function app-->Settings-->Application settings-->Manage application settings-->App settings and key-value pairs for the settings SP_USERNAME, SP_PASSWORD, and TENANTID, SubscriptionId(You also could use other values or more key pairs).
Modify your script as below:
# Set Service Principal credentials
# SP_PASSWORD, SP_USERNAME, TENANTID are app settings
$secpasswd = ConvertTo-SecureString $env:SP_PASSWORD -AsPlainText -Force;
$mycreds = New-Object System.Management.Automation.PSCredential ($env:SP_USERNAME, $secpasswd)
Add-AzureRmAccount -ServicePrincipal -Tenant $env:TENANTID -Credential $mycreds;
Get-AzureRmSubscription –SubscriptionId $env:subscriptionId | Select-AzureRmSubscription
When you want to modify your account information, you don't need modify your script, you only need modify app setting. You could modify app setting by using Azure CLI.
Yes. You can import custom powershell modules.
Create a shared directory e.g. bin under D:\home\site\wwwroot
Copy module to the shared directory
Call Import-Module SharedDir\MyModule.psm1 or SharedDir\MyScript.ps1 or SharedDir\MyModule.psd1 or SharedDir\MyLib.dll
Also, here is a sample that might help.
Related
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 use 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.
EDIT:
I want to retrieve session data from a specific account using
PowerShell. According to this documentation:
https://learn.microsoft.com/en-us/powershell/module/skype/get-csusersession?view=skype-ps
Get-CsUserSession command is able to do this. I am using this
command according to the upper's link example
Get-CsUserSession -User account#companyX.onmicrosoft.com -StartDate "6/1/2018 07:00 PM"
and then I am getting the following error:
A parameter cannot be found that matches parameter name 'StartDate'.
+ CategoryInfo : InvalidArgument: (:) [Get-CsUserSession], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.Rtc.Management.Hosted.Data.GetCsUserSessionCmdlet
+ PSComputerName : admin1e.online.lync.com
What is wrong with that and what is the correct declaration?
I am making a connection to Skype for business service with the following script:
$credential = Get-Credential
Import-Module MSOnline
Connect-MsolService -Credential
$credential Import-Module SkypeOnlineConnector
$lyncSession = New-CsOnlineSession -Credential
$credential Import-PSSession $lyncSession
What I would like to do is to set using a particular static account and password from the PowerShell script (using some sort of declaration variable strings), instead of running this command and have to type the credentials in a separate window. Meaning that I want to avoid using $credential = Get-Credential command. Is this possible?
As stated in documentation you linked (only at the top paragraph though), you have to use StartTime not StartDate. The error you receive is the typical symptom that you either has a typo in parameter name or this parameter doesn't exist for that function.
I'll request to change the example in the docs a bit later, seems like someone who wrote them were mixing up with another cmdlet.
Edit: to store credentials you can export your password like this:
"P#ssword1" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File C:\Users\username\password2.txt
And then import like this:
$password = Get-Content -Path "C:\Users\USUARIOPC\password2.txt" | ConvertTo-SecureString -String $password
$credential = New-Object System.Management.Automation.PsCredential("yourlogin#domain.com", $password)
In the meantime, I tried the following query. Probably is not too safe to use a password in a script but for us who want to do it like this is a nice solution.
$username = "account1#companyX.onmicrosoft.com"
$password = "abcdefg"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
$credential = $cred
Import-Module MSOnline
Connect-MsolService -Credential $credential
Import-Module SkypeOnlineConnector
$SFBSession = New-CsOnlineSession -Credential $credential
Import-PSSession $SFBSession
I am using environment credential to get the username and password. When I echo them they are printed perfectly as ****.
The next comes the powershell commands, when I run them separately, all the commands works perfectly. But through Jenkins pipeline it throws me the following error:
groovy.lang.MissingPropertyException: No such property: psw for class: groovy.lang.Binding
Can anyone explain is this correct way to incorporate powershell in Jenkins pipeline?
environment {
CREDENTIAL = credentials('Test')
}
stage('Deployment') {
steps {
echo "$CREDENTIAL_USR"
echo "$CREDENTIAL_PSW"
powershell """($psw = ConvertTo-SecureString -String $CREDENTIAL_PSW -AsPlainText -Force)"""
powershell """($mySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $CREDENTIAL_USR, $psw -Verbose)"""
powershell """(Set-Item WSMan:/localhost/Client/TrustedHosts -Value "*" -Force)"""
powershell """($session = New-PSSession -ComputerName "192.111.111.111" -Credential $mySecureCreds)"""
In case someone is here, and still trying to figure out what is the issue. I will share the solution that worked for me.
Use escaping before variable "$" sign in multi-line string.
powershell ("""
\$psw = ConvertTo-SecureString -String \$CREDENTIAL_PSW -AsPlainText -Force
\$mySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList \$CREDENTIAL_USR, \$psw -Verbose
Set-Item WSMan:/localhost/Client/TrustedHosts -Value "*" -Force
\$session = New-PSSession -ComputerName "192.111.111.111" -Credential \$mySecureCreds
""")
You can easily run multiline powershell commands in jenkins pipeline like this. Example, if you want to login to azure using service principal, you'll do something like below:
powershell '''
$pass = ConvertTo-SecureString your_client_secret -AsPlainText –Force
$cred = New-Object -TypeName pscredential –ArgumentList your_client_id, $pass
Login-AzureRmAccount -Credential $cred -ServicePrincipal –TenantId your_tenant_id
-vaultName "eusdevmbe2keyvault" -name "normalizedcontainername").SecretValueText
'''
Check here for reference https://jenkins.io/blog/2017/07/26/powershell-pipeline/
At the moment you're running each line in its own powershell process, so the results of the line before are not available to the next command.
I think you just need to move the script into a multi-line string:
powershell ("""
$psw = ConvertTo-SecureString -String $CREDENTIAL_PSW -AsPlainText -Force
$mySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $CREDENTIAL_USR, $psw -Verbose
Set-Item WSMan:/localhost/Client/TrustedHosts -Value "*" -Force
$session = New-PSSession -ComputerName "192.111.111.111" -Credential $mySecureCreds
""")
I want to take SQL Azure back up to Azure Blob storage using PowerShell. I have used the following script, but it is popping up for credential whenever I try to run.
I will be using this script from windows task scheduler, so how can I put user id and password inside PowerShell script so that it won't ask for username/password for subscription?
$subscriptionId = "xxxxxxxxxxxxxxxxxxxxx"
Login-AzureRmAccount
Set-AzureRmContext -SubscriptionId $subscriptionId
# Database to export
$DatabaseName = "xxxxxxxxxxx"
$ResourceGroupName = "xxxxxxxxxxx"
$ServerName = "xxxxxxxxxxxx"
$serverAdmin = "xxxxxxxxxxxxxxx"
$serverPassword = "xxxxxxxxxxx"
$securePassword = ConvertTo-SecureString -String $serverPassword -AsPlainText -Force
$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $serverAdmin, $securePassword
# Generate a unique filename for the BACPAC
$bacpacFilename = $DatabaseName + (Get-Date).ToString("yyyyMMddHHmm") + ".bacpac"
# Storage account info for the BACPAC
$BaseStorageUri = "https://xxxxxxx.blob.core.windows.net/xxxxx/"
$BacpacUri = $BaseStorageUri + $bacpacFilename
$StorageKeytype = "StorageAccessKey"
$StorageKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$exportRequest = New-AzureRmSqlDatabaseExport -ResourceGroupName $ResourceGroupName -ServerName $ServerName `
-DatabaseName $DatabaseName -StorageKeytype $StorageKeytype -StorageKey $StorageKey -StorageUri $BacpacUri `
-AdministratorLogin $creds.UserName -AdministratorLoginPassword $creds.Password
You need to implement a non-interactive login in your script. Just modify your script as below:
##login Azure
$subscriptionId = "xxxxxxxxxxxxxxxxxxxxx"
$username = "<username>"
$password = "<password>"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
Login-AzureRmAccount -Credential $cred
Select-AzureRmSubscription -SubscriptionId $subscriptionId
Note: you cannot login non-intereractively to Azure using a Microsoft Live account, such as *#hotmail.com, *#outlook.com.
There are probably two ways you can achieve this.
The first is to use the credential parameter as part of the Login-AzureRMAccount call. You can create a PSCredential in the powershell code and then use that. For example: Login-AzureRmAccount -Credential $credential
The second, and probably the safer/more secure way, is to create a service principal and then place the certificate on the machine in question. You can find instructions on how to do this here. After you have that created, you can use the Login-AzureRMAccount with the -ServicePrincipalparameter. See this link for more information.
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 use 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.