This commit is contained in:
Zack Meier
2026-04-15 15:45:50 -05:00
commit 1d304511b8
613 changed files with 140998 additions and 0 deletions
@@ -0,0 +1,49 @@
trigger:
- main
name: 'ITD.Infra-Passwordstate'
variables:
major: 0
minor: 2
patch: $(Build.BuildID)
buildVer: $(major).$(minor).$(Build.BuildID)
pool: itdwinautop1
stages:
- stage: Build
jobs:
- job: Build
steps:
- task: PowerShell@2
inputs:
filePath: '$(System.DefaultWorkingDirectory)/Build/build.ps1'
- task: NuGetCommand@2
inputs:
command: 'pack'
packagesToPack: '$(System.DefaultWorkingDirectory)/ITD.Infra-Passwordstate.nuspec'
versioningScheme: byEnvVar
versionEnvVar: buildVer
buildProperties: 'VERSIONHERE=$(buildVer)'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'NuGetPackage'
publishLocation: 'Container'
- stage: Deploy
jobs:
- job: Deploy
steps:
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'NuGetPackage'
itemPattern: '**'
targetPath: '$(Pipeline.Workspace)'
- task: NuGetCommand@2
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/ITD.Infra-Passwordstate.$(major).$(minor).$(Build.BuildID).nupkg'
nuGetFeedType: external
publishFeedCredentials: 'ITD_PwshGallery'
@@ -0,0 +1,17 @@
$buildVersion = $env:BUILDVER
$moduleName = 'ITD.Infra-Passwordstate'
$manifestPath = Join-Path -Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY -ChildPath "$moduleName.psd1"
$modulePath = Join-Path -Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY -ChildPath "$moduleName.psm1"
## Update build version in manifest
$manifestContent = Get-Content -Path $manifestPath -Raw
$manifestContent = $manifestContent -replace '<ModuleVersion>', $buildVersion
## Update functions to export in manifest
Import-Module $modulePath
$funcStrings = (Get-Module ITD.Infra-Passwordstate).ExportedCommands.Values.Name
$funcStrings = "'$($funcStrings -join "','")'"
$manifestContent = $manifestContent -replace "<FunctionsToExport>", $funcStrings
$manifestContent | Set-Content -Path $manifestPath
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>ITD.Infra-Passwordstate</id>
<version>$VERSIONHERE$</version>
<authors>Zack Meier</authors>
<description>Functions for Passwordstate use</description>
</metadata>
<files>
<file src="**" exclude="**\.git\**;**\Build\**" />
</files>
</package>
@@ -0,0 +1,10 @@
@{
RootModule = 'ITD.Infra-Passwordstate.psm1'
ModuleVersion = '<ModuleVersion>'
GUID = '3b3f771e-962a-4f67-bca6-4e5d9df870c5'
Author = 'Zack Meier'
CompanyName = 'State of North Dakota'
PowerShellVersion = '5.1'
CompatiblePSEditions = 'Desktop','Core'
FunctionsToExport = @(<FunctionsToExport>)
}
@@ -0,0 +1,23 @@
#Get public and private function definition files.
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
#Dot source the files
Foreach($import in @($Public + $Private))
{
Try
{
. $import.fullname
}
Catch
{
Write-Error -Message "Failed to import function $($import.fullname): $_"
}
}
# Here I might...
# Read in or create an initial config file and variable
# Export Public functions ($Public.BaseName) for WIP modules
# Set variables visible to the module and its functions only
Export-ModuleMember -Function $Public.Basename
@@ -0,0 +1,52 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Export-ITDPasswordList {
[CmdletBinding()]
param (
[string]
$PasswordList,
[string]
$Destination,
[PSCredential]
$Credential
)
begin {
$PasswordListSearch = Get-ITDPasswordList -PasswordList $PasswordList -Credential $Credential
switch (@($PasswordListSearch).count) {
{ $_ -gt 1 } {
Write-Error -Message "More than one password list found, adjust search" -ErrorAction Stop
}
{ $_ -le 0} {
Write-Error -Message "Zero password lists found, adjust search" -ErrorAction Stop
}
{ 1 }{
$PasswordListId = $PasswordListSearch.PasswordListId
}
}
}
process {
$PasswordstateUrl = ("https://itdpv.nd.gov/winapi/passwords/" + $PasswordListId + "?QueryAll&PreventAuditing=true")
$Passwords = Invoke-RestMethod -Method GET -Uri $PasswordstateUrl -Credential $Credential
$Passwords | Export-Csv -Path $Destination
}
end {
}
}
@@ -0,0 +1,49 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Find-ITDPassword {
[CmdletBinding()]
param (
[string]
$Title,
[string]
$UserName,
[PSCredential]
$Credential
)
begin {
}
process {
$Uri = 'https://itdpv.nd.gov/winapi/searchpasswords/?'
If ($Title) { $Uri += 'title=' + $Title + '&' }
If ($UserName) { $Uri += 'username=' + "$UserName" + '&' }
$Uri = $Uri.TrimEnd('&')
$InvokeResult = Invoke-RestMethod -Method Get -Uri $Uri -Credential $Credential -ErrorAction SilentlyContinue
Write-Output $InvokeResult
}
end {
}
}
@@ -0,0 +1,99 @@
<#
.SYNOPSIS
Retrive password from ITD Passwordstate
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -VerboseZM
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Get-ITDPassword {
[CmdletBinding()]
param (
[string]
$Title,
[string]
$UserName,
[PSCredential]
$Credential,
[Parameter(ParameterSetName = "ToClipboard")]
[switch]
$ToClipboard,
[switch]
$FullRecord
)
begin {
}
process {
$Uri = 'https://itdpv.nd.gov/winapi/searchpasswords/?'
If ($PSBoundParameters.ContainsKey('Title')) {
$Uri += 'title=' + $Title + '&'
}
If ($PSBoundParameters.ContainsKey('Username')) {
$Uri += 'username=' + "$UserName" + '&'
}
$Uri = $Uri.TrimEnd('&')
$InvokeRestMethodParams = @{
Method = 'Get';
Uri = $Uri;
SkipHttpErrorCheck = $true;
}
If ($PSBoundParameters.ContainsKey('Credential')) {
$InvokeRestMethodParams += @{Credential = $Credential }
}
Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true }
}
$InvokeResult = Invoke-RestMethod @InvokeRestMethodParams
switch ($InvokeResult) {
{ $_ -eq $null } {
Write-Error -Message "No password found"
Break
}
{ $_ | Get-Member -MemberType Properties | Where-Object { $_.Name -eq 'errors' } } {
If ($InvokeResult.errors.message -eq 'Not found') {
Write-Warning -Message "Search for Password records return zero results"
}
}
Default {
$OutResult = $InvokeResult | Select-Object PasswordListID, PasswordList, PasswordID, Title, Description, UserName, @{n = 'SecurePassword'; e = { $_.Password | ConvertTo-SecureString -AsPlainText -Force } }, AccountTypeId, AccountType
If (@($OutResult).count -eq 1) {
If ($PSCmdlet.ParameterSetName -eq "ToClipboard") {
$InvokeResult.Password | Set-Clipboard
}
If ($FullRecord) {
Write-Output $OutResult
}
Else {
$OutCred = New-Object System.Management.Automation.PSCredential($OutResult.UserName, $OutResult.SecurePassword)
Write-Output $OutCred
}
}
Else {
Write-Output $OutResult
}
}
}
}
end {
}
}
@@ -0,0 +1,35 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Get-ITDPasswordAccountTypeId {
[CmdletBinding()]
Param(
[ValidateSet('VMware ESXi','Active Directory','HP iLO')]
[string]
$AccountType
)
Begin {
}
Process {
switch ($AccountType) {
'VMware ESXi' { $AccountTypeId = 34 }
'Active Directory' { $AccountTypeId = 70 }
'HP iLO' { $AccountTypeId = 1084 }
}
}
End {
return $AccountTypeId
}
}
@@ -0,0 +1,58 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Get-ITDPasswordList {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]
$PasswordList,
[PSCredential]
$Credential
)
begin {
}
process {
$Uri = "https://itdpv.nd.gov/winapi/searchpasswordlists/?"
If ($PasswordList) { $Uri += "PasswordList=$PasswordList" }
$Uri = $Uri.TrimEnd('&')
$InvokeRestMethodParams = @{
Method = 'Get';
Uri = $Uri;
}
If ($PSBoundParameters.ContainsKey('Credential')){
$InvokeRestMethodParams += @{Credential = $Credential}
} Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true}
}
$reply = Invoke-RestMethod -Method Get -Uri $Uri -Credential $Credential
If ($PasswordList) {
$result = $reply | Where-Object PasswordList -EQ $PasswordList
}
Else {
$result = $reply
}
}
end {
Write-Output $result
}
}
@@ -0,0 +1,134 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function New-ITDPassword {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
#[ValidateSet('Office365', 'VMware_Systems', 'CSRC', 'Shared Linux Password List', 'Peoplesoft Share PW', 'Cohesity', 'VDI')]
[string]
$PasswordList,
[Parameter(Mandatory = $true)]
[string]
$Title,
[Parameter(Mandatory = $true)]
[string]
$Description,
[string]
$AccountType,
[Parameter(ParameterSetName = 'GeneratePassword', Mandatory)]
[string]
$UserName,
[string]
$Notes,
[Parameter(ParameterSetName = 'EnterCredential')]
[PSCredential]
$CredentialToSave,
[PSCredential]
$Credential
)
begin {
$PSList = Get-ITDPasswordList -PasswordList $PasswordList -Credential $Credential
If (@($PSList).count -gt 1) { Write-Error "More than one PasswordList match." -ErrorAction Stop }
}
process {
switch ($PSCmdlet.ParameterSetName) {
'EnterCredential' {
Write-Verbose -Message "EnterCredential"
$Username = $CredentialToSave.UserName
$Password = $CredentialToSave.GetNetworkCredential().Password
}
'GeneratePassword' {
Write-Verbose -Message "GeneratePassword"
$Password = New-ITDRandomPassword -Credential $Credential
}
}
Write-Verbose -Message "Create password object"
$PasswordObj = [PSCustomObject]@{
'PasswordListID' = $PSList.PasswordListID;
'Title' = $Title;
'Description' = $Description;
'UserName' = $Username;
'Password' = $Password;
'Notes' = ("Auto-generated by " + $Credential.UserName + " @ " + (Get-Date -UFormat "%Y/%m/%d %H:%M:%S"));
}
switch ($PSBoundParameters.Keys) {
Notes {
$PasswordObj.Notes += ("`n" + $Notes)
}
}
If ($AccountType) {
$AccountTypeId = Get-ITDPasswordAccountTypeId -AccountType $AccountType
$PasswordObj | Add-Member -Name AccountTypeId -MemberType NoteProperty -Value $AccountTypeId
}
else {
$PasswordObj | Add-Member -Name AccountTypeId -MemberType NoteProperty -Value 0
}
$InvokeRestMethodParams = @{
Method = 'Post';
Uri = 'https://itdpv.nd.gov/winapi/passwords';
ContentType = 'application/json';
Body = ($PasswordObj | ConvertTo-Json);
}
If ($PSBoundParameters.ContainsKey('Credential')){
$InvokeRestMethodParams += @{Credential = $Credential}
} Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true}
}
Write-Verbose -Message "Invoke Passwordstate record creation"
$InvokeResult = Invoke-RestMethod @InvokeRestMethodParams
#Write-Verbose -Message "Store Invoke result in variable"
#$OutResult = $InvokeResult | Select-Object PasswordList, Title, Description, UserName, @{n = 'SecurePassword'; e = { $_.Password | ConvertTo-SecureString -AsPlainText -Force } }, AccountTypeId, AccountType
<# storing the returned PSCredential object (see code above) sometimes causes the following error:
[error] Exception calling ".ctor" with "2" argument(s): "Cannot process argument because the value of argument "password" is null. Change the value of argument "password" to a non-null value."
Running Get-ITDPassword does not cause the error, unsure of cause. Unsure of the reason why, not looking into it further
#>
Write-Verbose -Message "Retrieve new password"
$GetITDPasswordParams = @{
Title = $Title;
UserName = $UserName;
}
If ($PSBoundParameters.ContainsKey('Credential')){
$GetITDPasswordParams += @{Credential = $Credential}
} Else {
$GetITDPasswordParams += @{UseDefaultCredentials = $true}
}
$OutResult = Get-ITDPassword @GetITDPasswordParams
#Write-Verbose -Message "put OutResult in credential variable and return"
#$OutCred = New-Object System.Management.Automation.PSCredential($OutResult.UserName, $OutResult.SecurePassword)
}
end {
Write-Output $OutResult
}
}
@@ -0,0 +1,52 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function New-ITDRandomPassword {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
Begin {
}
Process {
$InvokeRestMethodParams = @{
Method = 'Get';
Uri = 'https://itdpv.nd.gov/winapi/generatepassword/?PasswordGeneratorID=2';
ErrorAction = 'Stop';
}
If ($PSBoundParameters.ContainsKey('Credential')){
$InvokeRestMethodParams += @{Credential = $Credential}
} Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true}
}
$NewPassword = (Invoke-RestMethod @InvokeRestMethodParams).Password
$Length = $NewPassword.Length
While ($null -ne $NewPassword -and $Length -lt 20) {
$NewPassword2 = (Invoke-RestMethod @InvokeRestMethodParams).Password
$NewPassword += $NewPassword2.split('-')[1]
$Length = $NewPassword.Length
}
If (!($NewPassword -match '\d')) { $NewPassword += (Get-Random -Minimum 0 -Maximum 9) }
}
End {
return $NewPassword
}
}
@@ -0,0 +1,95 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Remove-ITDPassword {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0, ParameterSetName = "Title")]
[ValidateNotNullOrEmpty()]
[String]
$Title,
[switch]
$Force,
[PSCredential]
$Credential
)
begin {
}
process {
# Find the passwords
$GetITDPasswordParams = @{
Title = $Title;
}
If ($PSBoundParameters.ContainsKey('Credential')) {
$InvokeRestMethodParams += @{Credential = $Credential }
}
Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true }
}
$ExistingRecords = Get-ITDPassword @GetITDPasswordParams
switch ($ExistingRecords.count) {
{ [int]0 } {
Write-Warning -Message "Title $Title not found."
}
{ $_ -ge 1 } {
If (-not $Force) {
$VerifyString = ( ([string]@($ExistingRecords).Count) + " record(s) have been found, all will be removed.")
$question = 'Are you sure you want to proceed?'
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))
$decision = $Host.UI.PromptForChoice($VerifyString, $question, $choices, 1)
}
if ($decision -eq 0 -or $Force -eq $true) {
ForEach ($ExistingRecord in $ExistingRecords) {
$Uri = ("https://itdpv.nd.gov/winapi/passwords/" + $ExistingRecord.PasswordID + "?MoveToRecycleBin=True")
$InvokeRestMethodParams = @{
Method = 'Delete';
Uri = $Uri;
ContentType = 'application/json';
}
If ($PSBoundParameters.ContainsKey('Credential')) {
$InvokeRestMethodParams += @{Credential = $Credential }
}
Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true }
}
Invoke-RestMethod @InvokeRestMethodParams
}
}
else {
}
}
}
}
end {
}
}
@@ -0,0 +1,116 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Update-ITDPassword {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0, ParameterSetName = "Id")]
[ValidateRange(1, [UInt32]::MaxValue)]
[Int]$Id,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0, ParameterSetName = "Title")]
[ValidateNotNullOrEmpty()]
[String]$Title,
[String]
$Notes,
[switch]
$AppendNotes,
[PSCredential]
$Credential,
[switch]
$Force,
[switch]
$All
)
begin {
}
process {
$GetITDPasswordParams = @{
Title = $Title;
}
If ($PSBoundParameters.ContainsKey('Credential')) {
$InvokeRestMethodParams += @{Credential = $Credential }
}
Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true }
}
$ExistingRecords = Get-ITDPassword @GetITDPasswordParams
If (-not $Force) {
$title = ( ([string]@($ExistingRecords).Count) + " record(s) have been found, all will be modified.")
$question = 'Are you sure you want to proceed?'
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))
$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
}
if ($Force -eq $true -or $decision -eq 0) {
ForEach ($ExistingRecord in $ExistingRecords) {
$PasswordObj = @{
'PasswordID' = $ExistingRecord.PasswordID
}
switch ($PSBoundParameters.Keys) {
'Notes' {
if ($PSBoundParameters.AppendNotes) {
$PasswordObj.Notes = $ExistingRecord.Notes + "<div>&nbsp;</div>$($PSBoundParameters.Notes)"
}
else {
$PasswordObj.Notes = $PSBoundParameters.Notes
}
}
}
$InvokeRestMethodParams = @{
Method = 'Put';
Uri = 'https://itdpv.nd.gov/winapi/passwords';
ContentType = 'application/json';
Body = ($PasswordObj | ConvertTo-Json);
}
If ($PSBoundParameters.ContainsKey('Credential')) {
$InvokeRestMethodParams += @{Credential = $Credential }
}
Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true }
}
$InvokeRestMethodParams.Body
Invoke-RestMethod @InvokeRestMethodParams
}
}
else {
}
}
end {
}
}
@@ -0,0 +1,20 @@
# Introduction
TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
# Getting Started
TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
1. Installation process
2. Software dependencies
3. Latest releases
4. API references
# Build and Test
TODO: Describe and show how to build your code and run the tests.
# Contribute
TODO: Explain how other users and developers can contribute to make your code better.
If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files:
- [ASP.NET Core](https://github.com/aspnet/Home)
- [Visual Studio Code](https://github.com/Microsoft/vscode)
- [Chakra Core](https://github.com/Microsoft/ChakraCore)