I have a requirement to download files from an AWS S3 bucket to a local folder, count the number of files in the local folder, check against S3, and send an email with the number of files.
I tried to download files from S3 but I am getting an error like get-s3object commandnotfoundexception. How do I resolve this issue?
Here is my code:
# Your account access key - must have read access to your S3 Bucket
$accessKey = "YOUR-ACCESS-KEY"
# Your account secret access key
$secretKey = "YOUR-SECRET-KEY"
# The region associated with your bucket e.g. eu-west-1, us-east-1 etc. (see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-regions)
$region = "eu-west-1"
# The name of your S3 Bucket
$bucket = "my-test-bucket"
# The folder in your bucket to copy, including trailing slash. Leave blank to copy the entire bucket
$keyPrefix = "my-folder/"
# The local file path where files should be copied
$localPath = "C:\s3-downloads\"
$objects = Get-S3Object -BucketName $bucket -KeyPrefix $keyPrefix -AccessKey $accessKey -SecretKey $secretKey -Region $region
foreach($object in $objects) {
$localFileName = $object.Key -replace $keyPrefix, ''
if ($localFileName -ne '') {
$localFilePath = Join-Path $localPath $localFileName
Copy-S3Object -BucketName $bucket -Key $object.Key -LocalFile $localFilePath -AccessKey $accessKey -SecretKey $secretKey -Region $region
}
}
Since this question is one of the top Google results for "powershell download s3 files" I'm going to answer the question in the title (even though the actual question text is different):
Read-S3Object -BucketName "my-s3-bucket" -KeyPrefix "path/to/directory" -Folder .
You might need to call Set-AWSCredentials if it's not a public bucket.
Similar to Will's example, if you want to download the whole content of a "folder" keeping the directory structure try:
Get-S3Object -BucketName "my-bucket" -KeyPrefix "path/to/directory" | Read-S3Object -Folder .
MS doc at https://docs.aws.amazon.com/powershell/latest/reference/items/Read-S3Object.html provides examples with fancier filtering.
If you have installed the AWS PowerShell Module, you haven't correctly loaded it into your current session. We're identifying this as the issue because the error you specified means that the given cmdlet can't be found.
Verify first that the module is installed, by any of the options below:
Load module into an existing session: (PowerShell v3 and v4):
From the documentation:
In PowerShell 4.0 and later releases, Import-Module also searches the Program Files folder for installed modules, so it is not necessary to provide the full path to the module. You can run the following command to import the AWSPowerShell module. In PowerShell 3.0 and later, running a cmdlet in the module also automatically imports a module into your session.
To verify correct installation, add the following command to the beginning of your script:
PS C:\> Import-Module AWSPowerShell
Load module into an existing session: (PowerShell v2):
To verify correct installation, add the following command to the beginning of your script:
PS C:\> Import-Module "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1"
Open a new session with Windows PowerShell for AWS Desktop Shortcut:
A shortcut is added to your desktop that starts PowerShell with the correct module loaded into the session. If your installation was successful, this shortcut should be present and should also correctly load the AWS PowerShell module without additional effort from you.
From the documentation:
The installer creates a Start Menu group called, Amazon Web Services,
which contains a shortcut called Windows PowerShell for AWS. For
PowerShell 2.0, this shortcut automatically imports the AWSPowerShell
module and then runs the Initialize-AWSDefaults cmdlet. For PowerShell
3.0, the AWSPowerShell module is loaded automatically whenever you run an AWS cmdlet. So, for PowerShell 3.0, the shortcut created by the
installer only runs the Initialize-AWSDefaults cmdlet. For more
information about Initialize-AWSDefaults, see Using AWS Credentials.
Further Reading:
AWS PowerShell Documentation - Download and Install the AWS Tools for Windows PowerShell
AWS PowerShell Documentation - Setting up the AWS Tools for Windows PowerShell
Related
I created ps script trying to send files to S3 bucket.
I specified a profile name called Reports and basic script look like this:
# Config
Set-AWSCredential -ProfileName GoReports
$bucket_name = 'aws.bucketName'
# Data preparation stage
# ...
# Send to AWS S3
Write-S3Object -BucketName $bucket_name -File "c:\backup\sales.gz" -Key "/group1/shop1/sales.gz"
Remove-Item "c:\backup\sales.gz" -Include *.gz
I use TaskScheduler on windows to launch this task. Every step has its own status logged.
Now when I look into my eventlog I see that sometimes all the files are sent correctly but sometimes it gives me a shout:
No credentials specified or obtained from persisted/shell defaults
What can be the reason?
Task is set to be launched with highest privileges.
I need to move PowerShell Az module from one machine to another offline (both machines have the same windows (10 Pro 1809), .net, powershell (5.1), etc versions)
I can't use either Private PowerShellGet Repositories or MSI installer
I run Save-Module -Name Az -Path 'C:\Users\kag\Documents\ps_modules' -RequiredVersion 3.7.0 -Force on "donor" machine and it gives me 50+ dirs exported:
I copy all to "receiver" machine and running:
Get-ChildItem "C:\Users\kag\Documents\ps_modules\*" -Recurse | Unblock-File
Import-Module -name "C:\Users\kag\Documents\ps_modules\Az" -Verbose
..but getting errors for all dependencies:
Any ideas how to correctly move Az module offline?
Here my comments as answer:
It seems the path you saved the module in C:\Users\kag\Documents\ps_modules is not one of the module paths PowerShell knows of.
You can test which paths are used by PowerShell to find your modules by typing
$env:PSModulePath.split(';')
in the console.
Below is an excerpt from Stefan Stranger's Blog
You can add a temporary path that is available for the current session only:
$env:PSModulePath = $env:PSModulePath + ";C:\Users\kag\Documents\ps_modules"
To make that permanent, you can either add the line above to your PowerShell profile, or manually add it to the registry:
$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "User")
[Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + ";C:\Users\kag\Documents\ps_modules", "User")
use "User" to store this path for the current user only. Use "Machine" to have that path available for all users
I'm having problems creating a custom DSC composite resource and getting it uploaded into a Azure Automation module list that I was hoping someone could shed some light on. I've created a basic PowerShell DSC composite resource by executing the following code:
$parentModulePath = 'C:\Program Files\WindowsPowerShell\Modules\CompositeExample'
mkdir $parentModulePath
New-ModuleManifest -RootModule CompositeExample –Path "$parentModulePath\CompositeExample.psd1"
$resourceModulePath = "$parentModulePath\DSCResources\CompositeResource"
mkdir $resourceModulePath
New-ModuleManifest -RootModule 'CompositeResource.schema.psm1' –Path "$resourceModulePath\CompositeResource.psd1"
Add-Content –Path "$resourceModulePath\CompositeResource.schema.psm1" –Value ''
And then in the CompositeResource.schema.psm1 file I've added the following code:
Configuration CompositeResource
{
Import-DscResource -ModuleName PSDesiredStateConfiguration
File ExampleFolder
{
DestinationPath = "C:\Example"
Type = "Directory"
}
}
Now if I zip up the C:\Program Files\WindowsPowerShell\Modules\CompositeExample folder as CompositeExample_1.0.zip and upload it to a 'classic' DSC server and reference it in a separate configuration it works perfectly fine.
However, if I add it as a module in Azure Automation (as CompositeModule.zip) I get the following error:
Error importing the module CompositeExample. Import failed with the following error:
Orchestrator.Shared.AsyncModuleImport.ModuleImportException: An error occurred during
module validation. When importing the module to an internal PowerShell session, it was not
able to be loaded by PowerShell. There is likely an issue with the contents of the module
that results in PowerShell's not being able to load it. Please verify that the module
imports successfully in a local PowerShell session, correct any issues, and then try
importing again.
Do modules need to be 'bundled' in a different way for Azure, or require additional files?
Ok, the problem was me specifying the -RootModule line when creating the root module manifest. 'Classic' DSC just seems to ignore it, whereas Azure Automation throws an error as the file doesn't exist. So the code to create the composite module would be
$parentModulePath = 'C:\Program Files\WindowsPowerShell\Modules\CompositeExample'
mkdir $parentModulePath
New-ModuleManifest –Path "$parentModulePath\CompositeExample.psd1"
$resourceModulePath = "$parentModulePath\DSCResources\CompositeResource"
mkdir $resourceModulePath
New-ModuleManifest -RootModule 'CompositeResource.schema.psm1' –Path "$resourceModulePath\CompositeResource.psd1"
Add-Content –Path "$resourceModulePath\CompositeResource.schema.psm1" –Value ''
Azure Automation then allows this to be added as a module without any errors.
I have an Azure Cloud Service Worker Role which needs a separate Windows Service installed to redirect application tracing to a centralized server. I've placed the installation binaries for this Windows Service in a Storage Account's file storage as shown below. I then have my startup task call a batch file, which in turn executes a power-shell script to retrieve the file and install the service
When Azure deploys a new instance of the role, the script execution fails with the following error:
Cannot find path
'\\{name}.file.core.windows.net\utilities\slab1-1.zip' because it does
not exist
However, when I run the script after connecting through RDP, all is fine. Does anybody know why this might be happening? Here is the script below...
cmdkey /add:$storageAccountName.file.core.windows.net /user:$shareUser /pass:$shareAccessKey
net use * \\$storageAccountName.file.core.windows.net\utilities
mkdir slab
copy \\$storageAccountName.file.core.windows.net\utilities\$package .\slab\$package
I always have problem here and there by using a script to access the mounted azure file drive. I believe this is more or less related to the drive is mounted only for the current user and may not always work the same when called from a script.
I ended up pulling files from azure file the hard way without network drive.
$source= $stroageAccountName
$sourceKey = $shareAccessKey
$sharename = "utilities"
$package = "slab1-1.zip"
$dest = ".\slab\" + $package
#Define Azure file share root
$ctx=New-AzureStorageContext $source $sourceKey
$share = get-AzureStorageShare $sharename -Context $ctx
Get-AzureStorageFileContent -share $share -Destination $dest -Path $package -confirm:$false
Code example here will get you a good start:
https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/
It would be harder to manage if you have more complex folder structure, but objects there are CloudFileDirectory and CloudFile, property and methods there works seamlessly for me in powershell 4.0
*Azure Powershell module is required for 'Get-AzureStorageFileContent' cmdlet
I use powershell to download a blob from blobstorage in an Azure startup task. I updated Microsoft.WindowsAzure.Storage library today from 3.0.3.0 to 4.0.1.0 via NuGet.
After the library update files are still downloaded correctly but I get same sort of warning in command window:
'Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.'
function download_from_storage ($container, $blob, $connection, $destination) {
Add-Type -Path ((Get-Location).Path + '\Microsoft.WindowsAzure.Storage.dll')
$storageAccount = [Microsoft.WindowsAzure.Storage.CloudStorageAccount]::Parse($connection)
$blobClient = New-Object Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient($storageAccount.BlobEndpoint, $storageAccount.Credentials)
$container = $blobClient.GetContainerReference($container)
$remoteBlob = $container.GetBlockBlobReference($blob)
$remoteBlob.DownloadToFile($destination + "\" + $blob, [System.IO.FileMode]::OpenOrCreate)
}
$connection_string = 'DefaultEndpointsProtocol=https;AccountName=<AcountName>;AccountKey=<Accountkey>'
# JRE
$jre = 'jre-7u60-windows-x64.exe'
$node = 'node-v0.10.29-x64.msi'
download_from_storage 'java-runtime' $jre $connection_string (Get-Location).Path
download_from_storage 'nodejs' $node $connection_string (Get-Location).Path
Since it is still working I am just clueless why the message occurs in the first place.
This is not exactly an answer to your question but here is a much simpler way of downloading files from blob storage:
$dlPath = "C:\temp\"
$container = "BlobContainer"
Set-AzureSubscription "NameOfYourSubscription" -CurrentStorageAccount "storageAccountName"
Get-AzureStorageContainer $container | Get-AzureStorageBlob |
Get-AzureStorageBlobContent -Destination $container
You can do this by installing Azure PowerShell itself in the startup task and then execute the download Azure blob cmdlet. Here are rouphly the steps
Installing Azure PowerShell automatically
Create new service project (New-AzureServiceProject)
Execute Add-AzureWebRole
Change the cscfg to use osFamily=3 (to use new PS version which is compatible with Azure PS)
Copy Azure PowerShell MSI under WebRole1\bin directory
Edit WebRole1\startup.cmd to include this line msiexec /i AzurePowerShell.msi /quiet
Authenticating Azure PowerShell so it can execute cmdlets (if you want to use storage cmdlets only you can ignore this step and pass your storage key/name when executing the Get-AzureStorageBlobContent cmdlet)
Copy a latest publish settings file (myPublishSettings.publishsettings) inside WebRole1\bin folder
Edit WebRole1\startup.cmd to include this line after the one added before: PowerShell.exe –Command “Import-AzurePublishSettingsFile .\myPublishSettings.publishsettings)