Skip to content

Commit c72d23a

Browse files
authoredSep 29, 2023
Merge pull request #4 from VeeamCommunity/mazouz-branch
Mazouz branch
2 parents e978b30 + 0db238d commit c72d23a

10 files changed

+1131
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Contributing
2+
3+
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
4+
5+
* Reporting a bug
6+
* Discussing the current state of the code
7+
* Submitting a fix
8+
* Proposing new features
9+
10+
All contributions to this repository must be signed as described on our [Developer Certificate of Origin](DCO.md). Your signature certifies that you wrote the contribution or have the right to pass it on as an open source contribution.
11+
12+
Please note we have a [Code of Conduct](#code-of-conduct). Please follow it in all your interactions with the project.
13+
14+
## Report Bugs/Feature Requests using the Github Issue Tracker
15+
16+
We use GitHub's Issue Tracker to track bugs/feature Requests. Report a bug or feature request by [opening a new issue](https://github.com/VeeamCommunity/{repo-name}/issues/new/choose). It's that easy!
17+
18+
## License
19+
20+
By contributing, you agree that your contributions will be licensed under the projects original open source license.
21+
22+
## Code of Conduct
23+
24+
### Our Pledge
25+
26+
In the interest of fostering an open and welcoming environment, we as
27+
contributors and maintainers pledge to making participation in our project and
28+
our community a harassment-free experience for everyone, regardless of age, body
29+
size, disability, ethnicity, gender identity and expression, level of experience,
30+
nationality, personal appearance, race, religion, or sexual identity and
31+
orientation.
32+
33+
### Our Standards
34+
35+
Examples of behavior that contributes to creating a positive environment
36+
include:
37+
38+
* Using welcoming and inclusive language
39+
* Being respectful of differing viewpoints and experiences
40+
* Gracefully accepting constructive criticism
41+
* Focusing on what is best for the community
42+
* Showing empathy towards other community members
43+
44+
Examples of unacceptable behavior by participants include:
45+
46+
* The use of sexualized language or imagery and unwelcome sexual attention or
47+
advances
48+
* Trolling, insulting/derogatory comments, and personal or political attacks
49+
* Public or private harassment
50+
* Publishing others' private information, such as a physical or electronic
51+
address, without explicit permission
52+
* Other conduct which could reasonably be considered inappropriate in a
53+
professional setting
54+
55+
### Our Responsibilities
56+
57+
Project maintainers are responsible for clarifying the standards of acceptable
58+
behavior and are expected to take appropriate and fair corrective action in
59+
response to any instances of unacceptable behavior.
60+
61+
Project maintainers have the right and responsibility to remove, edit, or
62+
reject comments, commits, code, wiki edits, issues, and other contributions
63+
that are not aligned to this Code of Conduct, or to ban temporarily or
64+
permanently any contributor for other behaviors that they deem inappropriate,
65+
threatening, offensive, or harmful.
66+
67+
### Scope
68+
69+
This Code of Conduct applies both within project spaces and in public spaces
70+
when an individual is representing the project or its community. Examples of
71+
representing a project or community include using an official project e-mail
72+
address, posting via an official social media account, or acting as an appointed
73+
representative at an online or offline event. Representation of a project may be
74+
further defined and clarified by project maintainers.
75+
76+
### Enforcement
77+
78+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
79+
reported by contacting the owner at <maurice@kevenaar.name>. All
80+
complaints will be reviewed and investigated and will result in a response that
81+
is deemed necessary and appropriate to the circumstances. The owner is
82+
obligated to maintain confidentiality with regard to the reporter of an incident.
83+
Further details of specific enforcement policies may be posted separately.
84+
85+
Project maintainers who do not follow or enforce the Code of Conduct in good
86+
faith may face temporary or permanent repercussions as determined by other
87+
members of the project's leadership.
88+
89+
### Attribution
90+
91+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
92+
available at [http://contributor-covenant.org/version/1/4][version]
93+
94+
[homepage]: http://contributor-covenant.org
95+
[version]: http://contributor-covenant.org/version/1/4/

‎Release/veeam-powershell-sdk/DCO.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Developer Certificate of Origin
2+
3+
Developer Certificate of Origin
4+
Version 1.1
5+
6+
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
7+
1 Letterman Drive
8+
Suite D4700
9+
San Francisco, CA, 94129
10+
11+
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
12+
13+
Developer's Certificate of Origin 1.1
14+
15+
By making a contribution to this project, I certify that:
16+
17+
(a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
18+
19+
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
20+
21+
(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
22+
23+
(d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
24+
25+
---
26+
27+
To acknowledge the Developer Certificate of Origin (DCO), sign your commits by adding `Signed-off-by: John Doe <john.doe@email.com>` to the last line of each Git commit message. The e-mail address used to sign must match the e-mail address of the Git author. If you set your `user.name` and `user.email` git config values, you can sign your commit automatically with `git commit -s`.

‎Release/veeam-powershell-sdk/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 VeeamCommunity
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎Release/veeam-powershell-sdk/ReleaseNotes.md

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#
2+
# Module manifest for module 'veeam-powershell-sdk'
3+
#
4+
# Generated by: Adam Mazouz
5+
#
6+
# Generated on: 9/28/2023
7+
#
8+
9+
@{
10+
11+
# Script module or binary module file associated with this manifest.
12+
RootModule = './veeam-powershell-sdk.psm1'
13+
14+
# Version number of this module.
15+
ModuleVersion = '0.1.0'
16+
17+
# Supported PSEditions
18+
# CompatiblePSEditions = @()
19+
20+
# ID used to uniquely identify this module
21+
GUID = 'e8408256-561a-4cbd-ac4c-d4bbd988594a'
22+
23+
# Author of this module
24+
Author = 'Adam Mazouz'
25+
26+
# Company or vendor of this module
27+
CompanyName = 'Unknown'
28+
29+
# Copyright statement for this module
30+
Copyright = '(c) Adam Mazouz. All rights reserved.'
31+
32+
# Description of the functionality provided by this module
33+
Description = 'This is a poc created for Veeam Community Hackathon'
34+
35+
# Minimum version of the PowerShell engine required by this module
36+
#PowerShellVersion = '7.0'
37+
38+
# Name of the PowerShell host required by this module
39+
# PowerShellHostName = ''
40+
41+
# Minimum version of the PowerShell host required by this module
42+
# PowerShellHostVersion = ''
43+
44+
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45+
# DotNetFrameworkVersion = ''
46+
47+
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48+
# ClrVersion = ''
49+
50+
# Processor architecture (None, X86, Amd64) required by this module
51+
# ProcessorArchitecture = ''
52+
53+
# Modules that must be imported into the global environment prior to importing this module
54+
# RequiredModules = @()
55+
56+
# Assemblies that must be loaded prior to importing this module
57+
# RequiredAssemblies = @()
58+
59+
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
60+
# ScriptsToProcess = @()
61+
62+
# Type files (.ps1xml) to be loaded when importing this module
63+
# TypesToProcess = @()
64+
65+
# Format files (.ps1xml) to be loaded when importing this module
66+
# FormatsToProcess = @()
67+
68+
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69+
# NestedModules = @()
70+
71+
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72+
FunctionsToExport = '*'
73+
74+
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75+
CmdletsToExport = '*'
76+
77+
# Variables to export from this module
78+
VariablesToExport = '*'
79+
80+
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81+
AliasesToExport = '*'
82+
83+
# DSC resources to export from this module
84+
# DscResourcesToExport = @()
85+
86+
# List of all modules packaged with this module
87+
# ModuleList = @()
88+
89+
# List of all files packaged with this module
90+
# FileList = @()
91+
92+
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93+
PrivateData = @{
94+
95+
PSData = @{
96+
97+
# Tags applied to this module. These help with module discovery in online galleries.
98+
# Tags = @()
99+
100+
# A URL to the license for this module.
101+
# LicenseUri = ''
102+
103+
# A URL to the main website for this project.
104+
# ProjectUri = ''
105+
106+
# A URL to an icon representing this module.
107+
IconUri = 'https://camo.githubusercontent.com/741bf52ece3e9b35ad4e067a0b34b3ecc31c9a3c7fed2526e9b058d94fcb8986/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f6d6b6576656e6161722f63686f636f6c617465792d7061636b6167657340633437626466343366633537613634306234303961383231666561643038303034323234356133662f69636f6e732f766565616d2d6261636b75702d616e642d7265706c69636174696f6e2d69736f2e706e67'
108+
109+
# ReleaseNotes of this module
110+
# ReleaseNotes = ''
111+
112+
# Prerelease string of this module
113+
# Prerelease = ''
114+
115+
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
116+
# RequireLicenseAcceptance = $false
117+
118+
# External dependent modules of this module
119+
# ExternalModuleDependencies = @()
120+
121+
} # End of PSData hashtable
122+
123+
} # End of PrivateData hashtable
124+
125+
# HelpInfo URI of this module
126+
# HelpInfoURI = ''
127+
128+
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129+
# DefaultCommandPrefix = ''
130+
131+
}
132+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
$ErrorActionPreference = 'Stop'
2+
function New-VBRConnection {
3+
<#
4+
.SYNOPSIS
5+
Uses New-VBRConnection to store the connection in a global parameter
6+
.DESCRIPTION
7+
Creates a Veeam Server connection and stores it in global variable $Global:DefaultVeeamBR.
8+
An FQDN or IP, credentials, and ignore certificate boolean
9+
.OUTPUTS
10+
Returns the Veeam Server connection.
11+
.EXAMPLE
12+
13+
14+
#>
15+
16+
[CmdletBinding()]
17+
Param(
18+
19+
[Parameter(Position=0,mandatory=$true)]
20+
[string]$Endpoint,
21+
22+
[Parameter(Position=1,mandatory=$true)]
23+
[string]$Port,
24+
25+
[Parameter(Position=2,mandatory=$true)]
26+
[string]$User,
27+
28+
[Parameter(Position=3,mandatory=$true)]
29+
[string]$Pass
30+
31+
)
32+
33+
$apiUrl = "https://'$Endpoint':'$Port'/api/oauth2/token"
34+
35+
36+
37+
# Define the headers for the API request
38+
$headers = @{
39+
"Content-Type" = "application/x-www-form-urlencoded"
40+
"x-api-version" = "1.1-rev0"
41+
}
42+
43+
## TO-DO: Grant_type options
44+
$body = @{
45+
"grant_type" = "password"
46+
"username" = $User
47+
"password" = $Pass
48+
}
49+
50+
# Send an authentication request to obtain a session token
51+
try {
52+
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Post -Body $body -SkipCertificateCheck
53+
54+
if (($response.access_token) -or ($response.StatusCode -eq 200) ) {
55+
$VBRAuthentication = @{
56+
$session_endpoint = $Endpoint
57+
$session_port = $Port
58+
$session_access_tocken = $response.access_token
59+
}
60+
Write-Host "Successfully authenticated."
61+
return $VBRAuthentication
62+
}
63+
else {
64+
Write-Host "Authentication failed. Status code: $($response.StatusCode), Message: $($response.Content)"
65+
}
66+
}
67+
catch {
68+
Write-Host "An error occurred: $($_.Exception.Message)"
69+
}
70+
}
71+
72+
function Get-BackupJobs {
73+
[CmdletBinding()]
74+
Param(
75+
[Parameter(Position=0,mandatory=$true)]
76+
[VeeamServer.Authentication]$VBRAuthentication
77+
)
78+
79+
VBRAuthentication
80+
$apiUrl = "https://'$($VBRAuthentication.$session_endpoint)':'$($VBRAuthentication.$session_post)'/v1/jobs?skip=0&limit=0&orderColumn=Name&orderAsc=true&nameFilter=string&typeFilter=Backup"
81+
82+
# Define the headers for the API request
83+
$headers = @{
84+
"x-api-version" = "1.1-rev0"
85+
"Authorization" = "Bearer '$($VBRAccessToken.$session_access_tocken)'"
86+
}
87+
88+
89+
Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method GET -SkipCertificateCheck
90+
}

‎ReleaseNotes.md

Whitespace-only changes.

‎build.ps1

+371
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
##############################################################################
2+
# PREVIEW VERSION OF PSAKE SCRIPT FOR MODULE BUILD & PUBLISH TO THE PSGALLERY
3+
##############################################################################
4+
#
5+
# We are hoping to add support for publishing modules to the PowerShell gallery
6+
# and private repositories in a future release of this extension. This is an
7+
# early look at the approach we are considering which is to supply a
8+
# PSake-based script that will:
9+
#
10+
# 1. Create a directory from which to publish your module.
11+
# 2. Copy the appropriate module files to that directory excluding items like
12+
# the .vscode directory, Pester tests, etc. These are configurable in Build.ps1.
13+
# 3. Verify all existing Pester tests pass.
14+
# 4. Publish the module to the desired repository (defaulting to the PSGallery).
15+
#
16+
# Requirements: PSake. If you don't have this module installed use the following
17+
# command to install it:
18+
#
19+
# PS C:\> Install-Module PSake -Scope CurrentUser
20+
#
21+
##############################################################################
22+
# This is a PSake script that supports the following tasks:
23+
# clean, build, test and publish. The default task is build.
24+
#
25+
# The publish task uses the Publish-Module command to publish
26+
# to either the PowerShell Gallery (the default) or you can change
27+
# the $Repository property to the name of an alternate repository.
28+
#
29+
# The test task invokes Pester to run any Pester tests in your
30+
# workspace folder. Name your test scripts <TestName>.Tests.ps1
31+
# and Pester will find and run the tests contained in the files.
32+
#
33+
# You can run this build script directly using the invoke-psake
34+
# command which will execute the build task. This task "builds"
35+
# a temporary folder from which the module can be published.
36+
#
37+
# PS C:\> invoke-psake build.ps1
38+
#
39+
# You can run your Pester tests (if any) by running the following command.
40+
#
41+
# PS C:\> invoke-psake build.ps1 -taskList test
42+
#
43+
# You can execute the publish task with the following command. Note that
44+
# the publish task will run the test task first. The Pester tests must pass
45+
# before the publish task will run. The first time you run the publish
46+
# command, you will be prompted to enter your PowerShell Gallery NuGetApiKey.
47+
# After entering the key, it is encrypted and stored so you will not have to
48+
# enter it again.
49+
#
50+
# PS C:\> invoke-psake build.ps1 -taskList publish
51+
#
52+
# You can verify the stored and encrypted NuGetApiKey by running the following
53+
# command. This will display your NuGetApiKey in plain text!
54+
#
55+
# PS C:\> invoke-psake build.ps1 -taskList showKey
56+
#
57+
# You can store a new NuGetApiKey with this command. You can leave off
58+
# the -properties parameter and you'll be prompted for the key.
59+
#
60+
# PS C:\> invoke-psake build.ps1 -taskList storeKey -properties @{NuGetApiKey='test123'}
61+
#
62+
63+
###############################################################################
64+
# Customize these properties for your module.
65+
###############################################################################
66+
Properties {
67+
# The name of your module should match the basename of the PSD1 file.
68+
#$ModuleName = (Get-Item .\Veeam.PowerShell.SDK\*.psd1 |
69+
# Foreach-Object {$null = Test-ModuleManifest -Path $_ -ErrorAction SilentlyContinue; if ($?) {$_}})[0].BaseName
70+
$ModuleName = Get-Item *.psd1 | Test-ModuleManifest
71+
72+
# Path to the release notes file. Set to $null if the release notes reside in the manifest file.
73+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
74+
$ReleaseNotesPath = "$PSScriptRoot\ReleaseNotes.md"
75+
76+
# The directory used to publish the module from. If you are using Git, the
77+
# $PublishRootDir should be ignored if it is under the workspace directory.
78+
$PublishRootDir = "$PSScriptRoot\Release"
79+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
80+
$PublishDir = "$PublishRootDir\$ModuleName"
81+
82+
# Docs
83+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
84+
$DocsRootDir = "$PSScriptRoot\docs"
85+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
86+
$DefaultLocale = 'en-US'
87+
88+
# The following items will not be copied to the $PublishDir.
89+
# Add items that should not be published with the module.
90+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
91+
$Exclude = @(
92+
(Split-Path $PSCommandPath -Leaf),
93+
'Release',
94+
'docs',
95+
'examples',
96+
'helper',
97+
'media',
98+
'tests',
99+
'.git*',
100+
'.vscode',
101+
# These files are unique to this examples dir.
102+
'DebugTest.ps1',
103+
'PSScriptAnalyzerSettings.psd1',
104+
'Readme.md',
105+
'Stop*.ps1'
106+
)
107+
108+
# Name of the repository you wish to publish to. Default repo is the PSGallery.
109+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
110+
$PublishRepository = $null
111+
112+
# Your NuGet API key for the PSGallery. Leave it as $null and the first time
113+
# you publish you will be prompted to enter your API key. The build will
114+
# store the key encrypted in a file, so that on subsequent publishes you
115+
# will no longer be prompted for the API key.
116+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
117+
$NuGetApiKey = $null
118+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
119+
$EncryptedApiKeyPath = "$env:LOCALAPPDATA\vscode-powershell\NuGetApiKey.clixml"
120+
}
121+
122+
###############################################################################
123+
# Customize these tasks for performing operations before and/or after publish.
124+
###############################################################################
125+
Task PrePublish {
126+
}
127+
128+
Task PostPublish {
129+
}
130+
131+
###############################################################################
132+
# Core task implementations - this possibly "could" ship as part of the
133+
# vscode-powershell extension and then get dot sourced into this file.
134+
###############################################################################
135+
Task default -depends Build
136+
137+
#Task Publish -depends Test, BuildHelp, PrePublish, PublishImpl, PostPublish {
138+
#}
139+
Task Publish -depends Test, PrePublish, PublishImpl, PostPublish {
140+
}
141+
142+
Task PublishImpl -depends Test -requiredVariables EncryptedApiKeyPath, PublishDir {
143+
if ($NuGetApiKey) {
144+
"Using script embedded NuGetApiKey"
145+
}
146+
elseif (Test-Path -LiteralPath $EncryptedApiKeyPath) {
147+
$NuGetApiKey = LoadAndUnencryptNuGetApiKey $EncryptedApiKeyPath
148+
"Using stored NuGetApiKey"
149+
}
150+
else {
151+
$cred = PromptUserForNuGetApiKeyCredential -DestinationPath $EncryptedApiKeyPath
152+
$NuGetApiKey = $cred.GetNetworkCredential().Password
153+
"The NuGetApiKey has been stored in $EncryptedApiKeyPath"
154+
}
155+
156+
$publishParams = @{
157+
Path = $PublishDir
158+
NuGetApiKey = $NuGetApiKey
159+
}
160+
161+
if ($PublishRepository) {
162+
$publishParams['Repository'] = $PublishRepository
163+
}
164+
165+
# Consider not using -ReleaseNotes parameter when Update-ModuleManifest has been fixed.
166+
if ($ReleaseNotesPath) {
167+
$publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath)
168+
}
169+
170+
"Calling Publish-Module..."
171+
Publish-Module @publishParams
172+
}
173+
174+
Task Test -depends Build {
175+
Import-Module Pester
176+
Invoke-Pester $PSScriptRoot
177+
}
178+
179+
Task Build -depends Clean, Init -requiredVariables PublishDir, Exclude, ModuleName {
180+
Copy-Item -Path $PSScriptRoot\* -Destination $PublishDir -Recurse -Exclude $Exclude
181+
182+
# Get contents of the ReleaseNotes file and update the copied module manifest file
183+
# with the release notes.
184+
# DO NOT USE UNTIL UPDATE-MODULEMANIFEST IS FIXED - DOES NOT HANDLE SINGLE QUOTES CORRECTLY.
185+
# if ($ReleaseNotesPath) {
186+
# $releaseNotes = @(Get-Content $ReleaseNotesPath)
187+
# Update-ModuleManifest -Path $PublishDir\${ModuleName}.psd1 -ReleaseNotes $releaseNotes
188+
# }
189+
}
190+
191+
Task Clean -requiredVariables PublishRootDir {
192+
# Sanity check the dir we are about to "clean". If $PublishRootDir were to
193+
# inadvertently get set to $null, the Remove-Item commmand removes the
194+
# contents of \*. That's a bad day. Ask me how I know? :-(
195+
if ((Test-Path $PublishRootDir) -and $PublishRootDir.Contains($PSScriptRoot)) {
196+
Remove-Item $PublishRootDir\* -Recurse -Force
197+
}
198+
}
199+
200+
Task Init -requiredVariables PublishDir {
201+
if (!(Test-Path $PublishDir)) {
202+
$null = New-Item $PublishDir -ItemType Directory
203+
}
204+
}
205+
206+
Task RemoveKey -requiredVariables EncryptedApiKeyPath {
207+
if (Test-Path -LiteralPath $EncryptedApiKeyPath) {
208+
Remove-Item -LiteralPath $EncryptedApiKeyPath
209+
}
210+
}
211+
212+
Task StoreKey -requiredVariables EncryptedApiKeyPath {
213+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
214+
$nuGetApiKeyCred = PromptUserForNuGetApiKeyCredential -DestinationPath $EncryptedApiKeyPath
215+
"The NuGetApiKey has been stored in $EncryptedApiKeyPath"
216+
}
217+
218+
Task ShowKey -requiredVariables EncryptedApiKeyPath {
219+
if ($NuGetApiKey) {
220+
"The embedded (partial) NuGetApiKey is: $($NuGetApiKey[0..7])"
221+
}
222+
else {
223+
$NuGetApiKey = LoadAndUnencryptNuGetApiKey -Path $EncryptedApiKeyPath
224+
"The stored (partial) NuGetApiKey is: $($NuGetApiKey[0..7])"
225+
}
226+
227+
"To see the full key, use the task 'ShowFullKey'"
228+
}
229+
230+
Task ShowFullKey -requiredVariables EncryptedApiKeyPath {
231+
if ($NuGetApiKey) {
232+
"The embedded NuGetApiKey is: $NuGetApiKey"
233+
}
234+
else {
235+
$NuGetApiKey = LoadAndUnencryptNuGetApiKey -Path $EncryptedApiKeyPath
236+
"The stored NuGetApiKey is: $NuGetApiKey"
237+
}
238+
}
239+
240+
Task ? -description 'Lists the available tasks' {
241+
"Available tasks:"
242+
$PSake.Context.Peek().Tasks.Keys | Sort-Object
243+
}
244+
245+
246+
Task BuildHelp -depends Build, GenerateMarkdown, GenerateHelpFiles {
247+
}
248+
249+
Task GenerateMarkdown -requiredVariables DefaultLocale, DocsRootDir, ModuleName, PublishDir {
250+
if (!(Get-Module platyPS -ListAvailable)) {
251+
"platyPS module is not installed. Skipping $($psake.context.currentTaskName) task."
252+
return
253+
}
254+
255+
$moduleInfo = Import-Module $PublishDir\$ModuleName.psd1 -Global -Force -PassThru
256+
257+
try {
258+
if ($moduleInfo.ExportedCommands.Count -eq 0) {
259+
"No commands have been exported. Skipping $($psake.context.currentTaskName) task."
260+
return
261+
}
262+
263+
if (!(Test-Path -LiteralPath $DocsRootDir)) {
264+
New-Item $DocsRootDir -ItemType Directory > $null
265+
}
266+
267+
if (Get-ChildItem -LiteralPath $DocsRootDir -Filter *.md -Recurse) {
268+
Get-ChildItem -LiteralPath $DocsRootDir -Directory | ForEach-Object {
269+
[Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; Update-MarkdownHelp -Path $_.FullName -Verbose:$VerbosePreference > $null
270+
}
271+
}
272+
273+
# ErrorAction set to SilentlyContinue so this command will not overwrite an existing MD file.
274+
[Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; New-MarkdownHelp -Module $ModuleName -Locale $DefaultLocale -Force -OutputFolder $DocsRootDir\$DefaultLocale `
275+
-WithModulePage:$false -ErrorAction SilentlyContinue -Verbose:$VerbosePreference > $null
276+
}
277+
finally {
278+
Remove-Module $ModuleName -Force
279+
}
280+
}
281+
282+
Task GenerateHelpFiles -requiredVariables DocsRootDir, ModuleName, PublishDir {
283+
if (!(Get-Module platyPS -ListAvailable)) {
284+
"platyPS module is not installed. Skipping $($psake.context.currentTaskName) task."
285+
return
286+
}
287+
288+
if (!(Get-ChildItem -LiteralPath $DocsRootDir -Filter *.md -Recurse -ErrorAction SilentlyContinue)) {
289+
"No markdown help files to process. Skipping $($psake.context.currentTaskName) task."
290+
return
291+
}
292+
293+
$helpLocales = (Get-ChildItem -Path $DocsRootDir -Directory).Name
294+
295+
# Generate the module's primary MAML help file.
296+
foreach ($locale in $helpLocales) {
297+
[Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'; New-ExternalHelp -Path $DocsRootDir\$locale -OutputPath $PublishDir\$locale -Force `
298+
-ErrorAction SilentlyContinue -Verbose:$VerbosePreference > $null
299+
}
300+
}
301+
302+
###############################################################################
303+
# Helper functions
304+
###############################################################################
305+
function PromptUserForNuGetApiKeyCredential {
306+
[Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')]
307+
param(
308+
[Parameter()]
309+
[ValidateNotNullOrEmpty()]
310+
[string]
311+
$DestinationPath
312+
)
313+
314+
$message = "Enter your NuGet API Key in the password field (or nothing, this isn't used yet in the preview)"
315+
$nuGetApiKeyCred = Get-Credential -Message $message -UserName "ignored"
316+
317+
if ($DestinationPath) {
318+
EncryptAndSaveNuGetApiKey -NuGetApiKeySecureString $nuGetApiKeyCred.Password -Path $DestinationPath
319+
}
320+
321+
$nuGetApiKeyCred
322+
}
323+
324+
function EncryptAndSaveNuGetApiKey {
325+
[Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingConvertToSecureStringWithPlainText", '')]
326+
[Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')]
327+
param(
328+
[Parameter(Mandatory, ParameterSetName='SecureString')]
329+
[ValidateNotNull()]
330+
[SecureString]
331+
$NuGetApiKeySecureString,
332+
333+
[Parameter(Mandatory, ParameterSetName='PlainText')]
334+
[ValidateNotNullOrEmpty()]
335+
[string]
336+
$NuGetApiKey,
337+
338+
[Parameter(Mandatory)]
339+
$Path
340+
)
341+
342+
if ($PSCmdlet.ParameterSetName -eq 'PlainText') {
343+
$NuGetApiKeySecureString = ConvertTo-SecureString -String $NuGetApiKey -AsPlainText -Force
344+
}
345+
346+
$parentDir = Split-Path $Path -Parent
347+
if (!(Test-Path -LiteralPath $parentDir)) {
348+
$null = New-Item -Path $parentDir -ItemType Directory
349+
}
350+
elseif (Test-Path -LiteralPath $Path) {
351+
Remove-Item -LiteralPath $Path
352+
}
353+
354+
$NuGetApiKeySecureString | ConvertFrom-SecureString | Export-Clixml $Path
355+
Write-Verbose "The NuGetApiKey has been encrypted and saved to $Path"
356+
}
357+
358+
function LoadAndUnencryptNuGetApiKey {
359+
[Diagnostics.CodeAnalysis.SuppressMessage("PSProvideDefaultParameterValue", '')]
360+
param(
361+
[Parameter(Mandatory)]
362+
[ValidateNotNullOrEmpty()]
363+
[string]
364+
$Path
365+
)
366+
367+
$storedKey = Import-Clixml $Path | ConvertTo-SecureString
368+
$cred = New-Object -TypeName PSCredential -ArgumentList 'jpgr',$storedKey
369+
$cred.GetNetworkCredential().Password
370+
Write-Verbose "The NuGetApiKey has been loaded and unencrypted from $Path"
371+
}

‎veeam-powershell-sdk.psd1

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#
2+
# Module manifest for module 'veeam-powershell-sdk'
3+
#
4+
# Generated by: Adam Mazouz
5+
#
6+
# Generated on: 9/28/2023
7+
#
8+
9+
@{
10+
11+
# Script module or binary module file associated with this manifest.
12+
RootModule = './veeam-powershell-sdk.psm1'
13+
14+
# Version number of this module.
15+
ModuleVersion = '0.2.0'
16+
17+
# Supported PSEditions
18+
# CompatiblePSEditions = @()
19+
20+
# ID used to uniquely identify this module
21+
GUID = 'e8408256-561a-4cbd-ac4c-d4bbd988594a'
22+
23+
# Author of this module
24+
Author = 'Adam Mazouz'
25+
26+
# Company or vendor of this module
27+
CompanyName = 'Unknown'
28+
29+
# Copyright statement for this module
30+
Copyright = '(c) Adam Mazouz. All rights reserved.'
31+
32+
# Description of the functionality provided by this module
33+
Description = 'This is a poc created for Veeam Community Hackathon'
34+
35+
# Minimum version of the PowerShell engine required by this module
36+
#PowerShellVersion = '7.0'
37+
38+
# Name of the PowerShell host required by this module
39+
# PowerShellHostName = ''
40+
41+
# Minimum version of the PowerShell host required by this module
42+
# PowerShellHostVersion = ''
43+
44+
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45+
# DotNetFrameworkVersion = ''
46+
47+
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48+
# ClrVersion = ''
49+
50+
# Processor architecture (None, X86, Amd64) required by this module
51+
# ProcessorArchitecture = ''
52+
53+
# Modules that must be imported into the global environment prior to importing this module
54+
# RequiredModules = @()
55+
56+
# Assemblies that must be loaded prior to importing this module
57+
# RequiredAssemblies = @()
58+
59+
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
60+
# ScriptsToProcess = @()
61+
62+
# Type files (.ps1xml) to be loaded when importing this module
63+
# TypesToProcess = @()
64+
65+
# Format files (.ps1xml) to be loaded when importing this module
66+
# FormatsToProcess = @()
67+
68+
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69+
# NestedModules = @()
70+
71+
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72+
FunctionsToExport = '*'
73+
74+
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75+
CmdletsToExport = '*'
76+
77+
# Variables to export from this module
78+
VariablesToExport = '*'
79+
80+
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81+
AliasesToExport = '*'
82+
83+
# DSC resources to export from this module
84+
# DscResourcesToExport = @()
85+
86+
# List of all modules packaged with this module
87+
# ModuleList = @()
88+
89+
# List of all files packaged with this module
90+
# FileList = @()
91+
92+
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93+
PrivateData = @{
94+
95+
PSData = @{
96+
97+
# Tags applied to this module. These help with module discovery in online galleries.
98+
# Tags = @()
99+
100+
# A URL to the license for this module.
101+
# LicenseUri = ''
102+
103+
# A URL to the main website for this project.
104+
# ProjectUri = ''
105+
106+
# A URL to an icon representing this module.
107+
IconUri = 'https://camo.githubusercontent.com/741bf52ece3e9b35ad4e067a0b34b3ecc31c9a3c7fed2526e9b058d94fcb8986/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f6d6b6576656e6161722f63686f636f6c617465792d7061636b6167657340633437626466343366633537613634306234303961383231666561643038303034323234356133662f69636f6e732f766565616d2d6261636b75702d616e642d7265706c69636174696f6e2d69736f2e706e67'
108+
109+
# ReleaseNotes of this module
110+
# ReleaseNotes = ''
111+
112+
# Prerelease string of this module
113+
# Prerelease = ''
114+
115+
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
116+
# RequireLicenseAcceptance = $false
117+
118+
# External dependent modules of this module
119+
# ExternalModuleDependencies = @()
120+
121+
} # End of PSData hashtable
122+
123+
} # End of PrivateData hashtable
124+
125+
# HelpInfo URI of this module
126+
# HelpInfoURI = ''
127+
128+
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129+
# DefaultCommandPrefix = ''
130+
131+
}
132+

‎veeam-powershell-sdk.psm1

+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
$ErrorActionPreference = 'Stop'
2+
function New-VBRConnection {
3+
<#
4+
.SYNOPSIS
5+
Uses New-VBRConnection to store the connection in a global parameter
6+
.DESCRIPTION
7+
Creates a Veeam Server connection and stores it in global variable $Global:DefaultVeeamBR.
8+
An FQDN or IP, credentials, and ignore certificate boolean
9+
.OUTPUTS
10+
Returns the Veeam Server connection.
11+
.EXAMPLE
12+
New-VBRConnection -Endpoint <FQDN or IP> -Port <default 9419> -Credential $(Get-Credential)
13+
14+
#>
15+
16+
[CmdletBinding()]
17+
Param(
18+
19+
[Parameter(Position=0,mandatory=$true)]
20+
[string]$Endpoint,
21+
22+
[Parameter(Position=1,mandatory=$true)]
23+
[string]$Port,
24+
25+
[Parameter(Mandatory=$true,ParameterSetName="Credential")]
26+
[ValidateNotNullOrEmpty()]
27+
[Management.Automation.PSCredential]$Credential
28+
29+
)
30+
31+
$apiUrl = "https://$($Endpoint):$($Port)/api/oauth2/token"
32+
33+
$User = $Credential.UserName
34+
$Pass = $Credential.GetNetworkCredential().Password
35+
36+
# Define the headers for the API request
37+
$headers = @{
38+
"Content-Type" = "application/x-www-form-urlencoded"
39+
"x-api-version" = "1.1-rev0"
40+
}
41+
42+
## TO-DO: Grant_type options
43+
$body = @{
44+
"grant_type" = "password"
45+
"username" = $User
46+
"password" = $Pass
47+
}
48+
49+
# Send an authentication request to obtain a session token
50+
try {
51+
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Post -Body $body -SkipCertificateCheck
52+
53+
if (($response.access_token) -or ($response.StatusCode -eq 200) ) {
54+
Write-Host "Successfully authenticated."
55+
$VBRAuthentication = [PSCustomObject]@{
56+
Session_endpoint = $Endpoint
57+
Session_port = $Port
58+
Session_access_token = $response.access_token
59+
}
60+
61+
return $VBRAuthentication
62+
}
63+
else {
64+
Write-Host "Authentication failed. Status code: $($response.StatusCode), Message: $($response.Content)"
65+
}
66+
}
67+
catch {
68+
Write-Host "An error occurred: $($_.Exception.Message)"
69+
}
70+
}
71+
72+
function Get-Jobs {
73+
<#
74+
.SYNOPSIS
75+
Uses Get-BackupJobs to retrive the backup jobs coordinated by the backup server/
76+
.DESCRIPTION
77+
This allows you to get an array of all jobs coordinated by the backup server.
78+
.OUTPUTS
79+
Returns the all jobs.
80+
.EXAMPLE
81+
82+
83+
#>
84+
85+
[CmdletBinding()]
86+
Param(
87+
[Parameter(Position=0,mandatory=$true)]
88+
[PSCustomObject]$VBRConnection,
89+
90+
[Parameter(Position=1,mandatory=$false)]
91+
[String]$JobID
92+
)
93+
94+
95+
if ($JobID -eq $null){
96+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/v1/jobs"
97+
} else {
98+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/v1/jobs/" + $JobID
99+
}
100+
101+
# Define the headers for the API request
102+
$headers = @{
103+
"x-api-version" = "1.1-rev0"
104+
"Authorization" = "Bearer $($VBRConnection.Session_access_token)"
105+
}
106+
107+
# Send a request to get a list of backup jobs
108+
try {
109+
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method GET -SkipCertificateCheck
110+
111+
# Process the response data as needed
112+
return $response.data
113+
}
114+
catch {
115+
Write-Host "An error occurred: $($_.Exception.Message)"
116+
return $null
117+
}
118+
}
119+
120+
121+
function Get-Backups {
122+
<#
123+
.SYNOPSIS
124+
Uses Get-Backups to retrive the backup by the backup server.
125+
.DESCRIPTION
126+
This allows you to get a list of all the backups coordinated by the backup server.
127+
.OUTPUTS
128+
Returns the all backups.
129+
.EXAMPLE
130+
131+
132+
#>
133+
134+
[CmdletBinding()]
135+
Param(
136+
[Parameter(Position=0,mandatory=$true)]
137+
[PSCustomObject]$VBRConnection,
138+
139+
[Parameter(Position=1,mandatory=$false)]
140+
[String]$BackupID
141+
)
142+
143+
144+
if ($BackupID -eq $null){
145+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/v1/backups"
146+
} else {
147+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/v1/backups/" + $BackupID
148+
}
149+
150+
# Define the headers for the API request
151+
$headers = @{
152+
"x-api-version" = "1.1-rev0"
153+
"Authorization" = "Bearer $($VBRConnection.Session_access_token)"
154+
}
155+
156+
# Send a request to get a list of backup jobs
157+
try {
158+
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method GET -SkipCertificateCheck
159+
160+
# Process the response data as needed
161+
return $response.data
162+
}
163+
catch {
164+
Write-Host "An error occurred: $($_.Exception.Message)"
165+
return $null
166+
}
167+
}
168+
169+
function Get-Repositories {
170+
<#
171+
.SYNOPSIS
172+
Uses Get-Repositories to retrive the backup by the backup server.
173+
.DESCRIPTION
174+
This allows you to get a list of all the backups coordinated by the backup server.
175+
.OUTPUTS
176+
Returns the all backups.
177+
.EXAMPLE
178+
179+
180+
#>
181+
182+
[CmdletBinding()]
183+
Param(
184+
[Parameter(Position=0,mandatory=$true)]
185+
[PSCustomObject]$VBRConnection,
186+
187+
[Parameter(Position=1,mandatory=$false)]
188+
[String]$RepositoryID
189+
)
190+
191+
192+
if ($RepositoryID -eq $null){
193+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/api/v1/backupInfrastructure/repositories"
194+
} else {
195+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/api/v1/backupInfrastructure/repositories/" + $RepositoryID
196+
}
197+
198+
# Define the headers for the API request
199+
$headers = @{
200+
"x-api-version" = "1.1-rev0"
201+
"Authorization" = "Bearer $($VBRConnection.Session_access_token)"
202+
}
203+
204+
# Send a request to get a list of backup jobs
205+
try {
206+
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method GET -SkipCertificateCheck
207+
208+
# Process the response data as needed
209+
return $response.data
210+
}
211+
catch {
212+
Write-Host "An error occurred: $($_.Exception.Message)"
213+
return $null
214+
}
215+
}
216+
217+
218+
function Add-RepositoryAzureBlob {
219+
[CmdletBinding()]
220+
Param(
221+
[Parameter(Position=0,mandatory=$true)]
222+
[PSCustomObject]$VBRConnection,
223+
224+
[Parameter(Position=1,mandatory=$true)]
225+
[String]$Name,
226+
227+
[Parameter(Position=2,mandatory=$true)]
228+
[String]$Desciption,
229+
230+
[Parameter(Position=1,mandatory=$true)]
231+
[PSCustomObject]$AzureAccount
232+
)
233+
234+
$apiUrl = "https://$($VBRConnection.Session_endpoint):$($VBRConnection.Session_post)/api/v1/backupInfrastructure/repositories"
235+
236+
# Define the headers for the API request
237+
$headers = @{
238+
"x-api-version" = "1.1-rev0"
239+
"Authorization" = "Bearer $($VBRConnection.Session_access_token)"
240+
}
241+
242+
# Define the body for the API request
243+
$body = @{
244+
"kind" = "AzureBlob"
245+
}
246+
247+
# Send a request to get a list of backup jobs
248+
try {
249+
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Body $body -Method POST -SkipCertificateCheck
250+
251+
# Process the response data as needed
252+
return $response.data
253+
}
254+
catch {
255+
Write-Host "An error occurred: $($_.Exception.Message)"
256+
return $null
257+
}
258+
259+
260+
}
261+
262+
263+

0 commit comments

Comments
 (0)
Please sign in to comment.