Public Containers in Storage Accounts - azure

First post. My Powershell knowledge isnt great. I am trying to list out all containers that have the "PublicAccess" attribute set to On. I am trying to use the script provided by MS.
$rgName = "<Resource Group name>"
$accountName = "<Storage Account Name>"
$storageAccount = Get-AzStorageAccount -ResourceGroupName $rgName -Name $accountName
$ctx = $storageAccount.Context
Get-AzStorageContainer -Context $ctx | Select Name, PublicAccess
However I need to do this on a large amount of storage accounts. In the past I have used "foreach($item in $list)" to pass things into a small script. But never for multiple lists. Can anyone help?

Based off your extended requirements in the comments, this should work. (I've not tested it and not handled any potential errors related to permissions or anything else)
# Create a collection for the items found.
$StorageAccounts = [System.Collections.Generic.List[System.Object]] #{}
# Loop through the available Azure contexts.
foreach ($Context in (Get-AzContext -ListAvailable)) {
# Set each subscription in turn, voiding the output.
[System.Void](Set-AzContext -Context $Context)
# Create an object with the container name, public access values and the name of the storage account/subscription.
$StorageAccountInfo = Get-AZStorageAccount | Get-AzStorageContainer | Select-Object Name, PublicAccess, #{l = "StorageAccountName"; e = { $_.Context.StorageAccountName } }, #{l = "Subscription"; e = { $Context.Subscription.Name } }
# If there is data found, add it to the collection.
if ($null -ne $StorageAccountInfo) {
$StorageAccounts.AddRange($StorageAccountInfo)
}
}
# Export the collected information to Csv.
$StorageAccounts | Export-Csv -Path .\myStorageAccounts.csv -NoClobber -Encoding utf8

Related

List all Storage Accounts and containers in Aure w/Powershell

I am a novice at Powershell. I have been tasked with listing all storage accounts, along with all the underlying containers, for one of our Azure subscriptions. So I looked to see if a script existed, but couldn't find one. I then set about heavily modifying one that was originally for something different. Figured it would be a good learning exercise.
So what I am wanting my script to do is to work through the subscription, spit out all the storage accounts, and then go through each storage account to list all the containers within them. There are dozens of accounts to go through, each with multiple containers. Once done, throw it into a formatted CSV.
So far I can get the script to output the storage accounts, but nothing more than that. I am running this on my own test environment before hitting the live one, just in case.
Hoping that someone can throw some pointers as to what I'm doing wrong.
Script as below:
##################################################
# Gather storage account information
# across all subscriptions
##################################################
Write-Host "Gathering storage account information...`n"
[System.Collections.ArrayList]$saUsage = New-Object -TypeName System.Collections.ArrayList
# Loop through each subscription
foreach ($subscriptionId in $SubscriptionIDs) {
# Set context to the subscription
Select-AzSubscription -SubscriptionId $subscriptionID | Out-Null
$context = Get-AzContext
Write-Host "The subscription context is set to: $($context.Name)`n"
$storageAccounts = Get-AzResource -ResourceType 'Microsoft.Storage/storageAccounts'
$containers = Get-AzResource -ResourceType
'Microsoft.Storage/storageAccounts/blobServices/containers'
}
# Check the account can access storage accounts within the subscription
if (!$storageAccounts) {
Write-Host -ForegroundColor Red "Account '$($context.Account.Id)' does not have access to any
storage accounts in subscription '$($context.Name)'"
$storageAccounts | Format-Table StorageAccountName, ResourceGroupName, Location
continue
}
Write-Host "Progress Status:"
[int]$i = 1
Loop through each storage account and gather usage information
foreach ($storageAccount in $storageAccounts) {
Write-Host "[$i of $($storageAccounts.Count)] $($storageAccount.Name)"
$i++
Gather storage account details and store as a PS custom object
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $container.containerName
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
foreach($container in $storageAccount.BlobContainersOperationsExtensions.get) {
if($container.containerName) {
# Gather storage account container details and store as a PS custom object
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $container.containerName
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
# Output storage account usage results to .CSV
if($saUsage) {
# Output to CSV
$saUsage | Export-Csv -Path $SAOutputPath -NoTypeInformation
Write-Output "`nExported storage account usage report at $SAOutputPath`n"
}
Regarding the issue, please refer to the following script
$context = Get-AzContext
$storageAccounts = Get-AzResource -ResourceType 'Microsoft.Storage/storageAccounts'
[System.Collections.ArrayList]$saUsage = New-Object -TypeName System.Collections.ArrayList
foreach ($storageAccount in $storageAccounts) {
#list containers
$conatiners= Get-AzRmStorageContainer -ResourceGroupName $storageAccount.ResourceGroupName -StorageAccountName $storageAccount.Name
if($conatiners -ne $null){
foreach($container in $conatiners){
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $container.Name
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
}else{
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $null
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
}
$saUsage | Export-Csv -Path e:\test.csv -NoTypeInformation

How to get list of Azure container files?

I'm working on PS script to list all Storage Accounts, which contains files with a modified date less than < X.
I'm able to list all SA containers, it's not a big deal but I'm not sure how to get further and list all files inside a particular container.
$storageAccCtx = (Get-AzStorageAccount -Name acc_name -ResourceGroupName acc_rg).Context
Get-AzStorageContainer -Context $storageAccCtx
I couldn't find any cmdlet for this.
Could anyone, please, advise what should I use next? Thanks.
Once you have the StorageContext, you can use this below Azure Storage Management Cmdlet to list all BlockBlob.
Get-AzStorageBlob -Container containerName -Context $storageAccCtx
To get list of all Azure Storage Management Cmdlet, please follow this documentation https://learn.microsoft.com/en-us/powershell/module/az.storage/?view=azps-4.8.0
You can use Get-AzStorageBlob to list the blobs in a storage container, the cmdlet is documented here. In a script you could use this cmdlet as follows to return all the blobs older than a particular date:
$CutOffDate = Get-Date -Year 2020 -Month 10 -Day 19
$OldBlobs = #()
$StorageAccounts = Get-AzStorageAccount
foreach ($StorageAccount in $StorageAccounts) {
$Containers = Get-AzStorageContainer -Context $StorageAccount.Context
foreach ($Container in $Containers) {
$ContainerBlobs = Get-AzStorageBlob -Container $Container.Name -Context $StorageAccount.Context
$OldBlobs += $ContainerBlobs | Where-Object { $_.LastModified -lt $CutOffDate }
}
}
$OldBlobs

How to get the list of azure servers having Auto-Shutdown disabled using PowerShell?

I want to get the list of azure servers having auto-shutdown disabled on them, I have the below script but the issue with the script is that it gets the list of RG's under the Subscription GUID but repeats the output after every loop.
Import-AzureRmContext -Path "$PSScriptRoot\AzureProfile.json"
Select-AzureRmSubscription -SubscriptionId {subscriptionId}
[array]$ResourceGroupArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId
foreach ($resourceGroup in $ResourceGroupArray){
$targetResourceId = (Get-AzureRmVM -ResourceGroupName $resourcegroup.ResourceGroupName -Name $resourceGroup.Name).Id
$shutdownInformation = (Get-AzureRmResource -ResourceGroupName $resourcegroup.ResourceGroupName -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
Write-Host "ID: " $targetResourceId
$shutdownInformation
The output for each VM is displayed in the following format,
What I want is simple, I want the VM name and its status of Auto-shutdown to be displayed on the screen so that its easy for me to find out which all VM have auto-shutdown currently disabled on them.
Any help related to this would be helpful.
You just need to get the microsoft.devtestlab/schedules resource ID using:
/subscriptions/{subscriptionId}/resourceGroups/{rgName}/providers/microsoft.devtestlab/schedules/shutdown-computevm-{vmName}
Then iterate over all your VMs using Get-AzVM, Get the microsoft.devtestlab/schedules resource using Get-AzResource, then output VM name and status into a table using Format-Table.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzVM) {
try {
$shutdownResource = Get-AzResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
To set the context to the correct subscription, we can use Set-AzContext.
The above however is using the latest Az modules. You can do the same using the equivalent AzureRm modules.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzureRmContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzureRmVM) {
try {
$shutdownResource = Get-AzureRmResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
Although I do recommend moving to the Az module since support for AzureRm is ending December 2020. You can read the documentation for more information about this.
The above code should give you an output similar to the following
VMName ShutdownStatus
------ --------------
vm1 Enabled
vm2 Disabled
Update
The Call operator & is used here to run the for loop as a script block. You can read more about this in about_Script_Blocks.
Try something like this to get the auto-shutdown status of all VMs. Instead of trying to get the schedules inside the loop, get all the ones in the subscription and match them based on the VM's full resource Id.
[array]$VMArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId, Id
$ShutdownInformation = (Get-AzureRmResource -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
foreach($vm in $VMArray) {
$ShutdownStatus = "Not Configured"
$Schedule = $ShutdownInformation | Where-Object { $_.targetResourceId -eq $vm.Id } | Select -First 1
if($Schedule -ne $null) {
$ShutdownStatus = $Schedule.status
}
Write-Host $vm.VmId $ShutdownStatus
}

Passing multiple Parameters in single Azure Storage Script for various environments

I have a powershell script that creates the storage and blob account for a given subscription that works fine . Subscription Name, resource group keeps changing for different environments like DEV,UAT,PROD
STRUCTURE OF MY TEMPLATE / CODE :
param(
[string] $subscriptionName ="ABC",
[string] $resourceGroupName = "XYZ",
[string] $resourceGroupLocation ="westus",
[string] $templateFilePath = "template.json",
[string] $parametersFilePath = "parameters.json"
)
Function RegisterRP {
Param(
[string]$ResourceProviderNamespace
)
Write-Host "Registering resource provider '$ResourceProviderNamespace'";
Register-AzureRmResourceProvider -ProviderNamespace $ResourceProviderNamespace;
}
$ErrorActionPreference = "Stop"
$confirmExecution = Read-Host -Prompt "Hit Enter to continue."
if($confirmExecution -ne '') {
Write-Host "Script was stopped by user." -ForegroundColor Yellow
exit
}
# sign in
Write-Host "Logging in...";
Login-AzureRmAccount;
# select subscription
Write-Host "Selecting subscription '$subscriptionName'";
Select-AzureRmSubscription -SubscriptionName $subscriptionName;
# Register RPs
$resourceProviders = #("microsoft.storage");
if($resourceProviders.length) {
Write-Host "Registering resource providers"
foreach($resourceProvider in $resourceProviders) {
RegisterRP($resourceProvider);
}
}
#Create or check for existing resource group
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
if(!$resourceGroup)
{
Write-Host "Resource group '$resourceGroupName' does not exist. To create a new resource group, please enter a location.";
if(!$resourceGroupLocation) {
$resourceGroupLocation = Read-Host "resourceGroupLocation";
}
Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
New-AzureRmResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
}
else{
Write-Host "Using existing resource group '$resourceGroupName'";
}
# Start the deployment
Write-Host "Starting deployment...";
if(Test-Path $parametersFilePath) {
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath -storageAccounts_name $storageAccountName
} else {
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName -TemplateFile $templateFilePath; -storageAccounts_name $storageAccountName
}
Approach 1 :
Created multiple powershell scripts for each denvironment
Created 1 Menu Based powershell script that calls the other script and executes like : Select 1 for Dev , 2 for UAt , 3 for PROD , this approach works but is not effective .
Approach 2 :
I would like to combine all scripts and just have one script for all environments and based on select should allow me to create the storage accounts. Only Subscription and resource group change rest all structure of the powershell remains same .
I tried using GET function commandlets and it selects but still throws the error
[string] $subscriptionName = Get-AzureSubscription,
[string] $resourceGroupName = Get-AzureRmLocation,
If i try to use it using an array based approach like passing the values as below im unable to understand how do i pass these array based values to the code and get it to work .
$environment=#('DEV','TEST','QA','PROD')
$resourcegroupname = #('test','test1','test2','test3')
$subscriptionName = #('devsub1','devsub2','test3','prod4')
I'm trying to call the functions using :
$environment[0]
$subscriptionName[0]
It returns the value as below if i execute it seperately but how do i pass these values to my script to create storage account ?
DEV
devsub1
Requesting expert help if anyone has come across such scenarios earlier and if you can help in changing the above code and provide a tested code that would be of great help.
APPROACH 3:
$subscription = #(Get-AzureRmSubscription)
$resourcegroup = #(Get-AzureRmResourceGroup)
$Environment = #('DEV','TEST','QA','PROD')
$resourceGroupName = $resourcegroup | Out-GridView -PassThru -Title 'Pick the environment'
$subscriptionName = $subscription | Out-GridView -PassThru -Title 'Pick the subscription'
Write-Host "Subscription:" $subscriptionName
Write-Host "ResourceGroup:" $resourcegroup
OUTPUT :
If you look at resource group it fails to give the selection option for resource group .
Subscription: < it returns the subscription name >
ResourceGroup: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup Microsoft.Azure.Commands.ResourceManager.Cmd
lets.SdkModels.PSResourceGroup Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup Microsoft.Azure.Commands.Res
ourceManager.Cmdlets.SdkModels.PSResourceGroup
What you are proposing is an interesting approach. I would likely an input parameter that defines which environment the work will be done in, and then have a conditional block that sets the dynamic variables for that environment. There would be some duplication of initialization code for each environment, but the main code block would still be unified.

Foreach loop for listing unmanaged disks in Azure

It's very easy to list azure managed disks in PS, but unmanaged ones are very tricky to list, as they're not objects from azure POV. I tried to wrote foreach loop to list me all unamanged disks (i.e. *.vhd files) for each storage account. This is the code I wrote:
$StorageAccounts = Get-AzureRmStorageAccount
$sa = $StorageAccounts | foreach-object {
#Get the Management key for the storage account
$key1 = (Get-AzureRmStorageAccountKey -ResourceGroupName $_.ResourceGroupName -name $_.StorageAccountName)[0].value
#Get the Storage Context to access the Storage Container
$storageContext = New-AzureStorageContext -StorageAccountName $_.StorageAccountName -StorageAccountKey $key1
#Get the Storage Container in the Variable
$storageContainer = Get-AzureStorageContainer -Context $storageContext
$blob = Get-AzureStorageBlob -Container $storageContainer.name -Context $storageContext
[PSCustomObject]#{
"Name" = $blob.Name
"Length" = $blob.Length
"Storage Account Name" = $_.StorageAccountName
}
}
I want the loop to fetch all the vhd's for each storageaccount and parse it into pscustomobject to list me all vhd*s from all storage accounts, but I get an error:
Get-AzureStorageBlob : Cannot validate argument on parameter
'Container'. The argument is null or empty. Provide an argument that
is not null or empty, and then try the command again. At line:13
char:41
Get-AzureStorageBlob : Cannot convert 'System.Object[]' to the type
'System.String' required by parameter 'Container'. Specified method is not > supported.
At line:13 char:41
Why loop is not parsing data to $storageContainer in line 11? I can see what's inside other two vars like $key1 and $storageContext.
you can rewrite your script in this fashion:
$StorageAccounts = Get-AzureRmStorageAccount
$StorageAccounts.foreach{
$ctx = $_.Context
$containers = Get-AzureStorageContainer -Context $ctx
$containers.foreach{
$blobs = Get-AzureStorageBlob -Container $_.name -Context $ctx
$blobs.foreach{
do_something
}
}
}
you dont need to get keys to construct context, because storage account variable contains the context. and then you need to iterate containers and blobs

Resources