PSCredentialManager.psm1
function Get-CachedCredential { [OutputType([pscustomobject])] [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string[]]$ComputerName, [Parameter()] [ValidateNotNullOrEmpty()] [string]$Name ) $output = @() if (-not $PSBoundParameters.ContainsKey('ComputerName') -and -not ($PSBoundParameters.ContainsKey('Name'))) { ConvertTo-CachedCredential -CmdKeyOutput (cmdkey /list) } elseif (-not $PSBoundParameters.ContainsKey('ComputerName') -and $PSBoundParameters.ContainsKey('Name')) { ConvertTo-CachedCredential -CmdKeyOutput (cmdkey /list:$Name) } else { if (-not (Test-PsExecInstalled)) { Install-PsExec } $cred = Get-Credential -Message 'Enter credential to authenticate to remote computer(s).' -UserName (whoami) foreach ($c in $ComputerName) { $cmdkeyOutput = Invoke-PsExec -ComputerName $c -Command 'cmdkey /list' -Credential $cred ConvertTo-CachedCredential -CmdKeyOutput $cmdkeyOutput } } } function Test-PsRemoting { param ( [Parameter(Mandatory = $true)] $computername ) try { Write-Verbose "Testing for enabled remoting" $result = Invoke-Command -ComputerName $computername { 1 } } catch { return $false } ## I’ve never seen this happen, but if you want to be ## thorough…. if ($result -ne 1) { Write-Verbose "Remoting to $computerName returned an unexpected result." return $false } $true } function Install-PsExec { [OutputType([void])] [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string]$Uri = 'https://download.sysinternals.com/files/PSTools.zip' ) $zipPath = "$env:TEMP\PSTools.zip" $folder = "$env:TEMP\PSTools" if (-not (Test-Path -Path $zipPath -PathType Container)) { Invoke-WebRequest -Uri $Uri -UseBasicParsing -OutFile $zipPath Expand-Archive -Path $zipPath -DestinationPath $folder } $null = & "$folder\psexec.exe" -accepteula } function Invoke-PsExec { [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ComputerName, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Command, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [pscredential]$Credential ) $x = $Command -split ' ' $cmd = $x[0] $cmdArgs = $x[1..($x.Length)] @("$env:TEMP\err.txt","$env:TEMP\out.txt").foreach({ Remove-Item -Path $_ -ErrorAction Ignore }) $startParams = @{ FilePath = "$env:temp\pstools\psexec.exe" Wait = $true NoNewWindow = $true ArgumentList = "\\$ComputerName -user $($Credential.UserName) -pass $($Credential.GetNetworkCredential().Password) $cmd $cmdArgs" RedirectStandardError = "$env:TEMP\err.txt" RedirectStandardOutput = "$env:TEMP\out.txt" } Start-Process @startParams Get-Content -Path "$env:TEMP\out.txt" -Raw } function Test-PsExecInstalled { [OutputType('bool')] [CmdletBinding()] param () if (-not (Test-Path -Path "$env:TEMP\PSTools\psexec.exe" -PathType Leaf)) { $false } else { $true } } function Remove-CachedCredential { [OutputType([void])] [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string]$ComputerName ) cmdkey /delete:targetname } function New-CachedCredential { [OutputType([void])] [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Username, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Password, [Parameter()] [ValidateNotNullOrEmpty()] [string]$ComputerName ) cmdkey /add:targetname /user:username /pass:password cmdkey /add:targetname /user:username /pass cmdkey /add:targetname /user:username cmdkey /add:targetname /smartcard } function ConvertTo-MatchValue { [OutputType('string')] [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$String, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$RegularExpression ) ([regex]::Match($String,$RegularExpression)).Groups[1].Value } function ConvertTo-CachedCredential { [OutputType('pscustomobject')] [CmdletBinding()] param ( [Parameter(Mandatory)] $CmdKeyOutput ) if (-not ($CmdKeyOutput.where({ $_ -match '\* NONE \*' }))) { if (@($CmdKeyOutput).Count -eq 1) { $CmdKeyOutput = $CmdKeyOutput -split "`n" } $nullsRemoved = $CmdKeyOutput.where({ $_ }) $i = 0 foreach ($j in $nullsRemoved) { if ($j -match '^\s+Target:') { [pscustomobject]@{ Name = (ConvertTo-MatchValue -String $j -RegularExpression 'Target: .+:target=(.*)$').Trim() Category = (ConvertTo-MatchValue -String $j -RegularExpression 'Target: (.+):').Trim() Type = (ConvertTo-MatchValue -String $nullsRemoved[$i + 1] -RegularExpression 'Type: (.+)$').Trim() User = (ConvertTo-MatchValue -String $nullsRemoved[$i + 2] -RegularExpression 'User: (.+)$').Trim() Persistence = ($nullsRemoved[$i + 3]).Trim() } } $i++ } } } |