Write-Credential.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

#----------------------------------------------------[Function synopsis]-----------------------------------------------------

Function Write-Credential {

<#
   .SYNOPSIS
    Saves credentials to disk system as secure string for re-use
 
   .DESCRIPTION
    Saves credentials to disk system as secure string for re-use.
    User will be prompted to enter user name and password which will be saved. Username will be re-used exactly as specified, i.e. depending on target use you may want to specify domain\user or user@domain.com
    Only currently logged in user will be able to decrypt and use saved credentials. Other users even if they will have access to saved files, will not be able to decrypt it.
 
   .Example
    Write-Credential Dev
    User is prompted for credentials (user name and password) which are saved to default location.
 
   .EXAMPLE
    Write-Credential BAcc -Path P:\cred
    User is prompted for credentials for B account, which are afterwards saved to P: disk.
 
   .PARAMETER Environment
    Name of environment for which credentials are saved. It will be used in Get commands, and also as part of file names.
    If you want to save credentials for multiple users in same environment, use different Environment names, like EnvAdmin and EnvUser.
    You may specify multiple environments.
 
   .PARAMETER Path
    Optional parameter which defines where credentials will be saved. If not specified, %APPDATA%\CredentialsManager is used.
    If specified, default value will be updated and re-used on next calls within the same PowerShell session.
 
   .PARAMETER PassThru
    Switch parameter which defines if credentials created by this cmdlet will be passed through the pipeline. Default is false.
 
   .OUTPUTS
    Cmdlet is not returning any value by default.
    If switch PassThru is specified, it returns Credentials object as Get-Credential, System.Management.Automation.PSCredential.
 
   .NOTES
    NAME: Write-Credential
    AUTHOR: Igor Iric, IricIgor@Gmail.com
    CREATEDATE: October, 2015
 
 #>



#-------------------------------------------------[Parameters definitions]--------------------------------------------------

[cmdletbinding()]

Param(
  [parameter(Mandatory=$true,ValueFromPipeline=$true)][string[]]$Environment,
  [parameter(Mandatory=$false,ValueFromPipeline=$false)][string]$Path=$Script:CredentialsPath,
  [switch]$PassThru
) #end param

#-------------------------------------------------[Constant declarations]---------------------------------------------------




#-------------------------------------------------[Function initialization]--------------------------------------------------
BEGIN {
    # function begin phase
    # handling Path parameter, if folder not exisiting create it and set hidden

    
    if (!$Path) {
        # if path is not specified, it means also global needs to be initialized
        $Script:CredentialsPath = Join-Path -Path $env:APPDATA  -ChildPath 'CredentialsManager'
        Write-Verbose -Message "Setting default path to: $Script:CredentialsPath"
        $Path = $Script:CredentialsPath
        Write-Verbose -Message "Using default path $Path"
    }

    if (!(Test-Path -Path $Path)) {
        # folder not existing -> create it
        try {
            Write-Verbose -Message "Trying to create exports folder $Path"
            $Folder = New-Item -Path $Path -ErrorAction Stop -ItemType Directory
            $PathFolderCreated = $true
        } catch {
            # folder creation error
            $PathFolderCreated = $false
            throw $Error[0]
        }

        if ($PathFolderCreated) {
            Write-Verbose -Message 'Exports folder created.'
            # set folder to be hidden, if creating it
            $Folder.Attributes = $Folder.Attributes -bor [io.fileattributes]::Hidden
            if ($Path -ne $Script:CredentialsPath) {
                Write-Verbose -Message "Updating default path to $Path."
                $Script:CredentialsPath = $Path
            }               
        }
    } # end of folder creation part
}

#---------------------------------------------------[Function processing]----------------------------------------------------
PROCESS {

    foreach ($E in @($Environment)) {
    # function process phase, executed once for each element in main Prameter
    
        # main code
        Write-Verbose -Message '----------------------'
        Write-Verbose -Message "Processing environment $E..."
        $VerboseMessage = "Environment $E processed with issues." # it will be updated at the end, if successfull

        # prompt user for credentials
        $Cred = Get-Credential -Message "Enter your credentials for $E..."
        if (!$Cred) {
            Write-Error -Message 'Credentials not obtained. Ensure you are not clicking on Cancel.'
        } elseif ($Cred.Password.Length -eq 0) {
            Write-Error -Message 'Blank passwords not supported.'
        } else {
            # if credentials are obtained, proceed
            Write-Verbose -Message "Credentials for $E obtained."
            $FileNameUser = Join-Path -Path $Path -ChildPath ($E + '_UserName.cred')
            $FileNamePass = Join-Path -Path $Path -ChildPath ($E + '_Password.cred')

            # if files are existing, delete it
            try {
                Write-Verbose -Message "Trying to delete existing file(s) for $E..."
                if (Test-Path -Path $FileNameUser) {Remove-Item -Path $FileNameUser -ErrorAction Stop}
                if (Test-Path -Path $FileNamePass) {Remove-Item -Path $FileNamePass -ErrorAction Stop}
                Write-Verbose -Message 'Files deleted.'
            } catch {
                Write-Error -Message ('Credential files can not be updated. '+($Error[0].Exception))
            }

            # if files are not existing, export values
            if ((!(Test-Path -Path $FileNameUser)) -and (!(Test-Path -Path $FileNamePass))) {
                # create encrypted values
                $EncUser = ConvertTo-SecureString -String ($Cred.UserName) -AsPlainText -Force | ConvertFrom-SecureString 
                $EncPass = ConvertFrom-SecureString -SecureString ($Cred.Password)
                # save them
                try {
                    Write-Verbose -Message "Attempting to save credentials to $Path..."
                    $EncUser | Out-File $FileNameUser
                    $EncPass | Out-File $FileNamePass
                    $VerboseMessage = "Environment $E processed successfully."
                    Write-Verbose -Message 'Credentials saved.'
                } catch {
                    Write-Error -Message ('Credential files can not be updated. '+($Error[0].Exception))
                }
            }
        }
        
        # return values
        if ($PassThru) {
            Write-Verbose -Message "Returning credentials for $E to output."
            Return $Cred
        }

        Write-Verbose -Message $VerboseMessage
    } # end of foreach

} # end of function

#-----------------------------------------------------[Function closing]-----------------------------------------------------

END {
    # function closing phase
    Write-Verbose -Message 'Write-Credential finishing.'

}

} # end of function code
#----------------------------------------------------[End of function]------------------------------------------------------

#---------------------------------------------------[Comments section]------------------------------------------------------